轉自;http://blog.csdn.net/ljh081231/article/details/79152578算法
本文在文章[1]的基礎上,從源代碼實現角度對WebRTC的GCC算法進行分析。主要內容包括: RTCP RR的數據源、報文構造和接收,接收端基於數據包到達延遲的碼率估計,發送端碼率的計算以及生效於目標模塊。網絡
擁塞控制是實時流媒體應用的重要服務質量保證。經過本文和文章[1][2],從數學基礎、算法步驟到實現細節,對WebRTC的擁塞控制GCC算法有一個全面深刻的理解,爲進一步學習WebRTC奠基良好基礎。框架
本節內容基本上是文章[1]第1節的複習,目的是再次複習GCC算法的主要框架,梳理其算法流程中的數據流和控制流,以此做爲後續章節的行文提綱。GCC算法的數據流和控制流如圖1所示。異步
對發送端來說,GCC算法主要負責兩件事:1)接收來自接收端的數據包信息反饋,包括來自RTCP RR報文的丟包率和來自RTCP REMB報文的接收端估計碼率,綜合本地的碼率配置信息,計算獲得目標碼率A。2)把目標碼率A生效於目標模塊,包括PacedSender模塊,RTPSender模塊和ViEEncoder模塊等。tcp
對於接收端來說,GCC算法主要負責兩件事:1)統計RTP數據包的接收信息,包括丟包數、接收RTP數據包的最高序列號等,構造RTCP RR報文,發送回發送端。2)針對每個到達的RTP數據包,執行基於到達時間延遲的碼率估計算法,獲得接收端估計碼率,構造RTCP REMB報文,發送回發送端。ide
因而可知,GCC算法由發送端和接收端配合共同實現,接收端負責碼率反饋數據的生成,發送端負責根據碼率反饋數據計算目標碼率,並生效於目標模塊。本文接下來基於本節所述的GCC算法的四項子任務,分別詳細分析之。函數
關於WebRTC上的RTP/RTCP協議的具體實現細節,可參考文章[3]。本節主要從RR報文的數據流角度,對其數據源、報文構造和收發進行分析。其數據源和報文構造如圖2所示,報文接收和做用於碼率控制模塊如圖3所示。學習
在數據接收端,RTP數據包從Network線程到達Worker線程,通過Call對象,VideoReceiveStream對象到達RtpStreamReceiver對象。在該對象中,主要執行三項任務:1)接收端碼率估計;2) 轉發RTP數據包到VCM模塊;3)接收端數據統計。其中1)是下一節的重點,2)是RTP數據包進一步組幀和解碼的地方;3)是統計RTP數據包接收信息,做爲RTCP RR報文和其餘數據統計模塊的數據來源,是咱們本節重點分析的部分。ui
在RtpStreamReceiver對象中,RTP數據包通過解析獲得頭部信息,做爲輸入參數調用ReceiveStatistianImpl::IncomingPacket()。該函數中分別調用UpdateCounters()和NotifyRtpCallback(),前者用來更新對象內部的統計信息,如接收數據包計數等,後者用來更新RTP回調對象的統計信息,該信息用來做爲getStats調用的數據源。編碼
RTCP發送模塊在ModuleProcess線程中工做,RTCP報文週期性發送。當線程判斷須要發送RTCP報文時,調用SendRTCP()進行發送。接下來調用PrepareReport()準備各種型RTCP報文的數據。對於咱們關心的RR報文,會調用AddReportBlock()獲取數據源並構造ReportBlock對象:該函數首先經過ReceiveStatistianImpl::GetStatistics()拿到類型爲RtcpStatistics的數據源,而後以此填充ReportBlock對象。GetStatistics()會調用CalculateRtcpStatistics()計算ReportBlock的每一項數據,包括丟包數、接收數據包最高序列號等。ReportBlock對象會在接下來的報文構造環節經過BuildRR()進行序列化。RTCP報文進行序列化以後,交給Network線程進行網絡層發送。
在發送端(即RTCP報文接收端),RTCP報文通過Network線程到達Worker線程,最後到達ModuleRtpRtcpImpl模塊調用IncomingRtcpPacket()進行報文解析工做。解析完成之後,調用TriggerCallbacksFromRTCPPackets()反饋到回調模塊。在碼率估計方面,會反饋到BitrateController模塊。ReportBlock消息最終會到達BitrateControllerImpl對象,進行下一步的目標碼率肯定。
至此,關於RTCP RR報文在擁塞控制中的執行流程分析完畢。
接收端基於數據包到達延遲的碼率估計是整個GCC算法最複雜的部分,本節在分析WebRTC代碼的基礎上,闡述該部分的實現細節。
接收端基於延遲碼率估計的基本思想是:RTP數據包的到達時間延遲m(i)反映網絡擁塞情況。當延遲很小時,說明網絡擁塞不嚴重,能夠適當增大目標碼率;當延遲變大時,說明網絡擁塞變嚴重,須要減少目標碼率;當延遲維持在一個低水平時,目標碼率維持不變。其主要由三個模塊組成:到達時間濾波器,過載檢查器和速率控制器。
在實現上,WebRTC定義該模塊爲遠端碼率估計模塊RemoteBitrateEstimator,整個模塊的工做流程如圖4所示。須要注意的是,該模塊須要RTP報文擴展頭部abs-send-time的支持,用以記錄RTP數據包在發送端的絕對發送時間,詳細請參考文獻[4]。
接收端收到RTP數據包後,通過一系列調用到RtpStreamReceiver對象,由該對象調用遠端碼率估計模塊的總控對象RemoteBitrateEstimatorAbsSendTime,由該對象的總控函數IncomingPacketInfo()負責整個碼率估計流程,如圖4所示,算法從左到右依次調用子對象的功能函數。
總控函數首先調用InterArrival::ComputeDeltas()函數,用以計算相鄰數據包組的到達時間相對延遲,該部分對應文章[1]的3.1節內容。在計算到達時間相對延遲時,用到了RTP報文頭部擴展abs-send-time。另外,實現細節上要注意數據包組的劃分,以及對亂序和突發時間的處理。
接下來算法調用OveruseEstimator::Update()函數,用以估計數據包的網絡延遲,該部分對應文章[1]的3.2節內容。對網絡延遲的估計用到了Kalman濾波,算法的具體細節請參考文章[2]。Kalman濾波的結果爲網絡延遲m(i),做爲下一階段網絡狀態檢測的輸入參數。
算法接着調用OveruseDetector::Detect(),用來檢測當前網絡的擁塞情況,該部分對應文章[1]的3.2節內容。網絡狀態檢測用當前網絡延遲m(i)和閾值gamma_1進行比較,判斷出overuse,underuse和normal三種網絡狀態之一。在算法細節上,要注意overuse的斷定相對複雜一些:當m(i) > gamma_1時,計算處於當前狀態的持續時間t(ou),若是t(ou) > gamma_2,而且m(i) > m(i-1),則發出網絡過載信號Overuse。若是m(i)小於m(i-1),即便高於閥值gamma_1也不須要發出過載信號。在斷定網絡擁塞狀態以後,還要調用UpdateThreshold()更新閾值gamma_1。
算法接着調用AimdRateControl::Update()和UpdateBandwidthEstimate()函數,用以估計當前網絡狀態下的目標碼率Ar,該部分對應文章[1]的3.3節。算法基於當前網絡狀態和碼率變化趨勢有限狀態機,採用AIMD(Additive Increase Multiplicative Decrease)方法計算目標碼率,具體計算公式請參考文章[1]。須要注意的是,當算法處於開始階段時,會採用Multiplicative Increase方法快速增長碼率,以加快碼率估計速度。
此時,咱們已經拿到接收端估計的目標碼率Ar。接下來以Ar爲參數調用VieRemb對象的OnReceiveBitrateChange()函數,發送REMB報文到發送端。REMB報文會推送到RTCP模塊,並設置REMB報文發送時間爲當即發送。關於REMB報文接下來的發送和接收流程,和第1節描述的RTCP報文通常處理流程是同樣的,即通過序列化發送到網絡,而後發送端收到之後,反序列化出描述結構,最後經過回調函數到達發送端碼率控制模塊BitrateControllerImpl。
至此,接收端基於延遲的碼率估計過程描述完畢。
在發送端,目標碼率計算和生效是異步進行的,即Worker線程從RTCP接收模塊經回調函數拿到丟包率和REMB碼率以後,計算獲得目標碼率A;而後ModuleProcess線程異步把目標碼率A生效到目標模塊如PacedSender和ViEEncoder等。下面分別描述碼率計算和生效過程。
碼率計算過程如圖5所示:Worker線程從RTCPReceiver模塊通過回調函數拿到RTCP RR報文和REMB報文的數據,到達BitrateController模塊。RR報文中的丟包率會進入Update()函數中計算碼率,碼率計算公式如文章[1]第2節所述。而後算法流程進入CapBitrateToThreshold()函數,和配置的最大最小碼率和遠端估計碼率進行比較後,肯定最終目標碼率。而REMB報文的接收端估計碼率Ar則直接進入CapBitrateToThreshold()函數參與目標碼率的肯定。目標碼率由文章[1]的3.4節所示公式進行肯定。須要注意的是,RR報文和REMB報文通常不在同一個RTCP報文裏。
發送端碼率生效過程如圖6所示:ModuleProcess線程調用擁塞控制總控對象CongestionController週期性從碼率控制模塊BitrateControllerImpl中獲取當前最新目標碼率A,而後判斷目標碼率是否有變化。如果,則把最新目標碼率設置到相關模塊中,主要包括PacedSender模塊,RTPSender模塊和ViEEncoder模塊。
對於PacedSender模塊,設置碼率主要是爲了平滑RTP數據包的發送速率,儘可能避免數據包Burst形成碼率波動。對於RTPSender模塊,設置碼率是爲了給NACK模塊預留碼率,若是預留碼率太小,則在某些狀況下對於NACK報文請求選擇不響應。對於ViEEncoder模塊,設置碼率有兩個用途:1)控制發送端丟幀策略,根據設定碼率和漏桶算法決定是否丟棄當前幀。2)控制編碼器內部碼率控制,設定碼率做爲參數傳輸到編碼器內部,參與內部碼率控制過程。
至此,發送端碼率計算和生效過程分析完畢。
本文結合文章[1],深刻WebRTC代碼內部,詳細分析了WebRTC的GCC算法的實現細節。經過本文,對WebRTC的代碼結構和擁塞控制實現細節有了更深層次的理解,爲進一步學習WebRTC奠基良好基礎。