21、音频系统深度调优:AudioFlinger原理、音频路由策略、回声消除与降噪、音频延迟优化

各位好,欢迎来到第21讲。今天聊点硬核的——音频系统调优。

说实话,在车载Android系统里,音频这块儿是最容易出“玄学问题”的。有时候声音断断续续,有时候通话有回声,有时候导航和音乐打架。这些问题的根子,大多藏在AudioFlinger、音频路由、以及延迟优化这几个环节里。

我当年在调一个海外车载项目时,客户反馈说“蓝牙通话时对方能听到自己的回声”,折腾了两周,最后发现是音频路由策略里一个flag没设对。嗯,从那以后,我对音频路由就格外小心了。

21.1 AudioFlinger的工作原理

AudioFlinger是Android音频系统的核心服务。说白了,它就是个音频数据的中转站和混音器。

所有App播放的声音,最终都要送到AudioFlinger手里。它负责把这些音频流混合到一起,再送到硬件设备去播放。反过来,麦克风采集的声音,也要经过它分发给各个App。

核心架构图:

AudioFlinger 核心架构 App 1 (音乐) App 2 (导航) App 3 (通话) AudioFlinger 混音器 (Mixer) | 线程管理 | 路由策略 效果处理 (回声消除/降噪) Audio HAL (输出) Audio HAL (输入) 扬声器 / DAC 麦克风 / ADC

AudioFlinger内部有几个关键概念:

  • PlaybackThread / RecordThread:每个音频设备对应一个工作线程。比如扬声器一个线程,蓝牙一个线程。
  • Mixer:混音器。多个音频流进来,它负责叠加、增益控制、采样率转换。
  • EffectChain:效果链。回声消除、降噪这些处理就挂在这里。

我个人习惯,在调试AudioFlinger问题时,先看dumpsys media.audio_flinger的输出。这里面有线程状态、混音配置、延迟信息,非常有用。

调试小技巧:

adb shell dumpsys media.audio_flinger --threads 可以列出所有音频线程。如果某个线程状态是“standby”,说明它没在工作,可能是路由没切过来。

21.2 音频路由策略

音频路由,就是决定“声音从哪个设备出去,从哪个设备进来”。

在Android里,路由策略由AudioPolicyManager管理。它根据当前的音频使用场景(音乐、导航、通话、语音命令)来切换路由。

路由策略的核心逻辑:

// 伪代码示意
AudioPolicyManager::getOutputForDevice() {
    // 1. 根据音频流类型选择策略
    // 2. 检查设备可用性(蓝牙是否连接?耳机是否插入?)
    // 3. 应用策略规则(比如导航声音从主扬声器出)
    // 4. 返回选中的设备ID
}

车载场景下,路由策略比手机复杂得多。你想想看,车上可能有:

  • 主扬声器(前门、后门)
  • 头枕扬声器(有些高端车有)
  • 蓝牙电话
  • CarPlay / Android Auto
  • 语音助手麦克风阵列

我在项目中遇到过一个问题:导航语音和音乐同时播放时,导航声音特别小。查了半天,发现是路由策略里把导航的增益设成了-6dB,而音乐是0dB。后来在audio_policy_configuration.xml里调整了gain属性才解决。

关键配置文件:

/vendor/etc/audio_policy_configuration.xml/vendor/etc/audio_policy_engine_configuration.xml

这两个文件定义了设备拓扑、路由规则、增益配置。调路由策略,基本就是改这两个文件。

21.3 回声消除与降噪

回声消除(AEC)和降噪(NS)是车载音频的硬骨头。

为什么?因为车内空间小,扬声器和麦克风距离近。你这边说话,对方的声音从扬声器出来,又被麦克风收回去,就形成了回声。

回声消除的原理:

  1. 参考信号提取:从扬声器播放的音频流中取一份副本。
  2. 自适应滤波:用算法模拟回声路径,从麦克风信号中减去回声成分。
  3. 双讲检测:判断是单方说话还是双方同时说话,避免误消。

在Android里,AEC/NS通常由AudioEffect框架实现。具体来说:

  • AcousticEchoCanceler:系统内置的AEC效果器。
  • NoiseSuppressor:系统内置的降噪效果器。

我曾经在一个项目里,发现AEC效果很差。排查后发现,参考信号延迟没对齐——扬声器到麦克风的物理延迟是20ms,但算法默认是10ms。后来在HAL层里修正了延迟参数,回声才消干净。

注意:

AEC的效果高度依赖参考信号的质量。如果参考信号被裁剪或压缩过,AEC算法会失效。所以,在音频链路上,尽量保证参考信号是原始PCM数据,不要经过任何处理。

21.4 音频延迟优化

音频延迟,就是从“App发出音频数据”到“扬声器发出声音”的时间差。车载场景下,延迟太大会导致:

  • 导航语音和画面不同步
  • 语音助手响应迟钝
  • 蓝牙通话感觉像对讲机

延迟的构成:

环节 典型延迟 优化方向
App缓冲区 10-30ms 减小缓冲区大小
AudioFlinger混音 5-15ms 使用FastMixer线程
HAL层传输 5-20ms 优化DMA传输
硬件DAC/功放 5-10ms 选择低延迟Codec

优化手段:

  1. 使用FastMixer:AudioFlinger的FastMixer线程专为低延迟设计,它绕过了一些中间处理,直接和HAL通信。
  2. 调整缓冲区大小:在audio_hw.xml或HAL代码中,把period_sizeperiod_count调小。比如从1024帧降到256帧。
  3. 禁用不必要的效果器:每个效果器都会增加延迟。如果不需要AEC,就别开。
  4. 使用MMAP模式:Android 8.0引入的MMAP模式,让App直接和HAL共享内存,延迟可以降到10ms以下。
我的经验:

调延迟时,先用dumpsys media.audio_flinger --latency看当前延迟值。然后逐步减小缓冲区,每次减半,直到出现爆音为止。那个临界值就是最优配置。

嗯,音频调优就是这样——没有银弹,只有一步步测量、调整、验证。车载音频尤其如此,因为车内声学环境复杂,每个车型都要单独调。

好了,这一讲的内容就到这里。音频系统是个大话题,后面我们还会在具体模块里深入。


公众号:蓝海资料掘金营,微信deep3321