1. 网络抖动概述

什么是网络抖动

网络抖动,说白了就是数据包到达时间的不确定性。你发送端每隔 20ms 发一个包,接收端收到的时间间隔可能是 18ms、25ms、30ms 不等。这个偏差,就是抖动。

我刚开始做 WebRTC 的时候,总觉得抖动不就是延迟吗?后来踩了坑才明白——延迟是「慢」,抖动是「乱」。延迟你可以通过缓冲来对抗,但抖动是随机变化,处理起来麻烦得多。

用公式表达的话:

抖动 = | 实际到达间隔 - 期望到达间隔 |

举个例子。你发三个包,间隔都是 20ms:

  • 包1:0ms 发送,10ms 到达(延迟 10ms)
  • 包2:20ms 发送,45ms 到达(延迟 25ms)
  • 包3:40ms 发送,55ms 到达(延迟 15ms)

你看,延迟在变,但真正让接收端难受的是包2和包3之间的到达间隔只有 10ms,而包1和包2之间是 35ms。这种不均匀,就是抖动。

核心要点:抖动 ≠ 延迟。延迟是单向时间,抖动是延迟的变化量。WebRTC 的流控机制,本质上就是在跟这个「变化量」较劲。

抖动对实时通信的影响

抖动对实时通信的影响,我归纳为三个层面:

影响层面 表现 用户感知
音频 声音断断续续、变调、卡顿 听不清对方说话,像在信号不好的对讲机里
视频 画面冻结、跳帧、马赛克 人物动作不连贯,像幻灯片
交互 操作延迟、不同步 你说了话,对方三秒后才回应

我记得有一次做跨国会议系统测试,网络抖动峰值到了 120ms。音频直接变成了机器人声,视频每两秒卡一次。用户反馈说「你们这个产品还不如打电话」。嗯,那次之后我彻底理解了抖动有多致命。

为什么会这样?因为实时通信对时间敏感。音频播放器需要稳定的数据流,你突然来一个包、突然又断两秒,解码器就乱了。视频更是如此——参考帧丢了,后面一连串帧都得等。

避坑提醒:我曾经以为只要缓冲区够大就能解决抖动。结果延迟飙升到 500ms,用户直接骂街。缓冲区是把双刃剑——吞抖动的同时也在吞实时性。

WebRTC 面临的挑战

WebRTC 在设计之初就面临一个核心矛盾:既要实时,又要抗抖动。这不是选择题,是必答题。

具体来说,挑战集中在以下几个方面:

  • 网络不可控:WebRTC 跑在公共互联网上,Wi-Fi 切换、4G/5G 信号波动、路由器缓存、跨运营商路由,每一个环节都可能引入抖动。你没法控制用户的网络环境。
  • 实时性要求高:语音通话的端到端延迟要求通常 < 150ms,视频 < 300ms。超过这个阈值,用户就会觉得「卡」。缓冲区不能太大。
  • 多流竞争:音频、视频、数据通道共用一条网络链路。音频要低延迟,视频要高带宽,数据要可靠。三种流量互相挤兑,抖动更复杂。
  • 设备差异大:从旗舰手机到老旧笔记本,CPU 算力、解码能力、屏幕刷新率都不一样。同样的抖动,在不同设备上表现天差地别。

我个人的习惯是,把 WebRTC 的抗抖动能力拆成三个层次来看:

  1. 检测层:怎么准确测量当前的抖动值?
  2. 缓冲层:怎么用合适的缓冲区吸收抖动?
  3. 反馈层:怎么把抖动信息告诉发送端,让它调整发送策略?

这三个层次环环相扣,任何一个环节出问题,整个流控就崩了。

一个小技巧:我在做抖动检测时,不会只看瞬时值。我会用滑动窗口算抖动趋势——比如过去 1 秒内的抖动均值 + 标准差。这样能过滤掉毛刺,看到真正的网络状态。

下面这张图,是我自己总结的 WebRTC 抖动对抗体系。你可以把它当作本章的知识地图:

WebRTC 抖动对抗体系 抖动来源 Wi-Fi 波动 · 路由缓存 跨运营商 · 信号切换 检测层 到达间隔 · 抖动计算 滑动窗口 · 趋势分析 缓冲层 JitterBuffer · 动态调整 丢包补偿 · 时间缩放 反馈层 REMB · NACK · TWCC 码率调整 · 发送策略 发送端 编码器 · 码率控制 FEC · 重传策略 目标:流畅的实时通信体验 检测 → 缓冲 → 反馈 闭环迭代,持续对抗

你看这个闭环:抖动从网络进来,检测层先测量,缓冲层吸收短期波动,反馈层把信息送回发送端,发送端调整策略。每一层都有自己的职责,也都有自己的坑。

举个例子。我在做 JitterBuffer 调优时,发现缓冲区太小会导致频繁丢包,太大又会让延迟超标。后来我加了一个自适应算法——根据过去 500ms 的抖动趋势动态调整缓冲区深度。效果还不错,延迟控制在 80ms 以内,丢包率从 5% 降到了 0.5%。

嗯,这就是 WebRTC 对抗抖动的核心思路。后面的章节,我会带你一层一层拆开来看,每个环节怎么设计、怎么调试、怎么避坑。