AudioFlinger 笔记

12 阅读6分钟

理解了 audioserver 的整体架构后,我们深入剖析其核心引擎——AudioFlinger。如果说 audioserver 是音频系统的大脑,那么 AudioFlinger 就是那颗 最强劲的心脏,负责所有音频数据的实际搬运、混合和处理。

🎯 AudioFlinger 的角色定位

AudioFlinger 是 Android 音频系统的底层服务,运行在 audioserver 进程中,作为 Binder 服务 注册在 ServiceManager 中。它的核心使命是:

  • 接收来自多个应用(AudioTrack 客户端)的音频数据流。
  • 处理这些数据:混音、重采样、格式转换、音量/效果处理。
  • 分发到正确的硬件设备(扬声器、耳机、蓝牙等)进行播放。
  • 录制时,从麦克风等输入设备捕获数据,分发给录音客户端(AudioRecord)。

简单说,AudioFlinger 是音频数据从“多路输入”到“单路输出”(或反之)的汇合点与分发中心

🧱 核心架构:线程 + 模块

AudioFlinger 内部采用 多线程 + 效果模块 的架构。其关键组件如下:

组件职责
PlaybackThread播放线程基类,管理特定输出设备的音频数据流。
- MixerThread最常见的播放线程,支持多个 AudioTrack 混音。
- DirectOutputThread直通线程,不混音,用于低延迟或高采样率音频。
- OffloadThread硬件解码线程,将压缩音频(如 MP3、AAC)直接交给 DSP 处理,省电。
- BitmapThread用于 HDMI 直通等场景。
RecordThread录制线程,从输入设备读取数据并分发给 AudioRecord 客户端。
EffectModule效果器模块(均衡器、混响、重低音等)。
EffectChain将多个效果器串联成链,按顺序处理音频。
HAL 接口通过 HIDL/AIDL 与底层音频硬件抽象层通信。

🔄 播放数据流全景

一个典型的播放流程如下(以音乐播放器为例):

  1. 客户端创建 AudioTrack:应用通过 AudioTrack JNI 调用 Native 层,AudioTrack 通过 Binder 向 AudioFlinger 注册一个 Track
  2. 线程分配AudioPolicyService 根据流类型、设备等策略,告诉 AudioFlinger 将该 Track 挂载到哪个 PlaybackThread(例如默认的 MixerThread)。
  3. 共享内存:AudioFlinger 为每个 Track 分配一块 共享内存IMemory),客户端直接将 PCM 数据写入该内存。
  4. 混音循环:播放线程循环执行:
    • 从所有活跃 Track 的共享内存中读取数据。
    • 对每个 Track 进行重采样(统一到线程采样率)、格式转换、音量调节、单声道/立体声转换。
    • 调用 Mixer 将所有 Track 数据按浮点/整型累加混合。
    • 应用 全局效果器(如 SoundFX)。
    • 将混音后的数据写入 输出流(通过 HAL 向设备发送)。
  5. 回调通知:AudioFlinger 通过共享内存的控制信息通知客户端已消费了数据,以便客户端写入新数据。

🧵 播放线程详解:混音器与直通

MixerThread(混音线程)

  • 支持 最多约 32 路 音频流同时混音(取决于配置)。
  • 内部维护一个 mMixer 对象,执行混音算法。
  • 支持 动态重采样:如果 Track 采样率与线程采样率不同,使用 SRC(采样率转换器)进行转换。
  • 混音后数据格式通常为 PCM 16-bit 或 Float。
  • 该线程运行在普通调度优先级,但可启用 FastMixer(见后文性能优化)。

DirectOutputThread(直通线程)

  • 每个 Track 独占一个线程,不混音。
  • 用于 低延迟(如 VoIP、游戏音效)或 高采样率(如 192kHz 高解析度音频)场景。
  • 直接将 Track 数据交给 HAL,绕过混音器,避免额外延迟。

OffloadThread(硬件解码线程)

  • 用于播放 MP3、AAC 等压缩音频。
  • 将压缩数据直接通过 HAL 传递给 DSP 解码,而不是在 CPU 上解码成 PCM。
  • 极大降低功耗,常用于音乐播放。
  • 系统会优先使用 Offload,但若需要混音(如播放通知音),则切换回 MixerThread。

🎛️ 效果处理(Effect)

AudioFlinger 支持两种效果附着方式:

  • Track 级效果:仅应用于某个特定 Track,如语音通话的回声消除、降噪。
  • 线程级效果:应用于整个输出混音后的最终数据,如全局均衡器、低音增强。

效果通过 EffectModule 管理,多个效果串成 EffectChain。每个效果器是一个动态库(.so),实现 effect_handle_t 接口。AudioFlinger 通过 EffectApi 加载并调用它们。

处理流程示例(MixerThread 混音后):

混音数据 → 效果链第1个 → 第2个 → ... → 最终写入 HAL

🎙️ 录制数据流

录制相对简单:

  • 每个 AudioRecord 客户端对应 RecordThread 中的一个 RecordTrack
  • RecordThread 从 HAL 读取输入设备(麦克风)的 PCM 数据。
  • 将数据 复制 到每个活跃 RecordTrack 的共享内存中。
  • 支持同时录制:多个应用可同时录音,AudioFlinger 会分发相同的数据。

录制时也可应用效果,如噪声抑制、自动增益控制等。

⚡ 性能优化:FastMixer 与 FastTrack

Android 从 4.0 开始引入 FastMixer 架构,极大降低播放延迟(可达 10ms 以下)。

  • FastMixer:一个运行在 高优先级实时线程SCHED_FIFO)中的轻量级混音器,与普通 MixerThread 并存。
  • FastTrack:客户端若请求低延迟(通过 AudioTrackAUDIO_OUTPUT_FLAG_FAST 标志),AudioFlinger 会尝试将其分配到 FastTrack。
  • 流程:
    • 普通 Track 在 MixerThread 中混音,结果放入一个 双缓冲区
    • FastMixer 直接读取该缓冲区并快速写入 HAL,同时也可混入 FastTrack 数据。
    • 这避免了 MixerThread 因调度延迟导致缓冲区欠载。

该机制依赖于底层 HAL 支持小缓冲区大小,且硬件需提供可靠的低延迟路径。

🔌 与 HAL 的交互

AudioFlinger 通过 HIDL(Android 8-12)或 AIDL(Android 13+) 与音频 HAL 服务通信。HAL 服务位于独立进程(如 android.hardware.audio.service),实现 IDeviceIStreamInIStreamOut 等接口。

典型的 HAL 调用链:

AudioFlinger::PlaybackThread::threadLoop()
   → mOutput->write(mMixBuffer, size)   // mOutput 是 HAL 输出流代理
      → 通过 Binder 调用 HAL 服务的 StreamOut::write()
         → 最终由 HAL 实现写入 ALSA / TinyAlsa 等内核驱动

AudioFlinger 会动态打开/关闭设备(扬声器、耳机、USB 声卡等),这些决策由 AudioPolicyService 下达,但实际执行打开/关闭 HAL 流的是 AudioFlinger。

🛡️ 安全与权限

  • AudioFlinger 运行在 audioserver 用户组,拥有访问 /dev/snd/* 等音频设备的权限。
  • 通过 SELinux 策略(audioserver.te)限制其只能访问音频相关资源。
  • 客户端 Binder 调用时会检查调用者权限(如 RECORD_AUDIO 录音权限)。

📝 总结:AudioFlinger 的关键设计

方面设计要点
并发播放多线程 + 混音器,支持数十路音频流同时播放
低延迟FastMixer 实时线程 + FastTrack 直通路径
功耗优化OffloadThread 硬件解码,避免 CPU 解码
灵活性直通线程支持高采样率/位深,不强制混音
扩展性效果链机制,可动态加载自定义音频效果库
健壮性每个播放/录制线程独立,崩溃不影响其他线程

AudioFlinger 是整个 Android 音频架构的 数据平面,而 AudioPolicyService控制平面。两者分离,使得音频策略可以独立演进,同时 AudioFlinger 专注于高效、低延迟的数据搬运与处理。理解 AudioFlinger 的工作原理,是深入定制音频 HAL、优化音频性能或调试音频问题的关键。