这篇写什么?
按一下音量键,屏幕上的格子变了,声音也变了——中间其实是 AudioPolicy(策略) 和 AudioFlinger(混音执行) 一起干活。厂商适配音量时,几乎都会碰到两件事:
- 软音量:在软件侧(Track / Mixer)把 PCM 乘上增益
- 硬件音量:写到芯片 / 功放寄存器(或经 HAL 设 port gain)
最终听到的声音 = 两者(再加 EQ、MS12 DAP 等)叠在一起。
一句话:
按键 → AudioService 记 index、刷 UI
→ AudioSystem → AudioPolicy 算 volumeDb / 下发
→ AudioFlinger 软音量(master × stream × track)
→ HAL 软处理 / 硬件增益 → 喇叭

一、先分清两层:谁负责「记」、谁负责「算」、谁负责「乘」
| 层级 | 主要职责 |
|---|---|
| Java(AudioService) | 响应按键、决定调哪路 stream、记 UI 刻度(index)、更新音量条 |
| Native Policy(AudioPolicyManager) | 按设备 / 音量曲线把 index 换成 dB / 策略结果,通知该动的 output |
| Native Flinger(AudioFlinger) | 混音时对 Track 做 软音量(master × type × …) |
| HAL | 把策略落到 port gain / 寄存器 / MS12 postgain,并在写 PCM 时再乘一遍 sink gain(视方案) |
所以调试时别只盯一个进程:
- UI 变了、声音没变 → 多半卡在 Policy→Flinger/HAL
- 声音变了、UI 不对 → 多半卡在 Java index / alias
- 媒体小声、HDMI-ARC 却满幅 → 常见是 硬音量 / 固定音量设备 策略
二、Java 层:响应按键 → 记下 index
2.1 入口链路(概念)
音量键 / 触控调节
→ AudioManager
→ AudioService
handleVolumeKey
→ adjustSuggestedStreamVolume // 判断调哪路 stream
→ adjustStreamVolume // alias、device、发消息
→ Handler: MSG_SET_DEVICE_VOLUME
→ setDeviceVolume
→ applyDeviceVolume_syncVSS
→ AudioSystem.setStreamVolumeIndex(...) // 进入 Native
2.2 几个容易晕的点
1)Suggested stream ≠ 最终 stream
adjustSuggestedStreamVolume 会结合「用户是否锁了音量控制流」「当前真正活跃的流(音乐 / 铃音 / 通知…)」选出最终 streamType。电视上多数流常 alias 到 MUSIC,所以你会看到「调铃音也在动媒体曲线」一类现象——往往是 alias 设计,不是乱调。
2)Alias 组别
不同 streamType 可能共享同一套音量策略(mStreamVolumeAlias)。adjustStreamVolume 先解析 alias,再 getDeviceForStream 找当前输出设备。
3)消息机制
真正「把 index 写进设备状态」常走 Handler(如 MSG_SET_DEVICE_VOLUME → setDeviceVolume),避免在按键线程里塞太多同步工作。setDeviceVolume 还会把同一 alias 下其它流一并 apply,所以 log 里会刷很多 stream——跟当前关心的那一类即可。
4)index 是刻度,不是 dB
applyDeviceVolume_syncVSS 算出的 index 是 UI 进度(例如音乐 0~15)。静音、A2DP 绝对音量、full volume 设备等会改 index 算法。最后调用:
AudioSystem.setStreamVolumeIndex(streamType, index, device)
Java 层到此基本结束;真正响度计算在 Native。
三、Native:Policy 算策略,Flinger 做软音量
3.1 AudioSystem → AudioPolicyService
AudioSystem::setStreamVolumeIndex 通过 Binder 找到 media.audio_policy,转到:
AudioPolicyManager::setStreamVolumeIndex
→ 按 stream 取 attributes / volume group
→ setVolumeIndexForAttributes
→ setVolumeCurveIndex(记下曲线上的 index)
→ 遍历活跃 output
→ checkAndSetVolume(算 volumeDb 并 setVolume)
这里体现 Policy 的价值:不是简单 index → 音量,还要看:
- 当前是否静音、通话 / BT SCO 互斥
- 固定音量设备(有的通路强制 0 dB 软件衰减,改交给耳机或功放)
- 多 strategy 抢同一输出时的优先级(硬件增益场景尤其明显)
- TV 等平台上,是否用 MUSIC 曲线统一驱动、开机动画期间特殊衰减等
算完后 outputDesc->setVolume(...),把结果交给执行侧;必要时再 setVoiceVolume。
3.2 AudioFlinger:软音量在混音时落地
软音量经典形态(示意):
最终增益 ≈ masterVolume × streamTypeVolume × trackVolume × VolumeShaper …
在 Direct / Mixer 线程的 prepareTracks_l 里,会对活跃 track 调用类似 processVolume_l:
- 主静音 / 流静音 / 播放限制 → 增益置 0
- 否则按上面公式算左右声道
- 有 effect chain 时,音量常交给 effect;否则
setVolumeForOutput_l直接设输出
可以记: Policy 决定「这一路该多少」;Flinger 在 每条 track / 每次混音准备 时把数乘到 PCM(或交给下游)。
四、HAL:硬件增益与写数时再乘一遍
到芯片侧,常见两条腿:
4.1 端口配置:adev_set_audio_port_config(配置阶段)
Framework / Policy 通过 port config 下发 GAIN 时,HAL 会:
- 校验
AUDIO_PORT_CONFIG_GAIN - 在 patch 列表里找到对应补丁
- 按 sink / source 角色写入
sink_gain[]/src_gain[] - 扬声器增益变化时做 easing(淡入淡出),避免「咔」一下跳变
- 若走 Dolby MS12,可能同步 DAP postgain / main volume
这是「把策略增益记进 HAL 设备状态」。
4.2 数据处理:audio_hal_data_processing(写流阶段)
真正出 PCM 时,HAL 常再:
- 按输出格式分支(IEC61937 / AC3 / DTS / PCM32 / TV 8ch 映射…)
- 对 SPK/HP 乘上
sink_gain、EQ、线路增益等 - MS12 管音量时,软件侧可能 强制 volume=1.0,避免双重衰减
- easing 进行中时,由 ease 进程接管,而不是再暴力
apply_volume
所以:同一套 index,可能一部分在 Flinger 软乘,一部分在 HAL/MS12/功放——查「为什么音量不线性」时要两边对照。
五、软音量 vs 硬件音量(适配时怎么选)
| 软音量 | 硬件音量 | |
|---|---|---|
| 改什么 | PCM 样本幅度 | 功放 / Codec / MS12 增益 |
| 优点 | 实现快、流级别灵活 | 底噪、动态范围、功耗往往更好 |
| 缺点 | 减太狠伤信噪比 | 要适配每路输出设备 |
| 常见组合 | App/媒体流精细调节 | 总音量、TV 喇叭主音量 |
TV / Soundbar 上常见策略:
- 喇叭:偏硬件增益 +(可选)软 easing
- HDMI-ARC / 部分数字口:软件常固定 0 dB,音量交给回传设备(CEC/功放)
- A2DP:看是否支持 AVRCP 绝对音量,决定 HAL 是否还要再衰减
六、排查清单(实用)
- UI index 变了吗?(Java
sendVolumeUpdate) - Policy 是否算出合理 volumeDb?(
checkAndSetVolume/ 曲线) - Flinger track 软音量是否更新?(
processVolume_l/ mute) - HAL
sink_gain变了吗?(adev_set_audio_port_config) - 写 PCM 时是否又乘了一次?是否与 MS12 双重控制冲突?
- 当前设备是 SPEAKER 还是 ARC/耳机? 策略可能完全不同
Log 建议同时抓:audioserver、audio_policy、HAL 音量相关 tag;只抓一层很容易误判。
总结
Android 音量不是「一个 API 改寄存器」这么简单,而是:
- Java 负责交互与 index
- AudioPolicy 负责曲线、设备、优先级 → dB
- AudioFlinger 负责混音路径上的软音量
- HAL 负责硬件增益与出流时再应用
把 软 / 硬分工 和 当前输出设备 想清楚,音量适配和「调了没反应」类问题会好查很多。
相关阅读
评论
还没有评论,来做第一个吧
读完了不评论,作者会以为你在沉思