第九板块:Android 多媒体体系 | 第二十三篇:AudioFlinger 与 AudioPolicyService 音频架构
所属板块:第九板块 — Android 多媒体体系
前置知识:第二十二篇中的网络体系、Linux 内核驱动、Binder IPC、SELinux、Cgroup 资源隔离
本篇定位:这是 Android 设备听觉体验的中央处理器。如果说屏幕是输出视觉,那么音频系统就是输出声音的神经中枢。本篇将彻底拆解 AudioFlinger 的混音(Mixing)引擎、AudioPolicyService 的策略决策逻辑、音频流(AudioTrack/AudioRecord) 的生命周期、音频焦点(Audio Focus) 的仲裁机制、低延迟音频(Fast Mixer) 的实现。我们将深入 HAL(Hardware Abstraction Layer)、Kernel ALSA 驱动 与 Framework Native 层,揭示 Android 如何在多应用同时发声时,既保证低延迟又保证互不干扰。
1. 核心结论先行(Thesis Statement)
Android 的音频系统是一个基于策略与合成的实时流水线。
- AudioFlinger 的本质:音频合成工厂。它运行在 System Server 之外的独立 Native 进程中,负责接收所有应用的音频数据(PCM),进行混音(Mixing)、重采样(Resampling)、格式转换,并最终写入 HAL 接口。
- AudioPolicyService 的本质:音频交通警。它运行在 System Server 中,负责制定规则:哪个设备(Speaker/Headset/BT)发声、音量多大、是否允许某个应用发声(音频焦点)。
- 音频流的本质:共享内存(Shared Memory)的搬运。应用通过
AudioTrack将 PCM 数据写入匿名共享内存(Ashmem),AudioFlinger 读取并混音。 - 低延迟的本质:绕过普通混音器。通过 Fast Mixer 线程,建立从应用到底层驱动的直通路径(Passthrough),减少缓冲区拷贝。
2. 音频架构全景图
2.1 从应用播放到喇叭发声
graph TB
subgraph App ["应用进程"]
AT["AudioTrack (Java/Native)"]
AFocus["AudioManager (请求焦点)"]
end
subgraph SystemServer ["System Server"]
APS["AudioPolicyService"]
AFlinger["AudioFlinger"]
end
subgraph HAL ["硬件抽象层"]
AudioHAL["audio.primary.so"]
end
subgraph Kernel ["Linux 内核"]
ALSA["ALSA Driver (snd_pcm)"]
Dev["/dev/snd/pcmC0D0p"]
end
subgraph Hardware ["硬件"]
Codec["Audio Codec"]
Speaker["Speaker/Headset"]
end
AT -->|"1. 写入 PCM 数据"| AFlinger
AFocus -->|"2. 请求焦点"| APS
APS -->|"3. 决策 (选设备/算音量)"| AFlinger
AFlinger -->|"4. 混音/重采样"| AudioHAL
AudioHAL -->|"5. pcm_write()"| ALSA
ALSA -->|"6. DMA 传输"| Dev
Dev -->|"7. I2S 信号"| Codec
Codec -->|"8. 模拟信号"| Speaker
2.2 核心组件职责表
| 组件 | 层级 | 职责 | 学术定义 |
|---|---|---|---|
| AudioPolicyService | Framework | 决策者 | 管理音频路由、音量曲线、音频焦点、设备选择。 |
| AudioFlinger | Native | 执行者 | 管理音频流、混音线程、重采样、与 HAL 交互。 |
| PlaybackThread | Native | 工作线程 | AudioFlinger 中的线程,负责特定输出设备的混音循环。 |
| AudioTrack | Framework | 客户端接口 | 应用向音频系统输送数据的接口。 |
| AudioHAL | HAL | 硬件接口 | 厂商实现的库,屏蔽不同硬件的差异。 |
3. AudioFlinger 的混音引擎
3.1 音频流(Track)的生命周期
AudioFlinger 为每个播放请求创建一个 Track。
stateDiagram-v2
[*] --> Idle: 创建 AudioTrack
Idle --> Active: start()
Active --> Flushing: flush()
Flushing --> Active
Active --> Paused: pause()
Paused --> Active: start()
Active --> Stopped: stop()
Stopped --> [*]: 释放资源
3.2 混音线程(PlaybackThread)
AudioFlinger 针对不同的输出设备创建不同的线程。
| 线程类型 | 特点 | 适用场景 |
|---|---|---|
| MixerThread | 最常用。支持多路混音,重采样。 | 音乐、游戏音效。 |
| DirectOutputThread | 直通。不经过混音器,直接写入 HAL。 | HDMI 源码输出、USB 音频。 |
| OffloadThread | 硬解码。将压缩数据(MP3/AAC)直接送给 DSP 解码。 | 音乐播放(省电)。 |
3.3 混音算法(Mixing)
AudioFlinger 使用 Fixed-point Arithmetic(定点运算) 进行混音,以保证性能和精度。
学术定义:
- 混音公式:
- 重采样(Resampling):如果应用的采样率(如 44.1kHz)与硬件采样率(如 48kHz)不匹配,必须进行重采样。AudioFlinger 使用 SRC(Sample Rate Converter) 算法。
- 溢出处理:混音后的值可能超过 16-bit 范围(-32768 ~ 32767),需要进行 Clipping(削波) 处理。
4. AudioPolicyService 的策略决策
4.1 音频焦点(Audio Focus)仲裁
当多个应用同时请求播放时,APS 决定谁有权发声。
学术定义:
- 焦点类型:
AUDIOFOCUS_GAIN:长时间播放(音乐)。AUDIOFOCUS_GAIN_TRANSIENT:短暂播放(导航提示)。AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:短暂播放,允许原声音量降低(通知音)。
- 仲裁逻辑:
- 新应用请求焦点。
- APS 检查当前焦点持有者。
- 根据焦点类型和优先级,决定是 抢占(Abandon) 还是 拒绝(Fail)。
sequenceDiagram
participant Nav as 导航应用
participant Music as 音乐应用
participant APS as AudioPolicyService
Music->>APS: requestFocus(GAIN)
APS->>Music: 授予焦点 (AUDIOFOCUS_REQUEST_GRANTED)
Music->>Music: 开始播放
Nav->>APS: requestFocus(GAIN_TRANSIENT_MAY_DUCK)
APS->>Music: 通知降低音量 (onAudioFocusChange)
APS->>Nav: 授予焦点
Nav->>Nav: 播放导航音 (音乐音量变小)
4.2 设备路由选择
APS 根据设备连接状态和策略选择输出设备。
| 设备状态 | 路由决策 |
|---|---|
| 仅扬声器 | 路由到 Speaker。 |
| 插入有线耳机 | 路由到 Headset(强制切换)。 |
| 连接蓝牙 A2DP | 路由到 Bluetooth(如果未插耳机)。 |
| HDMI 连接 | 路由到 HDMI(数字音频)。 |
5. 低延迟音频(Fast Mixer)
5.1 普通路径 vs 快速路径
| 特性 | 普通路径 (MixerThread) | 快速路径 (Fast Mixer) |
|---|---|---|
| 缓冲区大小 | 大 (20-100ms) | 极小 (2-5ms) |
| 线程优先级 | 普通 | SCHED_FIFO (实时) |
| 重采样 | 支持 | 不支持 (必须匹配硬件) |
| 混音 | 多路混音 | 单路直通 |
| 适用场景 | 音乐、视频 | 游戏、VOIP、乐器 |
5.2 Fast Mixer 的实现
Fast Mixer 是一个独立的线程,绑定到特定的 CPU 核心,使用 FIFO 调度策略。
学术定义:
- SCHED_FIFO:实时调度策略。一旦线程运行,除非主动放弃或更高优先级抢占,否则不会被切换出去。
- CPU Affinity:将线程绑定到特定的 CPU 核心,避免缓存失效和上下文切换延迟。
6. 关键源码深度解析
6.1 AudioFlinger 的混音循环
// frameworks/av/services/audioflinger/Threads.cpp
void AudioFlinger::MixerThread::threadLoop() {
while (!exitPending()) {
// 1. 等待音频硬件就绪 (poll)
waitForPcmSync();
// 2. 准备混音缓冲区
memset(mMixBuffer, 0, mMixBufferSize);
// 3. 遍历所有活跃的 Track
for (const sp<Track>& track : mActiveTracks) {
// 读取 Track 数据
track->getNextBuffer(&buffer);
// 重采样
resample(buffer);
// 混音 (定点运算)
mix(mMixBuffer, buffer, track->volume);
}
// 4. 写入 HAL
mOutput->write(mMixBuffer, mMixBufferSize);
}
}
6.2 AudioPolicyService 的焦点管理
// frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
status_t AudioPolicyService::requestAudioFocus(...) {
// 1. 检查是否已有焦点持有者
sp<AudioFocusInfo> current = mFocusStack.top();
// 2. 检查优先级
if (newFocus.priority <= current.priority) {
// 抢占当前焦点
current->client->onAudioFocusChange(AUDIOFOCUS_LOSS);
mFocusStack.pop();
}
// 3. 授予新焦点
mFocusStack.push(newFocus);
return NO_ERROR;
}
7. 音频系统的常见误区
| 误区 | 学术解释 |
|---|---|
| 音量越大,声音越响 | 音量是数字增益(Digital Gain),过大会导致 Clipping(削波失真)。 |
| 采样率越高,音质越好 | 如果源文件是 44.1kHz,强行升到 48kHz 会有损音质(SRC 误差)。 |
| 蓝牙音频是无损的 | 绝大多数蓝牙音频使用 SBC 编码(有损压缩),LDAC/aptX HD 才是接近无损。 |
| 应用可以直接控制硬件 | 不可以。所有音频必须经过 AudioFlinger 混音,应用只能控制自己的 Track 音量。 |
8. 本篇总结(Knowledge Closure)
| 关键点 | 纯学术定义 |
|---|---|
| AudioFlinger 的本质 | 音频合成工厂,负责混音、重采样、格式转换。 |
| AudioPolicyService 的本质 | 音频交通警,负责路由、音量、焦点仲裁。 |
| 音频流路径 | 应用 -> AudioTrack -> Shared Memory -> AudioFlinger -> HAL -> Kernel。 |
| 低延迟实现 | Fast Mixer + SCHED_FIFO + CPU Affinity + 小缓冲区。 |
| 音频焦点 | 基于优先级的抢占式仲裁机制。 |
9. 第九板块结语
至此,第九板块:Android 多媒体体系 已完成核心架构解析。
我们从 AudioFlinger 的混音引擎 出发,深入 AudioPolicyService 的策略决策,探索 音频焦点的仲裁逻辑,最终抵达 低延迟音频的实时实现。
我们揭示了 Android 音频系统的设计哲学:用策略隔离应用,用混音共享硬件,用实时线程保障延迟。
下一篇预告:第九板块:Android 多媒体体系 | 第二十四篇:Camera Service 与 HAL3 成像流水线