音視頻框架-webrtc中的網絡反饋與控制

webrtc中的網絡反饋與控制

引言

站在風口上,豬都能飛起來。雷布斯的這句名言,已經被大家傳的家喻戶曉了,說起當下站在風口上的豬,除了丁老闆的未央豬,這頭實實在在的豬,視頻直播應該可以算一個。今年各種直播平臺,各個輪次的融資消息應接不暇。對於互聯網技術從業者來說,RTC(Real Time Communication,實時通信)這個站着視頻直播背後的技術也重新開始變得火熱起來。視頻直播算是互聯網應用的新領域,但實時通信技術卻算不上是比較新的技術,傳統的視頻電話、會議系統等都是實時通信技術的應用,但互聯網視頻直播肯定有其新的特點,也就會有新的技術演進。

WebRTC

現在大多視頻直播平臺主要還是採用的RTMP(Real Time Messaging Protocol,實時消息傳輸協議)技術來實現,RTMP基於可靠的TCP傳輸,協議簡單,開發成本低,跟flash等流媒體服務支持較好,還有一個重要的原因就是CDN支持良好,目前視頻直播服務還是嚴重依賴CDN服務來實現的。當然其缺點也是因爲其基於可靠的TCP協議,音視頻傳輸的一個顯著特點是數據量大,並且對實時性要求比較高,而傳統的TCP協議是一個面向連接的協議,它的重傳機制和擁塞控制機制都是不適用於實時傳輸的。基於TCP的音視頻傳輸,傳輸控制嚴重依賴TCP協議本身的控制機制,網絡成本較大又不夠靈活,在弱網環境丟包率高的情況下導致直播卡頓明顯,另外其本身的延時性不佳,對於實時性要求較高的應用場景就力不從心,比如基於其來實現現在熱門的互動直播,就會很困難。

由於音視頻技術本身的特性,其對網絡丟包有一定程度的天然容忍性,使用UDP進行傳輸纔是一個理想的選擇。使用UDP協議開發者可以在傳輸層進行靈活的網絡擁塞控制、流量反饋與控制,通過一些定製化的調優可以達到比較好的弱網優化效果,來保證更好的音視頻傳輸流暢、低延時體驗;不過反過來,這個優勢的實現也就是開發成本了。這時該WebRTC出場了,WebRTC(Web Real-Time Communication,網頁即時通信),是一個實時音視頻通信的開發框架,其本身足夠強大,不僅有基於UDP的數據傳輸,還包括ICE、STUN、TURN等實現信令交互、網絡打洞等,其天然對瀏覽器的支持也是一個重要優點,背後是強大的Google在支撐,基於WebRTC,只需要簡單的幾個接口就可以實現一個擁有實時音視頻通信功能的demo。

WebRTC框架

Alt pic

WebRTC的問題

話說到這裏,彷彿Google已經再次拯救了世界,我們這些音視頻狗好像可以過上活少錢多離家近的生活了一樣。但是,但是功能不等於品質,由於UDP不是一個可靠的傳輸協議,在複雜的公網網絡環境下,各種突發流量、偶爾的傳輸錯誤、網絡抖動、超時等等都會引起丟包異常,都會在一定程度上影響音視頻通信的質量,網上一篇介紹WebRTC的科普文中有一句話說到,“demo和實用之間還差着一萬個WebRTC”,額,古人誠不我欺。

應對方法

不過又但是了,辦法總是比困難多的,不然要我們幹啥,怎麼顯得我們牛逼。 這裏說說爲解決上述所說的網絡傳輸問題,在網絡傳輸層可以做的一些事情,這些辦法和事情包括NACK、jitterbuffer、帶寬自適應、前向糾錯編碼(FEC)等,這些本身在WebRTC的實現中基本都包含,Google也算給指明瞭方向,只是我們在實際使用中,還是要彌補demo到實用之間的距離。

RTP/RTCP協議

在介紹這些措施之前,我們先看一下WebRTC中所使用的數據傳輸協議。前面說到WebRTC使用UDP協議進行音視頻數據的傳輸,實際上使用的是RTP/RTCP協議。RTP協議是Internet上針對流媒體傳輸的基礎協議,詳細說明在互聯網上傳輸音視頻的標準數據包格式,它是一個應用型的傳輸層協議,位於UDP上,本身只保證實時數據的傳輸,不提供任何傳輸可靠性的保證和流量的擁塞控制機制,RTCP協議則負責流媒體的傳輸質量保證,提供流量控制和擁塞控制等機制。在RTP會話期間,各參與者週期性彼此發送RTCP報文,報文中包含各參與者數據發送和接收等統計信息,參與者可以根據報文中信息動態控制流媒體傳輸。在WebRTC項目中,RTP/RTCP作爲傳輸模塊的一部分,負責對發送端採集到的媒體數據進行進行封包,然後交給上層網絡模塊發送;在接收端RTP/RTCP模塊收到上層模塊的數據包後,進行解包操作,最後把負載發送到解碼模塊。因此可以說RTP/RTCP是WebRTC的重要基礎。RFC3550/3551定義RTP/RTCP協議的基本內容,包括報文格式、傳輸規則等。除此之外,IETF還定義一系列擴展協議,包括RTP協議基於檔次的擴展和RTCP協議基於報文類型的擴展,比如RFC4584等。

RTP/RTCP議棧示意圖

Alt pic

NACK與重傳

NACK(negative-acknowledge character),就是否定應答,與之對應的是TCP中的ACK(acknowledge character)。我們知道在TCP中,接收端對於收到的包都要進行應答即發送ACK包,發送端通過接受ACK包,來確定發送的包已經被成功接收,以此來保證網絡包的傳輸可靠。RTP協議不來保證傳輸的可靠性,所以接收端也就不會發送ACK包,但是對於‘丟失’的包,沒有收到的包,如果覺得這個包比較重要,可以給對端發送NACK包,來告訴對端,這個包我沒有收到,你如果‘還有’的話,就給我重新發送一遍(Retransmission)。我們可以理解爲,對於ACK機制來說,發送端沒有收到ACK,我就重新發送,是一種push的方式,對於NACK來說,接收端沒有收到,主動請求,是一種pull的模式。如果對於每個‘丟失’的包,都發起NACK的話,那也就和ACK沒有大的不同了,但是正如前面描述中各種模棱兩可的話所說,我們可以根據需要、根據策略,選擇性的發起丟包重傳,甚至可以選擇完全不進行重傳,而是通過其他的容錯機制來進行保障,因爲發起重傳,也就意味着接收端要等待這個包,等待就會增加延時。比如在WebRTC的實現中,對於音頻的傳輸,在收發兩端進行協商的時候就約定了,音頻包就不進行重傳了,丟了就丟了吧。說到這裏插一句話,我們這裏說到的網絡反饋和控制的機制,基本都是要收發兩端進行協商的,比如這裏說的重傳,如果要支持的話,對於發送端來說,就需要一個發送端緩存,發送出去的包,需要暫留一段時間,不然即便收到了NACK包,也沒辦法重傳了。對於接收端來說,我們前面說到的丟包,都加了引號,其實是說,這個“丟包”,有可能是真的丟了,也有可能是順序亂了。我們知道網絡包的到達,有時候不是一定嚴格按照包序到達的,我收到了很多較新的包了,某個舊的包還沒有收到,我就認爲它丟了,也沒準兒一會兒它又到了。那麼對於接收端,我要等多久,才認爲它‘丟包’了呢?可以是根據亂序的偏移來決定發起重傳,也可以根據預計到達時間已經超過一定時間了來發起重傳。發起重傳後,我得等這個重傳的包吧,那我等多久呢?一般是等待一個rtt+jitter的時常,如果這個時間內還沒有到達,可以選擇丟棄不要了,也可以選擇再次發起重傳,可是也不能一直等下去吧,這個就要看下面要說到的jitterbuffer。

jitterbuffer

在網絡傳輸中總是存在着抖動,由於網絡擁塞、路由變化等等原因,導致網絡包不是按時間均勻到達的,還有上面說的包不是按照包序有序到達,這時候就需要一個緩衝區,來緩存網絡包,進行等待和排序,將這個網路‘抖動’給過濾掉,從而可以穩定有序的將包再發給後面的處理邏輯。假如是個固定長度的buffer,那麼當緩衝區滿了的時候,如果一個包還沒有收到,那麼就不會再等待這個包了。試想,在一定的網絡抖動條件下,這個buffer設置的過小,就會導致發起的重傳比較多,如果設置的過大,必然又會增加jitterbuffer中等待的延時,從而導致整個音視頻通信延時的增加。所以理想的做法是,根據網絡的狀況,按照一定的策略,動態的來調整jitterbuffer的大小。比如在網絡比較好的時候,設置小一點,這時對於‘丟包’儘快的發起重傳,我們也是可以期望在較快時間內就得到的,從而降低延時;網絡不好的時候,可以適當設置大一點,因爲這時本來網絡條件就較差,更多的重傳只能是更加惡化網絡環境。當然,僅僅是動態的jitterbuffer也是無法完全解決這個問題的,根本上還是應該根據網絡狀況來調整發送的碼率,網絡環境差的情況下,主動降低碼率,通過減少網絡負荷,來保證傳輸的流暢性。這就是下面要說的帶寬自適應。

jitterbuffer示意圖

Alt pic

帶寬自適應

帶寬自適應是指在音視頻的收發過程中,根據網絡帶寬的變化,自動的來調整發送碼率,來適應帶寬的變化。在帶寬足夠的情況下,增加幀率和碼率,提高音視頻的質量,帶來更好的通信體驗。在帶寬不足的情況下,主動降低碼率或者幀率,保證通信的流暢性和可用性,也是帶來更好的通信體驗。帶寬自適應的核心,就是如何準確的估計帶寬。WebRTC在實現帶寬自適應時採用了Google提出一個稱爲REMB(Receiver Estimated Max Bitrate,最大接收帶寬估計)的帶寬估計算法。這個算法的大概思路是在接收端根據丟包率或者延時情況維護一個狀態機(參見下圖)。以根據丟包率爲例,在判斷爲overuse時,就根據一定的係數減少當前remb值,當判斷爲underuse時又根據增加係數來增加remb值;然後將這個值通過rtcp包發送給發送端,發送端根據該值來動態的調整碼率。在發送端,WebRTC的實現中在調整碼率時還會參考rtcp中的丟包率,當然這些我們都可以根據自己的策略進行修改。關於接收端(服務端)REMB帶寬估計的實現,則是需要自己來實現,可以實現得更復雜和完善,來實現更佳準確的帶寬估計,更佳敏捷的帶寬自適應。

接收端帶寬估計

Alt pic

REMB狀態機

Alt pic

前向糾錯編碼

最後我們再來說一下FEC(Forward Error Correction,前向糾錯),也叫前向糾錯碼,是通過增加冗餘來增強容錯性的一種方法。沒有FEC的情況下,當接收端發現有包丟失時,需要通過發送NACK來發起重傳,前文中我們已經說過,重傳是會影響延時性的,而FEC則是在發送通過糾刪碼來增加一些冗餘數據,這樣接收端在數據丟失的情況下可以根據冗餘數據來重建丟失的數據。通過增加FEC來避免和減少NACK/重傳,從而減少丟包導致的延時。其缺點也是顯然的,增加的FEC冗餘數據佔據了有效帶寬,這又是一種取捨了,不過FEC的冗餘度也是可以根據網絡狀況來動態的調整的。我們這裏說的FEC是整個RTP傳輸層的,在使用WebRTC的過程中,還會發現,在WebRTC使用的音頻opus編碼中還有一個稱爲inband的FEC,就是在opus的編碼過程中增加一定的FEC冗餘,我想這也就是爲什麼我們前面說到的WebRTC中音頻在協商的時候就不進行NACK重傳了。

FEC示意圖

Alt pic

小結

上面的介紹基本就是WebRTC中網絡反饋與控制的方法和策略了,這些策略和方法相輔相成共同作用,才能使得WebRTC音視頻通信擁有良好的體驗和品質。

轉載自:http://blog.csdn.net/y_xianjun/article/details/53928947

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章