JitterBuffer
Jitter
“Jitter”指的是連續到達的媒體包之間時間間隔的變化。在網絡傳輸中,由于:
- 網絡擁塞
- 路由路徑變化
- 隊列排隊
- 不同鏈路帶寬差異
導致包之間的接收時間不一致,這就是網絡“抖動”。
作用
**JitterBuffer(抖動緩沖區)**的作用是:
- 緩沖網絡傳輸過來的數據包
- 重新排序亂序的包
- 緩沖一定時間再輸出
- 實現穩定的音視頻幀輸出,避免播放中出現 卡頓、跳幀、音頻破音
工作流程圖
網絡接收 ← UDP/RTP 包 ← jitterbuffer ← 解碼器 ← 播放器/渲染器↑ ↑排序 + 重組 + 時間控制 + 丟包填補(PLC)
流程詳解
1. 接收數據包
- 每個 RTP 包有
sequence number
和timestamp
。 - 收到包后,判斷是否亂序、丟包。
2. 緩存和排序
- 將包插入 buffer 中合適位置(基于
sequence number
排序)。
3. 播放控制
- 到達播放時間時,提取對應時間戳的包進行解碼。
- 若包未到達(丟包或延遲):
- 等待一段時間(等待時間配置或自適應);
- 或直接丟幀;
- 或填補(音頻使用 PLC,視頻可能重復前幀或跳過)。
4. 自適應控制
- 根據網絡條件(RTCP 報告、丟包率、延遲)動態調整緩沖大小(WebRTC 的核心機制之一)。
常用參數
參數 | 說明 |
---|---|
初始緩沖時長(如 50ms) | 啟動播放前預緩存的時長 |
最大緩沖時長(如 200ms) | 抖動緩沖的最大范圍 |
播放時鐘 | 控制何時從 buffer 中讀包 |
最大亂序范圍 | 防止惡意/錯誤亂序拖垮 buffer |
WebRTC中JitterBuffer
WebRTC 是目前最復雜、最智能的抖動緩沖實現之一,支持:
- 音頻 JitterBuffer
- 視頻 JitterBuffer
- 網絡自適應算法
- FEC(前向糾錯)/NACK(重傳)
- Audio/Video 同步
音頻 JitterBuffer
模塊路徑:webrtc/modules/audio_coding/neteq/
功能
- 亂序處理;
- 丟包補償(使用 PLC、CNG、FEC);
- 動態調節;
- 語音平滑(低碼率時很關鍵);
原理
RTP Packet↓NetEq::InsertPacket↓[DecoderBuffer + PacketBuffer]↓NetEq::GetAudio (解碼并補償)↓音頻幀 → 播放器
PLC、CNG、FEC
概念
縮寫 | 全稱 | 作用 |
---|---|---|
PLC | Packet Loss Concealment | 在音頻丟包時生成“偽造音頻”以避免突兀中斷 |
CNG | Comfort Noise Generation | 在靜音時生成背景噪聲,防止“死寂”現象 |
FEC | Forward Error Correction | 通過多發送冗余信息,在接收端恢復丟失的數據包 |
PLC(Packet Loss Concealment)
目標:幀丟失時,合成一個與上一幀相似的語音片段,避免“卡頓”或“啞音”。
常用方法:
- 波形復制:簡單地復制上一幀波形;
- 線性預測(LPC):建模語音信號特性,預測缺失內容;
- 譜域合成:復制頻譜形狀,適用于寬帶語音(如 Opus);
WebRTC 實現:
- 位于
NetEq
模塊中的Expand
類; - 插入虛擬音頻幀(通常是 10ms);
- 結合時間戳推進邏輯,自動銜接解碼幀。
NetEq::GetAudio()
會判斷是否缺幀,如缺則調用Expand::Process()
生成偽音頻。
CNG(Comfort Noise Generation)
目標:通話靜音時生成背景噪聲,增強自然感、避免“真空”感。
常用方法:
- 在“活動語音”段估計背景噪聲特征;
- 靜音時合成類似背景噪聲(白噪聲加濾波);
- 由編碼器定期發送
SID
(Silence Insertion Descriptor)幀;
WebRTC 實現:
- 使用 RFC 3389 標準 CNG;
- 位于 NetEq 的
ComfortNoise
模塊; - 接收
SID
RTP 包并生成偽噪聲; - 在編碼器中設置:
audio_coding_module->EnableCN(true);
FEC(Forward Error Correction)
目標:通過發送冗余信息,讓接收端自行恢復丟失的幀。
常用方法:
- Opus 內建 FEC:發送低碼率副本;
- Redundant Encoding (RED):同一個 RTP 包攜帶多個編碼幀;
- ULPFEC(RFC 5109):按 RTP 層進行異或編碼恢復丟包;
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 | 編碼 + 解碼 | 是 | 高 | 無 | 主動對抗丟包,避免掉幀 |
WebRTC 中啟用方式
啟用 PLC(默認開啟)
無需顯式設置,NetEq 自動啟用:
NetEq::GetAudio() 自動判斷是否丟包 → Expand::Process()
啟用 CNG
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;
啟用 FEC(以 Opus 為例)
config.send_codec_spec.enable_fec = true;
也可通過 SDP 啟用 RED + ULPFEC:
a=rtpmap:111 opus/48000/2
a=fmtp:111 useinbandfec=1; usedtx=1
NetEq
功能
功能 | 說明 |
---|---|
抖動緩沖 | 緩解網絡抖動帶來的亂序、延遲不穩定 |
解碼 | 插件式音頻解碼器支持 |
丟包補償(PLC) | 使用語音擴展、靜音插入等技術“補”上丟幀 |
噪聲生成(CNG) | 模擬背景噪聲防止靜音突兀 |
拓展播放/速率控制 | 實現播放速度調節(例如加速恢復) |
DTMF 支持 | 電話撥號音的內聯處理 |
關鍵類:NetEqImpl
核心類是:
class NetEqImpl : public NetEq {public:int InsertPacket(const RTPHeader& header, rtc::ArrayView<const uint8_t> payload) override;int GetAudio(AudioFrame* audio_frame) override;...
};
InsertPacket()
int NetEqImpl::InsertPacket(const RTPHeader& header,rtc::ArrayView<const uint8_t> payload)
處理 RTP 包輸入:
- 插入
packet_buffer_
- 檢查有效性、亂序
- 更新時間戳信息
GetAudio()
int NetEqImpl::GetAudio(AudioFrame* audio_frame)
執行一次音頻播放輸出:
- 調用
decision_logic_->GetDecision()
選擇行為 - 行為包括:
kNormal
:正常解碼kExpand
:PLC 補償kAccelerate
:播放加速kCng
:背景噪聲
- 執行相應模塊生成音頻幀返回
運行機制:時間推進和緩沖策略
NetEq 使用內部“播放時鐘”推進播放,假設 10ms 一幀,每次 GetAudio()
會:
- 計算目標
timestamp
- 判斷當前 packet buffer 是否含有該 timestamp 的幀
- 沒有 → 觸發補償
- 有 → 解碼返回
源碼解析
PacketBuffer
存儲 RTP 包,支持按 timestamp 排序 + 亂序插入:
class PacketBuffer {bool InsertPacket(Packet&& packet);absl::optional<Packet> GetNextPacket(uint32_t timestamp);
};
DecoderDatabase
注冊各種 RTP payload type 到解碼器:
class DecoderDatabase {bool RegisterPayload(uint8_t payload_type, AudioDecoder* decoder);AudioDecoder* GetDecoder(uint8_t payload_type);
};
可擴展添加自定義解碼器。
Expand(PLC)
用于在丟包時合成連續音頻:
class Expand {void Process(AudioFrame* frame);
};
算法核心:基于最近解碼幀的頻率模式生成偽數據。
視頻 JitterBuffer
模塊路徑:webrtc/modules/video_coding/
功能
- 基于幀(Frame)級緩存;
- 管理多個 RTP 包拼裝一個視頻幀;
- 處理 I/P/B 幀依賴關系;
- 異步解碼與播放,配合 AVSync。
核心類:
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
源碼解析
FrameBuffer 接口類
class FrameBuffer {public:void InsertFrame(std::unique_ptr<EncodedFrame> frame);std::unique_ptr<EncodedFrame> NextFrame();
};
特點:
- 接收完整幀(非 RTP 包級);
- 和 NACK 控制、幀到達策略分離;
- 提供解碼時間控制(配合
Timing
類);
RtpVideoStreamReceiver
接收 RTP 包并重組幀,組裝完成后推入 FrameBuffer
:
bool RtpVideoStreamReceiver::OnRtpPacket(const RtpPacketReceived& packet)
- 組裝
VCMPacket
(含 marker bit, seq, timestamp); - 查找是否構成完整幀(依賴
FrameBuffer::InsertFrame()
); - 完整幀則通知解碼線程處理。
VideoReceiveStream::StartDecodeLoop()
負責調用解碼邏輯:
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 差計算出:
- 當前幀是否提前(buffering)
- 當前幀是否延遲(丟幀)
- 幀間 jitter 均值估計(變更播放時鐘)
丟包處理(NACK / Frame Missing)
FrameBuffer::InsertFrame()
內部跟蹤丟幀(依據 sequence number);- 控制模塊向上層觸發 NACK;
- 使用
rtp_rtcp::RTCPeerFeedback
上報丟幀; - 等待 retransmit 后再組幀。
動態自適應機制
WebRTC 會根據網絡反饋(RTCP)動態調整 jitterbuffer:
網絡狀態 | Buffer 調整策略 |
---|---|
抖動變大 | 增大 buffer 延遲,提升穩定性 |
網絡穩定 | 減小 buffer,降低延遲 |
丟包嚴重 | 增加 buffer + 請求重傳(NACK) |
無法重傳 | 使用 FEC 或插入靜音/偽幀 |
與 AV 同步的協作
WebRTC 中,音頻是時鐘主導(anchor),視頻 jitterbuffer 會與音頻同步,控制渲染時間戳,使音畫同步。
總結
WebRTC 的 JitterBuffer 構建了高度模塊化、可插拔、跨平臺的實時緩沖機制,實現了在復雜網絡環境下高質量的音視頻通信體驗。
特性 | 音頻(NetEq) | 視頻(FrameBuffer) |
---|---|---|
緩沖粒度 | RTP 包(10ms) | 視頻幀 |
解碼策略 | 嚴格 10ms 推進 | 根據時間和幀依賴 |
丟包處理 | PLC / CNG | NACK / 丟棄 |
時間同步 | 插值輸出 / 靜音填充 | Timing::RenderTimeMs 控制 |
解碼控制 | 內部自動控制 | 外部線程主動拉幀解碼 |
延遲適配 | 加速 / 減速 | 控制解碼時機或丟幀 |