AAOS 音频焦点请求
文章目录
- 前言
- 基本概念
- 提供给应用来获取音频焦点的api
- AAOS中的音频焦点管理
- 交互矩阵
- duck的实现流程
- AAOS 测试应用kitchensink焦点相关
前言
本文章的目标是首先了解Android中音频焦点的基本概念,理解代码中相关音频焦点的使用方法。其次理解AAOS 中相关交互矩阵概念,理解其实现焦点管理的流程。
基本概念
-
音频焦点的目标是 是确保在多个应用程序同时播放音频时,用户能够顺利地听到他们想要听的声音,并防止多个应用同时混合输出声音,造成用户困扰。也就是每次要去播放某个声音的时候 先去请求焦点,请求到焦点 后才能开始播放。
-
音频焦点是在Android API 8中引入的一个概念。它用于表示用户一次只能专注于一个音频流,比如听音乐或播客,但不能同时进行。在某些情况下,多个音频流可以同时播放,但用户只会真正聆听(专注于)其中一个,而其他音频在后台播放。例如,在导航提示播放时,同时降低音量播放音乐。当应用程序请求音频焦点时,它表示希望“拥有”音频焦点来播放音频。
提供给应用来获取音频焦点的api
android 的audioManager 提供了requestAudioFocus 的接口来获取焦点
AudioFocusRequest mFocusRequest = new AudioFocusRequest.Builder(focusRequest).setAudioAttributes(mAttrib).setOnAudioFocusChangeListener(mFocusListener).setForceDucking(false).setWillPauseWhenDucked(false).setAcceptsDelayedFocusGain(false).build();ret = mAudioManager.requestAudioFocus(mFocusRequest);
mFocusRequest 的构造有几个参数可以传递
- attribute可以认为是音频播放的原因如 USAGE_MEDIA或者 USAGE_VOICE_COMMUNICATION等等建议为请求使用与音频/媒体播放相同的AudioAttributes。 如果未设置任何属性,则会使用默认属性AudioAttributes.USAGE_MEDIA。
- AudioFocusChangeListener延时焦点注册的回调,当延时焦点获取到的时候会回调到注册的函数中。
- 是否强制降低音量
- 当焦点被duck的时候 是否进行pause操作
- 是否接受获取到焦点是延时焦点
当然还支持其他不同的参数设置,这些参数设置是为了满足不同的场景来使用。比如:在用户听音频书籍或播客时,设备播放导航提示时,用户希望音频暂停而不是降低音量,因为同时听导航提示和语音内容会让人难以理解。因此,系统不会自动对播放音频书籍或博客的应用程序进行降低音量。 如果应用程序想要需要暂停而不是降低音量,可以使用Builder.setWillPauseWhenDucked(true) 设置之后 在其他应用占用了焦点后框架不会自动为应用降低音量而是回调到应用注册的函数中。
不同类型的焦点请求:
- AudioManager.AUDIOFOCUS_GAIN:表示您的应用程序现在是用户正在听取的唯一音频源。音频播放的持续时间未知,可能非常长:在用户完成与您的应用程序的交互后,不希望其他音频流继续播放。这种焦点通常用于音乐播放、游戏或视频播放器。
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:用于在应用程序暂时从当前拥有者那里获取焦点,但用户期望一旦应用程序不再需要音频焦点时,播放会回到之前的状态。例如,用于播放闹钟或进行VoIP通话。播放是有限的:闹钟会超时或被取消,VoIP通话有开始和结束。当其中任何事件结束时,如果用户在开始时正在听音乐,则用户希望音乐恢复,而不希望同时听两者。
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:这种焦点请求类型与AUDIOFOCUS_GAIN_TRANSIENT相似,都是临时性的焦点请求。但其还表示在拥有焦点的同时,允许另一个应用以降低的音量(“ducked”)继续播放。例如,在播放导航提示或通知时,允许音乐继续播放,但音量不足以妨碍用户听清导航提示。典型的"ducked"应用程序的衰减率为0.2f(或-14dB),例如播放时可以使用**MediaPlayer.setVolume(0.2f)**来实现。
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:也用于临时请求,但还表示应用程序希望设备在此期间不播放任何其他内容。这通常用于音频录制或语音识别等情况,在此期间不希望系统播放通知等内容。
AAOS中的音频焦点管理
AAOS请求处理是CarService 这边处理,所谓的处理 就是根据传递进来的请求参数 和目前持有的场景来决定 是否让这个焦点请求成功。 这个具体的规则是基于交互矩阵来实现的。具体来所通过重写 AudioPolicy的相关回调 来截获原来的audioRequest,然后处理完成后设置到AudioManger 中。主要是重写下面的那些实现。
public static abstract class AudioPolicyFocusListener {public void onAudioFocusGrant(AudioFocusInfo afi, int requestResult) {}public void onAudioFocusLoss(AudioFocusInfo afi, boolean wasNotified) {}/*** Called whenever an application requests audio focus.* Only ever called if the {@link AudioPolicy} was built with* {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to {@code true}.* @param afi information about the focus request and the requester* @param requestResult deprecated after the addition of* {@link AudioManager#setFocusRequestResult(AudioFocusInfo, int, AudioPolicy)}* in Android P, always equal to {@link #AUDIOFOCUS_REQUEST_GRANTED}.*/public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {}/*** Called whenever an application abandons audio focus.* Only ever called if the {@link AudioPolicy} was built with* {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to {@code true}.* @param afi information about the focus request being abandoned and the original* requester.*/public void onAudioFocusAbandon(AudioFocusInfo afi) {}}
AAOS中的音频焦点管理具体外部设置focus流程:
- 首先在创建外部的audioPolicy时,会设置AudioPolicyFocusListener注册外部的focus处理的handler到policy并设置IsAudioFocusPolicy 为true将外部的 audioPolicy注册到audioManger,实际是注册到audioservice,
- 在audioservice中管理焦点请求的类是mMediaFocusControl。在有外部注册的AudioPolicyFocusListener的情况下,所有外部通过audiomanger调用的requestfocus。都会在通过audioPolicy的notifyAudioFocusRequest来处理,这边是一个handler 发送MSG_FOCUS_REQUEST消息 然后处理消息的地方将使用外部注册的mFocusListener.onAudioFocusRequest来处理。这个地方会回调caraudioservice 注册进去的mFocusHandler来处理
- mFocusHandler是实现了audiopolicy的AudioPolicyFocusListener的接口主要包括focus grant\loss\request\loss几种情况。
- carAudioService 中requestFoces实现的流程,这个流程简单来说就是根据AAOS定义的交互矩阵和当前已经获取的焦点类型和当前请求焦点的类型 来判断 当前的这个焦点请求是可以获取还是拒绝。
交互矩阵
为了支持 AAOS 的需求,系统会根据请求的 CarAudioContext
和当前焦点持有者的 CarAudioContext 之间的预定义交互来处理音频焦点请求。交互类型分以下三种:独占、拒绝和并发。
-
独占交互
简单来说就是当前应用持有的焦点会被将要请求焦点的应用占有,当前应用失去焦点。
-
拒绝交互
简单来说当前应用持有的焦点会一直保持,其他应用无法获取当前的焦点。
-
并发交互
当前应用和其他应用可以同时拥有焦点,AAOS特有的。
AAOS 最独特的地方就是并发交互。在这种交互模式下,请求音频焦点的车载应用可与其他应用同时持有焦点。若要实现并发交互,必须满足以下条件。即:
-
传入的焦点请求的是
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
。 -
当前焦点持有者未设置
setPauseWhenDucked(true)
。如果满足上述条件,焦点请求将返回
AUDIOFOCUS_REQUEST_GRANTED
,而当前焦点持有者的焦点不会发生任何变化。不过,如果当前焦点持有者选择接收闪避事件或在闪避时暂停,则会失去焦点,就像独占交互一样。
-
下表显示了由 CarAudioService
定义的交互矩阵。行内容和列内容分别表示当前焦点持有者和传入请求的 CarAudioContext
。
举例:如果音乐媒体应用目前正持有音频焦点,而导航应用要请求获得焦点,那么通过该矩阵便能知道,这两个交互可以同时进行。
由于并发交互的缘故,可能会存在多个焦点持有者。在这种情况下,系统会将传入的焦点请求与当前的各个焦点持有者进行比较,然后决定应用哪种交互。此时,最保守的交互会胜出(先是拒绝交互,然后是独占交互,最后是并发交互)。
下表罗列了传入焦点请求的 CarAudioContext(列)与现有焦点持有者的上下文(行)之间的焦点交互。每个单元格表示两种上下文的预期交互类型,其中:
-
R 代表拒绝交互
-
E 代表独占交互
-
C 代表并发交互
duck的实现流程
duck指的是两个音频都在播放的时候,其中一个音频主动的降低音量。
-
AOSP legacy模式
关键代码MediaFocusControl.java、FocusRequester.java
- 根据是不是有外部注册的focusPolicy, 使用的是框架的 还是外部的音频焦点请求策略。如果使用框架的,在音频焦点失去的时候,同时本应用的焦点类型是AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK那么就会调用frameworkHandleFocusLoss,这里面会调用mFocusController.duckPlayers进行处理. 这其中会调用addDuck其中会调用applyVolumeShaper, 对进行duck的音频设置曲线。
- 在audiotrack的PlaybackThread 线程中 有外部的数据写入的时候 调用mixthread的prepareTracks_l 从volumeShaper这边获取音量,这个音量是经过sharp处理的,duck的时候 就是原来的0.2倍,这个音量最后会乘上音频数据。 从而实现了音量的降低。
-
AAOS 动态路由
- AAOS 动态路由目前的实现是所有的焦点的获取都是由外部的CarAudioService 进行处理的。其中在焦点类型为AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK(当前请求焦点的播放需要正在播放的声音能够降低音量)需要调用audioControl hal的onDevicesToDuckChange来降低音量。
- 主要是onDevicesToDuckChange起作用, 在carAudioService request policy中会回调这个, 这个调用到AudioControl hal。hal 中调用 set_device_address_is_ducked 这个是属于audio_hw 也就是audio hal 中,在这里面是设置具体的哪个address为duck,设置为duck的 在后面往这边写数据的时候会乘上一个值。相当于是减小音量了。
AAOS 测试应用kitchensink焦点相关
- 代码位置:packages\services\Car\tests\EmbeddedKitchenSinkApp\src\com\google\android\car\kitchensink\audio\AudioTestFragment.java
- 首先进行音乐music播放,这个播放是循环的, 然后在在播放过程中可以选择Nav 导航播放 USAGE_ASSISTANCE_NAVIGATION_GUIDANCE ,或者 Vr USAGE_ASSISTANT播放这两个获取的焦点不同。
- Nav获取的焦点是AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,也就是music播放还是可以获取到焦点播放不会暂停,但是会降低音量。Vr获取到的是 AUDIOFOCUS_GAIN_TRANSIENT,music音乐播放会完全暂停。其暂停的操作是通过audioservice发送focuschange的消息到请求焦点的回调中。
相关文章:

AAOS 音频焦点请求
文章目录 前言基本概念提供给应用来获取音频焦点的apiAAOS中的音频焦点管理交互矩阵duck的实现流程AAOS 测试应用kitchensink焦点相关 前言 本文章的目标是首先了解Android中音频焦点的基本概念,理解代码中相关音频焦点的使用方法。其次理解AAOS 中相关交互矩阵概念…...

订单系统中的幂等实现
一.订单提交的例子 一个订单生成并支付的过程,大致为:用户点击前端页面提交订单->后端根据此次提交信息生成订单->用户确认订单并进行支付操作->支付成功。 主要分为前端层面,后端系统层面,数据库层面。前端层面不详述…...

三个常用查询:根据用户名 / token查询用户信息+链表分页条件查询
目录 1.根据用户名或者token查询用户信息 会员信息实体类 统一状态Result类 controller层 service层及实现类 dao层 测试: 2.链表分页条件查询 会员等级实体类 封装条件类PageVo controller层 service层及实现类 dao层 Mapper.xml层 测试 vue前端参考 1.根据用户名…...

列表、张量、向量和矩阵的关系
在数学和编程中,列表、张量、向量和矩阵之间有一定的关系。这些概念在不同领域和语境中有略微不同的定义和用法,以下是它们之间的一般关系: 列表(List): 列表是编程语言中的一种数据结构,用于存…...

华为数通HCIP-ISIS高级
isis区域间的互访 1、L2区域 to L1区域 在L1区域发布的路由会以L1-LSP在L1区域内传递,到达L1-2路由器时,L1-2路由器会将该L1-LSP转换为L2-LSP在L2区域内传递; 因此L2区域的设备可以学习到L1区域的明细路由,进行访问;…...

CorelDraw怎么做立体字效果?CorelDraw制作漂亮的3d立体字教程
1、打开软件CorelDRAW 2019,用文本工具写上我们所需要的大标题。建议字体选用比较粗的适合做标题的字体。 2、给字填充颜色,此时填充的颜色就是以后立体字正面的颜色。我填充了红色,并加上了灰色的描边。 3、选中文本,单击界面左侧…...

大致了解Redis
为了保证数据的可靠性,Redis 需要在磁盘上读写 AOF 和 RDB,但在高并发场景里,这就会直接带来两个新问题:一个是写 AOF 和RDB 会造成 Redis 性能抖动,另一个是 Redis 集群数据同步和实例恢复时,读 RDB 比较慢…...

javaweb会话技术
cookie的入门使用 package com.hspedu.cookie;import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import …...

android app控制ros机器人三(android登录界面)
接下来是二次开发的具体环节了,由于存在用户需求,用到ros-mobile不多,更偏向于android开发。 用ppt画了简单的展示界面,与用后交流界面的功能布局。先开发一代简易版本的app,后续可以丰富完善。ctrlcv上线。 登录界面…...

Android版本的发展4-13
Android 4.4 KitKat 1、通过主机卡模拟实现新的 NFC 功能。 2、低功耗传感器,传感器批处理,步测器和计步器。 3、全屏沉浸模式,隐藏所有系统 UI,例如状态栏和导航栏。它适用于鲜艳的视觉内容,例如照片、视频、地图、…...

【2023.7.29】浅谈手办——新人入坑指南
目录 前言入坑指南1.声明2.介绍3.树状图 总结参考文章 前言 出于对动漫的热爱,相信很多人都会买手办,本人在大一时开始入手了第一个手办,超大猿王路飞(高约50cm),当时对手办还不是很了解,只知道…...

使用贝叶斯算法完成文档分类问题
贝叶斯原理 贝叶斯原理(Bayes theorem)是一种用于计算条件概率的数学公式。它是以18世纪英国数学家托马斯贝叶斯(Thomas Bayes)的名字命名的。贝叶斯原理表达了在已知某个事件发生的情况下,另一个事件发生的概率。具体…...

【Kafka】消息队列Kafka进阶
目录 Kafka分区机制生产者分区写入策略轮询策略随机策略(不用)按key分配策略乱序问题自定义分区策略 消费者组Rebalance机制消费者分区分配策略Range范围分配策略RoundRobin轮询策略Stricky粘性分配策略 Kafka副本机制producer的ACKs参数acks配置为0acks…...

学习day55
消息订阅与发布 消息订阅与发布是一种组件间通信的方式,适用于任意组件间通信 使用步骤: 安装pubsub:npm i pubsub-js 引入:import pubsub from pubsub-js 接收数据:A组件想接收数据,则在A组件中订阅消息…...

C++-Rust-一次性掌握两门语言
C-Rust-一次性掌握两门语言 简介特色数据类型声明常量、变量判断与循环函数抽象化的对象:类与接口枚举模板与泛型Lambda匿名函数表达式 简介 本文主要是通过介绍C和Rust的基础语法达成极速入门两门开发语言。 C是在C语言的基础之上添加了面向对象的类、重载、模板等…...

汇编调用C语言定义的全局变量
在threadx移植中,系统的systick通过了宏定义的方式定义,很难对接库函数的时钟频率,不太利于进行维护 所以在C文件中自己定义了一个systick_Div的变量,通过宏定义方式设定systick的时钟频率 在汇编下要加载这个systick分频系数 …...

WEB 文件包含 /伪协议
首先谈谈什么是文件包含 WEB入门——文件包含漏洞与PHP伪协议_文件包含php伪协议_HasntStartIsOver的博客-CSDN博客 文件包含 程序员在编写的时候 可能写了自己的 函数 如果想多次调用 那么就需要 重新写在源代码中 太过于麻烦了只需要写入 funcation.php然后在需要引用的地…...

ComPDFKit PDF SDK库(支持Windows、Web、Android、iOS、Mac等平台)
ComPDFKit提供专业、全平台支持的PDF开发库,包括Windows、Mac、Linux、Android、iOS、Web平台。开发者可以快速、灵活整合PDF功能到各开发平台的软件、程序、系统中。丰富的功能,多种开发语言,灵活的部署方案可供选择,满足您对PDF…...

微服务契约测试框架-Pact
契约测试 契约测试的思想就是将原本的 Consumer 与 Provider 间同步的集成测试,通过契约进行解耦,变成 Consumer 与 Provider 端两个各自独立的、异步的单元测试。 契约测试的优点: 契约测试与单元测试以及其它测试之间没有重复,…...

LightGlue论文翻译
LightGlue:光速下的局部特征匹配 摘要 - 我们介绍 LightGlue,一个深度神经网络,学习匹配图像中的局部特征。我们重新审视 SuperGlue 的多重设计决策,稀疏匹配的最新技术,并得出简单而有效的改进。累积起来,它们使 Lig…...

iOS开发-CAShapeLayer与UIBezierPath实现微信首页的下拉菜单效果
iOS开发-CAShapeLayer与UIBezierPath实现微信首页的下拉菜单效果 之前开发中遇到需要使用实现微信首页的下拉菜单效果。用到了CAShapeLayer与UIBezierPath绘制菜单外框。 一、效果图 二、CAShapeLayer与UIBezierPath 2.1、CAShapeLayer是什么? CAShapeLayer继承自…...

《Elasticsearch 源码解析与优化实战》第5章:选主流程
《Elasticsearch 源码解析与优化实战》第5章:选主流程 - 墨天轮 一、简介 Discovery 模块负责发现集群中的节点,以及选择主节点。ES 支持多种不同 Discovery 类型选择,内置的实现称为Zen Discovery ,其他的包括公有云平台亚马逊的EC2、谷歌…...

Spring Cloud Alibaba - Nacos源码分析(三)
目录 一、Nacos客户端服务订阅的事件机制 1、监听事件的注册 2、ServiceInfo处理 serviceInfoHolder.processServiceInfo 一、Nacos客户端服务订阅的事件机制 Nacos客户端订阅的核心流程:Nacos客户端通过一个定时任务,每6秒从注册中心获取实例列表&…...

DOCKER镜像和容器
1.前言 初见DOCKER,感觉和我们常用的虚拟机(VMware,viurebox)类似,是一个独立于宿主机的模块,可以解决程序在各个系统间的移植,但它真的仅仅是这样嘛? 2.容器的优缺点 1.1.容器…...

探索网页原型设计:构建出色的用户体验
在当今数字化时代,用户对网页体验的要求日益提高。在网页设计过程中,扮演着至关重要的角色。通过网页原型设计,产品经理能够更好地展示和传达网页的整体布局、导航结构、元素位置和交互效果,从而使团队成员更清晰地了解设计意图&a…...

48,排序算法merge
功能描述: 两个容器元素合并,并储存到另一容器中 函数原型: merge(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest); //容器元素合并,并存储到另一个容器中 //注意:两个容器必须是有序的…...

【MySQL】复合查询
复合查询目录 一、基本查询二、多表查询三、自连接四、子查询4.1 单行子查询4.2 多行子查询4.3 多列子查询4.4 在from子句中使用子查询4.5 合并查询4.5.1 union4.5.2 union all 五、实战OJ 一、基本查询 --查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的…...

JavaScript中的this指向及绑定规则
在JavaScript中,this是一个特殊的关键字,用于表示函数执行的上下文对象,也就是当前函数被调用时所在的对象。由于JavaScript的函数调用方式多种多样,this的指向也因此而变化。本文将介绍JavaScript中this的指向及绑定规则…...

css中预编译理解,它们之间区别
css预编译? css预编译器用一种专门的编程语言,它可以对web页面样式然后再编译成正常css文件,可以更加方便和高效的编写css代表。主要作用就是为css提供了变量,函数,嵌套,继承,混合等功能&#…...

如何使用Java处理JSON数据?
在Java中,您可以使用许多库来处理JSON数据。以下是使用一种常见的库 Gson 的示例: 首先,确保您已经将 Gson 库添加到您的项目中。您可以在 Maven 中添加以下依赖项: <dependency><groupId>com.google.code.gson<…...