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

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

作者 David更新于 第 68 篇(共 112 篇)

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

NetEq 每次 GetAudio,都要凭当前状态(缓冲量 vs 目标、包到没到)做一个抉择:这 10ms 的音频,怎么产出?g3doc 列出六种操作。这一章把它们讲全——它们是 NetEq 全部戏法的清单。

六种操作

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

NetEq 的六种操作,覆盖了“缓冲多、缓冲少、有包、没包、静音”所有情形:

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

前三种(Normal/Accelerate/Preemptive)是缓冲量的常规调节——根据缓冲 vs 目标微调播放速度。后三种(Expand/Merge/CNG)是应对特殊情况——丢包、丢包后恢复、静音。六种合起来,NetEq 对任何输入情形都有对策,保证声卡每次都能拿到一段音频。

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

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

对端静音时,不能真的播“绝对安静”——那会让人以为通话断了。NetEq 生成柔和的“舒适噪声”填补静默,维持“线路还在”的感觉。 配合发送侧的 Opus DTX:你不说话时,发送端停发或只发极少的噪声参数省带宽;接收端的 NetEq 收到“进入静音”的信号,就本地生成一段和你环境本底噪声相似的柔和噪声播放。于是听者感觉“对方没说话,但线路是通的、有环境底噪”,而非“死一般寂静让人怀疑掉线”。

绝对的安静反而让人不安——这是通信心理学的一个洞察。老式电话在你不说话时也有轻微“嘶嘶”底噪,正是这个作用。NetEq 的舒适噪声把这个体验数字化地重建了,还顺便省了静音期的带宽。一个小细节,体现了 WebRTC 对“听感体验”的深究。

DecisionLogic:谁来选

选哪种操作,由 DecisionLogic(modules/audio_coding/neteq/decision_logic.cc)拍板。每次 GetAudio,它综合:

图表加载中…

DecisionLogic 是 NetEq 的中枢神经——每 10ms 做一次这个抉择,把延迟管理、丢包应对、静音处理统一到一个决策点。

小结与下一章

NetEq 每次 GetAudio 从六种操作选一个:Normal(正常解码)、Acceleration(加速追缓冲)、Preemptive expand(减速攒缓冲)、Expand(丢包隐藏)、Merge(隐藏后拼接)、Comfort noise(静音填柔和噪声,因绝对安静让人不安)。前三管缓冲调节、后三管特殊情况。DecisionLogic 每 10ms 综合缓冲状态、包在不在、是否静音,拍板选哪种。

六种里最见功力的两类:丢包隐藏(Expand/Merge) 和 时间伸缩(Accelerate/Preemptive)。下一章先看丢包隐藏——怎么“编造”出以假乱真的音频。👉 NetEq 丢包隐藏。

参考资料

  • [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、缓冲与延迟。

本页目录