# NetEq 总览 · 自适应抖动缓冲 + 丢包隐藏

> NetEq 是 WebRTC 音频接收侧的明珠——自适应抖动缓冲兼丢包隐藏器。这一章读 modules/audio_coding/neteq 的 g3doc：它 InsertPacket 收包、GetAudio 出音频的两个核心接口，以及它「平滑播放、低瑕疵、低延迟」三个相互冲突的目标怎么权衡。

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

# NetEq 总览 · 自适应抖动缓冲 + 丢包隐藏

音频接收侧的核心，是一个 WebRTC 里公认精妙的模块——**NetEq**。它的 g3doc 一句话定义了它：

> NetEq is the **audio jitter buffer** and **packet loss concealer**.

它同时是[抖动缓冲](https://daiw.org/manual/webrtc/video-jitter-buffer)和**丢包隐藏器**——把音频接收侧最难的两件事融为一体。第 7 部分接下来五章都在讲它。先总览。

## 三个冲突的目标

NetEq 的 g3doc 点明它要同时追求三个**相互冲突**的目标：

<Callout type="info">
  **NetEq 要同时：① 平滑播放（smooth playout）② 低瑕疵（少改动原始音频）③ 低延迟——而这三者两两冲突。**

  - **平滑 vs 低延迟** —— 要平滑（[吸收抖动](https://daiw.org/manual/webrtc/video-jitter-buffer)），得**多缓冲**；但缓冲越多，**延迟越大**。这是[视频抖动缓冲那章](https://daiw.org/manual/webrtc/video-jitter-buffer)见过的经典矛盾。
  - **低瑕疵 vs 低延迟** —— 丢了包 / 缓冲空了，要么[等（增延迟）](https://daiw.org/manual/webrtc/neteq-timestretch)，要么[编造填充（引入瑕疵）](https://daiw.org/manual/webrtc/neteq-plc)。想低延迟就得多编造，想少瑕疵就得多等。

  NetEq 的全部精妙，就在于**在这个三角里，根据实时网络状况动态找最优点**——网络好就压低延迟、少缓冲；网络抖就多缓冲、动用[各种修复手段](https://daiw.org/manual/webrtc/neteq-operations)保平滑。它是“自适应”的（“adaptive jitter buffer”），缓冲延迟**持续优化**，不是固定值。
</Callout>

## 两个接口：InsertPacket 与 GetAudio

NetEq 的 API 出奇地简单——就两个函数（`api/neteq/neteq.h`）：

```cpp
// api/neteq/neteq.h(概念)
InsertPacket(packet);        // 网络来了个音频包,塞进来
GetAudio(&output, ...);      // 声卡要一小段音频,给出来
```

<Callout type="info">
  **NetEq 由两股节奏驱动：网络“不规律地”[塞包（InsertPacket）](https://daiw.org/manual/webrtc/neteq-buffer-delay)，声卡“极规律地”要音频（GetAudio）——NetEq 的使命就是把前者的参差，变成后者的平稳。**

  - **`InsertPacket`（网络侧，不规律）** —— [收到一个音频包](https://daiw.org/manual/webrtc/rtp-demuxer)就调用。包到得[忽快忽慢、还可能乱序 / 丢失](https://daiw.org/manual/webrtc/rtp-packet)。NetEq 把它放进[包缓冲区](https://daiw.org/manual/webrtc/neteq-buffer-delay)，并**分析包间到达时间**、更新[抖动统计](https://daiw.org/manual/webrtc/neteq-buffer-delay)（[太晚的包丢弃](https://daiw.org/manual/webrtc/neteq-buffer-delay)）。
  - **`GetAudio`（声卡侧，极规律）** —— 声卡每隔固定时间（如 10ms）**雷打不动**地来要一段音频播放。NetEq **必须每次都给出**一段——哪怕包还没到 / 丢了，也得[编点什么出来](https://daiw.org/manual/webrtc/neteq-plc)（不能让声卡“饿着”，否则就是可闻的断音）。

  这个“**输入不规律、输出必须规律**”的错位，是 NetEq 一切复杂性的根源。声卡不等人——它每 10ms 准时来敲门，NetEq 手里有包就[解码给它（Normal）](https://daiw.org/manual/webrtc/neteq-operations)，没包就得[变戏法](https://daiw.org/manual/webrtc/neteq-operations)（时间伸缩、丢包隐藏）。**把“网络的混乱”翻译成“声卡的秩序”，且尽量不让人听出破绽**——这就是 NetEq 每 10ms 都在做的事。
</Callout>

## GetAudio 的六种可能

每次 `GetAudio`，NetEq 会根据当前状态（[缓冲多少、包到没到](https://daiw.org/manual/webrtc/neteq-buffer-delay)），从**六种操作**里选一个来产出这段音频（g3doc 列得很清楚，[下下章详解](https://daiw.org/manual/webrtc/neteq-operations)）：Normal（正常解码）、Acceleration（加速）、Preemptive expand（减速）、Expand（[丢包隐藏](https://daiw.org/manual/webrtc/neteq-plc)）、Merge（拼接）、Comfort noise（[舒适噪声](https://daiw.org/manual/webrtc/neteq-operations)）。这六种操作就是 NetEq 的“戏法”——先记住有这么六种，后面逐个看。

## 它在哪

NetEq 住在 [ACM 的接收侧](https://daiw.org/manual/webrtc/acm)内部，被[声卡的取音频回调](https://daiw.org/manual/webrtc/audio-device-mixer)驱动 `GetAudio`。它[可替换](https://daiw.org/manual/webrtc/factory-and-context)（`neteq_factory`），但默认实现就是这套久经打磨的算法。

## 小结与下一章

**NetEq** 是音频接收侧的明珠——**自适应抖动缓冲 + 丢包隐藏器**，追求三个冲突目标（**平滑、低瑕疵、低延迟**）的动态最优。两个接口：**`InsertPacket`**（网络**不规律**塞包，分析[抖动](https://daiw.org/manual/webrtc/neteq-buffer-delay)）、**`GetAudio`**（声卡**极规律**要音频，必须每次都给）。这个“输入乱、输出必须齐”的错位是它复杂性的根源。每次 `GetAudio` 从[六种操作](https://daiw.org/manual/webrtc/neteq-operations)选一个产出音频。它住在 [ACM](https://daiw.org/manual/webrtc/acm) 内。

先看它怎么管缓冲、以及“该缓冲多少”这个自适应的核心。👉 [NetEq 缓冲与延迟](https://daiw.org/manual/webrtc/neteq-buffer-delay)。

## 参考资料

- [1] libwebrtc 源码.`modules/audio_coding/neteq/g3doc/index.md`、`api/neteq/neteq.h`（`InsertPacket` / `GetAudio`）。
- [2] libwebrtc 源码.`modules/audio_coding/neteq/neteq_impl.h` / `.cc`。
- [3] 关联[视频抖动缓冲](https://daiw.org/manual/webrtc/video-jitter-buffer)——同类问题的音频版。
