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

1引言

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

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

本文基于WebRTC的M66版本和相關RFC,深度分析學習最新Sendside-BWE算法的實現。

2 GCC算法回顧

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

圖1 GCC算法整體結構

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

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

圖2 GCC發送端基于丟包率的碼率估計

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

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

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

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

3 Sendside-BWE算法框架

從本節開始系統分析Sendside-BWE算法的框架和實現,圖4顯示該算法的基本實現框架,以及和GCC算法的對比。

圖4 Sendside-BWE算法和GCC算法的實現和對比[8]

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

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

表5 GCC和Sendside-BWE關鍵模塊異同

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

4 Sendside-BWE算法實現

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

4.1 Sendside-BWE在SDP層協商

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

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

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

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

然后,SDP協商過程按照常規操作進行。

4.2 發送端發送RTP報文

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

圖6 TransportSequenceNumber擴展格式

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

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

然后RTP報文走正常的構造發送路徑發送到網絡。

4.3 接收端接收RTP并構造TransportCC報文

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

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

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

圖7 TransportCC報文格式

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

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

然后按照常規RTCP報文流程發送到發送端。

4.4 發送端接收TransportCC報文并解析

接收端接收操作就是常規的RTCP接收、解析并回調的流程,在worker線程中:

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

然后就是Send-side BWE算法在發送端的核心實現。

4.5 SendSideCongestionController碼率估計

SendSideCongestionController是Sendside-BWE算法在發送端的核心實現,關于其的分析全部是細節描述。本節限于篇幅,僅勾勒出其大致的函數調用棧和流程說明。

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

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

DelayBasedBwe對象是真正實現碼率估計的地方,其內部調用函數棧如下:

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

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

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

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

至此,關于Sendside-BWE算法的實現初步分析完畢。

5 Sendside-BWE實測數據

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

圖8 Sendside-BWE和GCC算法對比

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

6 總結

本文在總結對比GCC和Sendside-BWE算法基礎上,深入學習Sendside-BWE算法的框架和實現細節,為進一步學習WebRTC擁塞控制算法和優化算法細節打下堅實基礎。

參考文獻

[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視頻接收緩沖區基于KalmanFilter的延遲模型.http://www.lxweimin.com/p/bb34995c549a
[6] WebRTC基于GCC的擁塞控制(上) - 算法分析 http://www.lxweimin.com/p/0f7ee0e0b3be
[7] WebRTC基于GCC的擁塞控制(下) - 實現分析 http://www.lxweimin.com/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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
禁止轉載,如需轉載請通過簡信或評論聯系作者。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,397評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內容