文|網易智慧企業資深流媒體開發工程師算法
背 景服務器
科技的進步以及通信基建的高速發展,使得人們對交流的模式要求愈來愈即時,對交流內容要求愈來愈具象,這些要求催化着內容交換模式的不斷髮展,從傳統的信件,到短信電話再到互聯網場景下的微信語音、抖音短視頻、視頻直播及實時音視頻通話。隨着5G正式商用元年的真正到來,更加即時與具象的實時音視頻通信將被更普遍的應用。實時音視頻系統,是一個相對比較複雜的內容傳輸系統,從大的流程上來說,系統覆蓋音視頻採集、音視頻編碼、音視頻傳輸、音視頻解碼、音視頻繪製。想要作到高質量的音視頻通話,每一個環節都須要豐富的手段才能進行各類場景及設備的適配與效果提優。微信
實時音視頻的最顯著的特色是低延遲,也就是說實時音視頻對於網絡的要求是很是高的,甚至能夠說是矛盾的。一方面它爲了追求低延遲,它可以容許網絡傳輸中的丟包,另外一方面由於視頻編解碼的傳遞參考性,任何的丟包都會形成很大的視頻質量的損失,最終將下降實時通話的QoE評價,因此又不能容忍網絡傳輸中的丟包。爲此搭建一個高質量實時音視頻系統,尤爲是多方參與的會議系統,應對於參與通話各方上下行網絡複雜性(帶寬受限/丟包/抖動/高時延)的傳輸QoS策略的設計是很是有必要的。本文就會議場景下,服務器端的QoS策略,作一些詳細的分享。網絡
會議場景分段QoS併發
會議場景的通話,決定了參與通話的各方都要經過中轉的流媒體分發服務器進行傳輸內容的交換。會話傳輸鏈路能夠劃分爲實時通話發送端到流媒體分發服務器的上行傳輸鏈路,以及流媒體分發服務器到實時通話接受端的下行傳輸鏈路。上下行傳輸鏈路,從服務器角度而言其承擔傳輸角色是不一樣的,傳輸策略做用輕重亦不相同,爲此針對於這種多人會議場景,須要制定上下行獨立的QoS傳輸方案,去保障上下行的傳輸質量。咱們稱之爲分段QoS策略。框架
上行QoS高併發
網易雲信的設計裏,QoS的強控制權都交由發送端。接收端作被動的接受信息反饋和丟包請求與恢復。針對於上行QoS的策略,服務器端做爲接收端,設計了一系列的QoS手段,進行高可靠的鏈路傳輸。包括但不侷限於:丟包重傳請求(NACK)、前向糾錯(FEC)、關鍵幀請求(PLI/FIR)、接受信息反饋(FeedBack)等手段。這裏選取兩個抗丟包手段作一些深刻的講解。性能
丟包重傳請求 測試
丟包重傳請求,簡單的實現就是服務器做爲接收端,在實時接收傳輸的流媒體的時候,進行傳輸層媒體包序的連續性檢查,當出現非連續包出現的時候,通過必定的超時時間(考慮到實時音的低時延要求每每這個超時時間會設置的比較短),便會向發送端進行丟失包的重傳請求。因爲丟包的不肯定性,丟失的包序的分佈也會呈現出不肯定性。爲此咱們須要設計出一個合適的重傳協議來覆蓋丟包的各類分佈狀況,達到重傳請求的最小帶寬佔用的目的。優化
咱們設計了靈活NACK請求協議,其協議設計能夠很好的解決上述狀況:
協議容許單個NACK請求包對多個流,進行不一樣丟包狀況的重傳請求。
前向糾錯
前向糾錯(FEC)實際上是一種冗餘錯誤恢復的算法。應用在網絡傳輸中,主要是用來抵抗網絡丟包致使的信源錯誤。
其具體的作法就是將原始的信源數據進行可逆的運算,生成額外的冗餘包,在實際發送的時候會將原始包和冗餘包分爲一組發送到網絡上。在網絡出現丟包的時候,接收端能夠經過同一分組的原始包和冗餘包進行逆運算去還原所丟失的原始包。固然這裏的還原是有條件的,還原的成功率跟咱們冗餘算法的冗餘度大小有關,通常狀況下成正相關。但過多的冗餘包會佔據不少的發送流量,這樣實際上是不利於正常的媒體傳輸的。
關於冗餘算法的選取在服務器端也是很是重要的一個課題,主要涉及到兩點:
-
冗餘度在算法層面是否支持動態調整。
-
計算複雜度可否知足服務器性能要求。
第一點很容易理解,由於網絡丟包是複雜多變的,固定冗餘度的算法要麼會帶來帶寬的浪費要麼恢復效果不理想。第二點的話,源自於實時音視頻服務器主要的角色是作媒體分發的,其根本要求是分發的高效,一旦FEC的算法複雜度太高,在高併發高I/O吞吐的狀況下,勢必會下降服務器併發性能,甚至會引入額外的端到端的delay。
目前已經實現的FEC算法不少,簡單有基於異或的實現,複雜的有基於矩陣運算的,以及一些其餘的算法,這裏就不詳細描述了。
網易雲信實踐
以上簡單的介紹了丟包重傳請求和前向糾錯的策略。這兩種機制是常見的抗丟包策略。在具體的應用上,各個音視頻廠商,只是在協議實現和算法選取上略有不一樣而已。既然ARQ和FEC都是爲了對抗丟包而制定出來的策略,那麼在網易雲信中咱們如何作最優的策略選取的呢?
首先在作策略選取以前,咱們先回顧一下兩種策略對抗丟包的不一樣思路。
第一種丟包重傳策略(ARQ),解決的是當前丟包已經發生,須要作短暫的時延犧牲(即作丟包重傳的時候會形成Jitter),來對抗丟包,其優勢明顯,即不會實時的佔用信道帶寬,缺點就是引入的Delay,一些不當的NACK請求策略的設計甚至會形成流量尖刺。
第二種FEC策略,其做用效果是實時觀測丟包率的變化,作丟包率的預估,實時產生冗餘數據來對抗可能出現的丟包。其優勢在基本不須要犧牲時延,能夠作快速的丟包恢復。但其缺點亦很明顯,即依賴於丟包預測的準確度,太高的冗餘會形成帶寬流量的浪費,甚至擠壓正常的信源的傳輸,致使一個不健康的信道傳輸狀態。
下面介紹一下網易雲信對這兩種策略組合的使用方法。
1. 創建網絡狀態的觀測器。
其主要監控當前網絡的丟包率、抖動、時延、擁塞狀態。觀測器的創建質量好壞會很大程度的反應到咱們的抗丟包效果上去,在丟包率上咱們會根據關心的閾值去作不一樣區間的採樣標本,作多個細分丟包率的觀測和預估。這裏的丟包率有平均RTT內的丟包率,有去抖動的丟包率,以及跟NACK請求相關的丟包重傳超時時間相關的丟包率。觀測器主要的做用是進行網絡可數據化的狀態偵測。爲後側的策略提供網絡類型的分析,並提供確切的指標,供核心調控模塊來調節自適應的參數。
2. ARQ手段先行,FEC手段作兜底。
具體的意思是咱們會根據預設的最大端到端Delay(這個Delay跟用戶設置模式有關,能夠動態調節),再根據觀測器觀測出來的相關網絡指標去計算ARQ的成功率,剩下的失敗率由FEC作兜底。具體算法以下:假設當前選取的網絡平均丟包爲L,當前Rtt爲R,咱們能容忍的最大Delay時間爲D,最小NACK請求間隔爲I,則單個包能夠進行NACK的請求次數C = (D-R) / I,那麼通過重傳以後,單個包仍處於丟失的機率爲:XL = L * LC= L(C+1),那麼FEC冗餘率設計的參考丟包率TL = a * XL + b * BL,其中a爲增益係數,屬於自適應調整參數,BL是基於觀測器獲得的網絡基本(最小)丟包率,b爲調節係數(b 小於等於1.0),通常在網絡帶寬不受限的狀況下,將b設置爲 1.0。此外基於丟包率如何去選取冗餘度,有不少計算方式,這裏就不展開了。
3. 基於接收端反饋以及模塊自檢的策略調整。
服務器做爲接收端會創建抗丟包效果評估模塊,具體到指標有NACK成功率,NACK響應時長,FEC 成功率等。發送端會基於此類的反饋,以及兩個模塊自身的相關統計數據,如Rtx(重傳包)、FEC流量與原始信源的流量佔比,以及擁塞控制模塊的擁塞狀態等,進行模塊內策略相關的參數(D、I、a、b等)的動態的調整。
網絡自己是複雜的,須要有一個合理的調度器來控制ARQ和FEC抗丟包模塊的協同做用,要作到具體網絡狀況作具體的調節,咱們的抗丟包策略不該形成過多的網絡信道的擠壓,進而反向壓制了信源的質量,甚至致使擁塞的時而發生,這樣將會和咱們的抗丟包策略設計的初衷背道而馳。
下行QoS
相比較上行QoS,服務器在下行QoS能夠作的策略能夠更多,上文提到了咱們的QoS設計裏更多的控制權是交由發送方,對於下行QoS服務器角色即是發送方。除去抗丟包手段以外,服務器須要作的幾個重要的QoS相關的工做在於:
-
設計出下行接收端可彈性接收流組合的方案。
-
準確的探測出用戶真實的下行帶寬。
-
制定合理的帶寬分配方案。
-
進行流量的平滑發送以及擁塞控制。
下行QoS模塊控制總圖
設計合理的接收端可彈性接收的方案,是整個下行QoS的設計基礎。一個完整的擁塞控制系統,其必然要完成兩個基本的工做:
-
感知當前信道的傳輸狀態,這個狀態能夠是信道的最大帶寬,也能夠是當前合適傳輸速度。
-
可以根據這個狀態對發送信源進行調節,將信源的碼率控制在可承受範圍以內。
因此,對於服務器端下行擁塞控制而言道理也是同樣。服務器設計了多流+SVC的機制進行下行流量的控制。來實現對下行傳輸鏈路的控制,應對於用戶不一樣的下行狀態,作到最佳的QoE效果。
多流機制
咱們的多流機制選取大小雙流的方案,爲了給服務器下行調節最大空間,以及考慮實際體驗效果,這裏的大小流的分辨率也不是固定的,會隨着服務器調節的碼率,作彈性的伸縮。針對於多流而言,上行用戶能夠根據本身的網絡能力作不一樣流的發佈,下行用戶能夠根據自身的須要以及網絡帶寬,作符合自身能力的流的訂閱。另外輔助SVC的策略,服務器能夠作到最大的調節空間,充分利用用戶的下行網絡帶寬,作到用戶接收的最佳體驗。這裏發送端彈性分辨率的雙流機制以及SVC方案,服務器就不作過多的描述了,感興趣的同窗能夠繼續關注咱們網易雲信的相關技術分享。
帶寬探測
帶寬探測。這個模塊實現的好壞,直接影響到下行QoS的效果。對於擁塞控制而言,開源的實現有GCC,PCC,BBR及其餘的擁塞控制方法。
網易雲信服務器下行QoS是基於Google的BBR算法,在實時音視頻場景下作了大量的優化,進而創建了完整的擁塞控制方案。
選取BBR算法兩個最主要的緣由:
-
基於可測量的準確帶寬。
-
算法層面的最大帶寬利用率。
服務器下行和客戶端上行擁塞控制的本質區別在於,下行要求的帶寬大。客戶端上行能夠經過平滑的調整信源作到最佳的發送速率,而服務器只是基於現有上行流的轉發,要作到平滑的信源調節很是困難。因此客戶端的擁塞控制通常使用GCC比較多,緣由在於GCC更側重於發送碼率的動態調節來進行擁塞控制。
BBR自己的算法這裏就不具體描述了,Webrtc對BBR在實時音頻場景下的應用也有代碼的實現,處於測試階段。
在網易雲信實際運用BBR作下行帶寬探測的時候,咱們作了不少優化,這裏羅列一些筆者認爲在實時音場景下,尤爲在服務器端作帶寬探測,BBR建議作相應優化的點:
-
Probe_RTT 階段的隱藏弱化
-
上行網絡丟包帶寬補償
-
上行網絡RTT突變以及高Jitter場景優化
-
下行鏈路抖動以及丟包的優化
-
Padding流量的優化
-
快速上探機制的實現
這裏的上下行網絡,是針對於BBR網絡帶寬探測端而言的。通過咱們一系列的優化,基本將帶寬探測的準確度作到95%左右。
900kbps + 15% loss + 100jitter
帶寬分配策略
帶寬分配模塊要作的事情,其實就是結合下行用戶的探測出來的帶寬,以及下行用戶的原有的訂閱關係,幫用戶智能的選取最佳接收流的組合。在介紹具體介紹帶寬分配策略以前,簡單回顧一下咱們下行QoS的設計基礎,即多流+ SVC的機制:用戶上行的多流中的每條流都會在發佈的時候把本身的可調控碼率空間信息,即檔位信息告知發佈訂閱管理器。經過這樣的實現,服務器即可制定靈活的帶寬分配方案。
基於此實現,那麼對於服務器下行接收而言,能作的手段有兩種:
-
源端無感知的,接收端大小流切換
-
源端配合的流內碼率(檔位)調整
這兩種手段都交由統一的帶寬分配策略來控制,具體的思路有兩點:
1. 儘量不去反向壓制發送端的編碼碼率,在基於可選取的大小流的基礎上作最佳接收流的組合,來匹配用戶下行可實際接收的帶寬。
2. 反向壓制發送端編碼碼率須要創建在接收端用戶舉手表決的基礎上進行結果裁定。
平滑發送及擁塞控制
平滑發送及擁塞控制。前面幾個模塊講的是用戶怎麼接收的問題,最終如何控制下行的發送,交由這個模塊來管理。這個模塊的設計的每一個細節和用戶體驗息息相關。大的思路有以下幾點:
1. 平滑發送。就平滑發送而言,咱們主要的實現是建立Pacer對象,在單獨的發送線程中,起高精定時器,進行發送的平滑,讓網絡流量不會在觀察區間內有Burst的現象。
2. 基於流級別的優先級策略以及可選擇性發送策略。緩衝在發送隊列的流,會有不一樣的優先級。在咱們的默認設計裏優先級順序爲 重傳包 > 音頻包 > 大於視頻包 > 被切掉的流 > Padding包。另外也設計了用戶態的流的優先級。整體策略是用戶態優先級最高,而後再參考QoS自己的優先級。可選擇性發送策略的設計主要基於SVC,觀察Pacer的堆積狀況,以及對應流的堆積狀況,進行轉發分層的選取。
3. 擁塞避免。這個模塊的實現,主要是從BBR帶寬探測模塊獲取建議的發送碼率,而且嚴格按照碼率發送,在某些場景下如真實媒體數據不足的狀況,甚至能夠減小發送碼率。固然這些行爲都可以讓帶寬探測模塊感知到。
4. 擁塞緩解。這裏的擁塞緩解更可能是模塊內部擁塞狀態的緩解。主要的方法是經過獲取發送隊列的堆積狀況,來進行模塊內部擁塞狀態的判斷。一旦源端超發或者帶寬分配模塊調節沒那麼靈敏,致使模塊出現擁塞狀態。那麼就要及時的進行堆積的處理,而不是把數據放到網絡上,形成網絡的擁塞,帶來更多不肯定因素。這裏堆積判斷,主要基於Trendline 配合絕對Delay的固定閾值。
如圖,在t0時刻,Delay超過了咱們的絕對閾值,可是計算出來的Trend並不高,既不是一個持續擁塞的狀態,反而它多是一個擁塞緩解的狀態。在t1時刻這裏咱們看到Trend值已經很高,並且Delay已經超過咱們的閾值。那麼t1時刻是咱們須要進行擁塞緩解的時刻。擁塞緩解的具體作法就是根據流的優先級進行選擇性的丟棄。因此,在進行擁塞緩解的時候,咱們判斷擁塞的狀態必定要嚴謹,一旦主動代替網絡丟包,那麼用戶體驗確定會受影響。
平滑發送及擁塞控制總圖
總 結
以上從大的框架上講述網易雲信搭建的音視頻服務,在服務器端實現的一些QoS方案的介紹,其中細節不少,很難一一描述,但每每是細節決定最終的通話質量。
音視頻通信自己一個複雜的通信系統,本文開頭也提到了,QoS的設計也只是其中的一環,想要達到最佳的通話效果,每一個環節作到環節內的最優,環節間也要創建有效的反饋調節機制。才能將整個端到端的體驗作到最優,這樣才能獲得用戶的承認。