# NetEq 缓冲与延迟 · 该攒多少音频

> NetEq 自适应的核心，是「目标延迟」——该攒多少音频才能既抗抖动又不太延迟。这一章讲清包缓冲区怎么按时间戳存包、延迟管理器怎么从包间到达时间估出抖动、进而算出动态的目标缓冲水平，以及这个自适应如何随网络实时调整。

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

# NetEq 缓冲与延迟 · 该攒多少音频

[NetEq 是自适应的](https://daiw.org/manual/webrtc/neteq-overview)，而“自适应”的核心，就是一个数——**目标延迟（target delay）**：该攒多少音频在缓冲里？攒多了延迟大，攒少了[抖动一来就断音](https://daiw.org/manual/webrtc/neteq-overview)。算准这个数，是 NetEq 的第一要务。这一章看它怎么算。

## 包缓冲区：按时间戳排队

[`InsertPacket`](https://daiw.org/manual/webrtc/neteq-overview) 塞进来的包，先进**包缓冲区（packet buffer）**。它按 [RTP 时间戳](https://daiw.org/manual/webrtc/rtp-packet)给包排序——[网络可能乱序](https://daiw.org/manual/webrtc/rtp-packet)送达，缓冲区把它们重新排好，等到[播放时刻](https://daiw.org/manual/webrtc/video-timing)按顺序取出。缓冲区有容量上限（[满了会丢弃](https://daiw.org/manual/webrtc/neteq-overview)，罕见），太晚到的包（[错过播放时刻的](https://daiw.org/manual/webrtc/neteq-overview)）直接丢弃。它就是那个“[蓄水的水库](https://daiw.org/manual/webrtc/video-jitter-buffer)”，攒着一小段未来要播的音频。

## 延迟管理器：估抖动，定目标

“该攒多少”由 **延迟管理器（DelayManager）** 算，依据是**观测到的网络抖动**：

<Callout type="info">
  **延迟管理器分析[包的到达间隔](https://daiw.org/manual/webrtc/neteq-overview)，估出网络抖动有多大，据此算出“目标缓冲水平”——抖动越大，目标越高（多攒点扛抖动）；抖动越小，目标越低（少攒点降延迟）。**

  怎么估？[`InsertPacket` 时](https://daiw.org/manual/webrtc/neteq-overview)，NetEq 记录每个包**该来的时间**和**实际来的时间**之差——这个差的**波动**就是抖动。如果包大多准时到、偶尔晚一点点，抖动小，目标延迟就可以压得很低（如 40ms）；如果包到得忽早忽晚、时有大延迟，抖动大，目标延迟就得抬高（如 200ms），否则[缓冲频繁见底、断音](https://daiw.org/manual/webrtc/neteq-plc)。延迟管理器用统计方法（如追踪到达间隔的某个高分位数）量化“要扛住绝大多数包的延迟，得攒多少”，给出目标。**它把“网络有多不稳”翻译成“该攒多少音频”**——这是 NetEq 自适应的大脑。
</Callout>

## 缓冲和目标的差，驱动操作

有了“当前缓冲量”和“目标缓冲量”，每次 [`GetAudio`](https://daiw.org/manual/webrtc/neteq-overview) 时，NetEq 比较两者，决定[做哪种操作](https://daiw.org/manual/webrtc/neteq-operations)：

<Callout type="info">
  **当前缓冲 vs 目标缓冲的差，直接决定 NetEq 该[加速、减速、还是正常播](https://daiw.org/manual/webrtc/neteq-operations)：**

  - **缓冲 > 目标（攒多了）** —— 延迟偏大，该**追回来**：[加速播放（Acceleration）](https://daiw.org/manual/webrtc/neteq-timestretch)——把一段音频**时间压缩**一点（播得略快），消耗掉多余缓冲，把延迟降下来。
  - **缓冲 < 目标（快空了）** —— 有[断音风险](https://daiw.org/manual/webrtc/neteq-plc)，该**攒一攒**：[减速播放（Preemptive expand）](https://daiw.org/manual/webrtc/neteq-timestretch)——把一段音频**时间拉伸**一点（播得略慢），争取时间让缓冲回升。
  - **缓冲 ≈ 目标** —— 刚好，[正常解码播放（Normal）](https://daiw.org/manual/webrtc/neteq-operations)。

  妙处在于：**这些加速 / 减速是通过[时间伸缩](https://daiw.org/manual/webrtc/neteq-timestretch)实现的，不改变音调**（不像快进磁带会变尖），听感上几乎察觉不到。于是 NetEq 能**悄悄地、持续地**微调播放节奏，让缓冲量始终贴着目标——网络抖动被这套“弹性播放”吸收得神不知鬼不觉。这是 NetEq 比[视频抖动缓冲](https://daiw.org/manual/webrtc/video-jitter-buffer)精细得多的地方：视频只能“多缓冲或少缓冲”，音频还能“**弹性地伸缩时间**”来主动调节。
</Callout>

## 目标随网络实时变

延迟管理器**持续**更新目标——你从 Wi-Fi 走到[信号差的地方](https://daiw.org/manual/webrtc/network-monitoring)，抖动变大，它悄悄抬高目标（多攒点，你可能感觉到延迟略增但不断音）；回到好网络，它慢慢压低目标（追回低延迟）。**这个目标从不固定，一直跟着网络呼吸**——正是“自适应”的体现。它和[拥塞控制的闭环](https://daiw.org/manual/webrtc/rate-control)一样，是 WebRTC “实时追踪网络”哲学在音频侧的落地。

## 小结与下一章

NetEq 自适应的核心是**目标延迟**。**包缓冲区**按[时间戳](https://daiw.org/manual/webrtc/rtp-packet)排队存包（[乱序重排、太晚丢弃](https://daiw.org/manual/webrtc/neteq-overview)）。**延迟管理器**分析[包间到达时间](https://daiw.org/manual/webrtc/neteq-overview)估**抖动**，算出“目标缓冲水平”（抖动大则目标高）。**当前缓冲 vs 目标的差**驱动操作：多了[加速追回](https://daiw.org/manual/webrtc/neteq-timestretch)、少了[减速攒回](https://daiw.org/manual/webrtc/neteq-timestretch)、刚好[正常播](https://daiw.org/manual/webrtc/neteq-operations)——靠**不变调的[时间伸缩](https://daiw.org/manual/webrtc/neteq-timestretch)**悄悄调节。目标随网络实时变。

缓冲和目标的比较，产出[六种操作](https://daiw.org/manual/webrtc/neteq-overview)之一。下一章把这六种操作和背后的决策逻辑讲全。👉 [NetEq 的六种操作](https://daiw.org/manual/webrtc/neteq-operations)。

## 参考资料

- [1] libwebrtc 源码.`modules/audio_coding/neteq/packet_buffer.h`、`delay_manager.h`、`g3doc/index.md`。
- [2] libwebrtc 源码.`modules/audio_coding/neteq/decision_logic.h`。
- [3] 关联[视频抖动缓冲的流畅 vs 延迟权衡](https://daiw.org/manual/webrtc/video-jitter-buffer)。
