# AEC3 回声消除内核 · 估计回声再减掉

> AEC3 是 WebRTC 的回声消除引擎。它分两级：自适应线性滤波器建模声学路径、从远端参考预测回声并减掉；残余回声抑制器再把线性滤波没除净的部分压下去。这一章讲清这两级、延迟估计、以及 AEC3 为什么是 WebRTC 音频的明珠。

- 作者：David（道雾轩）
- 专栏：音视频与 WebRTC 详解（https://daiw.org/manual/webrtc.md）
- 最后更新：2026-07-14
- 原文：https://daiw.org/manual/webrtc/aec3-internals
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# AEC3 回声消除内核 · 估计回声再减掉

[回声问题](https://daiw.org/manual/webrtc/aec3-echo-problem)讲清了，现在看 WebRTC 怎么消——**AEC3**（Acoustic Echo Canceller v3，`modules/audio_processing/aec3/`）。它是 [APM 的明珠](https://daiw.org/manual/webrtc/apm-overview)，用两级把回声消得干干净净。这一章拆它的核心思路（不逐行啃 DSP，而是抓住“它凭什么能消”）。

## 核心思路：预测回声，减掉它

AEC3 的总思路一句话：

<Callout type="info">
  **AEC3 知道扬声器播了什么（[远端参考](https://daiw.org/manual/webrtc/apm-overview)），就用一个“模型”预测出“这段声音经声学路径漏回麦克风会是什么样”（即回声），然后从麦克风采的音里**把这个预测的回声减掉**——剩下的就是干净的近端语音。** 这就是“[必须同时知道播了什么和采了什么](https://daiw.org/manual/webrtc/apm-overview)”的用处：有了远端参考（播的），预测出回声；有了近端（采的），减掉回声。

  难点当然是那个“模型”——它得准确刻画[看不见、还在变的声学路径](https://daiw.org/manual/webrtc/aec3-echo-problem)。AEC3 用**自适应滤波**来实时逼近这条路径，并分**两级**处理。
</Callout>

## 第一级：自适应线性滤波

AEC3 的第一级是一个**自适应线性滤波器**：

<Callout type="info">
  **线性滤波器**在线学习**扬声器到麦克风的声学路径（建模成一组滤波系数），用它对[远端参考](https://daiw.org/manual/webrtc/apm-overview)做滤波，得到“预测的回声”，从近端减掉。它靠观测“减完还剩多少”来**持续调整**系数，越学越准。** 这是经典的自适应滤波（类似 NLMS 等算法）：

  - 它维护一组系数，代表当前估计的声学路径（[冲激响应](https://daiw.org/manual/webrtc/aec3-echo-problem)）。
  - 每一帧，用这组系数滤波远端参考 → 预测回声 → 从近端减掉 → 得到“残差”。
  - 用残差**反馈调整**系数：残差里若还有回声成分，说明系数不准，就微调——[路径一变](https://daiw.org/manual/webrtc/aec3-echo-problem)（你动了手机），它就重新收敛到新路径。

  线性滤波能消掉回声的**线性、可预测**部分——通常是回声的大头。但它有局限：扬声器 / 放大器的**非线性失真**、路径突变的瞬间，它消不干净，会留下**残余回声**。所以要有第二级。
</Callout>

## 第二级：残余回声抑制

第一级[减完还剩的残余回声](https://daiw.org/manual/webrtc/aec3-internals)，交给第二级——**残余回声抑制器**：

<Callout type="info">
  **抑制器在频域工作：估计“每个频段还剩多少残余回声”，据此**衰减**那些残余回声占主导的频段——像一个智能的、随回声动态调整的均衡器。** 它不像[线性滤波那样“精确相减”](https://daiw.org/manual/webrtc/aec3-internals)，而是“**按比例压制**”：某个频段残余回声多，就把这个频段整体压低。代价是可能**连带压掉一点近端语音**（那个频段的人声也被削），所以要精细——这里就要用上[双讲检测](https://daiw.org/manual/webrtc/aec3-echo-problem)：双讲时手下留情（别压太狠，保住近端语音），单讲时放心压（反正没有近端语音要保）。

  两级配合：**线性滤波精确消掉大部分（可预测的）回声，残余抑制兜底压掉剩下的（非线性、难预测的）回声**。一“减”一“压”，把回声消到听不见，同时尽量保住近端语音。这个“精确 + 兜底”的两级架构，是现代回声消除的标准范式，AEC3 把它打磨到了很高水准。
</Callout>

## 关键辅助：延迟估计

还有一个隐藏的关键：AEC3 得知道**远端参考和近端回声之间的延迟**——扬声器播出的声音，过多久才漏回麦克风？这个延迟（[含音频硬件缓冲 + 声学传播](https://daiw.org/manual/webrtc/aec3-echo-problem)）因设备而异、可能几十到几百毫秒，且[会变](https://daiw.org/manual/webrtc/aec3-echo-problem)。AEC3 有专门的**延迟估计**，把远端参考和近端**对齐**——不对齐，滤波器就“预测”错时刻的回声，消不掉。延迟估计错了，回声消除全盘失效，所以它是 AEC3 稳健性的基石。

## 一张 AEC3 流程图

```mermaid
flowchart LR
    REF["远端参考(扬声器播的)"] --> DELAY["延迟估计:与近端对齐"]
    DELAY --> LIN["① 线性自适应滤波<br/>预测回声 → 从近端减掉"]
    MIC["近端(麦克风采的)"] --> LIN
    LIN -->|"残差(还有残余回声)"| SUP["② 残余回声抑制<br/>频域衰减残余"]
    DT["双讲检测"] -.->|"双讲时手下留情"| SUP
    SUP --> CLEAN["干净近端语音 → 编码发送"]
```

## 小结与下一章

**AEC3** 消回声的思路：用[远端参考](https://daiw.org/manual/webrtc/apm-overview)**预测回声、从近端减掉**。两级：**① 自适应线性滤波**——[在线学习声学路径](https://daiw.org/manual/webrtc/aec3-echo-problem)、预测并精确相减（消可预测的大头），[路径变了持续重收敛](https://daiw.org/manual/webrtc/aec3-echo-problem)；**② 残余回声抑制**——频域**衰减**线性没除净的残余（非线性部分），配合[双讲检测](https://daiw.org/manual/webrtc/aec3-echo-problem)避免误伤近端语音。**延迟估计**把远近端对齐，是基石。一减一压，回声消到听不见。

回声消掉了，链条还有增益和降噪。下一章看自动增益 AGC。👉 [自动增益控制](https://daiw.org/manual/webrtc/agc)。

## 参考资料

- [1] libwebrtc 源码.`modules/audio_processing/aec3/`（`echo_canceller3.cc`、`adaptive_fir_filter.h`、`residual_echo_estimator.h`、`echo_path_delay_estimator.h`）。
- [2] 自适应滤波（NLMS）与残余回声抑制 —— AEC 的信号处理基础。
- [3] 关联[回声问题](https://daiw.org/manual/webrtc/aec3-echo-problem)、[APM 总览](https://daiw.org/manual/webrtc/apm-overview)。
