零基础入门多媒体音频(2)-音频焦点

说明:非全职写手,整个系列内容的顺序可能不是循序渐进,后期考虑调整。目前优先编写熟练度高以及最近工作中用到的的技术。

在音频领域的开发中,音频焦点是个很重要的概念。在面试中也是个高频话题。通过音频焦点的引入,可以实现多个应用对音频硬件资源的协同使用。(广义地讲,这里的应用也可以扩展到音频源,也就是我们经常看到的audio source。音频源顾名思义,就是可以不断提供音频数据的节点)

音频焦点代表音频应用对音频硬件资源的使用权。当多个应用需要使用音频硬件进行播放时,系统将根据播控矩阵进行硬件资源的分配以及对各个应用的相应处理。拥有音频焦点的程序才能按照预期进行播放。其他应用则需要根据策略进行对应的动作,比如暂停,降低音量,增加音量,退出播放。

我们先讲解android的音频焦点实现,然后再看看怎么在linux系统实现一套类似的系统。

Android音频焦点主要分为以下四种类型:

AUDIOFOCUS_GAIN:这是永久性的音频焦点。当应用程序获得这种焦点时,它表示该应用程序获得了独占性的音频焦点,可以播放长时间的音频,例如音乐播放器。
AUDIOFOCUS_GAIN_TRANSIENT:这是暂时性的音频焦点。当应用程序获得这种焦点时,它表示该应用程序获得了短暂的音频焦点,可以播放短暂的音频,例如提示音或导航指示音。
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:这是请求附带“降低音量”的暂时性焦点。当应用程序获得这种焦点时,它只希望在短时间内播放音频,并允许前一个持有焦点的应用在降低其音量输出的情况下继续播放。这特别适合于语音导航、语音助手的场景使用。
AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:这是另一种暂时性的音频焦点,但它在获得焦点时,不希望系统播放任何其他音频。这种焦点类型常用于录音或者需要做语音识别的场景。

与获得焦点对应的是失去对应焦点。

AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
AUDIOFOCUS_LOSS
AUDIOFOCUS_LOSS_TRANSIENT ;
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK

每种音频焦点类型都有其特定的使用场景和优先级,Android系统会根据这些类型来管理和分配音频资源,确保在不同应用程序之间进行无缝的切换和管理,从而提升用户体验和设备性能。

在Android开发中,与音频焦点调用相关的接口主要集中在AudioManager类中。这些接口允许应用程序请求、放弃和监听音频焦点的变化。以下是几个关键的接口:

requestAudioFocus():
此方法用于请求音频焦点。应用程序需要创建一个AudioFocusRequest对象,并指定所需的音频焦点类型(如AUDIOFOCUS_GAIN, AUDIOFOCUS_GAIN_TRANSIENT等),然后调用此方法。系统会根据当前音频焦点的状态和请求的焦点类型来决定是否授予焦点。
abandonAudioFocus():
当应用程序不再需要音频焦点时,应调用此方法放弃焦点。这通常发生在应用程序暂停播放或退出时。放弃焦点是良好的编程实践,可以确保其他应用程序能够正常地获得和使用音频焦点。
setOnAudioFocusChangeListener():
通过此方法,应用程序可以设置一个监听器来监听音频焦点的变化。当音频焦点发生变化时(例如,其他应用程序请求或放弃焦点),系统会调用监听器的相应方法,通知应用程序焦点状态的变化。这允许应用程序根据焦点状态调整其行为,如暂停或恢复播放。

以上接口和枚举都在文件project_dir/frameworks/base/media/java/android/media/AudioManager.java
project_dir在这里指代android源码的根目录。

下面是一个音频焦点的使用示例。按照android提供接口的惯例,同样的功能会通过函数重载的方式提供不同复杂度的调用接口。一个最简单直接的接口形式是这个public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) 。durationHint就是刚刚提到的焦点类型。

import android.content.Context;  
import android.media.AudioFocusRequest;  
import android.media.AudioManager;  
import android.util.Log;  public class AudioFocusHelper {  private static final String TAG = "AudioFocusHelper";  private AudioManager audioManager;  private AudioFocusRequest.Builder focusRequestBuilder;  public AudioFocusHelper(Context context) {  audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);  focusRequestBuilder = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);  // 根据需要设置其他参数,例如音频属性  focusRequestBuilder.setAudioAttributes(  new AudioAttributes.Builder()  .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)  .setUsage(AudioAttributes.USAGE_MEDIA)  .build()  );  }  /**  * 申请音频焦点  */  public void requestAudioFocus() {  AudioFocusRequest focusRequest = focusRequestBuilder.build();  int result = audioManager.requestAudioFocus(focusRequest);  if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {  Log.d(TAG, "Audio focus granted");  // 音频焦点被授予,开始播放音频  startPlayingAudio();  } else {  Log.d(TAG, "Audio focus not granted");  // 处理未获得音频焦点的情况  }  }  /**  * 放弃音频焦点  */  public void abandonAudioFocus() {  audioManager.abandonAudioFocus(focusRequestBuilder.build());  Log.d(TAG, "Abandoned audio focus");  // 停止播放音频  stopPlayingAudio();  }  /**  * 开始播放音频  */  private void startPlayingAudio() {  // 实现音频播放的逻辑  Log.d(TAG, "Starting to play audio");  }  /**  * 停止播放音频  */  private void stopPlayingAudio() {  // 实现停止音频播放的逻辑  Log.d(TAG, "Stopping audio playback");  }  
}

分析audiofocus相关的API我们可以发现,Androidframework层用于决策音频焦点的因素有两个:1.获取音频焦点的类型,也就是上文列举的四种类型。 2.播放APK的stream类型,通俗的说就是播放场景。基于此,如果我们自己设计一个音频焦点的管理服务,也同样需要抽象出这两个要素。焦点类型+播放场景。播放场景或者说streamtype是Android音频框架中极其重要的一个概念,大家要有比较清晰的认识。

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

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

相关文章

stm32-定时器输入捕获

目录 一、输入捕获简介 二、输入捕获框图 1.定时器总框图 2.输入捕获框图 3.主从触发模式 三、固件库实现 1.定时器测量PWM频率 2.PWMI模式 一、输入捕获简介 二、输入捕获框图 1.定时器总框图 上图可知,四个输入捕获和输出比较共用4个CCR寄存器&#x…

Android SystemServer进程解析

SystemServer进程在android系统中占了举足轻重的地位,系统的所有服务和SystemUI都是由它启动。 一、SystemServer进程主函数流程 1、主函数三部曲 //frameworks/base/services/java/com/android/server/SystemServer.java /** * The main entry point from zy…

element ui el-select组件添加选项下拉加载

需求描述&#xff1a;在做搜索的时候由于有一个下拉列表接口返回数据特别多所以对列表进行了一个下拉触底加载的事件&#xff0c;但是官方文档是没有对应的api的所以自己使用指令写了一个方法。 实现代码&#xff1a; <el-selectv-model"sellerNameSearchVal"v-s…

维修SedoTreepoint染色机电脑Sedomat 1800+ 5500触摸屏控制器

染厂控制器 染厂机械触摸屏控制器 Sedomat 1808 Sedomat 1808 提供 7 英​​寸用户友好型触摸屏显示屏&#xff0c;防水等级为 IP67。它保证了恶劣环境下的高质量和可靠性。RFID阅读器提供了数据采集的可能性。内部I/O可配置以满足纱线、织物和其他类型染整机的要求。 除了这些…

代码之外的功夫:程序员精进之路 -- 阅读笔记及总结

第一章 设计原型 Ross自己也不是很明确自己的需求。——好家伙&#xff0c;太真实了。客户不能明确清晰地传递自己的需求&#xff0c;客户可能只有一个大概的目标。这时候&#xff0c;该怎么办&#xff1f; 这时候可以和客户沟通&#xff0c;先出一个草图&#xff08;线框图&…

安卓UI面试题 26-30

26. Window和DecorView是什么?DecorView又是如何和Window建立联系的?Window是 WindowManager 最顶层的视图,它负责背景(窗口背景)、Title之类的标准的UI元素, Window是一个抽 象类,整个Android系统中, PhoneWindow是 Window的唯一实现类。 至于 DecorView,它是一个顶级 …

vue+elementUI实现指定列的单元格可编辑

template中的代码如下&#xff1a; <div v-if"(item.label 高压侧 || item.label 低压侧)&&coloumnHeader.label 单柱片数"><div class"editableCell"><div v-if"item.label 高压侧" dblclick"changeValue(sco…

人工智能程序使用的编程语言

用C语言可以写人工智能程序吗&#xff1f; 可以用C语言编写具有人工智能功能的程序&#xff0c;但是较为复杂。C语言是一种通用的编程语言&#xff0c;它在执行速度和资源控制方面表现出色&#xff0c;这使得它适合于需要高性能处理的人工智能应用&#xff0c;如游戏AI&#xf…

邮件安全|“AI钓鱼邮件”愈发泛滥,钓鱼邮件如何防“钓”?

毋庸置疑&#xff0c;人工智能是把双刃剑。 在AI蓬勃发展的过程中&#xff0c;潜在的风险正在悄然滋长。 近日&#xff0c;网络安全公司Enea发布的一份报告指出&#xff0c;随着以人工智能驱动的语音钓鱼&#xff08;vishing&#xff09;和短信钓鱼&#xff08;smishing&…

tomcat中把项目放在任意目录中的步骤

java web 项目由idea开发&#xff0c;路径如下图所示&#xff1a; 1.在tomcat安装目录conf\Catalina\localhost 里面&#xff0c;编写lesson1.xml文件内容如下&#xff1a; <Context path"/lesson1" docBase"C:\Users\信息技术系\Desktop\2024\学校工作\jav…

详解uniapp的生命周期

这篇文章主要介绍了 uniapp 的生命周期, 应用生命周期是指应用程序从启动到关闭的整个过程&#xff0c;包括应用程序的启动、前后台切换、退出等, 需要的朋友可以参考下 Uniapp 作为一款跨平台应用开发框架&#xff0c;具有丰富的生命周期&#xff0c;以下是 Uniapp 的生命周期…

【一】【单片机】有关LED的实验

点亮一个LED灯 根据LED模块原理图&#xff0c;我们可以知道&#xff0c;通过控制P20、P21...P27这八个位置的高低电平&#xff0c;可以实现D1~D8八个LED灯的亮灭。VCC接的是高电平&#xff0c;如果P20接的是低电平&#xff0c;那么D1就可以亮。如果P20接的是高电平&#xff0c;…

【四 (4)数据可视化之 Ploty Express常用图表及代码实现 】

目录 文章导航一、介绍二、安装Plotly Express三、导入Plotly Express四、占比类图表1、饼图2、环形图3、堆叠条形图4、百分比堆叠条形图 五、比较排序类1、条形图2、漏斗图3、面积漏斗图 六、趋势类图表1、折线图2、多图例折线图3、分列折线图4、面积图5、多图例面积图 七、频…

逻辑数据平台的 NoETL 之道(内含QA)

作者简介&#xff1a; 余俊&#xff0c;Aloudata 合伙人 & 技术副总裁。拥有 18 年互联网技术和大数据平台相关架构经验。作为主架构师及核心研发主导并完成了 Alibaba B2B 首个海量分布式 KV 存储系统&#xff0c;作为网站架构师负责 Aliexpress 全球买全球卖交易系统的第…

【云原生-kubernetes系列】--kubernetes日志收集

1、ELK架构 1.1、部署ES集群 https://mirrors.tuna.tsinghua.edu.cn/elasticstack/apt/7.x/pool/main/e/elasticsearch/ 1、下载软件包 rootes-server1:~# wget https://mirrors.tuna.tsinghua.edu.cn/elasticstack/apt/7.x/pool/main/e/elasticsearch/elasticsearch-7.12.0-…

STL库中的string

文章目录 一、STL的六大组件二、string类2.1string中的size()方法2.2隐式类型的转换2.3string的多种构造2.4string中size与length是否有差异&#xff1f;2.4string中的capacity2.5string中的push_back和append2.6string中运算符重载operator2.7string中的reserve扩容2.8string中…

数据结构——字符串

1.leetcode 151 题目链接&#xff1a; . - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/reverse-words-in-a-string/…

C++:基类中的函数什么情况下声明为虚函数

在C中&#xff0c;基类中的函数应该在以下情况下声明为虚函数&#xff1a; 实现多态行为&#xff1a;如果你希望通过基类指针或引用来调用派生类中的重写函数&#xff0c;那么基类中的这个函数应该被声明为虚函数。这是实现运行时多态性的一种方式。 允许派生类重写&#xff1…

体验OceanBase OBD V2.5.0 组件内扩容和组件变更

背景 OBD 是OceanBase的命令行部署工具&#xff0c;在 obd V2.5.0 版本之前&#xff0c;其主要功能主要是部署各类组件&#xff0c;例如 oceanbase-ce,obproxy-ce,obagent 等。然而&#xff0c;它并不支持组件的变更操作以及组件内部的扩缩容调整。具体来说&#xff1a; 1、若…

C语言经典面试题目(八)

1、什么是文件指针&#xff1f;请解释文件指针的作用。 文件指针是在C语言中用来指向文件的指针变量。它主要用于对文件进行读写操作&#xff0c;通过文件指针可以控制文件的读写位置、读取文件内容、向文件中写入数据等操作。 文件指针的作用&#xff1a; 打开文件&#xff…