1. 课程导入

在 Android 系统中,音频是最贴近用户体验、又最容易在移植阶段暴露问题的子系统之一。应用层调用 AudioTrack 播放音乐、AudioRecord 采集语音,最终都要经过 AudioFlinger、Audio HAL,落到具体芯片平台的 DSP、Codec 与功放上。Audio HAL 正是 Android 音频框架与硬件驱动之间的“适配层”,它决定了同一套 Android 音频服务能否在不同 SoC、不同 Codec、不同外设方案上稳定工作。本课程围绕“如何把 Audio HAL 适配到目标硬件并调通”展开,本章先建立整体认知地图。

一、学习目标:从“能编译”到“能量测、能定位”

Audio HAL 适配不是单纯改配置,而是一项横跨框架、HAL、内核驱动与硬件调试的系统工程。完成本课程后,应达到以下目标:

  • 理解 Android 音频从 App 到硬件的完整数据通路,明确 Audio HAL 在其中的位置与职责边界。
  • 掌握 Audio HAL 的接口形态演进,能区分 HIDL、AIDL 与旧版 legacy HAL 的差异与迁移要点。
  • 能独立完成 audio_policy_configuration.xml、audio_device.xml 等核心配置的编写与校验。
  • 掌握 PCM 通路、Mixer 控件、路由切换的调试方法,能借助 tinymix、tinyplay、dumpsys media.audio_flinger 定位问题。
  • 具备典型故障的排障能力:无声、杂音、断续、录音异常、路由错误、延迟偏大等。

二、核心概念:先厘清五个关键对象

在动手适配前,必须把几个高频概念区分清楚,否则很容易在“配置改了却没生效”的循环里打转。

概念所在层级核心作用常见载体
AudioFlingerNative 框架层混音、重采样、输出/输入流管理audioserver 进程
Audio HALHAL 层向框架暴露设备与流接口,转发到驱动audio.primary.*.so
Audio Policy策略层决定“什么声音走什么设备”audio_policy_configuration.xml
ALSA / TinyALSA内核与用户态接口PCM、Mixer、Control 的实际操作/dev/snd/*
Codec / DSP硬件层数模转换、功放、降噪、回声消除芯片寄存器与固件

其中最容易混淆的是 Audio HAL 与 Audio Policy:HAL 负责“怎么把数据送出去”,Policy 负责“该不该送到这个设备”。很多“插耳机没声音”的问题,根因其实在 Policy 的路由规则,而不是 HAL 的 PCM 通路。

三、整体框架:一条数据通路的全貌

下图给出 Android 音频从应用到底层硬件的分层结构与数据流向,同时标出适配工作的主要切入点。理解这张图,后续每一章的调试都能快速定位到对应层级。

Android 音频分层框架与 Audio HAL 适配切入点 应用层 MediaPlayer / AudioTrack / AudioRecord / OpenSL ES / AAudio 框架层 AudioService · AudioPolicyService · AudioFlinger(混音/重采样/流管理) Audio HAL 层(适配核心) IDevicesFactory / IStreamOut / IStreamIn · audio.primary.*.so · audio_policy_configuration.xml 内核与驱动层 ALSA SoC · DAPM · PCM / Mixer / Control · /dev/snd/* 硬件层 Codec · DSP · 功放 · 扬声器 / 听筒 / 麦克风 / 耳机 / 蓝牙 播放数据下行 流接口调用 PCM 写入 / 读取 寄存器与时钟配置 适配切入点 HAL 实现 · 配置文件 · 路由 Mixer 控件 · 时钟与增益 调试观测点 dumpsys media.audio_flinger · dumpsys media.audio_policy tinymix · tinyplay / tinycap · logcat · /proc/asound

四、方法流程:Audio HAL 适配的标准动作

面对一块新板子,适配工作通常按“先通后优”的顺序推进,避免一开始就陷入细节。

  1. 确认硬件拓扑:梳理 Codec 型号、I2S/TDM 接口、功放使能脚、麦克风偏置、耳机检测方式。
  2. 打通内核通路:确认 DTS 中 dai-link、codec、machine driver 配置正确,/proc/asound/cards 能看到声卡。
  3. 验证裸 PCM:用 tinyplay 直接播放,绕过 Android 框架,先证明底层能出声。
  4. 配置 HAL 与 Policy:编写 audio_policy_configuration.xml,声明设备、流、路由与增益。
  5. 框架联调:通过 dumpsys 与 logcat 检查流是否创建、路由是否命中、参数是否匹配。
  6. 场景回归:覆盖播放、录音、通话、耳机插拔、蓝牙切换、低延迟等典型场景。
适配顺序口诀:先内核、后 HAL;先裸 PCM、后框架;先出声、后调优。 跳过底层直接改 Policy,往往会把简单问题复杂化。

五、典型场景与误区复盘

以一个常见案例说明:某项目插入耳机后扬声器仍在响,耳机无声。排查发现 audio_policy_configuration.xml 中耳机设备未加入 attachedDevices,且路由规则缺少 WIRED_HEADSET 到 media 的映射。修正配置后,框架在检测到耳机插入时会自动切换路由。这个案例说明:路由问题优先查 Policy,通路问题优先查 HAL 与驱动。

初学者常见误区包括:

  • 把 HAL 当成“驱动”,忽略 Policy 对设备选择的主导作用。
  • 只改 XML 不重启 audioserver,导致配置未重新加载。
  • 采样率、位宽、通道数与硬件能力不匹配,出现变速、杂音或无声。
  • 忽略增益与 Mixer 控件,通路已通但音量极小或静音。
  • 不做裸 PCM 验证,问题定位在框架与硬件之间反复摇摆。
建议在项目初期就建立一份“音频适配检查清单”,把声卡识别、PCM 播放、录音、路由、增益、场景回归逐项打勾,能显著缩短调试周期。

六、学习路径:本课程的知识推进

后续内容将沿着“框架认知 → HAL 接口 → 配置与路由 → 通路调试 → 场景与排障”的主线展开。建议学习时同步准备一台可调试的开发板,边看边用 tinymix、tinyplay 和 dumpsys 验证,把抽象概念落到真实寄存器与日志上。只有把“框架—HAL—驱动—硬件”这条链路走通一遍,Audio HAL 适配才算真正入门。

# 快速自检常用命令
adb shell cat /proc/asound/cards
adb shell tinymix
adb shell tinyplay /data/test.wav -D 0 -d 0
adb shell dumpsys media.audio_flinger | head -n 40
adb shell dumpsys media.audio_policy | head -n 40
adb logcat -s AudioFlinger AudioPolicyManager AudioHal

掌握这些基础后,再进入具体接口实现与配置细节,就能做到“知其然,也知其所以然”。