12、音频3A算法与降噪:自动增益控制(AGC)、自动噪声抑制(ANS)、回声消除(AEC)、Android AudioEffect使用

各位同学,今天我们来聊聊音频处理里最硬核、也最让人头疼的三个字母——3A

AGC、ANS、AEC,这三个缩写几乎出现在所有实时音视频SDK的配置项里。说白了,它们就是音频质量的三大护法。我当年刚接触直播项目时,以为只要把麦克风采集到的原始PCM数据扔出去就行了,结果被用户骂惨了——声音忽大忽小、背景噪音像在菜市场、对方还能听到自己的回声……嗯,从那以后,我再也不敢小看3A了。

12.1 什么是音频3A?

3A是三个独立但协同工作的算法模块:

  • AGC(自动增益控制):自动调整音量,让说话声保持在一个舒适的范围。
  • ANS(自动噪声抑制):过滤掉环境噪音,只保留人声。
  • AEC(回声消除):消除扬声器播放的声音再次被麦克风采集后产生的回声。

你想想看,如果这三个模块配合不好,就会出现「声音忽大忽小」「背景全是风扇声」「对方听到自己说话的回声」等灾难性体验。

核心观点:3A不是可选项,而是实时音视频通信的必需品。没有3A,你的RTMP推流就是裸奔。

音频3A算法处理流程 麦克风采集 AGC 自动增益控制 ANS 噪声抑制 AEC 回声消除 纯净音频输出 远端参考信号 处理顺序:AGC → ANS → AEC(实际可配置) AEC需要远端参考信号作为输入

12.2 自动增益控制(AGC)

AGC的作用很简单:让音量稳定。不管说话人离麦克风远还是近,不管他声音大还是小,AGC都会把音量调整到目标水平。

我在项目中遇到过一个问题:主播在直播时,有时凑近麦克风小声说话,有时又离得很远大声喊。如果没有AGC,观众听到的就是「蚊子叫」和「炸麦」交替出现。后来我们启用了WebRTC的AGC模块,配合一个合理的目标音量阈值,才解决了这个问题。

AGC的核心参数

参数 说明 推荐值
Target Level 目标音量(dBFS) -16 ~ -12 dBFS
Compression Ratio 压缩比,控制增益变化幅度 2:1 ~ 4:1
Attack Time 增益启动时间 5 ~ 20 ms
Release Time 增益释放时间 100 ~ 500 ms

我的经验:AGC的Attack Time不要设得太短,否则声音会有「抽吸感」——就是那种音量突然被拉起来又压下去的不自然感觉。我个人习惯设到10ms左右。

12.3 自动噪声抑制(ANS)

ANS的目标是干掉背景噪音。风扇声、键盘声、马路上的车流声……这些都需要被抑制掉,只保留人声。

ANS的原理其实不复杂:它通过分析音频频谱,区分出哪些是稳态噪声(比如空调声),哪些是瞬态信号(比如人声),然后对噪声频段做衰减。

但这里有个坑——过度抑制会导致人声失真。我曾经在一个项目中,为了追求「绝对安静」,把ANS的抑制强度拉到了最大。结果用户反馈说「声音像在水里说话一样」,这就是典型的「音乐噪声」问题。

ANS的常见算法

  • 谱减法:从原始信号中减去估计的噪声谱。简单但容易产生音乐噪声。
  • 维纳滤波:基于统计模型,效果更好,但计算量稍大。
  • 深度学习降噪:用RNN或CNN模型,效果最好,但需要模型文件,不适合低端设备。

注意:在Android上使用ANS时,要注意延迟。有些降噪算法会引入10~30ms的额外延迟,对于实时通信来说,这个延迟可能会破坏唇音同步。

12.4 回声消除(AEC)

AEC是3A里最复杂、也最容易出问题的一个。它的任务是:消除扬声器播放的声音再次被麦克风采集后产生的回声

你想想看,在视频通话中,对方的声音从你的扬声器播放出来,又被你的麦克风采集到,然后传回给对方——对方就听到了自己的回声。这就是AEC要解决的问题。

AEC的核心思路是:自适应滤波。它把远端参考信号(对方的声音)和麦克风采集的信号做对比,通过自适应滤波器模拟出回声路径,然后从麦克风信号中减去回声部分。

AEC的关键指标

指标 说明 优秀值
ERLE(回声返回损耗增强) 衡量回声消除能力的指标 > 30 dB
收敛时间 滤波器从启动到稳定所需时间 < 500 ms
双讲性能 双方同时说话时的处理能力 无明显回声且不丢字

避坑指南:我曾经在一个项目中,AEC怎么调都调不好,回声总是消除不干净。后来发现是扬声器和麦克风的物理距离太近,导致回声路径太短,滤波器来不及收敛。解决方案是:要么拉开物理距离,要么在软件层面增加一个延迟补偿。

12.5 Android AudioEffect 使用

Android从API 9开始就提供了AudioEffect框架,可以用来实现一些基础的音频效果。虽然它不像WebRTC的3A那么强大,但在某些场景下还是很有用的。

AudioEffect 支持的效果

  • AcousticEchoCanceler:回声消除(需要硬件支持)
  • AutomaticGainControl:自动增益控制(需要硬件支持)
  • NoiseSuppressor:噪声抑制(需要硬件支持)
  • Equalizer:均衡器
  • BassBoost:低音增强

注意,前三个效果(AEC、AGC、NS)需要硬件支持。也就是说,不是所有Android设备都能用。你可以通过isAvailable()方法来判断。

代码示例:使用AudioEffect的AGC

// 检查AGC是否可用
if (AutomaticGainControl.isAvailable()) {
    // 获取音频会话ID
    int audioSessionId = audioRecord.getAudioSessionId();
    
    // 创建AGC实例
    AutomaticGainControl agc = AutomaticGainControl.create(audioSessionId);
    
    if (agc != null) {
        // 启用AGC
        agc.setEnabled(true);
        Log.d("AGC", "AGC已启用");
    }
} else {
    Log.w("AGC", "当前设备不支持硬件AGC");
}

AudioEffect的局限性

说实话,Android原生的AudioEffect效果一般。我在项目中测试过,它的AEC在双讲场景下表现很差,经常出现回声残留。所以,对于专业的音视频应用,我建议还是使用WebRTC的3A模块,或者集成第三方的音频处理SDK。

我的建议:如果你只是做一个简单的语音聊天Demo,用AudioEffect就够了。但如果是商业级的直播或视频会议应用,请务必使用WebRTC的3A或者专业的音频处理库(如SpeexDSP、AudioProcessingModule)。

12.6 3A算法的调优经验

最后,分享一些我在项目中积累的调优经验:

  1. 先调AGC,再调ANS,最后调AEC。顺序很重要,因为AGC会影响音量,进而影响ANS和AEC的判断。
  2. 不要追求极致。AGC不要压得太狠,ANS不要抑得太干净,AEC不要消得太彻底。适度的保留一些「不完美」,反而听起来更自然。
  3. 双讲测试是AEC的照妖镜。很多AEC在单讲时表现完美,但双方同时说话时就露馅了。一定要做双讲测试。
  4. 注意延迟。3A算法会引入延迟,尤其是在低端设备上。建议在初始化时测量一下总延迟,如果超过50ms,就要考虑优化了。

好了,关于音频3A算法,今天就讲到这里。这些内容是我在实际项目中踩过坑、填过坑之后总结出来的,希望对你有帮助。


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