调节音量大小,通常有两种方式:1. 通过硬件调节:放大电流。2. 通过软件调节:调整pcm振幅。这里主要说一下通过软件调节音量的流程,基于Android12。我们知道音频流是通过AudioFlinger处理并输出的,那软件调节的音量设置信息肯定需要传递到AudioFlinger中。
Android中调节音量可以通过直接设置音量值的方式,也可以通过音量键进行逐步调节。
音量键调节
Android中通过InputFlinger捕获到按键后,会层层上传,最终区分音量键、主页键等逻辑处理在PhoneWindowManager.java。
interceptKeyBeforeDispatching
dispatchDirectAudioEvent
接着转到AudioService中处理,上层所有音频相关的逻辑基本上都是AudioManager提供接口,AudioService实现。这里由于PhoneWindowManager属于Framework,所以直接调用AudioService。
AudioService.java
- handleVolumeKey
- adjustSuggestedStreamVolume //这里会取到作用于当前音量调节的streamType
- adjustStreamVolume
- sendMsg
- setDeviceVolume
- applyDeviceVolume_syncVSS
- setStreamVolumeIndex
接下来传到AudioSystem。AudioSystem全是static函数,基本上就是接口传递,cpp层的最后一步。
AudioSystem.java
- setStreamVolumeIndexAS
- setStreamVolumeIndex
然后是JNI
android_media_AudioSystem.cpp
- android_media_AudioSystem_setStreamVolumeIndex
Navive层同样有一个AudioSystem对应
AudioSystem.cpp
- setStreamVolumeIndex
然后就转到了AudioPolicyService处理,这里在找代码的时候我一直以为在AudioPolicyService.cpp中,结果在AudioPolicyInterfaceImpl.cpp,从文件内容中可以看出AudioPolicyInterfaceImpl.cpp并不是一个单独的类,也是AudioPolicyService类一些函数的实现。我的理解是从AudioSystem调用过来的接口就在这个文件实现。
AudioPolicyInterfaceImpl.cpp
- setStreamVolumeIndex
然后进入AudioPolicyManager.cpp。这里的命名跟实际的逻辑有点让人混淆,Binder调用我们一般接口喜欢命名为XXXManager,服务命名为XXXService。而AudioPolicyService中,接口为IAudioPolicyService,实现为AudioPolicyService,在实现中再调用AudioPolicyManager,所以这里的AudioPolicyManager需要理解为AudioPolicyService中的一个manager。
AudioPolicyManager.cpp
- setStreamVolumeIndex
- setVolumeIndexForAttributes
- checkAndSetVolume //将volume index转为了float
继续调用AudioOutputDescriptor,AudioOutputDescriptor有两个子类,SwAudioOutputDescriptor和HwAudioOutputDescriptor。这里会走SwAudioOutputDescriptor。
AudioOutputDescriptor.cpp
- setVolume
AudioPolicyClientImpl.cpp
- setStreamVolume
饶了一圈回来,又进入到AudioPolicyService,和第一次不同,这次的实现逻辑在AudioPolicyService.cpp中。
AudioPolicyService.cpp
- setStreamVolume
- volumeCommand
- sendCommand
- threadLoop //threadloop中处理SET_VOLUME msg
又到AudioSystem里,不过这里主要是通过AudioSystem与AudioFlinger通信了。
AudioSystem.cpp
- setStreamVolume
这里终于传到AudioFlinger中了。
AudioFlinger.cpp
- setStreamVolume
Thread分为好几种,混音MixerThread和不混音DirectOutputThread等,不管是哪种都需要处理音量。PlaybackThread是它们的基类,并且又继承至VolumeInterface,VolumeInterface提供了setStreamVolume接口,AudioFlinger通过这个接口设置到Thread中,并保存起来。
Threads.cpp
- setStreamVolume
至此从上到下的音量设置流程就结束了。
这里再补充下音量实际被使用的地方。这里会将传进来的音量进一步进行计算,如果AudioTrack单独设置过音量,也需要乘上它的音量系数。
Threads.cpp
- prepareTracks_l
将左右声道的音量值传到AudioMixer进行混音计算。
AudioMixer.cpp
- setParameter
改变音量值调节
Android提供了AudioManager接口,支持直接改变音量值。
AudioManager.java
- setStreamVolume
AudioService.java
- setStreamVolume
- onSetStreamVolume
- setStreamVolumeInt
- sendMsg
再后面的逻辑就与音量键调节一致了。
另外说明一下,在car android系统中,音量设置逻辑又不一样,参考: