WebRTC基于TransportCC和Trendline Filter的發(fā)送端碼率估計(Sendside-BWE)

1引言

眾所周知,WebRTC的擁塞控制和碼率估計算法采用GCC算法[1]。該算法充分考慮了網(wǎng)絡(luò)丟包和網(wǎng)絡(luò)延遲對碼率估計的不同影響,分別基于丟包率和網(wǎng)絡(luò)延遲進(jìn)行碼率估計,最后綜合這另種碼率得出最優(yōu)值。在算法實現(xiàn)上,基于丟包率的碼率估計在發(fā)送端進(jìn)行,基于網(wǎng)絡(luò)延遲的碼率估計在接收端進(jìn)行。最后在發(fā)送端計算出最優(yōu)值,作用于Codec和PacedSender模塊。GCC算法能夠較好地基于網(wǎng)絡(luò)實時狀況估計網(wǎng)絡(luò)帶寬,為網(wǎng)絡(luò)實時通信應(yīng)用打下堅實基礎(chǔ)[2][3][4]。

然而,隨著時間推移,在實際測試中發(fā)現(xiàn)GCC算法逐漸顯出一些弊端,比如不能適應(yīng)所有網(wǎng)絡(luò)模型,應(yīng)對網(wǎng)絡(luò)峰值能力差,等等。為此,Google官方從M55版本引進(jìn)最新的擁塞控制算法Sendside-BWE,把所有碼率計算模塊都移到發(fā)送端進(jìn)行,并采用全新的Trendline濾波器取代之前的Kalman濾波器[5]。實測表明,新的算法實現(xiàn)能夠更好更快地進(jìn)行碼率估計和網(wǎng)絡(luò)過載恢復(fù)。

本文基于WebRTC的M66版本和相關(guān)RFC,深度分析學(xué)習(xí)最新Sendside-BWE算法的實現(xiàn)。

2 GCC算法回顧

關(guān)于GCC算法已經(jīng)有很多分析和論述[6][7],本文只回顧其算法框架,并分析其在實際應(yīng)用中存在的問題。

圖1 GCC算法整體結(jié)構(gòu)

GCC算法分兩部分:發(fā)送端基于丟包率的碼率控制和接收端基于延遲的碼率控制。基于丟包率的碼率控制運行在發(fā)送端,依靠RTCP RR報文進(jìn)行工作。WebRTC在發(fā)送端收到來自接收端的RTCP RR報文,根據(jù)其Report Block中攜帶的丟包率信息,動態(tài)調(diào)整發(fā)送端碼率As?;谘舆t的碼率控制運行在接收端,WebRTC根據(jù)數(shù)據(jù)包到達(dá)的時間延遲,通過到達(dá)時間濾波器,估算出網(wǎng)絡(luò)延遲m(t),然后經(jīng)過過載檢測器判斷當(dāng)前網(wǎng)絡(luò)的擁塞狀況,最后在碼率控制器根據(jù)規(guī)則計算出遠(yuǎn)端估計最大碼率Ar。得到Ar之后,通過RTCP REMB報文返回發(fā)送端。發(fā)送端綜合As、Ar和預(yù)配置的上下限,計算出最終的目標(biāo)碼率A,該碼率會作用到Encoder、RTP和PacedSender等模塊,控制發(fā)送端的碼率。

發(fā)送端基于丟包率的碼率估計計算公式:

圖2 GCC發(fā)送端基于丟包率的碼率估計

接收端基于延遲的碼率估計計算公式:

圖3 GCC接收端基于延遲的碼率估計

GCC算法充分考慮丟包率和延遲對碼率的影響,在實時通訊應(yīng)用(如視頻會議)中能夠發(fā)揮良好效果。然而,在某些特定應(yīng)用場景下(比如實時在線編輯),GCC算法的表現(xiàn)不太讓人滿意,主要體現(xiàn)在它應(yīng)對峰值流量的能力上,具體表現(xiàn)在:1)算法一開始基于Increase狀態(tài)增加碼率,當(dāng)檢測到Decrease狀態(tài)時調(diào)用Ar[t(i)] = Alpha * Rr[t(i)],這個時候?qū)崟r碼率Rr(ti)可能遠(yuǎn)小于Ar[t(i-1)],這樣在后續(xù)過程中Ar處于較低水平;此時若有視頻關(guān)鍵幀沖擊,則數(shù)據(jù)包大量在PacedSender的隊列中排隊,造成較大排隊延遲。2)基于1)中論述的情況,碼率估計模塊反饋給Codec的編碼碼率很低,但編碼器需要編碼關(guān)鍵幀時,內(nèi)部的碼率控制模塊控制出的最小碼率仍然大于反饋碼率。這兩種情況都會造成較大的發(fā)送端排隊延遲,進(jìn)而在接收端造成較大的JitterBuffer延遲,最終導(dǎo)致端到端延遲到達(dá)500ms的水平,這在實時在線編輯應(yīng)用中是無法容忍的。

基于此,Google官方從WebRTC M55開始引入新的碼率估計算法,把所有碼率計算模塊都移動到發(fā)送端,并采用全新的Trendline濾波器,基于碼率探測機制快速準(zhǔn)確地估計出實時碼率。

3 Sendside-BWE算法框架

從本節(jié)開始系統(tǒng)分析Sendside-BWE算法的框架和實現(xiàn),圖4顯示該算法的基本實現(xiàn)框架,以及和GCC算法的對比。

圖4 Sendside-BWE算法和GCC算法的實現(xiàn)和對比[8]

圖4中棕色線是Sendside-BWE算法的數(shù)據(jù)控制流回路:發(fā)送端在發(fā)送RTP數(shù)據(jù)包時,在RTP頭部擴展中設(shè)置傳輸層序列號TransportSequenceNumber;數(shù)據(jù)包到達(dá)接收端后記錄該序列號和包到達(dá)時間,然后接收端基于此構(gòu)造TransportCC報文返回到發(fā)送端;發(fā)送端解析該報文,并執(zhí)行Sendside-BWE算法,計算得到基于延遲的碼率Ar;最終Ar和基于丟包率的碼率As進(jìn)行比較得到最終目標(biāo)碼率,作用到PacedSender和Codec模塊,形成一個完整的反饋回路。圖4中紅色線是GCC算法的數(shù)據(jù)控制流回路:發(fā)送端在發(fā)送RTP數(shù)據(jù)包時,在RTP頭部擴展中設(shè)置絕對發(fā)送時間AbsSendTime;數(shù)據(jù)包到達(dá)接收端后記錄該絕對到達(dá)時間,然后基于此執(zhí)行GCC算法得到Ar,最后構(gòu)造REMB報文把Ar發(fā)送回發(fā)送端;發(fā)送端基于Ar和As得到最終目標(biāo)碼率,作用到PacedSender和Codec模塊,形成一個完整的反饋回路。

從中可以看出,Sendside-BWE算法充分復(fù)用GCC算法的框架和實現(xiàn),整個反饋回路基本類似:發(fā)送端在RTP頭部擴展中記錄碼率估計元數(shù)據(jù),碼率估計模塊基于此元數(shù)據(jù)估計出碼率As,在發(fā)送端基于丟包率計算Ar,發(fā)送端綜合As和Ar得到最終目標(biāo)碼率,并作用于Codec和PacedSender模塊。所不同的是:對于GCC算法,RTP報文頭部添加AbsSendTime擴展,在接收端執(zhí)行基于延遲的碼率估計,網(wǎng)絡(luò)延遲濾波器采用Kalman Filter,返回給發(fā)送端的是REMB報文;對于Sendside-BWE算法,RTP報文頭部添加TransportSequenceNumber擴展,在發(fā)送端執(zhí)行基于延遲的碼率估計,網(wǎng)絡(luò)延遲濾波器采用Trandline,返回給發(fā)送端的是TransportCC報文。表5總結(jié)出GCC算法和Sendside-BWE算法的異同。

表5 GCC和Sendside-BWE關(guān)鍵模塊異同

需要注意的是,從WebRTC M55開始啟用Sendside-BWE后,其GCC算法就只做前向兼容而沒有進(jìn)一步的功能開發(fā)、性能優(yōu)化和bug修正。因此,GCC是過去,Sendside-BWE是未來。

4 Sendside-BWE算法實現(xiàn)

本節(jié)論述Sendside-BWE算法的實現(xiàn)細(xì)節(jié),在論述上力求不過度注釋代碼,以免陷入細(xì)節(jié)無法自拔。本節(jié)按照如下順序論述Sendside-BWE的實現(xiàn)細(xì)節(jié):SDP協(xié)商,發(fā)送端發(fā)送RTP報文,接收端接受RTP報文及信息存儲,接收端構(gòu)造TransportCC報文,發(fā)送端解析TransportCC報文,發(fā)送端碼率估計。

4.1 Sendside-BWE在SDP層協(xié)商

TransportCC和remb一樣都是Codec的feedback params的一部分。為支持TransportCC,Codec在收集feedback params時需添加額外一條:

codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty));

其中,TransportCC在最終生成的SDP中體現(xiàn)為如下一條attribute:

a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01

然后,SDP協(xié)商過程按照常規(guī)操作進(jìn)行。

4.2 發(fā)送端發(fā)送RTP報文

發(fā)送端在發(fā)送RTP報文時,需要在RTP頭部添加新的擴展TransportSequenceNumber,該擴展格式如圖6所示。

圖6 TransportSequenceNumber擴展格式

注意這里的傳輸層序列號,和RTP報文格式中的媒體層序列號不是同一個東西。傳輸層序列號關(guān)注數(shù)據(jù)的傳輸特性,主要作用是碼率估計;媒體曾序列號關(guān)注數(shù)據(jù)的媒體特性,主要作用是組幀和抗丟包。它們的初始值不一樣,賦值點也不一樣,其中媒體層序列號在RTPSender::AssignSequenceNumber()處賦值,而傳輸層序列號在RTPSender::UpdateTransportSequenceNumber()處賦值。RTP報文在發(fā)送時構(gòu)造該頭部擴展的函數(shù)調(diào)用棧如下:

=> RTPSender::TimeToSendPacket();
?=> RTPSender::PrepareAndSendPacket();
??=> RTPSender::UpdateTransportSequenceNumber();
???=> RTPSender::AddPacketToTransportFeedback();s
????=> SendSideCongestionController::AddPacket();

然后RTP報文走正常的構(gòu)造發(fā)送路徑發(fā)送到網(wǎng)絡(luò)。

4.3 接收端接收RTP并構(gòu)造TransportCC報文

接收端worker線程在收到RTP報文后,解析并檢查其頭部擴展,根據(jù)其是否有TransportSN擴展,決定采用Sendside-BWE還是GCC,注意這兩種擁塞控制器是互斥的。對于Sendside-BWE,接收端代理解析擴展拿到傳輸層序列號,并記錄RTP報文的到達(dá)時間,構(gòu)造(transport-sn,arrival_time_ms)鍵值對,存儲在隊列中。整個過程的函數(shù)調(diào)用棧如下:

=> Call::DeliverRtp();
?=> NotifyBweOfReceivedPacket();
?=> RtpPacketReceived::GetHeader();
?=> ReceiveSideCongestionController::OnReceivedPacket();
??=> RemoteEstimatorProxy::IncomingPacket();
???=> OnPacketArrival(transport-sn, arrival_time_ms):
??????Packet_arrival_times_[seq] = arrival_time;

RemoteEstimatorProxy作為Sendside-BWE在接收端的代理,其實現(xiàn)遵從WebRTC的模塊機制,在Process線程以100ms為發(fā)送周期發(fā)送TransportCC報文[9],發(fā)送周期會根據(jù)當(dāng)前碼率動態(tài)調(diào)整,其取值范圍在[50ms, 250ms]之間,其本身可用的發(fā)送碼率為當(dāng)前可用碼率的5%。TransportFeedback報文是一種RTP 傳輸層feedback報文(pt=205),F(xiàn)MT為15。其格式如圖7所示:

圖7 TransportCC報文格式

TransportCC報文采用base + bitmap的思想,其各個字段的具體解釋請參考文獻(xiàn)[9],一個TransportCC報文能最多攜帶16個RTP報文的有效信息,每個RTP報文信息包括其傳輸層序列號和包到達(dá)時間。TransportCC報文在發(fā)送端構(gòu)造和發(fā)送的函數(shù)調(diào)用棧如下:

=> RemoteEstimatorProxy::Process();
?=> RemoteEstimatorProxy::BuildFeedbackPacket();
??=> TransportFeedback::AddReceivedPacket()
???=> PacketRouter::SendTransportFeedback(fbpacket);
????=> RTCPSender::SendFeedbackPacket(fbpacket);

然后按照常規(guī)RTCP報文流程發(fā)送到發(fā)送端。

4.4 發(fā)送端接收TransportCC報文并解析

接收端接收操作就是常規(guī)的RTCP接收、解析并回調(diào)的流程,在worker線程中:

=> WebRtcVideoChannel::OnRtcpReceived();
?=> Call::DeliverRtcp();
??=> RTCPReceiver::HandleTransportFeedback();
???=> RTCPReceiver::TriggerCallbacksFromRtcpPacket();
????=> TransportFeedbackObserver::OnTransportFeedback();
?????=> SendSideCongestionController::OnTransportFeedback();

然后就是Send-side BWE算法在發(fā)送端的核心實現(xiàn)。

4.5 SendSideCongestionController碼率估計

SendSideCongestionController是Sendside-BWE算法在發(fā)送端的核心實現(xiàn),關(guān)于其的分析全部是細(xì)節(jié)描述。本節(jié)限于篇幅,僅勾勒出其大致的函數(shù)調(diào)用棧和流程說明。

?=> SendSideCongestionController::OnTransportFeedback();
?=> AcknowledBitrateEstimator::IncomingPacketFeedbackVector();
?=> DelayBasedBwe::IncomingPacketFeedbackVector();
?=> BitrateControllerImpl::OnDelayBasedBweResult();
?=> SendSideCongestionController::MaybeTriggerOnNetworkChanged();
?=> ProbeController::RequestProbe();

在SendSideCongestionController的OnTransportFeedback()函數(shù)中,首先調(diào)用ALR碼率估計器得到一個實時碼率,然后以此為參數(shù)調(diào)用DelayBasedBwe計算得到最新的估計碼率Ar,把Ar經(jīng)過BitrateController對象和As綜合,得到最新的目標(biāo)碼率。最后通過函數(shù)MaybeTriggerOnNetworkChanged()把最新目標(biāo)碼率作用到Codec和PacedSender模塊。如果本次碼率估計從網(wǎng)絡(luò)過載中恢復(fù),則調(diào)用ProbeController對象發(fā)起下一次碼率探測。

DelayBasedBwe對象是真正實現(xiàn)碼率估計的地方,其內(nèi)部調(diào)用函數(shù)棧如下:

=> DelayBasedBwe::IncomingPacketFeedbackVector();
=> DelayBasedBwe::IncomingPacketFeedback();
?=> InterArrival::ComputeDeltas();
?=> TrendlineEstimator::Update();
=> DelayBasedBwe::MaybeUpdateEstimate();
?=> ProbeBitrateEstimator::FetchAndResetLastEstimatedBitrateBps();
?=> AimdRateControl::SetEstimator();

DelayBasedBwe首先調(diào)用IncomingPacketFeedback針對每個RTP報文信息進(jìn)行碼率估計,其內(nèi)部邏輯和GCC算法的相關(guān)步驟一致,在此不再贅述。需要注意的是,其內(nèi)部網(wǎng)絡(luò)延遲濾波器采用TrendlineEstimator。然后DelayBasedBwe調(diào)用MaybeUpdateEstimate()根據(jù)本次判定的網(wǎng)絡(luò)狀態(tài)計算得到最終的Ar,如GCC算法一樣。

Trendline濾波器的原理就是最小二乘法線性回歸求得網(wǎng)絡(luò)延遲波動的斜率,每個散列點表示為(arrival_time, smoothed_delay),其中arrival_time為RTP包到達(dá)時間,smoothed_delay為平滑后的發(fā)送接收相對延遲。最后根據(jù)當(dāng)前散列點集合,采用最小二乘法線性回歸計算得到本次估計的網(wǎng)絡(luò)延遲m(i)。其計算過程調(diào)用如下:

=> TrendlineEstimator::Update();
?=> LinearFitSlope();
?=> TrendlineEstimator::Detect();
??=> TrendlineEstimator::UpdateThreshold();

至此,關(guān)于Sendside-BWE算法的實現(xiàn)初步分析完畢。

5 Sendside-BWE實測數(shù)據(jù)

實際測試表明,和GCC算法相比,Sendside-BWE算法在快速碼率估計、碼率估計準(zhǔn)確性、抗網(wǎng)絡(luò)抖動等方面都具有非常大改善。由于保密原因,此處不能發(fā)布內(nèi)部測試數(shù)據(jù),僅貼出一組公開渠道獲得的快速碼率估計比較圖[10]。

圖8 Sendside-BWE和GCC算法對比

該圖表明,Sendside-BWE算法能夠在第一次TransportCC報文返回時即估計出實時網(wǎng)絡(luò)帶寬,相比GCC算法更快速更準(zhǔn)確。

6 總結(jié)

本文在總結(jié)對比GCC和Sendside-BWE算法基礎(chǔ)上,深入學(xué)習(xí)Sendside-BWE算法的框架和實現(xiàn)細(xì)節(jié),為進(jìn)一步學(xué)習(xí)WebRTC擁塞控制算法和優(yōu)化算法細(xì)節(jié)打下堅實基礎(chǔ)。

參考文獻(xiàn)

[1] A Google Congestion Control Algorithm for Real-Time Communication. draft-alvestrand-rmcat-congestion-03
[2] Understanding the Dynamic Behaviour of the Google Congestion Control for RTCWeb.
[3] Experimental Investigation of the Google Congestion Control for Real-Time Flows.
[4] Analysis and Design of the Google Congestion Control for Web Real-time Communication (WebRTC). MMSys’16, May 10-13, 2016, Klagenfurt, Austria
[5] WebRTC視頻接收緩沖區(qū)基于KalmanFilter的延遲模型.http://www.itdecent.cn/p/bb34995c549a
[6] WebRTC基于GCC的擁塞控制(上) - 算法分析 http://www.itdecent.cn/p/0f7ee0e0b3be
[7] WebRTC基于GCC的擁塞控制(下) - 實現(xiàn)分析 http://www.itdecent.cn/p/5259a8659112
[8] WebRTC的擁塞控制和帶寬策略 https://mp.weixin.qq.com/s/Ej63-FTe5-2pkxyXoXBUTw
[9] RTP Extensions for Transport-wide Congestion Control
draft-holmer-rmcat-transport-wide-cc-extensions-01
[10] Bandwidth Estimation in WebRTC (and the new Sender Side BWE) http://www.rtcbits.com/2017/01/bandwidth-estimation-in-webrtc-and-new.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容