“Jitter”指的是连续到达的媒体包之间时间间隔的变化。在网络传输中,由于:
导致包之间的接收时间不一致,这就是网络“抖动”。
**JitterBuffer(抖动缓冲区)**的作用是:
网络接收 ← UDP/RTP 包 ← jitterbuffer ← 解码器 ← 播放器/渲染器
↑ ↑
排序 + 重组 + 时间控制 + 丢包填补(PLC)
sequence number
和 timestamp
。sequence number
排序)。参数 | 说明 |
---|---|
初始缓冲时长(如 50ms) | 启动播放前预缓存的时长 |
最大缓冲时长(如 200ms) | 抖动缓冲的最大范围 |
播放时钟 | 控制何时从 buffer 中读包 |
最大乱序范围 | 防止恶意/错误乱序拖垮 buffer |
WebRTC 是目前最复杂、最智能的抖动缓冲实现之一,支持:
模块路径:webrtc/modules/audio_coding/neteq/
RTP Packet
↓
NetEq::InsertPacket
↓
[DecoderBuffer + PacketBuffer]
↓
NetEq::GetAudio (解码并补偿)
↓
音频帧 → 播放器
缩写 | 全称 | 作用 |
---|---|---|
PLC | Packet Loss Concealment | 在音频丢包时生成“伪造音频”以避免突兀中断 |
CNG | Comfort Noise Generation | 在静音时生成背景噪声,防止“死寂”现象 |
FEC | Forward Error Correction | 通过多发送冗余信息,在接收端恢复丢失的数据包 |
目标:帧丢失时,合成一个与上一帧相似的语音片段,避免“卡顿”或“哑音”。
常用方法:
WebRTC 实现:
NetEq
模块中的 Expand
类;
NetEq::GetAudio()
会判断是否缺帧,如缺则调用Expand::Process()
生成伪音频。
目标:通话静音时生成背景噪声,增强自然感、避免“真空”感。
常用方法:
SID
(Silence Insertion Descriptor)帧;WebRTC 实现:
ComfortNoise
模块;SID
RTP 包并生成伪噪声;audio_coding_module->EnableCN(true);
目标:通过发送冗余信息,让接收端自行恢复丢失的帧。
常用方法:
WebRTC 实现:
支持 Opus FEC(内建);
支持 RED + ULPFEC 组合(多用于视频,但音频也适用);
启用方式:
config.audio.send_codec_spec.codec_inst.pltype = 111; // opus
config.audio.send_codec_spec.enable_fec = true;
Opus 中 FEC 和 DTX 可协同工作(低带宽时启用 DTX 静音,失真时启用 FEC)
技术 | 工作阶段 | 需编码器支持 | 占带宽 | 延迟 | 对音质的作用 |
---|---|---|---|---|---|
PLC | 接收端 | 否 | 否 | 无 | 平滑丢包间断 |
CNG | 编码 + 解码 | 是 | 极低 | 无 | 模拟背景环境 |
FEC | 编码 + 解码 | 是 | 高 | 无 | 主动对抗丢包,避免掉帧 |
无需显式设置,NetEq 自动启用:
NetEq::GetAudio() 自动判断是否丢包 → Expand::Process()
AudioSendStream::Config config;
config.send_codec_spec.codec_inst.pltype = 9; // G.729 CN
config.send_codec_spec.enable_dtx = true; // 打开 DTX
对于 Opus,也可以开启 DTX(自动静音 + CNG):
config.send_codec_spec.enable_dtx = true;
config.send_codec_spec.enable_fec = true;
也可通过 SDP 启用 RED + ULPFEC:
a=rtpmap:111 opus/48000/2
a=fmtp:111 useinbandfec=1; usedtx=1
功能
功能 | 说明 |
---|---|
抖动缓冲 | 缓解网络抖动带来的乱序、延迟不稳定 |
解码 | 插件式音频解码器支持 |
丢包补偿(PLC) | 使用语音扩展、静音插入等技术“补”上丢帧 |
噪声生成(CNG) | 模拟背景噪声防止静音突兀 |
拓展播放/速率控制 | 实现播放速度调节(例如加速恢复) |
DTMF 支持 | 电话拨号音的内联处理 |
核心类是:
class NetEqImpl : public NetEq {
public:
int InsertPacket(const RTPHeader& header, rtc::ArrayView<const uint8_t> payload) override;
int GetAudio(AudioFrame* audio_frame) override;
...
};
int NetEqImpl::InsertPacket(const RTPHeader& header,
rtc::ArrayView<const uint8_t> payload)
处理 RTP 包输入:
packet_buffer_
int NetEqImpl::GetAudio(AudioFrame* audio_frame)
执行一次音频播放输出:
decision_logic_->GetDecision()
选择行为kNormal
:正常解码kExpand
:PLC 补偿kAccelerate
:播放加速kCng
:背景噪声NetEq 使用内部“播放时钟”推进播放,假设 10ms 一帧,每次 GetAudio()
会:
timestamp
存储 RTP 包,支持按 timestamp 排序 + 乱序插入:
class PacketBuffer {
bool InsertPacket(Packet&& packet);
absl::optional<Packet> GetNextPacket(uint32_t timestamp);
};
注册各种 RTP payload type 到解码器:
class DecoderDatabase {
bool RegisterPayload(uint8_t payload_type, AudioDecoder* decoder);
AudioDecoder* GetDecoder(uint8_t payload_type);
};
可扩展添加自定义解码器。
用于在丢包时合成连续音频:
class Expand {
void Process(AudioFrame* frame);
};
算法核心:基于最近解码帧的频率模式生成伪数据。
模块路径:webrtc/modules/video_coding/
核心类:
VCMJitterBuffer
:包级缓存;FrameBuffer
:帧组装器;FrameBufferController
:根据解码状态/网络反馈动态调节 buffer;1. DeliverRtp(RTP packet)
↓
2. Insert into FrameBuffer (reorders and assembles)
↓
3. Mark frame as complete
↓
4. Notify decoder thread (via AsyncInvoker)
↓
5. Decoder calls NextFrame()
↓
6. FrameBuffer returns suitable frame based on timing
class FrameBuffer {
public:
void InsertFrame(std::unique_ptr<EncodedFrame> frame);
std::unique_ptr<EncodedFrame> NextFrame();
};
特点:
Timing
类);接收 RTP 包并重组帧,组装完成后推入 FrameBuffer
:
bool RtpVideoStreamReceiver::OnRtpPacket(const RtpPacketReceived& packet)
VCMPacket
(含 marker bit, seq, timestamp);FrameBuffer::InsertFrame()
);负责调用解码逻辑:
std::unique_ptr<EncodedFrame> frame = frame_buffer_->NextFrame();
decoder_->Decode(frame);
解码线程会持续等待并从 FrameBuffer 中提取适合解码的帧。
Timing
类)视频帧不是立刻解码,而是要等待“最佳播放时间”:
Timing::RenderTimeMs(uint32_t frame_timestamp, int64_t now_ms)
内部通过系统时间、RTP timestamp 差计算出:
FrameBuffer::InsertFrame()
内部跟踪丢帧(依据 sequence number);rtp_rtcp::RTCPeerFeedback
上报丢帧;WebRTC 会根据网络反馈(RTCP)动态调整 jitterbuffer:
网络状态 | Buffer 调整策略 |
---|---|
抖动变大 | 增大 buffer 延迟,提升稳定性 |
网络稳定 | 减小 buffer,降低延迟 |
丢包严重 | 增加 buffer + 请求重传(NACK) |
无法重传 | 使用 FEC 或插入静音/伪帧 |
WebRTC 中,音频是时钟主导(anchor),视频 jitterbuffer 会与音频同步,控制渲染时间戳,使音画同步。
WebRTC 的 JitterBuffer 构建了高度模块化、可插拔、跨平台的实时缓冲机制,实现了在复杂网络环境下高质量的音视频通信体验。
特性 | 音频(NetEq) | 视频(FrameBuffer) |
---|---|---|
缓冲粒度 | RTP 包(10ms) | 视频帧 |
解码策略 | 严格 10ms 推进 | 根据时间和帧依赖 |
丢包处理 | PLC / CNG | NACK / 丢弃 |
时间同步 | 插值输出 / 静音填充 | Timing::RenderTimeMs 控制 |
解码控制 | 内部自动控制 | 外部线程主动拉帧解码 |
延迟适配 | 加速 / 减速 | 控制解码时机或丢帧 |