19、音频处理:回声消除、降噪处理、自动增益控制、音频3A算法简介

做WebRTC开发,绕不开音频处理。说实话,音频比视频更容易让用户崩溃。视频卡顿还能忍,但要是听到自己的回声,或者对方声音忽大忽小,用户立马就挂电话了。

今天我们来聊聊音频3A算法。这玩意儿是WebRTC音频引擎的基石。我最早接触它是在一个在线教育项目里,学生那边总是反馈「听到自己的声音」,排查了半天,其实就是回声消除没配置好。

3A指的是三个东西:AEC(回声消除)、ANS(降噪处理)、AGC(自动增益控制)。它们三个配合工作,才能让实时通话听起来舒服。

核心观点:3A不是独立工作的,它们有严格的执行顺序。顺序错了,效果会大打折扣。

WebRTC 音频 3A 处理流水线 麦克风输入 AEC 回声消除 ANS 降噪处理 AGC 自动增益 扬声器输出 参考信号(远端) 顺序:先消除回声 → 再降噪 → 最后调整音量

19.1 回声消除(AEC)—— 最头疼的一环

回声消除的原理,说白了就是:扬声器播放的声音,又被麦克风收了回来。WebRTC的做法是,拿远端音频信号做参考,从麦克风采集的信号里「减掉」它。

我遇到过最坑的情况是什么?有一次在会议室测试,回声就是消不掉。后来发现,是因为扬声器音量开太大,导致非线性失真严重。线性AEC算法根本处理不了。

注意:WebRTC的AEC模块对非线性失真很敏感。如果扬声器质量差或者音量过大,回声消除效果会急剧下降。我曾经建议团队换了个好点的音箱,问题直接解决。

WebRTC里AEC的核心参数就几个:

  • delay_agnostic:是否启用延迟无关模式。我一般建议开启,能应对网络抖动。
  • extended_filter:扩展滤波器长度。处理长回声场景时有用。
  • comfort_noise:舒适噪声填充。消回声太干净反而会让人感觉「断连」,加点背景噪声更自然。
// WebRTC AEC 配置示例(C++ 风格)
webrtc::AudioProcessing::Config config;
config.echo_canceller.enabled = true;
config.echo_canceller.mobile_mode = false;  // 桌面端用全模式
config.echo_canceller.export_delay = true;  // 导出延迟信息用于调试

小技巧:调试AEC时,可以把处理前后的音频dump下来,用Audacity对比。我经常这么干,一眼就能看出回声有没有被干掉。

19.2 降噪处理(ANS)—— 不是越安静越好

降噪的目标是去掉背景噪声,比如风扇声、键盘声、马路声。但这里有个度——降得太干净,声音会变得「塑料感」十足。

WebRTC的ANS模块用的是谱减法,说白了就是在频域里把噪声能量减掉。它分两种模式:

模式 适用场景 我的建议
低抑制(Low) 安静办公室 保留更多细节
高抑制(High) 嘈杂环境 注意语音失真
极强抑制(Very High) 极端噪声 慎用,会牺牲音质

我个人习惯用「中等」模式。你想想看,用户如果听到自己的声音像机器人,体验反而更差。

// 降噪配置
config.noise_suppression.enabled = true;
config.noise_suppression.level = 
    webrtc::AudioProcessing::Config::NoiseSuppression::kModerate;

避坑指南:我曾经把降噪开到最高,结果用户反馈「声音断断续续」。后来发现是降噪把正常的语音间隙当成了噪声给切掉了。所以,降噪不是越强越好。

19.3 自动增益控制(AGC)—— 音量要稳

AGC的作用是让音量保持在一个合适的水平。有人说话声音小,有人声音大,AGC自动帮你拉平。

WebRTC的AGC有两种模式:

  • 自适应数字模式:根据信号能量动态调整增益。适合大多数场景。
  • 固定增益模式:直接乘一个固定系数。适合已知环境。

我记得有个项目,用户总是抱怨「对方声音太小」。查了半天,发现是AGC的target_level设置得太低了。默认是3dB,我改到9dB后,问题解决。

// AGC 配置
config.gain_controller1.enabled = true;
config.gain_controller1.mode = 
    webrtc::AudioProcessing::Config::GainController1::kAdaptiveDigital;
config.gain_controller1.target_level_dbfs = 9;  // 目标电平
config.gain_controller1.compression_gain_db = 9; // 压缩增益

注意:AGC不要和系统音量混用。如果系统音量已经开到最大,AGC再往上加增益,只会引入噪声。我一般建议先调好系统音量,再让AGC做微调。

19.4 3A算法的协作顺序

为什么顺序重要?因为每个模块都会改变信号特性。如果先做AGC再消回声,AGC把音量放大后,回声也跟着放大了,AEC的压力就大了。

正确的顺序是:

  1. AEC先上:消除回声,保证参考信号干净。
  2. ANS跟上:去掉残留的噪声。
  3. AGC收尾:调整最终音量。

这个顺序是WebRTC内部写死的,你改不了。但理解它,能帮你更好地排查问题。

调试建议:如果发现音质有问题,可以逐个关闭3A模块,看看是哪个环节出了问题。我经常用这个「二分法」定位问题。

19.5 实战中的常见问题

最后分享几个我踩过的坑:

  • 回声消不掉:先检查扬声器和麦克风是否太近。物理隔离比算法更有效。
  • 声音忽大忽小:AGC的attack time和release time没调好。反应太快会「抽风」,太慢又跟不上。
  • 降噪后声音发闷:高频被削太多了。可以尝试降低降噪强度。

嗯,音频3A这块,说难不难,说简单也不简单。关键是要理解每个模块的脾气,然后对症下药。


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