# NetEq 的六种操作 · 每 10ms 的抉择

> 每次声卡要音频，NetEq 从六种操作里选一个：Normal、Acceleration、Preemptive expand、Expand、Merge、Comfort noise。这一章依据 g3doc 讲清这六种操作各是什么、DecisionLogic 怎么根据缓冲状态选择，以及它们如何合力把混乱的网络变成流畅的声音。

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

# NetEq 的六种操作 · 每 10ms 的抉择

[NetEq 每次 `GetAudio`](https://daiw.org/manual/webrtc/neteq-overview)，都要凭当前状态（[缓冲量 vs 目标](https://daiw.org/manual/webrtc/neteq-buffer-delay)、包到没到）做一个抉择：这 10ms 的音频，**怎么产出**？g3doc 列出**六种操作**。这一章把它们讲全——它们是 NetEq 全部戏法的清单。

## 六种操作

NetEq 的 g3doc 明确列出 `GetAudio` 输出的六种可能：

<Callout type="info">
  **NetEq 的六种操作，覆盖了“缓冲多、缓冲少、有包、没包、静音”所有情形：**

  | 操作 | 什么时候 | 做什么 |
  | --- | --- | --- |
  | **Normal（正常）** | [缓冲 ≈ 目标](https://daiw.org/manual/webrtc/neteq-buffer-delay)、有包 | 正常解码一个包播放 |
  | **Acceleration（加速）** | [缓冲 > 目标](https://daiw.org/manual/webrtc/neteq-buffer-delay)（攒多了） | [时间压缩](https://daiw.org/manual/webrtc/neteq-timestretch)播得略快，消耗缓冲、降延迟 |
  | **Preemptive expand（抢先扩展 / 减速）** | [缓冲 < 目标](https://daiw.org/manual/webrtc/neteq-buffer-delay)（快空了） | [时间拉伸](https://daiw.org/manual/webrtc/neteq-timestretch)播得略慢，攒缓冲、防断音 |
  | **Expand（扩展 / 丢包隐藏）** | 下一个包**没到 / 丢了** | [凭历史编造](https://daiw.org/manual/webrtc/neteq-plc)一段填充（PLC） |
  | **Merge（拼接）** | Expand 之后包**又来了** | 把[编造的填充](https://daiw.org/manual/webrtc/neteq-plc)和真实解码音频**平滑拼接** |
  | **Comfort noise（舒适噪声，CNG）** | 对端**静音**（[DTX](https://daiw.org/manual/webrtc/audio-codecs)） | 生成柔和的背景噪声填静默 |

  前三种（Normal/Accelerate/Preemptive）是**缓冲量的常规调节**——[根据缓冲 vs 目标](https://daiw.org/manual/webrtc/neteq-buffer-delay)微调播放速度。后三种（Expand/Merge/CNG）是**应对特殊情况**——[丢包](https://daiw.org/manual/webrtc/neteq-plc)、[丢包后恢复](https://daiw.org/manual/webrtc/neteq-plc)、[静音](https://daiw.org/manual/webrtc/audio-codecs)。六种合起来，NetEq 对**任何**输入情形都有对策，保证声卡[每次都能拿到一段音频](https://daiw.org/manual/webrtc/neteq-overview)。
</Callout>

## 舒适噪声：为什么静音不能真静音

六种里 **Comfort noise** 值得单说，它和一个反直觉的事实有关：

<Callout type="info">
  **对端静音时，不能真的播“绝对安静”——那会让人以为通话断了。NetEq 生成柔和的“舒适噪声”填补静默，维持“线路还在”的感觉。** 配合发送侧的 [Opus DTX](https://daiw.org/manual/webrtc/audio-codecs)：你不说话时，发送端[停发或只发极少的噪声参数](https://daiw.org/manual/webrtc/audio-codecs)省带宽；接收端的 NetEq 收到“进入静音”的信号，就**本地生成**一段和你环境本底噪声相似的柔和噪声播放。于是听者感觉“对方没说话，但线路是通的、有环境底噪”，而非“死一般寂静让人怀疑掉线”。

  **绝对的安静反而让人不安**——这是通信心理学的一个洞察。老式电话在你不说话时也有轻微“嘶嘶”底噪，正是这个作用。NetEq 的舒适噪声把这个体验数字化地重建了，还[顺便省了静音期的带宽](https://daiw.org/manual/webrtc/audio-codecs)。一个小细节，体现了 WebRTC 对“听感体验”的深究。
</Callout>

## DecisionLogic：谁来选

选哪种操作，由 **`DecisionLogic`**（`modules/audio_coding/neteq/decision_logic.cc`）拍板。每次 [`GetAudio`](https://daiw.org/manual/webrtc/neteq-overview)，它综合：

- [当前缓冲量 vs 目标延迟](https://daiw.org/manual/webrtc/neteq-buffer-delay)（决定 Normal/Accelerate/Preemptive）。
- 下一个包在不在（不在 → [Expand](https://daiw.org/manual/webrtc/neteq-plc)）。
- 是不是刚[丢包隐藏完、包又来了](https://daiw.org/manual/webrtc/neteq-plc)（→ Merge）。
- 是不是[静音期](https://daiw.org/manual/webrtc/audio-codecs)（→ CNG）。

```mermaid
flowchart TD
    GA["GetAudio(声卡每 10ms 要音频)"] --> DL["DecisionLogic 判断"]
    DL -->|"下个包没到"| EXP["Expand:丢包隐藏"]
    DL -->|"刚隐藏完,包来了"| MRG["Merge:平滑拼接"]
    DL -->|"静音期"| CNG["Comfort noise"]
    DL -->|"缓冲>目标"| ACC["Acceleration:加速"]
    DL -->|"缓冲<目标"| PRE["Preemptive expand:减速"]
    DL -->|"缓冲≈目标,有包"| NOR["Normal:正常解码"]
```

**`DecisionLogic` 是 NetEq 的中枢神经**——每 10ms 做一次这个抉择，把[延迟管理](https://daiw.org/manual/webrtc/neteq-buffer-delay)、[丢包应对](https://daiw.org/manual/webrtc/neteq-plc)、[静音处理](https://daiw.org/manual/webrtc/audio-codecs)统一到一个决策点。

## 小结与下一章

NetEq 每次 [`GetAudio`](https://daiw.org/manual/webrtc/neteq-overview) 从**六种操作**选一个：**Normal**（正常解码）、**Acceleration**（[加速追缓冲](https://daiw.org/manual/webrtc/neteq-timestretch)）、**Preemptive expand**（[减速攒缓冲](https://daiw.org/manual/webrtc/neteq-timestretch)）、**Expand**（[丢包隐藏](https://daiw.org/manual/webrtc/neteq-plc)）、**Merge**（[隐藏后拼接](https://daiw.org/manual/webrtc/neteq-plc)）、**Comfort noise**（[静音填柔和噪声](https://daiw.org/manual/webrtc/audio-codecs)，因绝对安静让人不安）。前三管[缓冲调节](https://daiw.org/manual/webrtc/neteq-buffer-delay)、后三管特殊情况。**`DecisionLogic`** 每 10ms 综合缓冲状态、包在不在、是否静音，拍板选哪种。

六种里最见功力的两类：**丢包隐藏（Expand/Merge）** 和 **时间伸缩（Accelerate/Preemptive）**。下一章先看丢包隐藏——怎么“编造”出以假乱真的音频。👉 [NetEq 丢包隐藏](https://daiw.org/manual/webrtc/neteq-plc)。

## 参考资料

- [1] libwebrtc 源码.`modules/audio_coding/neteq/g3doc/index.md`（六种操作）、`decision_logic.h` / `.cc`。
- [2] libwebrtc 源码.`modules/audio_coding/neteq/comfort_noise.h`、`normal.h`。
- [3] 关联 [Opus DTX](https://daiw.org/manual/webrtc/audio-codecs)、[缓冲与延迟](https://daiw.org/manual/webrtc/neteq-buffer-delay)。
