AAOS 音量调节流程概要

AAOS 音量调节流程概要

(基于android-14.0.0_r2 code)

一 AOSP 音量调整流程

 

        AOSP 默认调整的是软音量:大概流程如上图(这个图是网上拿的,一个TV平台的图),详细的流程时序图等大家可以自行网上查找,手机端的音量调整流程网上已经有很多资料,这里不多介绍了。

android 系统中抽象出来的音量相关的值有:

  1. master volume:  主音量,一般默认设置为1,如果设置为0,表示设备所有声音都为0
  2. track volume: track音量,这个用来控制播放的某一首歌曲的音量,主要是方便应用调整播放某一曲歌曲音量,而不影响全局;一般应用中用于其fadein/fadeout的实现以及框架中的volumeshaper的实现
  3. stream音量: 流音量,这个是目前软音量调整的主要音量。在vendor/etc/audio_policy_volume.xml中有对每个stream+device定义一套音量曲线,当真正调整音量的时候,在audiopolcymanager中根据这个曲线compute 实际的音量值(0~1之间的浮点数),然后binder调用到audioflinger中,在audioflinger 中的MixerThread::prepareTracks_l 函数中进行音量计算(音量的处理在混音之前,细节可以见);详细的细节见/frameworks/av/media/libaudioprocessing/AudioMixerBase.cppsetVolumeRampVariables函数中,这个函数中也会进行一次fadein/fadeout避免音量突变导致的pop音。
  4. adsp中音量控制:adsp 中的volume moudle中也可以进行相关的音量控制,对于voice/sco(modem通话)场景的音量就是将index 传递到这里,然后进行音量的调整
  5. codec 音量:后端codec 中的数字/模拟的 gain,这些一般都是调音工程师配置这个通道的时候固定死,很少动态调整;
  6. IOT设备端音量:对于一些IOT设备,如典型的支持绝对音量调整的蓝牙耳机,就是AP将音量的index 通过蓝牙标准协议 直接发送给蓝牙端,在蓝牙端进行音量调整
  7. pcm源的响度:分贝(decibel)是量度两个相同单位之数量比例的单位,主要用于度量声音强度,常用dB表示。在编程中,我们可以用以下公式计算两个声音之间的动态范围,单位为分贝:dB = 20 * log(A1 / A2)其中 A1 和 A2  是两个声音的振幅,在程序中表示每个声音样本的大小。声音采样大小(也就是量化深度)为1bit时,动态范围为0,因为只可能有一个振幅。采样大小为8bit也就是一个字节时,最大振幅是最小振幅的  256 倍。因此,动态范围是 48 分贝,计算公式如下:dB = 20 * log(256)48 分贝的动态范围大约是一个安静房间和一台运行着电动割草机之间的区别。如果将声音采样大小增加一倍到16bit,产生的动态范围则为 96 分贝,计算公式如下:dB = 20 * log(65536)。

      总而言之,决定你听见的最终声音的响度大小,是以上这些音量因素的综合作用决定的。只是在不同的设备形态或者场景中去调整其中的一个或者几个因素的组合去控制最终音频响度的大小。

二 AAOS 音量调整流程

1 环境配置差异:

AAOS 环境相比于AOSP 会打开下面两个配置:

1.1 config_useFixedVolume 配置成 true

<resources>

    <!-- Car uses hardware amplifier for volume. -->

    <bool name="config_useFixedVolume">true</bool>

</resources>

1.2 handleVolumeKeysInWindowManager 配置为true

<resources>

    <bool name="config_handleVolumeKeysInWindowManager">true</bool>

</resources>

  1. KEYCODE_VOLUME_UP
  2. KEYCODE_VOLUME_DOWN
  3. KEYCODE_VOLUME_MUTE

这个配置设置为true的作用是:让以上音量按键事件的调用流程不会走到应用测,而是默认都走都到input子系统会将输入事件传递给PhoneWindowManager,PhoneWindowManager又会将输入事件传递给AudioService,AudioService会将输入事件传递给CarAudioService在初始化时注册的callback。最终交由CarAudioService进行处理

详细的android input分发的流程可以参考以下文档:

按键事件分发分析之一(八)_action_multiple-CSDN博客

按键事件分发分析之二(九)_android seemplog-CSDN博客

PhoneWindowManager处理事件分析(十一)_interceptmotionbeforequeueingnoninteractive-CSDN博客

Android Input输入系统之五:KeyEvent按键调节音量加减流程_android dispatchkeyevent触发系统音量大小键-CSDN博客

1.3  config.xml中的 audioUseDynamicRouting 、audioUseCoreVolume、audioUseCoreRouting的配置及其作用

(1)audioUseDynamicRouting:决定是否使用动态路由,一般CarAudioService init 的时候解析car_audio_configuration.xml这个配置文件,获取音区zones、volume groups、devices address、context等信息,然后封装成audiomixer policy build规则,通过registerAudioPolicy接口注册到音频框架的audiopolicymanager,后续音频的播放中的设备选择逻辑就会使用这个动态路由策略选择逻辑,这个是车机座舱的多音区框架的重要组成部分的配置,一般车机会被配置成true;

(2)audioUseCoreVolume的配置,一般车机配置成false,不走软音量,否则音量调节流程会走到audiopolicymanager 中,跟手机类似了。

(3)audioUseCoreRouting的配置,一般车机配置成false,用于启用核心音频路由API的配置。它也可以在启用动态路由的情况下启用,因此,当可以有效地建立动态规则时,覆盖策略路由规则。典型的如果为true的话,会走到audiopolicymanager中进行设备切换的选择,跟手机就类似了

2 调节音量的关键调用流程

整体的具体调用栈如下:

PhoneWindowManager.java->interceptKeyBeforeDispatching()

    PhoneWindowManager.java->dispatchDirectAudioEvent()

        AudioService.java->handleVolumeKey()

            AudioService.java->adjustSuggestedStreamVolume()

                AudioService.java->notifyExternalVolumeController()

                    AudioPolicy.java->IAudioPolicyCallback.notifyVolumeAdjust()

                        CarAudioPolicyVolumeCallback.java->onVolumeAdjustment(int adjustment)

2.1 关键的调用流程1: CarService启动给 mExtVolumeController 赋值

具体代码的关键点如下:

具体流程时序图如下:

2.2 关键调用流程2:Carservice初始化的时候的一些配置类的确认

(1)  zonesHelper 是使用 CarAudioZonesHelper 还是 CarAudioZonesHelperLegacy;

 决定因素是系统以上目录是否存在相对应的配置文件,一般是存在的,所以会选择CarAudioZonesHelper class

(2)决定使用 决定使用 CoreAudioVolumeGroupCallback 还是 CarAudioPolicyVolumeCallback

看audioUseCoreVolume的配置,一般车机配置成false,不走软音量,否则音量调节流程会走到audiopolicymanager 中,跟手机类似了。

(3)VolumeGroup 是使用CoreAudioVolumeGroup 类还是AudioVolumeGroup类

audioUseCoreVolume的配置也会影响上面流程

正常的车机版本会VolumeGroup会选择AudioVolumeGroup类

2.3 关键调用流程3:groupId的获取流程(调整哪个设备哪个流音量的优先级)

根据音区zoneID还有内部的一些优先级的AudioAttributes定制获取特定音区,特定设备,特定audio usage的volume group ID;

这个以AAOS 原生的流程函数/packages/services/Car/service/src/com/android/car/audio/CarAudioPolicyVolumeCallback.java

中的evaluateVolumeAdjustmentInternal 函数中的mCarVolumeInfo.getVolumeGroupIdForAudioZone(zoneId)为例子

当系统中有多个active的USAGE的attribute存在的时候,写死的优先级定义如下:

packages/services/Car/service/src/com/android/car/audio/CarVolume.java:

总结一下找合适的VolumeGroup的逻辑是:

   (1) 先找到当前音区下所有正在播放声音的AudioTrack的AudioAttributes。

(2)CarAudioService在初始化时,会向AudioService注册一个PlaybackCallback,这样当有任何应用播放声音时,CarAudioService都能被通知到,并且会告知该声音的AudioAttributes,以及对应的播放Device。也就知道了目前哪些Device正在播放声音,CarAudioService就能通过car_audio_configuration.xml配置文件知道Device对应的音区是哪个了。

(3)找到当前音区下的这些AudioAttributes后,就可以找到它们所对应的CarAudioContext,当有多个CarAudioContext处于正在播放状态时,会按照上面截图中的系统默认优先级的定义去获取最终的CarAudioContext

(4)一个示例子:AUDIO_ATTRIBUTE_VOLUME_PRIORITY_V2常量定义的优先级如下:USAGE_VOICE_COMMUNICATION、USAGE_MEDIA、USAGE_ANNOUNCEMENT、USAGE_ASSISTANT。也就是说,当通话和音乐播放同时进行时,会优先设置通话的音量。

找到最优先的CarAudioContext后,就可以从<zoneConfig>中找到其对应的volumeGroup了。

2.4 关键的调用流程4:音量按键调节音量流程

//todo 按键调用到adjustSuggestedStreamVolume的流程(这个主要是input模块的流程)

下面的流程以adjustSuggestedStreamVolume为入口进行绘制(见1.2,音量按键的调节现在不会传递给app,所以都会在框架被拦截,从而走到这个入口)

总结上面的流程就是:

1. 在入口函数adjustSuggestedStreamVolume中调用到mCarAudioPolicyVolumeCallback.onVolumeAdjustment(adjustment, PRIMARY_AUDIO_ZONE),并且直接retrun bypass调后面的手机平台调节软音量的流程

2. 这里onVolumeAdjustment中先确认是否有oem自己的实现逻辑,oem volume 管理中主要实现的接口有:getSuggestedGroupForVolumeChange(调整音量流的优先级判定,当然如果需要自己增加新的接口,可以在这个里面先增加接口:/packages/services/Car/service/src/com/android/car/oem/CarOemAudioVolumeProxyService.java,然后再在自己的oemCarService 中实现具体的接口)

参考google 文档:车载音频插件服务 &nbsp;|&nbsp; Android 开源项目 &nbsp;|&nbsp; Android Open Source Project

3. 然后再上面的函数中调用getVolumeGroupIdForAudioContextLocked(zoneId) 根据既定的优先级规则获取合适的VolumeGroupId ,之后根据VolumeGroupId 和 zoneId获取该VolumeGroupId的当前gain,mingian,进而最终计算出需要真正调整的CurrentGain

4. 之后通过setCurrentGainIndexLocked去真正调节音量(这里说明一下,group有CoreAudioVolumeGroup 类和 AudioVolumeGroup类,两者的这个函数实现不同,AAOS一般是使用AudioVolumeGroup类中的实现);找到合适的VolumeGroup、获取该VolumeGroup的音量等级、设置该VolumeGroup下的所有Device音量;

5. 最后调用 mSettingsManager.storeVolumeGainIndexForUser (userId, mZoneId, mConfigId, mId, gainIndex);保存调整的音量信息到系统的setting数据库中;

6. 触发onVolumeGroupChange这个回调,让注册这个回调的应用可以收到相关的音量变化事件响应相应的UI操作,比如弹音量条等。

3 Android 系统中音量的抽象

分析方法:系统中可以dumpsys audio 的服务去看当前系统的音量状态

adb shell dumpsys audio > d:\dumpsys\audioservice.txt

adb shell dumpsys media.audio_flinger> d:\dumpsys\audio_flinge.txt

adb shell dumpsys media.audio_policy> d:\dumpsys\audio_policy.txt

adb shell dumpsys settings> d:\dumpsys\settingsDb.txt

3.1 AOSP中抽象的音量表示

手机产品中的音量dumpsys中的抽象定义:

3.2 AAOS中抽象的音量表示

/device/generic/car/emulator/audio/audio_policy_configuration.xml

/device/generic/car/emulator/audio/car_audio_configuration.xml

setting Db 中的表示格式:“ android.car.VOLUME_GROUP/zoneId/configId/groupId xxx ”

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值