3. Android音频架构总览
Android 音频系统是一个典型的跨层协作系统。从应用播放一段音乐,到扬声器真正发出声音,数据要穿过应用层、Framework 层、Native 层、HAL 层和内核层五个层次。理解这五层的职责边界与数据流向,是后续深入 AudioFlinger、AudioTrack、AudioPolicy 等模块的基础。本章先建立整体地图,后续章节再逐层拆解。
一、五层架构的核心职责
Android 音频架构的分层不是简单的代码目录划分,而是按“谁负责什么”来切分的。每一层只暴露有限接口给上层,屏蔽下层实现细节,从而让应用无需关心底层是 Codec 还是 DSP。
- 应用层:使用 MediaPlayer、SoundPool、AudioTrack、AudioRecord、OpenSL ES、AAudio 等 API 播放或录制音频,只关心“播放什么、录什么”,不关心混音与路由。
- Framework 层:以 AudioService、AudioManager、MediaPlayer 等 Java 类为核心,负责音频焦点、音量策略、设备切换、权限校验,并通过 JNI 调用 Native 层。
- Native 层:AudioFlinger 是音频系统的“心脏”,负责混音、重采样、音轨管理;AudioPolicyService 负责路由与策略决策;AudioTrack/AudioRecord 的 Native 实现负责与 AudioFlinger 建立共享内存通道。
- HAL 层:Audio HAL 定义标准接口(如 audio_hw_device、audio_stream_out),把 AudioFlinger 的混音结果交给具体硬件驱动,是 Native 与内核之间的“适配层”。
- 内核层:ALSA SoC、Codec 驱动、DMA、I2S/PDM 等负责把 PCM 数据真正送到扬声器或从麦克风取回数据。
二、数据流与控制流的分层关系
音频系统中存在两条方向不同的“流”:一条是 PCM 音频数据流,自下而上或自上而下传输;另一条是控制流,负责策略、路由、焦点、音量等决策。二者在 Native 层交汇,由 AudioFlinger 与 AudioPolicyService 协同完成。
以播放为例,数据流方向为:应用写入 PCM → AudioTrack Native → AudioFlinger 混音 → HAL 输出流 → 内核 ALSA → 扬声器。控制流方向为:应用请求音频焦点 → AudioService → AudioPolicyService → 选择输出设备 → 通知 AudioFlinger 切换路由。
三、关键组件在分层中的位置
初学者容易把 AudioFlinger 和 AudioPolicyService 混为一谈。二者都在 Native 层,但职责完全不同:AudioFlinger 是“执行者”,负责把多路音轨混成一路 PCM;AudioPolicyService 是“决策者”,负责决定用哪个设备、走哪条通路、音量多大。
| 层次 | 代表组件 | 核心职责 | 对外接口 |
|---|---|---|---|
| 应用层 | MediaPlayer、AudioTrack | 播放/录制业务逻辑 | Java/Kotlin API |
| Framework 层 | AudioService、AudioManager | 焦点、音量、权限、设备管理 | Binder + JNI |
| Native 层 | AudioFlinger、AudioPolicyService | 混音、重采样、路由决策 | IAudioFlinger、IAudioPolicyService |
| HAL 层 | audio_hw_device | 硬件抽象与适配 | C 结构体函数指针 |
| 内核层 | ALSA SoC、Codec 驱动 | DMA 传输、寄存器配置 | 字符设备 / sysfs |
四、典型场景:从点击播放到出声
假设用户在音乐 App 中点击播放按钮,系统内部大致经历以下步骤:
- 应用调用 MediaPlayer.start(),Framework 层创建 AudioTrack 并申请音频焦点。
- AudioService 校验权限后,通过 JNI 通知 Native 层创建 AudioTrack。
- AudioFlinger 为该音轨分配共享内存 Ring Buffer,并注册到混音线程。
- AudioPolicyService 根据当前设备状态(有线耳机/蓝牙/扬声器)选择输出通路。
- AudioFlinger 混音线程周期性地从 Ring Buffer 取数据,混音后写入 HAL 输出流。
- HAL 调用内核 ALSA 接口,DMA 将 PCM 搬运到 Codec,最终驱动扬声器发声。
dumpsys media.audio_flinger 查看当前音轨、混音线程与输出设备;用 dumpsys media.audio_policy 查看路由策略与设备状态。二者结合能快速定位“有音轨但没声音”这类问题。
五、常见误区与复盘
误区一:认为应用层直接调用 HAL。实际上应用必须经过 Framework 与 Native 层,任何绕过 AudioFlinger 的直通路径都会破坏混音与策略一致性。
误区二:把 AudioFlinger 当成“音频驱动”。AudioFlinger 只是软件混音器,真正操作硬件的是 HAL 与内核驱动。
误区三:忽略控制流。很多“播放失败”并非数据通路问题,而是音频焦点被抢占、路由未切换或音量被静音,属于控制流范畴。
# 查看音频服务状态
adb shell dumpsys media.audio_flinger
adb shell dumpsys media.audio_policy
# 查看内核声卡与 PCM 设备
adb shell cat /proc/asound/cards
adb shell cat /proc/asound/pcm