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 数据真正送到扬声器或从麦克风取回数据。
核心记忆点:应用层“要声音”,Framework 层“管策略”,Native 层“做混音”,HAL 层“转接口”,内核层“出声音”。

二、数据流与控制流的分层关系

音频系统中存在两条方向不同的“流”:一条是 PCM 音频数据流,自下而上或自上而下传输;另一条是控制流,负责策略、路由、焦点、音量等决策。二者在 Native 层交汇,由 AudioFlinger 与 AudioPolicyService 协同完成。

以播放为例,数据流方向为:应用写入 PCM → AudioTrack Native → AudioFlinger 混音 → HAL 输出流 → 内核 ALSA → 扬声器。控制流方向为:应用请求音频焦点 → AudioService → AudioPolicyService → 选择输出设备 → 通知 AudioFlinger 切换路由。

Android 音频五层架构与数据/控制流 应用层 MediaPlayer · AudioTrack · AudioRecord · SoundPool · AAudio · OpenSL ES Framework 层 AudioManager · AudioService · MediaPlayer(Java) · AudioSystem · JNI Native 层 AudioFlinger(混音/重采样/音轨管理) · AudioPolicyService(路由/策略) AudioTrack/AudioRecord Native · 共享内存 Ring Buffer HAL 层 audio_hw_device · audio_stream_out · audio_stream_in · 厂商实现 内核层 ALSA SoC · Codec 驱动 · DMA · I2S/PDM · 扬声器/麦克风 PCM 数据流 控制/策略流

三、关键组件在分层中的位置

初学者容易把 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 中点击播放按钮,系统内部大致经历以下步骤:

  1. 应用调用 MediaPlayer.start(),Framework 层创建 AudioTrack 并申请音频焦点。
  2. AudioService 校验权限后,通过 JNI 通知 Native 层创建 AudioTrack。
  3. AudioFlinger 为该音轨分配共享内存 Ring Buffer,并注册到混音线程。
  4. AudioPolicyService 根据当前设备状态(有线耳机/蓝牙/扬声器)选择输出通路。
  5. AudioFlinger 混音线程周期性地从 Ring Buffer 取数据,混音后写入 HAL 输出流。
  6. 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