Android 音量设置流程解析
常用API方法
setStreamVolume
java
public void setStreamVolume(int streamType, int index, int flags)
功能:直接设置指定音频流的音量
参数:
streamType:音频流类型(如AudioManager.STREAM_MUSIC)
index:音量级别(0到最大音量之间)
flags:标志位(如AudioManager.FLAG_SHOW_UI)
示例:
adjustStreamVolume
java
-public void adjustStreamVolume(int streamType, int direction, int flags)
功能:按照direction,音量+1-1这种
参数:
streamType:音频流类型
direction:调整方向(如AudioManager.ADJUST_RAISE、AudioManager.ADJUST_LOWER等)
flags:标志位
参数值 | 常量名 | 描述 |
---|---|---|
1 | ADJUST_RAISE | 提高音量 |
-1 | ADJUST_LOWER | 降低音量 |
0 | ADJUST_SAME | 保持当前音量 |
16 | ADJUST_MUTE | 静音 |
32 | ADJUST_UNMUTE | 取消静音 |
64 | ADJUST_TOGGLE_MUTE | 切换静音状态 |
adjustStreamVolume解析
AudioManager.java中adjustStreamVolume
做了哪些操作
- direction、streamtype的类型检查然后判断当前direction和stream_tpye是否是静音 如果是return
- 如果direction是静音,stream_type是STREAM_VOICE_CALL or STREAM_BLUETOOTH_SCO 检查app是否有MODIFY_PHONE_STATE权限、如果 stream is STREAM_ASSISTANT,那么检查app是否有MODIFY_AUDIO_ROUTING权限
- 通过stream_type获取当前合适的device,并且获取VolumeStreamState对象,这个对象是根据stream_type创建的,并且对象里面包含了各种device的默认音量大小
静音调整处理: - 如果是静音调整(ADJUST_MUTE或ADJUST_TOGGLE_MUTE),会设置系统音频静音状态
- 遍历所有音频流,对匹配的音频流进行静音/取消静音操作
- 特殊处理了STREAM_SYSTEM_ENFORCED流(如相机快门声)
音量增大处理: - 检查安全音量限制,如果超出安全音量会显示警告
- 对于非全音量设备,调整音量索引
- 如果当前是静音状态,会根据方向立即取消静音或延迟取消静音
- 如果是蓝牙设备就要把消息发给蓝牙的service postSetAvrcpAbsoluteVolumeIndex
- 如果是HDMI设备就调用 HdmiTvClient.java setSystemAudioVolume
是 否 App调用adjustStreamVolume AudioManager.java adjustStreamVolume AudioService.java adjustStreamVolume 静音调整? mute setAllVolumes applyAllVolumes setStreamVolumeIndex adjustIndex setDeviceVolume applyDeviceVolume_syncVSS
目前java层的代码已经分析完了,接下来要看native层的代码了
直接来看AudioPolicyManager.cpp
中setStreamVolumeIndex
主要功能如下:
- 根据stream_type获取attibutes
ProductStrategyMap ProductStrategy 1 ProductStrategy ... AudioAttributesVector AudioAttributesVector AudioAttributes 1 AudioAttributes ... AudioAttributes 1 AudioAttributes ...
ProductStrategyMap中的数据是通过解析audio_policy_engine_configuration.xml获取的如果没有配置则使用默认配置。
xml
<ProductStrategy name="STRATEGY_PHONE">
<AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL" volumeGroup="voice_call">
<Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION"/> </Attributes>
</AttributesGroup>
<AttributesGroup streamType="AUDIO_STREAM_BLUETOOTH_SCO" volumeGroup="bluetooth_sco">
<Attributes> <Flags value="AUDIO_FLAG_SCO"/> </Attributes>
</AttributesGroup>
</ProductStrategy>
比如上述xml配置中,可以看出这个ProductStrategy包含了两种stream_type分别是AUDIO_STREAM_VOICE_CALL和AUDIO_STREAM_BLUETOOTH_SCO。然后这个ProductStrategy包含了两个AudioAttributes。
audio_policy_engine_stream_volumes.xml
xml
<volumeGroup>
<name>voice_call</name>
<indexMin>1</indexMin>
<indexMax>7</indexMax>
<volume deviceCategory="DEVICE_CATEGORY_HEADSET">
<point>0,-4200</point>
<point>33,-2800</point>
<point>66,-1400</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
<point>0,-2400</point>
<point>33,-1600</point>
<point>66,-800</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
<point>0,-2700</point>
<point>33,-1800</point>
<point>66,-900</point>
<point>100,0</point>
</volume>
<volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
</volumeGroup>
上述xml作用是解释音量相关的信息,比如在不同设备的voice_call类型的音量曲线 最大、最小index等。 可以看出来AudioAttributes中的AttributesGroup和volumeGroup是一一对应,根据name可以看出。并且从下图可以看出AudioAttributesVector和VolumeGroup一一对应。通过mId链接。

-调用setVolumeIndexForAttributes
调用setVolumeIndexForAttributes,这个函数主要功能如下:
- 根据Attributes获取对应的VolumeGroup、音量曲线、VolumeSource、strategy
- setVolumeCurveIndex (根据index device 设置curves)
- 获取与音量曲线相关的输出设备。
- 遍历所有输出描述符(SwAudioOutputDescriptor),检查并应用音量调整。checkAndSetVolume
- 通知客户端音量组已发生变化。onAudioVolumeGroupChanged
checkAndSetVolume功能如下:
- 检查音量源是否被静音。静音直接返回NO_ERROR(这里检查的是volumeSources是否是静音状态,这个状态在adjustStreamVolume流程并不会被设置)
- 检查通话和蓝牙 SCO 音量冲突。
- 获取设备类型。
- 计算音量分贝值。(eswin在这一步把计算出来的volumeDb = 0.0f)
- 设置音量。(SwAudioOutputDescriptor::setVolume)
- 处理主输出设备的通话音量。(如果是主输出设备,并且在通过状态或者音量源是蓝牙,最终会调用到audio_hw.c中的setVoiceVolume,目的是提高实时性、硬件依赖性强)
接下来看一下setVolume的功能:
- 调用基类的 setVolume 方法进行基础设置。改变
mVolumeActivities[vs].setVolume(volumeDb)
- 处理空音频流类型,默认使用 AUDIO_STREAM_MUSIC。
- 遍历设备,检查设备类型和增益控制,设置设备增益,并且把软件层的增益设置为0。(前提是当前设备硬件支持音量增益,最后调用到hal的setAudioPortConfig,配置硬件是否支持增益需要更改audio_policy_configuration.xml添加useForVolume="true"即可)
- 将分贝值换算成振幅
- 处理蓝牙 SCO 设备的通话音量。setStreamVolume
- 设置音频流音量。调用到SF中的setStreamVolume,然后调用
Thread.cpp
中在指定的playbacktrhead中设置 mStreamTypes[stream].volume = value;
音量设置流程总结
是 否 Java层调用adjustStreamVolume AudioManager.java adjustStreamVolume AudioService.java adjustStreamVolume 静音调整? mute setAllVolumes applyAllVolumes setStreamVolumeIndex adjustIndex setDeviceVolume applyDeviceVolume_syncVSS AudioPolicyManager.cpp setStreamVolumeIndex AudioPolicyManager.cpp setVolumeIndexForAttributes checkAndSetVolume SwAudioOutputDescriptor.cpp setVolume Thread.cpp setVolume
setStreamVolume解析
在AudioService.java中 setStreamVolume 功能如下:
- 如果device是蓝牙并且是绝对音量那么就调用蓝牙音量设置postSetAvrcpAbsoluteVolumeIndex
- 如果是助听器调用ostSetHearingAidVolumeIndex
- 如果是HDMI设备调用setSystemAudioVolume
- 如果当前音频流类型为 STREAM_MUSIC,并且设备是固定音量设备,设置 FLAG_FIXED_VOLUME 标志位。如果音量值不为 0,则根据设备的安全音量状态,将音量值设置为安全音量值或最大音量值。
- 调用onSetStreamVolume
onSetStreamVolume功能如下:
-调用setStreamVolumeInt
AudioService.java setStreamVolume onSetStreamVolume setStreamVolumeInt 发送消息 MSG_SET_DEVICE_VOLUME Handler.handleMessage setDeviceVolume applyDeviceVolume_syncVSS