3. Android音频基础
在车载音频工程中,Android 音频框架是连接应用层与硬件编解码器(Codec)的桥梁。理解 AudioTrack、AudioRecord、AudioFlinger、AudioPolicy 以及音频流与音频设备之间的关系,是后续进行 HAL 定制、多音区管理、音效路由和低延迟优化的前提。本节从数据流向出发,梳理这些核心组件各自的职责与协作方式。
一、核心组件与数据流向
Android 音频系统可以粗略分为四层:应用层、框架服务层、HAL 层和内核/硬件层。应用通过 AudioTrack 播放音频、通过 AudioRecord 采集音频;这两个 Java API 最终都会通过 JNI 进入 native 层,与 AudioFlinger 交互。AudioFlinger 是音频系统的“混音与调度中心”,负责创建播放线程、混音多路音频流、管理输出设备;而 AudioPolicyService 则是“策略决策中心”,决定某条音频流应该走哪个设备、音量如何映射、何时切换路由。
可以用一句话概括:AudioPolicy 决定“往哪走”,AudioFlinger 负责“怎么混、怎么送”,AudioTrack/AudioRecord 是应用侧的出入口。
二、AudioTrack 与 AudioRecord:应用侧出入口
AudioTrack 用于播放 PCM 数据,支持两种模式:STATIC(一次性写入短音频,适合提示音)和 STREAM(持续写入,适合音乐、导航播报)。在车载场景中,导航播报、TTS、媒体音乐通常都走 STREAM 模式。创建 AudioTrack 时需要指定音频属性(AudioAttributes)、格式(采样率、声道、位深)和缓冲区大小。
// 典型 AudioTrack 创建(播放导航播报)
AudioAttributes attrs = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build();
AudioFormat format = new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setSampleRate(48000)
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
.build();
int bufSize = AudioTrack.getMinBufferSize(48000,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
AudioTrack track = new AudioTrack.Builder()
.setAudioAttributes(attrs)
.setAudioFormat(format)
.setBufferSizeInBytes(bufSize * 2)
.setTransferMode(AudioTrack.MODE_STREAM)
.build();
track.play();
track.write(pcmData, 0, pcmData.length);
AudioRecord 则用于采集,例如车载语音助手、免提通话、车内麦克风阵列。它同样需要指定音频源(MediaRecorder.AudioSource),如 VOICE_RECOGNITION、MIC、CAMCORDER 等。采集到的 PCM 数据可以送入语音识别引擎或回声消除模块。
三、AudioFlinger:混音与调度中心
AudioFlinger 位于 frameworks/av/services/audioflinger/,是 native 层的核心服务。它主要做三件事:
- 创建和管理线程:每个输出设备对应一个
PlaybackThread(MixerThread / DirectOutputThread / OffloadThread),每个输入设备对应一个RecordThread。 - 混音:将多个 AudioTrack 的 PCM 数据按音量、格式混合成一路输出。车载中常见的前排导航+后排媒体同时播放,就依赖 MixerThread 的多轨混音能力。
- 重采样与格式转换:当应用采样率与硬件采样率不一致时,AudioFlinger 会调用
AudioResampler进行转换。
关键理解:AudioFlinger 不决定“走哪个设备”,它只负责把数据混好并送到 AudioPolicy 指定的输出流上。设备选择、路由切换由 AudioPolicyService 完成。
四、AudioPolicy:路由与策略决策
AudioPolicyService 是 Android 音频的“交通指挥”。它根据音频流的 usage、content type、当前设备连接状态(如蓝牙、USB、耳机插入)以及车载音区配置,决定:
- 这条流应该输出到哪个设备(内置扬声器、蓝牙 A2DP、USB Audio、车载功放)?
- 音量组如何映射?不同音区(主驾、副驾、后排)的音量是否独立?
- 当设备热插拔时,是否需要暂停、切换或重新路由?
- 输入设备如何选择?麦克风阵列还是蓝牙麦克风?
在车载项目中,AudioPolicy 的配置文件通常位于 /vendor/etc/audio_policy_configuration.xml,其中定义了 audioPolicyConfiguration、modules、mixPorts、devicePorts 和 routes。HAL 工程师经常需要修改这个文件来适配多音区、多声道和外部功放。
五、音频流与音频设备的关系
Android 用 AudioAttributes 描述“这是什么声音”,用 AudioDeviceInfo 描述“声音从哪出/从哪进”。音频流(stream)是逻辑概念,音频设备(device)是物理概念,AudioPolicy 负责把逻辑流映射到物理设备。
| 概念 | 典型取值/示例 | 作用 |
|---|---|---|
| Usage | MEDIA / NAVIGATION / VOICE_COMMUNICATION | 决定路由优先级和音量策略 |
| Content Type | MUSIC / SPEECH / SONIFICATION | 影响音效处理和音量曲线 |
| Stream Type(旧) | STREAM_MUSIC / STREAM_VOICE_CALL | 兼容旧 API,逐步被 Attributes 替代 |
| Device Type | DEVICE_OUT_SPEAKER / BUS / BLUETOOTH_A2DP | 标识物理输出/输入设备 |
| Audio Port | mixPort / devicePort | Policy 配置中的路由端点 |
六、车载场景案例:导航播报与媒体音乐并存
假设主驾正在用媒体音乐,同时导航发起播报。系统处理流程如下:
- 导航 App 创建 AudioTrack,Usage 为
USAGE_ASSISTANCE_NAVIGATION_GUIDANCE。 - AudioPolicyManager 根据 usage 和当前设备状态,决定导航流走主音区扬声器,并可能触发媒体音乐“闪避”(ducking)。
- AudioFlinger 的 MixerThread 将导航 PCM 与媒体 PCM 按策略混音,导航音量优先。
- 混音后的数据通过
audio_stream_out->write()写入 HAL。 - HAL 将 PCM 送到 DSP/功放,最终由扬声器输出。
调试提示:如果导航播报时媒体没有闪避,优先检查 AudioPolicy 的 ducking 配置和 AudioAttributes 的 usage 是否正确;如果播报走错音区,检查 audio_policy_configuration.xml 中的 route 和 devicePort 映射。
七、常见误区与复盘
- 误区一:AudioFlinger 决定设备。实际上 AudioFlinger 只负责混音和线程管理,设备选择由 AudioPolicy 完成。
- 误区二:AudioTrack 缓冲区越大越好。缓冲区过大会增加延迟,车载导航播报要求低延迟,通常取
getMinBufferSize()的 2 倍左右。 - 误区三:采样率不匹配会自动处理。AudioFlinger 会重采样,但重采样会引入额外延迟和音质损失,HAL 层应尽量让应用与硬件采样率一致。
- 误区四:AudioRecord 采集不需要权限。Android 6.0 以后需要
RECORD_AUDIO运行时权限,车载系统还需注意隐私合规。
掌握 AudioTrack、AudioRecord、AudioFlinger、AudioPolicy 以及音频流与音频设备之间的协作关系,是后续进行 Audio HAL 定制、多音区路由、低延迟优化和车载音效调试的基础。在排查音频问题时,建议按照“应用属性 → Policy 路由 → Flinger 混音 → HAL 输出 → 硬件”的顺序逐层定位,避免盲目修改配置。