直播傳輸協議SRT

1. 爲什麼選擇SRT?

毋庸置疑,現今存量最大的直播協議是RTMP,但隨着新技術的不斷髮展與使用場景的不斷拓展,繼續使用RTMP會令人感到有些力不從心。RTMP協議的缺陷主要有以下四個方面:

RTMP協議缺陷

首先,RTMP協議太老,且最後一次更新是在2012年;同時HEVC/H.265/AV1等視頻格式都沒有官方定義,以至於需要國內CDN廠商自行定義。

RTMP連接過程較長,由於RTMP基於TCP(TCP存在三次握手),除此之外,其本身又存在c0/s0到c2/s2的三次握手,再加上connection,createstream,play/publish,總地來說RTMP完成一次建連需要進行9次會話,用於PC端勉強能夠接受,對於移動端網絡質量的要求則很高。

RTMP的擁塞控制完全依賴傳輸層,即完全依賴於TCP傳輸層的擁塞控制算法來進行擁塞管理,幾乎沒有什麼優化;RTMP本身基於TCP傳輸,無法提供帶寬自適應的算法。

在此背景下,衆多廠商開始着手提供一些新的直播協議供行業參考。如QUIC、SRT等。本次我們將重點講述SRT的特點與應用。

SRT協議的特點

Haivision聯手Wowza在UDT的基礎上針對音視頻實時性提出了SRT協議。SRT是基於UDT的協議(UDT協議是基於UDP的傳輸協議,在IETF已經提交了4個版本),具有非常良好的丟包重傳機制,丟包重傳的控制消息非常豐富,同時支持ACK、ACKACK、NACK。

我們都知道音視頻對於時間這一點非常在意,而SRT基於時間的報文發送,使其具有良好的防止流量突發的能力。SRT對上層提供了豐富的擁塞控制統計信息,包括RTT、丟包率、inflight、send/receive bitrate等。利用這些豐富的信息,我們可以實現帶寬預測,並根據帶寬的變化在編碼層去做自適應動態編碼與擁塞控制。

2. SRT協議原理分析

2.1 SRT基本思想

上圖可以涵蓋SRT的基本思想:對比編碼後的視音頻碼流(左側綠色折線“Source”)與經過公網傳輸後的碼流(紅色折線“NetworkTransmission”),可以看到編碼後的源視音頻碼流具有固定的幀間隔與一定特性的可變比特率,但經過公網傳輸後的碼流,其幀間隔變得不固定且碼率特性也被完全改變,解碼這樣的信號是一項十分艱鉅的挑戰,甚至根本無法解碼。

而如果使用加入糾錯的SRT協議進行公共互聯網傳輸,儘管編碼後的視音頻碼流經過公網傳輸幀間隔變得不固定,但由於SRT協議封裝中包含精準的時間戳,解碼接收端可以通過該時間戳重現固定的幀間隔。更重要的是,通過規定延時量,同時劃定了send buffer(發送端緩衝區)與receive buffer(接收端緩衝區),來自接收端的反饋信號(可以理解爲後向糾錯)通過一系列的設置、糾錯、流量控制,使編碼後的視音頻碼流擁有與原碼流幾乎一樣的碼率特性。

Encoder編碼器處理完成的數據會被輸入send buffer,send buffer會對數據進行時間校驗,也就是按照一定的時間順序編碼並通過internet發送至receivebuffer,receive buffer按照報文上的時間戳一點點處理,確保生成的數據與源碼流基本一致。

整個SRT協議的思想基於編碼,具有抗丟包、抗擁塞、抗抖動等特性。

2.2 SRT報文基礎

交互過程

SRT的報文基礎也就是其交互過程依次爲以上五個步驟:握手(Handshake)、重要信息(Capability)、媒體(Media)、控制信息(Control)與關閉(Shutdown)。與RTMP的九次握手不同,SRT的建連過程僅需兩個RTT。也就是Handshake Request與Capability Announce。Caller與Listener之間的進行的Handshake Request是一個簡化版的握手,用以提高效率;握手之後Caller與Listener間進行重要信息的交換,整個SRT的第一項關鍵步驟就是Caller與Listener在這裏交換了延時量與緩衝區的大小;隨後Caller與Listener之間開始媒體數據的傳輸,同時也傳輸了爲恢復幀間隔而封裝的精準時間戳;SRT的第二項關鍵步驟是Listener向Caller同步控制信息,用以對抗公網中的抖動、丟包等一系列突發狀況;最後,待至媒體數據傳輸完畢之後關閉傳輸。

數據報文

SRT的報文格式較爲簡單,分爲數據報文與控制報文。上圖展示了數據報文的數據結構,觀察結構我們可以發現上方兩層爲UDP部分,而在這之下是UDT部分。如果初始化爲0,則認爲其是數據報文。FF表示報文的序列, 0b10是分片的第一個報文,0b00是分片的中間報文,0b01是分片的最後一個報文,0b11表示單個報文並沒有分片。KK表示是否加密,R表示是否屬於重傳報文,Timestamp表示時間戳,Destination Socket ID是SRT自定義的一個socket id。由該數據結構我們可以看出:SRT的數據報文擁有精準的32位時間戳,package sequence number絕對夠用,且結構非常簡單。

下圖展示的則是控制報文的數據結構,右側表格展示了控制報文的常規類型,其中值得重點關注的有ACK、NACK、ACKACK等。

控制報文

2.3 SRT丟包重傳

2.3.1 Send/Receive Buffer

SRT在接收和發送端都有receive buffer與send buffer,send Buffer嚴格按照時間戳間隔來發送,定時器默認10毫秒。

2.3.2 ACK

丟包重傳最常見的便是ACK機制。以上圖爲例,假設發送端緩衝區發送五個數據包:1、2、3、4、5給接收端緩衝區,接收端緩衝區成功接收到這些數據包之後會向發送端緩衝區發送ACK——肯定應答已表示數據包被成功接收,發送端接收到ACK——肯定應答之後回收空間,刪除1、2、3、4、5這五個數據包並準備發送數據包6。

send buffer完全按照時間戳間隔處理數據,在確定的間隔(與ACKs,ACKACKs 和 Round Trip Time相關),接收方發送ACK給發送方,使得發送方把收到ack的packet從sender buffer中移除,其在buffer中的空間點將被回收。接收端的receivebuffer中存在Latency Window也就是延遲窗口,其作用爲按照時間戳一點點上送數據。並嚴格按照時間戳檢測,檢測週期默認爲10毫秒。

2.3.3 ACK/ACKACK/RTT

接收端在收到數據包後會向發送端反饋表示成功接收的ACK,例如上圖左側,接收端在收到第十一個數據包後向發送端反饋ACK(11),而發送端在收到來自接收端的ACK(11)之後會向對端再發送一個ACKACK用以表示收到ACK(11)。這一過程最大的意義在於可讓接收端計算出RTT,ACK發送的時間與對應ACKACK收到的時間之差就是RTT——Round Trip Time(RTT)是時間的度量,表示報文一個來回的耗時。SRT不能測量單方向的耗時,所以只能用RTT/2來表示單方向耗時。一個ACK(從接收方)會觸發ACKACK(從發送方)的發送,幾乎不帶其他延時。RTT可評估當前網絡質量,RTT高表示整個網絡的延遲很大,RTT低則說明網絡延遲較低。RTT由接收端計算而出,計算得出的RTT會通過ACK發送至發送端,發送端就可獲知當前網絡的質量如何。帶寬情況是不斷變化的,因此RTT也是一個隨網絡環境不斷變化的實時動態值。

2.3.4 ACK信息

ACK報文包含了豐富的關鍵信息。其中Last Acknowledge Packet Sequence Number表示當前收到第幾個包,RTT信息便於發送端評估網絡的質量,RTT的變化表示網絡變化情況。Available Buffer Size表示接收端緩存可用率,SRT是可以用作文件傳輸的,Available Buffer Size對文件傳輸的擁塞控制非常有用。當文件傳輸過快時接收端的內存緩存無法成功接收,此時發送端除了考慮網絡還需要考慮接收端的性能與緩存是否有足夠的空間與能力在短時間內接收龐大的文件。Packets Receiving Rate表示每秒鐘的收包率,這裏統計的是包的個數;而ReceivingRate表示接收包的比特率。

總而言之,接收端以10毫秒爲週期向發送端發送ACK,其中包括網絡RTT信息、接收端緩存信息、接收端比特率等關鍵數據,其中以上三個數據至關重要,直接反映出發送端到接收端之間的網絡環境狀態。

2.3.5 NACK

常規情況下QUIC或TCP僅提供ACK方式,也就是接收端向發送端反饋哪些包成功接收;而WebRTC的RTP或RTCP常用選擇NACK,也就是接收端向發送端反饋哪些包沒有成功接收。NACK回傳的是接收端沒收到的數據包的列表。

SRT同時支持ACK與NACK,這樣設定的原因在我看來是帶寬搶佔的強勢。例如,接收端向發送端發送ACK表示該數據包已經成功接收,不排除該ACK報文本身丟失,導致發送端以爲數據報文丟失而要超時重發,實際接收端對該數據包已經成功接收了。

還有一種情況是:NACK的週期性發送可能會造成發送端多發報文,例如發送端成功發送5號與6號數據包,卻一直未收到來自接收端的ACK消息,當達到重發的時間時發送端再次發送5號與6號數據包,在此之後發送端收到了來自接收端的NACK消息,表示接收端未成功接收5號數據包與6號數據包;於是發送端第三次發送5號數據包與6號數據包。一個週期下來,發送端發了兩次數據包。從協議原理角度分析,我們發現 SRT在丟包過程中對帶寬的消耗比QUIC與其他協議要高。 一旦出現丟包,SRT的重傳要多於其他協議,SRT以此來搶佔帶寬從而達到音視頻的同步效果。

2.4 SRT基於時間發送

按時間發送是一個標準的音視頻傳輸特性。我們知道編碼器發送是以編碼器的速度向外發送數據,但有時編碼器會太樂觀,完全按照編碼輸出向外發送會導致輸出超過預期過高的比特率。在這種情況下SRT Packet就不會足夠快地輸出,因爲SRT會最終被過低的錯誤配置影響到。

2.5 可配置比特率

SRT中包含三個配置選項:INPUTBW表示編碼器輸入帶寬,MAXBW表示最大帶寬,以及OVERHEAD(%)表示過載率,配置原則如上圖所示:

如果不配置INPUTBW與OVERHEAD(%)而僅配置MAXBW,則當前編碼器輸出的比特率是也就是MAXBW;

如果不配置MAXBW與INPUTBW而僅配置OVERHEAD(%),則當前編碼器輸出的比特率是(1080+)/100,默認爲25%;

第三種情況是不配置MAXBW而配置OVERHEAD(%)與INPUTBW,最大輸出比特率便爲(100+)/100。

SRT最大的特點便是可配置。在有配置的情況下按照配置來做,在無配置的情況下按實際測量的比特率來做。常規情況下我們不選擇進行配置,尤其是針對互聯網而言,因爲單一配置無法保證能夠在不同時段應對不同境況的網絡。通常我們選擇使用實際測量出的編碼比特率計算:*(1080+)/100。

2.6 SRT簡單擁塞控制——簡單,太簡單

接下來我們討論一下SRT的流控。我們知道在丟包重傳機制下,如果報文在網絡傳輸中丟失,則發送端會重新發送。例如在某網絡環境下發送端與接收端之間的帶寬僅有1M,現在由於背景流量與噪聲等影響,原來1M的帶寬減少100k變成了900k,此時就會出現10%的丟包;發送端未收到來自接收端的ACK或者收到NACK認爲出現丟包,於是嘗試重傳這10%的數據;但實際上發送端與接收端之間的帶寬就剩下900k了,而加上丟包重傳的發送量是1.1M,帶寬變窄發送的流量不降反增,就會導致網絡情況越來越糟糕,最後造成網絡擁塞卡頓頻繁,最後網絡崩潰。SRT單純地丟包重傳不能解決網絡擁塞的問題,出現網絡擁塞的最好解決方案是限流,降低帶寬流量壓力。

SRT的擁塞控制過於簡單,僅在congctrl.cpp中實現。其包括以下幾個變量:

M_iFlowWindowSize表示接收方的緩存大小,m_dCWndSize等於1秒內發送的bytes數據 / (RTT + 10),sendbufer表示發送方未發送buffer大小。其中這裏的1秒內發送的bytes數據,具體是指一個RTT內發送的數據。總結算法如下:m_iFlowWindowSize用以衡量接收方緩存是否耗盡,同時監測發送方每RTT發送數據size是否大於發送buffer大小。接收方緩存一般在傳輸文件時起作用。

在我看來,SRT在擁塞控制方面做得還遠遠不夠。

2.7 SRT協議總結

SRT在快速連接方面有明顯優勢,兩次握手成功即可建連;SRT的丟包重傳策略出色,ACK、ACKACK、NACK等提供了豐富的控制消息,還有RTT、Receive比特率等。但是同時我們經過測試也發現SRT在丟包時,發送數據的帶寬佔用率還是有些大,丟包率越高發送帶寬佔用越大。

SRT按照時間發送音視頻數據,根據實際的編碼比特率來發送音視頻數據;但SRT的擁塞控制過於簡單,只針對接收方緩存是否有能力接收與編碼比特率是否發送過快。

3.1 SRT在SRS4.0中的方案應用
3.1.1 最後一公里——SRT推流

我們推薦從編碼器到推流至邊緣節點的部分使用SRT。其目的主要有兩個:提高源流質量與基於SRT自適應比特率編碼,發送端和接收端配合從而解決最後一公里的推流問題。是自己對srt的理解。SRS支持 SRT的接收端推流,邊緣SRS在接收到來自推流端的SRT推流之後會將其轉爲RTMP並分發給中央節點,而後所有的邊緣節點都可以進行RTMP拉流。

3.1.2 SRT地址格式

作爲一個傳輸協議,SRT的一個弊端在於給出一個未定義的地址,我們不清楚這究竟是推流地址還是拉流地址,那麼如何進行匹配?

爲方便SRT編碼器推流,SRS4.0支持編碼器的簡單配置。如服務器IP、服務器Port以及streamid。根據SRT的官方文檔,SRT通過StreamID進行標識,簡配地址格式如上圖所示,帶有vhost虛擬主機配置的地址格式如下圖所示,其中m=publish/request表示推/拉流地址。顯而易見的是,對比RTMP,SRT地址的可讀性並不好,地址長而冗雜。

3.1.3 SRT各種網絡情況下的測試

測試各種網絡情況下的SRT我們不難發現,丟包率增加導致帶寬消耗增加,網絡狀況不良或發生擁塞時,發送端會發送更多的數據,這便會導致網絡狀況愈發惡化,丟包率變得更高,並以此惡性循環;除此之外,RTT增加也會導致延時增加,一樣會導致丟包率增加,帶寬消耗更大。

這裏我們提出的解決方案是預測網絡帶寬——通過當前的send bitrate、RTT、inflight等數據預測網絡帶寬;同時動態調整編碼比特率,根據預測的帶寬動態調整編碼比特率1來適應實時的帶寬,避免發生擁塞並提高視頻流暢度。

3.1.4 GCC算法自適應編碼架構

上圖展示的就是谷歌擁塞控制算法GCC的架構圖。如圖所示:發送端將報文發給接收端,接收端由幾個部分組成,其中計算接收報文Delay,也就是計算基於D(i,j) = (Rj-Sj) - (Ri-Si) 的變化的導數,得到m(ti)。除此之外,接收端設置的卡曼濾波算法會計算出一個門限值,通過該卡曼濾波的計算與比對,決定是增加碼率還是降低碼率,最終得出下一次網絡帶寬的預估值(Ar),並將數據返回給發送方。

3.2 自適應碼率的SRT推流

3.2.1基於SRT自適應碼率編碼
基於SRT自適應碼率編碼的關鍵參數如上圖左側所示:rtt_min表示1s內的RTT最小值,send_bitrate_max表示1s內最大的發送bitrate,常規情況我們大概200~300毫秒統計一次;inflight表示已經發送出去但還未接收到ACK的報文的個數,這種情況可能意味着報文還在傳輸鏈路的途中;BDP(bandwidth-delay product) BDP = send_bitrate_max*rtt_min表示一個RTT內發送的最大字節數。如果BDP大於(1.2 x inflight)表示網絡狀況良好,可以增加編碼碼率;如果BDP小於(0.8 x inflight)則意味着網絡狀況不佳需要減少編碼碼率,其他情況則維持現有編碼碼率不變。這樣便能較爲有效地避免網絡擁塞的情況發生。

3.2.2 基於SRT自適應碼率編碼——實例

我們以測試實例來驗證效果:通過Internet推流,來自於美國的SRT編碼器的數據推至杭州的節點,建立SRS4.0。該測試開源地址如圖中所示,使用FFmpeg配置編碼碼率爲1000kbps,傳輸過程中根據實際出口帶寬動態調整編碼碼率。由上圖右側圖線1我們可以看到自適應碼率最高可達到1400kbps,有良好的自適應效果;實際測試感受來看,視頻播放平滑無明顯卡頓,即便偶爾出現帶寬抖動也能夠迅速恢復。

  1. SRT與QUIC

接下來我們對比SRT與QUIC,總結二者特點。

4.1 SRT1.4的優缺點
SRT1.4的優缺點可以簡單概括爲以下內容:SRT的優點在於基於音視頻按照時間戳進行收發,可有效保證音視頻,同時ACK/ACKACK/NACK多種丟包糾正機制可有效降低延時與丟包率。SRT對上層提供豐富的傳輸層數據信息如RTT、lost packet rate、receive rate等。當然,SRT的缺點也不容忽視,如SRT的擁塞控制過於簡單,需要在傳輸層合入BBR算法,原生SRT不支持連接遷移等。
基於以上特點,我認爲SRT更加適合編碼器到最近節點的傳輸,也就是通過SRT探測出的RTT等相關信息實現自適應碼率編碼;除此之外,SRT也適合網絡節點固定、網絡情況固定的環境,合理配置lantency、send/recv buffer、ohead rate等SRT參數可達到事半功倍的效果。

4.2 QUIC的優缺點

QUIC的優點是連接快,同時具有可插拔的擁塞控制,包括CUBIC、BBR;另外在丟包重傳方面,QUIC擁有更多的ACK block,最大可達256個,並且對於RTT的計算更加準確(QUIC中存在獨立的Packet number,包括重傳包在內的Packet number也都不相同,非常有利於RTT的精確計算);最後還有QUIC支持連接遷移。

當然,QUIC同樣存在缺點:第一,報文頭大在發送報文中所佔比例較高。第二,丟包重傳只有ACK原生;第三,QUIC不支持丟包,一旦出現丟包,若沒有在timeout前恢復就會斷開連接。

基於以上優缺點,我認爲QUIC更適合運用在網絡丟包率較高的環境,因爲QUIC具有0RTT快速連接能力、丟包重傳中ACK回覆的block較大並且在擁塞控制方面表現非常優秀。除此之外QUIC也適合用於長距離傳輸當中,因爲網絡傳輸RTT較高,QUIC在連接斷開後重連是0RTT,傳輸數據更加高效。

4.3mediago服務:rtmp over quic

Mediago具有支持QUIC協議來傳輸RTMP直播流的特性,如RTMP over TCP推拉流、RTMP over QUIC推拉流以及對FLV的支持。服務器之間則支持基於TCP服務器間RTMP回源與基於QUIC服務器間RTMP回源,上圖中有測試鏈接,感興趣的朋友可以自己嘗試一下。

轉載至:https://segmentfault.com/a/1190000022071085

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