鸿蒙媒体开发系列05——音频并发播放管理与音量管理

news2024/9/20 1:53:55

 如果你也对鸿蒙开发感兴趣,加入“Harmony自习室”吧!扫描下方名片,关注公众号,公众号更新更快,同时也有更多学习资料和技术讨论群。

1、多音频播放的并发管理

多音频并发,即多个音频流同时播放。此场景下,如果系统不加管控,会造成多个音频流混音播放,容易让用户感到嘈杂,造成不好的用户体验。

1.1、音频打断策略

为了解决多个音频同时播放导致的混音混乱问题,系统预设了音频打断策略,对多音频播放的并发进行管控,只有持有音频焦点的音频流才可以正常播放,避免多个音频流无序并发播放的现象出现。

当应用开始播放音频时,系统首先为相应的音频流申请音频焦点,获得焦点的音频流可以播放;若焦点申请被拒绝,则不能播放。

在音频流播放的过程中,若被其他音频流打断,则会失去音频焦点。当音频流失去音频焦点时,只能暂停播放。

在应用播放音频的过程中,这些动作均由系统自行完成,无需应用主动触发。但为了维持应用和系统的状态一致性,保证良好的用户体验,最好我们主动监听音频打断事件,并在收到音频打断事件(InterruptEvent)时做出相应处理。

音频打断策略预设了两种焦点模式(共享焦点模式、独立焦点模式),针对同一应用创建的多个音频流,应用可通过设置焦点模式,选择由应用自主管控或由系统统一管控。

音频打断策略决定了应该对音频流采取何种操作,如暂停播放、继续播放、降低音量播放、恢复音量播放等,这些操作可能由系统或应用来执行。音频打断策略预置了两种打断类型(强制打断类型、共享打断类型),用于区分音频打断事件(InterruptEvent)的执行者。

👉🏻 焦点模式介绍

音频打断策略预设了两种焦点模式(InterruptMode):

  • 共享焦点模式(SHARE_MODE):由同一应用创建的多个音频流,共享一个音频焦点。这些音频流之间的并发规则由应用自主决定,音频打断策略不会介入。当其他应用创建的音频流与该应用的音频流并发播放时,才会触发音频打断策略的管控。

  • 独立焦点模式(INDEPENDENT_MODE):应用创建的每一个音频流均会独立拥有一个音频焦点,当多个音频流并发播放时,会触发音频打断策略的管控。

应用可以按需选择合适的焦点模式,在创建音频流时,系统默认采用共享焦点模式,应用可主动设置所需的模式。

设置焦点模式的方法:

  • 若使用AVPlayer开发音频播放功能,则可以通过修改AVPlayer的audioInterruptMode属性进行设置

import media from '@ohos.multimedia.media';// ....let avPlayer: media.AVPlayer | undefined = undefined;const player = media.createAVPlayer((error, video) => {  if (video != null) {    avPlayer = video;    avPlayer.audioInterruptMode = 0; // 共享焦点模式    avPlayer.audioInterruptMode = 1; // 独立焦点模式    console.info('createAVPlayer success');  } else {    console.error(`createAVPlayer fail, error message:${error.message}`);  }});// ....
  • 若使用AudioRenderer开发音频播放功能,则可以调用AudioRenderer的setInterruptMode函数进行设置,设置方式和AVPlayer类似,这里不再贴代码。

👉🏻 打断类型介绍

音频打断策略(包括两种焦点模式)决定了应该对各个音频流采取何种操作,如暂停播放、继续播放、降低音量播放、恢复音量播放等。而针对这些操作的执行过程,根据执行者的不同,可以分为两种打断类型(InterruptForceType):

  • 强制打断类型(INTERRUPT_FORCE):由系统进行操作,强制打断音频播放。

  • 共享打断类型(INTERRUPT_SHARE):由应用进行操作,可以选择打断或忽略。

对于音频打断策略的执行,系统默认采用强制打断类型(INTERRUPT_FORCE),应用无法更改。但对于一些策略(如继续播放等),系统无法强制执行,所以这两种打断类型均可能出现。应用可根据音频打断事件(InterruptEvent)的成员变量forceType的值,获取该事件采用的打断类型。

在应用播放音频的过程中,系统自动为音频流执行申请焦点、持有焦点、释放焦点等动作,当发生音频打断事件时,系统强制对音频流执行暂停、停止、降低音量、恢复音量等操作,并向应用发送音频打断事件(InterruptEvent)回调。由于系统会强制改变音频流状态,为了维持应用和系统的状态一致性,保证良好的用户体验,推荐应用监听音频打断事件,并在收到音频打断事件(InterruptEvent)时做出相应处理。

对于一些系统无法强制执行的操作(例如音频流继续播放的场景),会向应用发送包含了共享打断类型的音频打断事件,由应用自行执行相应操作,此时应用可以选择执行或忽略,系统不会干涉。

1.2、监听音频打断事件

在应用播放音频时,我们一般会监听音频打断事件,当音频打断事件发生时,系统会根据预设策略,对音频流做出相应的操作,并针对状态发生改变的音频流,向所属的应用发送音频打断事件。

应用收到音频打断事件后,需根据其内容提示,做出相应的处理,避免出现应用状态与预期效果不一致的问题。

监听音频打断事件的方法:

  • 若使用AVPlayer开发音频播放功能,则可以调用AVPlayer的on('audioInterrupt')函数进行监听,当收到音频打断事件(InterruptEvent)时,应用需根据其内容,做出相应的调整。

  • 若使用AudioRenderer开发音频播放功能,则可以调用AudioRenderer的on('audioInterrupt')函数进行监听,当收到音频打断事件(InterruptEvent)时,应用需根据其内容,做出相应的调整。

为了带给用户更好的体验,针对不同的音频打断事件内容,应用需要做出相应的处理操作。

这里我们使用AudioRenderer开发音频播放功能为例(若使用AVPlayer开发音频播放功能,处理方法类似),我们可结合实际情况编写,处理方法可以自行调整。代码如下:

let isPlay; // 是否正在播放,实际开发中,对应与音频播放状态相关的模块let isDucked; //是否降低音量,实际开发中,对应与音频音量相关的模块let started; // 标识符,记录“开始播放(start)”操作是否成功async function onAudioInterrupt(){  // 此处以使用AudioRenderer开发音频播放功能举例,变量audioRenderer即为播放时创建的AudioRenderer实例。  audioRenderer.on('audioInterrupt', async(interruptEvent) => {    // 在发生音频打断事件时,audioRenderer收到interruptEvent回调,此处根据其内容做相应处理    // 先读取interruptEvent.forceType的类型,判断系统是否已强制执行相应操作    // 再读取interruptEvent.hintType的类型,做出相应的处理    if (interruptEvent.forceType === audio.InterruptForceType.INTERRUPT_FORCE) {      // 强制打断类型(INTERRUPT_FORCE):音频相关处理已由系统执行,应用需更新自身状态,做相应调整       switch (interruptEvent.hintType) {        case audio.InterruptHint.INTERRUPT_HINT_PAUSE:          // 此分支表示系统已将音频流暂停(临时失去焦点),为保持状态一致,应用需切换至音频暂停状态          // 临时失去焦点:待其他音频流释放音频焦点后,本音频流会收到resume对应的音频打断事件,到时可自行继续播放          isPlay = false; // 此句为简化处理,代表应用切换至音频暂停状态的若干操作          break;        case audio.InterruptHint.INTERRUPT_HINT_STOP:          // 此分支表示系统已将音频流停止(永久失去焦点),为保持状态一致,应用需切换至音频暂停状态          // 永久失去焦点:后续不会再收到任何音频打断事件,若想恢复播放,需要用户主动触发。          isPlay = false; // 此句为简化处理,代表应用切换至音频暂停状态的若干操作          break;        case audio.InterruptHint.INTERRUPT_HINT_DUCK:          // 此分支表示系统已将音频音量降低(默认降到正常音量的20%),为保持状态一致,应用需切换至降低音量播放状态          // 若应用不接受降低音量播放,可在此处选择其他处理方式,如主动暂停等          isDucked = true; // 此句为简化处理,代表应用切换至降低音量播放状态的若干操作          break;        case audio.InterruptHint.INTERRUPT_HINT_UNDUCK:          // 此分支表示系统已将音频音量恢复正常,为保持状态一致,应用需切换至正常音量播放状态          isDucked = false; // 此句为简化处理,代表应用切换至正常音量播放状态的若干操作          break;        default:          break;      }    } else if (interruptEvent.forceType === audio.InterruptForceType.INTERRUPT_SHARE) {      // 共享打断类型(INTERRUPT_SHARE):应用可自主选择执行相关操作或忽略音频打断事件      switch (interruptEvent.hintType) {        case audio.InterruptHint.INTERRUPT_HINT_RESUME:          // 此分支表示临时失去焦点后被暂停的音频流此时可以继续播放,建议应用继续播放,切换至音频播放状态          // 若应用此时不想继续播放,可以忽略此音频打断事件,不进行处理即可          // 继续播放,此处主动执行start(),以标识符变量started记录start()的执行结果          await audioRenderer.start().then(async function () {            started = true; // start()执行成功          }).catch((err) => {            started = false; // start()执行失败          });          // 若start()执行成功,则切换至音频播放状态          if (started) {            isPlay = true; // 此句为简化处理,代表应用切换至音频播放状态的若干操作          } else {            // 音频继续播放执行失败          }          break;        default:          break;      }   }  });}

2、播放音量管理

播放音量的管理主要包括对系统音量的管理和对音频流音量的管理。系统音量与音频流音量分别是指HarmonyOS系统的总音量和指定音频流的音量,其中音频流音量的大小受制于系统音量,管理两者的接口不同。

2.1、系统音量

管理系统音量的接口是AudioVolumeManager,在使用之前,需要使用getVolumeManager()获取AudioVolumeManager实例。目前该接口只能获取音量信息及监听音量变化,不能主动调节系统音量。​​​​​​​

import audio from '@ohos.multimedia.audio';let audioManager = audio.getAudioManager();let audioVolumeManager = audioManager.getVolumeManager();

另外,通过设置监听事件,可以监听系统音量的变化:​​​​​​​

audioVolumeManager.on('volumeChange', (volumeEvent) => {  console.info(`VolumeType of stream: ${volumeEvent.volumeType} `);  console.info(`Volume level: ${volumeEvent.volume} `);  console.info(`Whether to updateUI: ${volumeEvent.updateUi} `);});

2.2、音频流音量

管理音频流音量的接口是AVPlayer或AudioRenderer的setVolume()方法,使用AVPlayer设置音频流音量的示例代码如下:​​​​​​​

let volume = 1.0  // 指定的音量大小,取值范围为[0.00-1.00],1表示最大音量avPlayer.setVolume(volume)

使用AudioRenderer设置音频流音量的示例代码如下:​​​​​​​

audioRenderer.setVolume(0.5).then(data=>{  // 音量范围为[0.0-1.0]  console.info('Invoke setVolume succeeded.');}).catch((err) => {    console.error(`Invoke setVolume failed, code is ${err.code}, message is ${err.message}`);});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2147564.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GAMES104:15 游戏引擎的玩法系统基础-学习笔记

文章目录 0,游戏性课程框架一,事件机制1.1 事件的定义1.2 callback的注册1.3 事件的分发系统 二,游戏逻辑与脚本系统2.1 特点和常见脚本语言2.2 脚本语言的GO管理2.3 脚本语言的架构2.4 可视化脚本 三,Gameplay 开发中的3C &#…

关雅荻发文批评某脱口秀节目审核问题:为博流量乱搞事情?

最近,针对某脱口秀节目中引发的网络舆情,电影制片人关雅荻发文严厉批评该视频平台的审核问题,指出“这家视频网站对应的节目审核环节严重失职,或者有意渎职,这个脱口秀节目制作方在自己内容策划和制作也有明显失职、严…

一招有效清理宠物浮毛,养宠搭子——质量好的宠物空气净化器推荐

害,好不容易毕业找到了工作进入社会,我以为可以自己决定事情了,结果上周又被我妈臭骂一通。因为我瞒着他们养猫了,他们来看我的时候才知道,说我刚出来养活自己都够呛,哪里还能照顾猫。在我好说歹说下&#…

数字电路与逻辑设计-触发器功能测试及其应用

一、实验目的 1.验证基本RS、JK、D、T和T’触发器的逻辑功能及使用方法; 2.能进行触发器之间的相互转换; 3.学习触发器的一些应用。 二、实验原理 触发器具有两个能够自行保持的稳定状态,用以表示逻辑状…

使用llama.cpp 在推理MiniCPM-1.2B模型

llama.cpp 是一个开源项目,它允许用户在C中实现与LLaMA(Large Language Model Meta AI)模型的交互。LLaMA模型是由Meta Platforms开发的一种大型语言模型,虽然llama.cpp本身并不包含LLaMA模型的训练代码或模型权重,但它…

vmware中的ubuntu系统扩容分区

1.虚拟机关机 右击虚拟机/设置,进入虚拟机设置 3.启动虚拟机,进入命令行 4.fdisk -l查看要扩展的分区名 5.resize要扩容的分区 su root parted /dev/sda resizepart 3 100% fdisk -l resize2fs /dev/sda3 df -T完成 6.其他 进入磁盘管理 fdisk /d…

MYSQL解说

MySQL是一个流行的开源关系型数据库管理系统(RDBMS),广泛用于网站和应用程序的后端数据存储。 MySQL的基础知识: 1. 数据库和表 数据库(Database):存储数据的逻辑容器。表(Table&…

JAVA——打印流

目录 一、printStream 二、printWriter 三、打印流的应用——输出重定向 输出语句重定向的意义 一、printStream 1. 作用: 打印流可以实现更方便、更高效的打印数据出去 跟着黑马实现一下:printStream 的底层实现效率更高,println输什么…

关于实时数仓的几点技术分享

一、实时数仓建设背景 业务需求的变化:随着互联网和移动互联网的快速发展,企业的业务需求变得越来越复杂和多样化,对数据处理的速度和质量要求也越来越高。传统的T1数据处理模式已经无法满足企业的需求,实时数据处理成为了一种必…

floodfill+DFS(2)

文章目录 太平洋大西洋流水问题扫雷游戏迷路的机器人 太平洋大西洋流水问题 class Solution { public:vector<vector<int>> res;int m 0, n 0;vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {m heights.size…

35.贪心算法2

1.按身高排序&#xff08;easy&#xff09; 2418. 按身高排序 - 力扣&#xff08;LeetCode&#xff09; 题目解析 算法原理 代码 class Solution {public String[] sortPeople(String[] names, int[] heights) {// 1. 创建⼀个下标数组int n names.length;Integer[] index …

tair性能挑战赛攻略心得-Zzzzz

关联比赛: 第二届数据库大赛—Tair性能挑战 赛题分析 赛题要求实现一个基于persistent memory&#xff08;AEP&#xff09;的持久化键值存储系统&#xff0c;并要求从数据正确性和系统读写性能两个方面来考虑系统设计。 正确性 数据正确性包括数据写入的持久性和原子性两个…

计算机三级网络技术总结(五)

HTTP端口号为80 三平台一出口&#xff1a;网络平台、业务平台、管理平台和城市宽带出口IEEE802.16最高传输速率为134Mbps链路状态数据库中保存的是全网的拓扑结构图&#xff0c;而非全网完整的路由表在无线局域网中&#xff0c;客户端设备用来访问接入点&#xff08;AP&#xf…

MySQL 中的索引覆盖扫描:加速查询的秘密武器

在 MySQL 数据库的使用中&#xff0c;索引是提高查询性能的重要工具。而索引覆盖扫描&#xff08;Index Covering Scan&#xff09;更是一种能显著提升查询效率的技术。本篇文章我们就来深入了解一下 MySQL 中的索引覆盖扫描是什么。 一、什么是索引覆盖扫描 在 MySQL 中&…

将有序数组——>二叉搜索树

给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵平衡二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#xff1a;[0,-10,5,null,-3,null,9] 也将被视为正确答案…

Python编码系列—Python桥接模式:连接抽象与实现的桥梁

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

【C语言二级考试】循环结构设计

C语言二级考试——循环结构程序设计 五.循环结构程序设计 1.for循环结构 2.while和do-while循环结构 3.continue语句和break语句 4.循环的嵌套 知识点参考【C语言】循环-CSDN博客 文章目录 1.for循环2.while和do-while循环结构3.continue语句和break语句4.循环的嵌套 1.for循环…

ORA-28032 Your password has expired and the database is set to read only

做个记录。 non-cdb 处于只读状态&#xff0c;CDB创建到noncdb的dblink后产生的报错&#xff0c;dblink可以成功创建&#xff0c;但无法连接到non-cdb。 解决&#xff1a;一开始以为是cdb的密码不正确&#xff0c;mos上找到问题&#xff0c;non-cdb的密码过期了&#xff0c;并且…

m4a怎么转换mp3格式?给你推荐八种m4a转MP3的转换方法

m4a怎么转换mp3格式&#xff1f;在数字音乐的世界中&#xff0c;音频格式的多样性常常让人感到困惑。m4a作为一种流行的音频格式&#xff0c;以其优良的音质和较小的文件体积受到许多用户的青睐&#xff0c;尤其是在苹果设备上。然而&#xff0c;尽管m4a文件在现代设备中表现良…

软件设计画图,流程图、甘特图、时间轴图、系统架构图、网络拓扑图、E-R图、思维导图

目录 一、流程图 二、甘特图 三、时间轴图 四、系统架构图 五、网络拓扑图 六、E-R图 七、思维导图 一、流程图 是一种用符号表示算法、工作流或流程的图形。用不同的图形表示不同含义&#xff0c;如椭圆表示开始和结束、菱形表示判断等。 画图工具WPS office 应用市场…