音频的QoS可以分:音频前处理3A算法、NetEQ两大类。

img

1、AEC(回声消除)

“别让对方听到自己的声音反弹”

1.1 作用:

视频通话时,如果你开着扬声器,对方的声音会从扬声器播放出来,然后被你的麦克风重新录下来,再传回给对方——对方就会听到自己的回声,非常影响体验。AEC的作用就是把这个回声干掉。

通俗原理:

WebRTC的AEC(源码在modules/audio_processing/aec3/目录)就像一个“回声侦探”:

  1. 它会拿到两个信号:一个是“即将从你的扬声器播放的声音”(参考信号,比如对方说的话),另一个是“你的麦克风实际录到的声音”(包含你的说话声+环境噪音+回声)。
  2. 它会分析“参考信号”的特征(比如频率、波形),然后在麦克风信号里找到“长得像参考信号”的部分(这就是回声)。
  3. 最后把这部分“回声”从麦克风信号里减掉,剩下的就是“你的声音+少量噪音”,传给对方。
1.2 源码关键
  • 核心文件aec3.cc(AEC3入口)、echo_path_estimator.cc(回声路径估计)、double_talk_detector.cc(双讲检测)。
  • 核心逻辑Aec3::Process函数接收麦克风信号(capture)和参考信号(render),通过回声路径估计器生成“预测回声”,从麦克风信号中减去后,再用残留回声抑制器处理剩余杂音。
  • 双讲处理double_talk_detector.cc通过比较本地语音和回声的能量,判断“是否两边同时说话”,避免误删本地声音。

2、AGC(自动增益控制)

“不管你大声小声,对方听着都舒服”

2.1 作用:

有的人说话离麦克风近,声音特别大;有的人离得远,声音特别小;还有人说话忽大忽小。AGC的作用就是自动调整音量,让传给对方的声音大小保持在一个合适的范围,不会刺耳也不会听不清。

通俗原理:

WebRTC的AGC(源码在modules/audio_processing/gain_control/)就像一个“自动音量旋钮”:

  1. 它会先“听”一下当前麦克风的声音有多大(比如用level_estimator.cc计算音量)。
  2. 如果声音太小(比如低于目标值-18dB,这个值可以配置),就把音量调大(增加增益);如果声音太大(快到刺耳的程度),就把音量调小(降低增益)。
  3. 为了避免音量突然跳变(比如突然从小声变大声吓一跳),它会慢慢调整(比如每次只调一点点,源码里的gain_applier.cc负责平滑处理)。
2.2 源码关键:
  • 核心文件gain_control_impl.cc(AGC入口)、digital_agc.cc(数字增益计算)、gain_applier.cc(平滑增益)。
  • 核心逻辑GainControlImpl::Process函数接收原始音频,digital_agc.cc中的LevelEstimator计算当前音量,ComputeGain函数根据目标音量计算需要的增益,最后由gain_applier.cc平滑应用增益,避免突变。
  • 模式选择:支持“数字增益”(最常用,kAdaptiveDigital)、“模拟增益”(需硬件支持)等,通过set_mode配置。

3、ANS(噪声抑制)

“过滤杂音,只留人声”

3.1 作用:

你在咖啡厅、办公室打电话时,背景里的空调声、键盘声、别人的说话声会被麦克风录进去,对方听着很吵。ANS的作用就是把这些噪音过滤掉,让对方更清晰地听到你的声音。

通俗原理:

WebRTC的ANS(源码在modules/audio_processing/noise_suppression/)就像一个“噪音过滤器”:

  1. 它会先“学习”环境噪音的特征(比如空调声是持续的、频率固定的),在你没说话的时候(通过voice_activity_detector.cc判断“是否在说话”),悄悄记录噪音的“样子”。
  2. 当你说话时,它会把麦克风信号里“长得像噪音”的部分减弱(比如用ns_core.cc里的算法,在频率域里把噪音对应的频段音量降低),而“长得像人声”的部分尽量保留。
  3. 你可以配置过滤强度(源码里的Level),比如“轻度过滤”(保留更多环境音,适合音乐场景)或“深度过滤”(几乎只剩人声,适合嘈杂环境)。
3.2 源码关键:
  • 核心文件noise_suppression_impl.cc(ANS入口)、ns_core.cc(降噪核心)、voice_activity_detector.cc(语音检测)。
  • 核心逻辑NoiseSuppressionImpl::Process函数接收带噪音的信号,ns_core.cc先将信号转成频域(FFT),UpdateNoiseEstimate估计噪声频谱,Suppress函数对每个频率点计算抑制增益(噪音频段增益低,人声频段增益高),最后转回时域输出。

4、WebRTC中3A算法的完整调用流程

WebRTC把3A算法包装成了一个“音频处理管道”,通过AudioProcessing类统一调度,调用流程分三步:初始化配置、实时处理、销毁资源。

阶段1:初始化音频处理器(配置3A参数)

#include "webrtc/modules/audio_processing/include/audio_processing.h"

// 1. 创建音频处理器实例(内部自动初始化3A模块)
webrtc::AudioProcessing* apm = webrtc::AudioProcessing::Create();
if (!apm) { /* 初始化失败处理 */ }

// 2. 配置AEC(回声消除)
webrtc::EchoCancellation* aec = apm->echo_cancellation();
aec->Enable(true); // 开启AEC
aec->set_suppression_level(webrtc::EchoCancellation::kHighSuppression); // 高抑制强度

// 3. 配置AGC(自动增益控制)
webrtc::GainControl* agc = apm->gain_control();
agc->Enable(true); // 开启AGC
agc->set_mode(webrtc::GainControl::kAdaptiveDigital); // 数字增益模式(最常用)
agc->set_target_level_dbfs(-18); // 目标音量(默认-18dBFS)

// 4. 配置ANS(噪声抑制)
webrtc::NoiseSuppression* ans = apm->noise_suppression();
ans->Enable(true); // 开启ANS
ans->set_level(webrtc::NoiseSuppression::kHigh); // 高降噪强度

阶段2:实时处理音频帧(3A算法实际工作)

实时通信中,音频按“帧”处理(通常10ms一帧,16kHz采样率下每帧160个样本):

const int sample_rate = 16000; // 采样率16kHz
const size_t frame_size = 160; // 每帧160样本(10ms)

int16_t mic_frame[frame_size]; // 麦克风采集的原始信号(含回声、噪音)
int16_t render_frame[frame_size]; // 扬声器参考信号(对方的声音)

while (通话进行中) {
  // 1. 读取麦克风和扬声器数据(实际由设备驱动提供)
  read_microphone(mic_frame, frame_size); // 从麦克风获取数据
  read_speaker(render_frame, frame_size); // 获取即将播放的对方声音

  // 2. 处理参考信号(供AEC学习回声特征)
  webrtc::AudioFrame render_audio;
  render_audio.UpdateFrame(0, render_frame, frame_size, sample_rate,
                          webrtc::AudioFrame::kNormalSpeech, 
                          webrtc::AudioFrame::kVadActive);
  apm->ProcessReverseStream(&render_audio); // 传给AEC作为参考

  // 3. 处理麦克风信号(依次应用AEC→AGC→ANS)
  webrtc::AudioFrame mic_audio;
  mic_audio.UpdateFrame(0, mic_frame, frame_size, sample_rate,
                       webrtc::AudioFrame::kNormalSpeech,
                       webrtc::AudioFrame::kVadActive);
  apm->ProcessStream(&mic_audio); // 核心处理:3A算法在此生效

  // 4. 处理后的信号可直接发送给对方
  send_to_remote(mic_audio.data(), frame_size);
}

流程说明

  • ProcessReverseStream:将扬声器信号存入AEC的缓存,用于后续回声预测。
  • ProcessStream:按顺序调用3A算法——先AEC消除回声,再AGC调整音量,最后ANS过滤噪声,输出“干净”的声音。

阶段3:销毁资源

delete apm; // 自动释放AEC、AGC、ANS等所有子模块资源

以下是3A算法(AEC、AGC、ANS)与WebRTC音频处理流程图中模块的对应表

流程图模块 对应3A算法 核心源码目录/文件 关键功能(通俗解释)
AEC模块 声学回声消除(AEC) aec3/aec3.cc
aec3/echo_path_estimator.cc
aec3/double_talk_detector.cc
1. 用Render信号(扬声器即将播放的参考信号,如对方声音,供 AEC 识别 “回声特征”)作为“回声模板”,在Capture信号(麦克风采集的原始信号,含人声 + 回声 + 噪音)中识别并减去回声;
2. 双讲检测避免误删本地人声
AGC模块 自动增益控制(AGC) gain_control/gain_control_impl.cc
gain_control/digital_agc.cc
gain_control/gain_applier.cc
1. 检测AEC处理后的信号音量;
2. 自动放大/缩小音量至目标值(如-18dBFS);
3. 平滑调整避免音量突变
ANS模块 声学噪声抑制(ANS) noise_suppression/noise_suppression_impl.cc
noise_suppression/ns_core.cc
noise_suppression/voice_activity_detector.cc
1. 学习环境噪音特征(如空调声);
2. 减弱信号中“像噪音”的频段,保留人声;
3. 语音检测辅助判断何时更新噪声模型
VAD模块(辅助) 静音检测(依赖3A) modules/audio_processing/voice_activity_detection/ 1. 判断处理后的信号是否含人声;
2. 无语音时触发静音,减少无效传输(省带宽)

补充说明:

  1. 流程顺序的必要性
    流程图中AEC→AGC→ANS的顺序是固定的:

    • 必须先消回声(AEC),否则AGC会放大回声,ANS可能误把回声当噪音处理;
    • AGC在中间调整音量,避免后续ANS因音量过小而误判;
    • ANS最后降噪,确保输出信号的纯净度。
  2. Render信号的特殊作用
    仅AEC需要Render信号(用于回声比对),其他模块(AGC、ANS)只处理麦克风信号(Capture)

  3. VAD的辅助性
    VAD不直接参与“信号优化”,但依赖3A处理后的信号判断“是否有语音”,是提升传输效率的辅助模块。

总结:3A算法的核心价值

在实时语音/视频通话中,3A算法是“体验的基石”:

  • 没有AEC,对方会听到自己的回声,通话变成“回音室”;
  • 没有AGC,对方要么听不清,要么被突然的大声吓一跳;
  • 没有ANS,嘈杂环境下的通话会变成“听噪音猜人话”。

WebRTC通过AudioProcessing类将复杂的3A算法封装成简单接口,开发者无需深入信号处理细节,只需按流程调用,就能快速实现高质量的实时音频通信——这也是WebRTC被广泛用于视频会议、语音聊天工具的重要原因。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐