天天看點

SRT協定翻譯SRT協定

SRT協定

srt是基于UDT傳輸協定,是使用者級别的協定,其保留UDT的核心思想和機制,但是做了多項改進,包括控制封包的修改,針對直播流改進了流控,改進了擁塞算法,封包加密算法。本文介紹srt協定本身。更多的相關實作在:https://github.com/Haivision/srt

簡介

srt傳輸協定為不可靠網絡提供安全,可靠的資料傳輸,如網際網路。任何資料都可以在srt協定上傳輸,特别是對音視訊流資料優化最為明顯。

在任何時候,srt都能用于視訊流的彙聚/分發節點,提供幾乎最好的品質和最低延時的視訊。

當封包作為流在源與目的之間傳輸,srt對網絡進行檢測和适應。srt幫助補償jitter和帶寬抖動,針對噪聲網絡中的擁塞。其錯誤恢複機制對網際網路的丢包影響最小化。srt也支援aes加密來保證端到端的安全。

SRT是基于UDT協定的(UDP-based data transfer)。雖然UDT是設計用來在公網中高吞吐的封包傳輸,UDT對視訊直播并沒有優勢。SRT是一個大的改進UDT版本,其對視訊直播有大的提升。

SRT在IP網絡中的低延時視訊傳輸,是以mpeg-ts格式作為UDP的單點傳播/多點傳播。其方案對網絡提供可靠性,通過使能FEC來減輕任何丢包。在城市間,國家間設定跨洋間的低延時通信都帶有更多的挑戰。雖然用衛星通信,或MPLS專網來實作,但是價格太貴。公用網際網路的連接配接,雖然便宜很多,但是需要大量的帶寬來實作丢包恢複。

即使UDT并不是為直播流而設計,但是其丢包恢複機制能提供基本的丢包恢複功能。SRT的最早版本包括新封包的重傳功能,能對直播流的丢包做快速響應。

為了達到低延時,SRT不得不引入分時機制。一個流在網際網路中傳輸,很多特效會被完全影響,包括延時/jitter/丢包。進而導緻解碼問題,音視訊解碼器不能解碼對應時間戳上的未收到的封包。如果應用buffer緩存來避免,但是卻會帶來延時。

SRT協定翻譯SRT協定

SRT的機制在接收方新建立了重要的特性,極大的降低buffer的需要。這些機制是SRT協定自身的一部分,是以一旦封包從SRT的一端發到接收端,流自身狀态已經被恢複成流本身的狀态。

SRT協定翻譯SRT協定

最初SRT協定又Haivision Systems公司開發,在2017年4月Wowza Media Systems将其開源。開源的SRT遵守MPL-2.0開源協定。選用MPL-2.0協定,因為想在對開源SRT的相容性,和估計開源社群去改進SRT協定之間做好平衡。任何第三方開發者都能自由的使用SRT開源代碼。但是如果他們修改和優化代碼,就必須把這些優化代碼送出到開源社群。

在2017年4月,Haivision和Wowza公司成立了SRT聯盟www.srtalliance.org,緻力于持續發展該協定。

SRT的UDT4适配

UDT是一種ARQ(自動重傳請求)協定。其應用的是ARQ的第三種演進方案(選擇性重傳)。 UDT4的應用在ietf中提出,在draft-gg-udt-03中。

UDT緻力于容量的最大使用,也就是當發送資料的時候,應用必須保證輸入buffer是足夠的。當以确定的比特率發送實時視訊,包的發送速度對比讀取檔案的速度是非常慢的。buffer耗盡會導緻一些UDT算法的複位。也就是說,當擁塞發生,發送方的算法會挂住UDP API,也會把封包放入丢棄隊列,這樣新的封包就不能被處理。實時的視訊不能被挂住的,是以封包可能被應用丢棄(因為發送API會被block住)。不像UDT,SRT對實時封包,重傳封包,丢失或要丢棄的舊豹紋都共享目前的帶寬。

SRT的早期開發就引入了大量針對UDT version4的改進:

  • 基于位元組統計
  • 基于毫秒機關來做延時控制(測量buffer的時間機關,更好的适配延時,使其不受流比特率的影響)
  • ACK消息的統計資訊(接受速率和估計連接配接容量)
  • 控制封包時間戳(這個在UDT的draft中有,但是不在UDT4的應用中)
  • 時間戳漂移更正算法
  • 周期的NAK報告(UDT4去使能這個特性,用于unACKed封包的逾時重傳,其對實時流應用會消耗過多的帶寬)
  • 基于時間戳的封包發送(可配置的延時)
  • SRT的握手是基于UDT自定義的控制封包,用于交換點到點間的配置和應用資訊,以確定無縫更新,當更新協定和保證向後相容
  • 基于配置和輸入速率的最大輸出速率
  • 加密優化

    早期SRT的開發,是在内網用Haivison的Makito X系列的編解碼器,其能模拟包的丢棄。

    當中間封包的丢失,會導緻解碼器的接收buffer耗盡(沒有封包送去解碼)。丢失的封包不能及時的重傳。解決方法是更早的觸發未确認收到封包的重傳(ARQ的自動重傳)。然而,這會導緻帶寬使用的迸發。基于逾時重傳的發生是當封包沒有很快的得到ack确認。在UDT4中,重傳發生隻是當丢失表空的時候。

    重傳所有ack逾時的封包,能解決這樣的實驗場景,當無網絡擁塞,有随機丢包影響封包傳輸。在多次重傳後,所有的封包都應該能被發送,接收者的隊列不會被挂住。但這會消耗大量的帶寬,因為沒有加入速率控制。

包結構

SRT保有UDT的UDP封包結構,但是有很多改進。基于UDT IETF internet Draft(draft-gg-udt-03.txt)的細節。

資料和控制封包

每個承載SRT的UDP封包都帶有SRT頭(其緊跟在UDP頭後面)。在所有的協定版本中,SRT頭包含4個32bits字段:

  • PH_SEQNO
  • PH_MSGNO
  • PH_TIMESTAMP
  • PH_ID

    SRT有兩類封包,PH_SEQNO字段的第一個bit用來辨別封包類型,0是資料封包,1是控制封包。如下的例子中,就是資料封包的例子,其’packet type’ bit=0:

    注意:在SRT version 1.3中的封包結構變化。為了提高早期版本的适應能力,新舊封包格式都在下面列出(大位元組序)。

    SRT協定翻譯SRT協定
  • FF=(2bits) 如封包中的位置
    1. 10b = 1st
    2. 00b = middle
    3. 01b = last
    4. 11b = single
  • O = (1bit) 表示消息是否按序發送,按序1,不按序0。在檔案/消息模式下(傳統的UDT),當該bit為0,那麼後面的消息是可以立刻發送而不用等待前面消息的發送完成。但是這在直播業務中是沒有用的,因為當TSBPD模式開啟時,為資料抽取而伺服器的功能完全不同。
  • KK=(2bits)表示是否資料已經被加密:
    1. 00b: 不加密
    2. 01b: 加密,偶數key
    3. 10b: 加密,奇數key
  • R=(1bit)重傳封包。如果是0,表示該封包是第一次發送;如果是1,就是重傳封包。

    在資料封包中,第3,4字段如下的定義:

  • Timestamp: 封包時間戳
  • ID: 封包分發的目的socket id,如果是connect的發起封包,該字段就是0

更多資料封包的細節在本文後面介紹。

SRT協定控制封包頭(“packet type” bit=1),其結構如下(未包含udp頭):

對于控制封包,頭兩個字段分别解釋如下:

  • 頭32bit:
    1. bit0: 類型,1就是控制封包
    2. bits1-15: 消息類型
    3. bits16-31: 消息擴充類型
-----------------------------------------------------------------------
  | type | Extended Type | description                                  |
  -----------------------------------------------------------------------
  |  0   |        0      | handshake                                    |
  -----------------------------------------------------------------------
  |  1   |        0      | keepalive                                    |
  -----------------------------------------------------------------------
  |  2   |        0      | ack                                          |
  -----------------------------------------------------------------------
  |  3   |        0      | nak(loss report)                             |
  -----------------------------------------------------------------------
  |  4   |        0      | congestion warning                           |
  -----------------------------------------------------------------------
  |  5   |        0      | shutdown                                     |
  -----------------------------------------------------------------------
  |  6   |        0      | ackack                                       |
  -----------------------------------------------------------------------
  |  7   |        0      | drop request                                 | 
  -----------------------------------------------------------------------
  |  8   |        0      | Peer Error                                   |
  -----------------------------------------------------------------------
  |0x7fff|        -      | Message Extension                            |
  -----------------------------------------------------------------------
  |0x7fff|        1      | SRT_HSREQ:SRT handleshake request            |
  -----------------------------------------------------------------------
  |0x7fff|        2      | SRT_HSRSP:SRT handleshake response           |
  -----------------------------------------------------------------------
  |0x7fff|        3      | SRT_KMREQ:Encryption Keying Material Request |
  -----------------------------------------------------------------------
  |0x7fff|        4      | SRT_KMRSP:Encryption Keying Material response|
  -----------------------------------------------------------------------

           

擴充消息機制是為未來的擴充,SRT可能因為某些原因今後會用到。後面的SRT擴充握手中會提及。

  • 第二個32bits:
    1. Additional info – 其在控制消息中被用作擴充空間字段。它的解析依賴于特殊消息類型,握手消息不使用它。

Handshake封包

Handshake控制封包(‘packet type’ bit=1) 是用來在兩點之間建立連接配接的。早期的SRT用handshake來交換參數,在連接配接建立之後,但是1.3版本吧交換參數作為handshake的自身的一部分。後面的Handshake一節專門用來解釋。

SRT協定翻譯SRT協定

KM 錯誤回報封包

Key Messge Error Response控制封包(‘packet type’ bit=1)是用來交換錯誤狀态消息。在加密一節中詳細介紹。

SRT協定翻譯SRT協定

ACK封包

ACK控制封包(‘packet type’ bit=1) 是用來提供封包發送狀态和RTT資訊的。在SRT資料傳輸和控制一節中詳細介紹。

SRT協定翻譯SRT協定

Keep-alive封包

Keep-alive封包(‘packet type’ bit=1) 是用來每10ms交換資訊,來保證SRT流在連接配接斷開後字段重連的。

SRT協定翻譯SRT協定

NAK控制封包

NAK控制封包(‘packet type’ bit=1) 是用來報告失敗的封包傳輸。在SRT資料傳輸和控制一節中詳細介紹。

SRT協定翻譯SRT協定

SHUTDOWN控制封包

shutdown控制封包(‘packet type’ bit=1) 用來發器關閉SRT連接配接。

SRT協定翻譯SRT協定

ACKACK控制封包

ACKACK控制封包(‘packet type’ bit=1) 用來回複收到ACK封包,并且可以用來計算RTT。在SRT資料傳輸和控制一節中介紹。

SRT協定翻譯SRT協定

擴充控制封包

擴充控制封包(‘packet type’ bit=1) 用來為原始UDT使用者控制消息。它們被用在SRT擴充握手封包中,可以通過獨立的消息,或内嵌在HANDSHAKE中。

SRT協定翻譯SRT協定

SRT資料互動

下表描述資料互動(包括控制資料)。注意,兩點間角色的變換。舉例,在會話過程中節點可以作為發起者,和監聽者,然後也能成為發送和接受者在資料傳輸過程中。

SRT協定翻譯SRT協定

SRT資料傳輸和控制

本節介紹直播的音視訊中,如何處理控制/資料封包的關鍵思想。

Buffers

當應用(編碼器)提供資料給srt來發送,它們被放入一個環狀的發送buffer中。它們用seqid來編号。封包放在buffer中,直到收到對端的ack,萬一它們會需要被重傳。每個封包都有一個時間戳,其基于連接配接時間(其在handshake中定義,在第一個封包發送之前)。

StartTime是應用建立SRT socket的時刻。封包時間戳是介于StartTime和封包被加到send buffer之間。

SRT協定翻譯SRT協定

注意:這裡的時間是從左到右的,最新的封包在右邊。

接收者也有個一樣的buffer。封包都放在buffer的隊列中,直到舊的封包被上層應用擷取。當配置的延時剛好到packet 2,那麼packet 1就應該送個上次應用而出隊了。

SRT協定翻譯SRT協定

時間戳是和連接配接關聯的。傳輸并不是基于絕對時間。排程執行時間應該是基于實際時鐘時間。時間的基準應該轉換每個封包的時間戳到本地時鐘時間。封包都是從發生方StartTime的便宜。任何時間相關參數都是基于本地StartTime來維護的,用來計算RTT,時間區和偏移,通過nanoseconds和其他。

Send Buffer Management

發送隊列(SndQ)是動态長度大小的,其包含了發送者buffer的内容相關多個引用。當發送隊列有内容發送,相關引用資訊就被加入到SndQ中。SndQ有多個buffers使用一個相同的channel(UDP socket)。

下表顯示出send buffer與SRT socket(CUDT)相關。SndQ包含socket引用,時間戳引用,本地索引資訊(其是在SndQ中位置)。相關引用對象也是SndQ的對象的一部分。

SRT協定翻譯SRT協定

SndQ是雙向連結清單,其有send buffer的CSnode的入口點。CSnode是SndQ類的一個對象(SndQ是哥隊列,但是也有其他的類成員)。CSnode并不與buffer内容相關。它有指針指向它的socket,timestamp 和buffer中的位置(其被插入到SndQ的位置)。

SndQ有個發送線程,其用來檢查是否有封包要發送。基于在入口中包含的資料,它什麼socket有封包ready可以被發送了。它檢查時間戳引用,判斷是否packet真的需要發送。如果沒有,還把它放入list中。如果ready,線程就把他從list中移除掉。

每次發送線程發送封包,發送線程會把封包重新插入list。它然後去檢視send buffer中的下一個packet。packet的時間戳決定SndQ中插入的位置,其是按照timestamps排序的。

控制封包是直接發送的。它們病不通過SndQ或發送隊列。這個SndQ更新變量,為了追蹤packet插入的位置,和那個packet是最後被對端ack的。

SRT Buffer延時

發生者和接受者有大量的buffer,其在SRT程式代碼中定義。在發送方,延時是時間,其是根據發送速率,SRT儲存封包,直到給他時機發送,延時的影響對發送方比較小,如果ack晚到或沒到,發送方隻是按照上下文規定來丢棄。但是接收方的延時影響就明顯很多。

延時是用毫秒來定義的值,其可以用來計算成百上千的高速率。延時能被認為是一個視窗,視窗滑移是基于時間,基于一個時間來進行視窗的滑移。

舉例,在下表中,packet #2是最舊的封包,也是接受者隊列的對頭(packet #1已經被上層應用取走)。

延時視窗在隊列中從左向右滑動。當packet #2移除視窗外,它就需要被上次應用取走(如去用作解碼)。

考慮到接收buffer存儲一系列的packets。我們也就說我們定義延時,其是一個有6個封包長度的周期。延時能被認為是6個封包視窗長度。

在延時視窗中恢複封包的能力,依賴與傳輸的時間。延時視窗高效通過RTT決定什麼封包能恢複,多少次被恢複。

SRT協定翻譯SRT協定

在準确的時刻,接受者buffer釋放第一個封包給上層應用。當延時視窗滑向下一個封包間隔,接受者釋放第二個封包給上層應用,以此類推。

現在我們看一下如果packet沒有收到(packet#4)會發生什麼。當延時視窗滑動,packet就應該可以上送給上層應用,但是該packet不存在。這就會導緻跳到下個packet。其不會被恢複,那麼它也将被移出丢棄list,并且永不會在要求重傳。

SRT協定翻譯SRT協定

滑移延時視窗可以被認為是一個區間,SRT能在區間内恢複大部分的packet。

另外一方面,發送者的buffer也有一個延時視窗。當時間流逝,最舊的封包就會移出延時視窗,永不會被恢複。因為即使它們再次被發送,它們将到達接收方太晚,而不能成功被接受者處理。

如果延時滑動視窗移除過期封包,其還沒有被成功發送的(接收方沒有ack成功),太晚而不用再去發送它們了。因為它們會在接受者的發送視窗之外–即使它們後面到達,它們也會被丢棄。是以這些封包應該被移除到發送buffer外。

接收方和發送方應該有相同的延時值是非常重要的,以便協調packet的及時到達和丢棄。在早期SRT版本中,發送方把延時參數放在發送給接受者的handshake中。如果接受者上配置的延時參數較大,它會把這個延時參數放在packet中,發送response給發送方。在SRT 1.3版本後,雙方都能在handshake的中立刻配置(不需要進一步的resoponse)。

當一個packet已經發送但是沒有收到ack并且逾時,這個packet就被移出發生方的延時視窗。它曾是發送者buffer的延時視窗,但是ackpos不會前移(在最後一個packet被ack确認其被收到,ACKPOS節點會指向下個packet)。當延時視窗前移并最舊的packet移出視窗,這個packet就可以被移除。SndQ的清理是手動的移動ACKPOS到延時視窗的下個packet。

所有再發送buffer的packets有保留的位置,其帶有配置的長度(7個188位元組,也就是1316,在加上udt頭)。有很多發送buffer,每個都包含連續按順序排列的packet。一個發送buffer是一個環形隊列,開始和結束節點可以在任何節點,但是不會重合。協定保留sequence資訊(基于ACK)。在傳送過程中,所有packet的seq number能達到更高的數字,實際buffer位置不能達到的。發送者的buffer使用位置來計算。一個在buffer中的item都有一個開始節點start position(STARTPOS)。發送buffer中的positon和packet中的sequence是可以互相轉化的,因為兩者都是同時增長。

SRT Sockets, Send List & Channel

考慮到socket 1 和 2, 每個都有自己的發送buffer。SndQ包含一個packets的清單來發送。有一個線程來持續檢查這個發送buffer。當一個封包可以被發送,一個CSnode被建立,其确認一個封包的socket,和在SndQ中一個相關的對象,SndQ講指向發送隊列尾部。

SRT協定翻譯SRT協定

每個packet都有timestamp,依賴timestamp來确定何時發送。SndQ清單是用timestamp來排列的。如果發送線程決定socket 1發送bufer有封包ready,它就把packet放入SndQ的隊列中。如果SndQ隊列是空,packet就被放在隊列頭,并帶上自己的時間戳,其決定封包什麼時候該被處理。

socket 2的發送buffer也能被加到SndQ中。發送線程将向buffer中要packet發送,線程會根據速率來計算packet的發送間隔。

SRT協定翻譯SRT協定

帶有包廂隔的時間戳決定packet重新插入SndQ的位置(在從socket1 buffer的packet之前,或之後)。

SndQ決定從哪個SRT socket去取下一個packet來發送。send buffer和socket綁定,而SndQ卻是跟channle更加相關。幾個socket都發送到同一目的地,是以它們是多路複用的。

當packet被加到socket,SndQ也會被更新。當一個packet已經可以被發送,其也被基于時間戳重新插入到SndQ中的正确位置。

這個處理過程在SndQ中發生。對每個packet封包,有一個線程去檢查是否該發送。如果沒有,就什麼也不錯。否則,線程要求SRT socket把這個packet發送到channel。在SndQ的條目有SRT socket的引用。

當一個packet被寫到send buffer,它也被加入到SndQ中,其也通過CSnode來確定其不會産生重複的條目項。SndQ重複的移除條目項,并同時插入新的packet到正确的位置上。

在不同SRT socket的packet的時間戳是本地的,其定義的時間是發送時對比目前時間。在packet加入到SndQ的時刻,他的時間戳對比目前的時間決定其在SndQ中的位置。

Send buffer的操作和SndQ的操作是分離的。packet被加入到buffer,且然後SndQ被通知有packet需要發送。它們各自有自己的行為。

send buffer的内容會被加入到應用線程中(sender線程)。然後有另外一個線程和SndQ互動,其通過輸入buffer的速率負責控制packet間隔。輸出是通過buffer中的packet間隔來調整控制。

Packet Acknowledgement(ACKs)

在确定的間隔(與ACKs, ACKACKs 和 Round Trip Time相關),接收方發送ACK給發送方,使得發送方把收到ack的packet從sender buffer中移除,其在buffer中的空間點将被回收。ACK包含了packet的sequence number,其是剛最新收到封包的seq+1。當沒有封包丢失的情況下,ack傳回的seq應該是n+1(n是接收到的packet的seq number)。

舉例,如果接受者發送packet 6的ACK(如下),意味着比這個sequence數小的封包都收到了,能從發送者的buffer中移除。

SRT協定翻譯SRT協定

在丢失的案例中,ACK(seq)就是丢失清單中的第一個封包,其就是最新收到封包的seq+1。

Packet Retransmission (NAKs)

如果packet 4到達了接受者的buffer,但是packet 3并沒有到達,NAK封包就需要發送給發送着。NAK被加到一個清單(周期的NAK報告),其周期的發送給發送方,以此避免NAK封包本身傳輸中丢失或延遲到達。

SRT協定翻譯SRT協定

如果packet 2到達,但是packet 3沒有,那麼當packet 4到達後,NAK就應該按照規則發送來發起要求重傳。

SRT協定翻譯SRT協定

Packet Acknowledgment in SRT

UDT草案定義周期發送的NAK控制封包,其包含一個丢失封包的清單。UDT4應用去使能這個特性,而用定時重傳的方法來代替。NAK的發送僅僅發生在一個丢失封包被檢測到(也就是下一個封包都收到了,但是上一個封包未能收到)。如果NAK本身丢失,ACK會阻塞在這個packet,同時阻止發送更多的封包給接收端直到丢棄list為空。在發送方,因為如果沒收到NAK封包,丢失的封包也不會被加入到丢失list中去,并會影響到沒有收到ACK封包的重傳。

UDT處理擁塞的方法是通過阻止重傳直到丢失清單為空,這個做法基本上是錯的。因為重傳丢失清單封包優先會很大可能阻塞住接收方。

在SRT接下來的修改中(舉例NAK周期發送,基于時間戳的發送,太晚封包丢棄等等),會降低ACK-timeout重傳的發生。

Timestamp-based Packet Delivery(TsbPD)

這個特性是使用UDT packet頭中的timestamp。早期的SRT TsbPD設計是想複制編碼器的輸出,來作為解碼器的輸入。這個設計沒有考慮到傳輸的瓶頸,封包傳輸越快,丢失的封包重傳也就越快,避免了低延時。但是SRT協定是基于網絡帶寬受限的情況下開發的,能占有網絡沒有任何限制。

另外一個問題是原始SRT TsbPd的設計是基于CPU限制的。ts packet的時間戳是基于系統能産生和辨別packet的時間戳。如果接收者沒有同樣的CPU容量,也就不能複制發送者的模式。

SRT的目前版本,TsbPD允許接受者以相同的速率發送packet封包給接收者,其速率是SRT發送者編碼器的發送速率。基本上,在接收者把收到的封包上送給應用前,發送者在封包中的時間戳會被調整成接收者的本地時間(補償時間偏移或不同的時間軸)。packet能被SRT基于配置的接收者延時來保有。更高的延時能容忍更大的封包丢失發生率,或更大的封包丢失突發率。接收到的封包在它們被play後再丢棄掉。

packet的timestamp(微秒)是關聯到SRT的連接配接建立時間。原始的UDT 編碼用packet 發送時間來作為packet的timestamp。對于TsbPD特性來說,是不正确的,因為如果一個新的時間(目前的發送時間)用來重傳封包,會導緻亂序,因為按時間把重傳封包插入到隊列中。封包應該基于sequence number來插入。

當一個packet在應用把packet封包放入SRT的原始時間(微秒)就是packet的timestamp。TsbPD特性用這個時間來作為packet第一次發送的timestamp,和接下來任何時間重傳封包的timestamp。時間戳和配置的延時控制控制恢複buffer和實時發送到對方的packet。

UDT協定本身并不使用packet timestamp,是以這個修改對UDT協定并不影響,也不會影響到目前已存在的擁塞控制方法。

Fast Retransmit:快速重傳

原始的UDT4未确認ack的封包重傳是基于逾時機制,這樣對于實時資料并不友好。隻要在loss list中還有封包,沒有收到ack的封包就不會被重傳。因為丢失封包的重傳是并發發生的,當重傳定時器到逾時時刻,會開始一波并發事件,其會影響到實時資料(擁塞視窗,發送者buffer慢,丢包等等)。

快速重傳在擁塞視窗滿之前,通過重傳沒有收到ACK的封包來解決這個問題。發送着把在合理時間内沒有收到ACK的封包都放入loss list中,合理的時間基于RTT和丢棄封包的timestamp。

快速重傳機制,減少了接收者buffer size,和延時。其也讓丢包數量變量變化更平滑,對比于擁塞視窗滿時的重傳。然而,這個特性也是對帶寬非常饑渴的。SRT發送者的這個特性是與SRT1.0接收者可以互通配合的。當有了周期的NAK報告後,這個特性就很少用了,或僅僅作為看門狗。

Periodic NAK Reports:周期發送NAK

SRT1.0在封包丢包率大于2%後是非常不高效的。很多封包重傳都不止一次,其實都沒有完全确認清楚該封包是否真的丢失。造成的情況是,帶寬的瓶頸和延時無法承受這樣丢包率造成的重傳。

Periodic NAK Reports在UDT4的源碼中被去使能了。這個特性在SRT1.1.0的接收者中被重新開啟,用來提高SRT适應高丢包環境,和所有的丢包環境。因為重傳帶寬的超出,這樣的應用會造成大概兩倍的丢包率。對于SRT配置參數的限制内,10%的抗丢包是可以達到的。

SRT的Periodic NAK Reports是基于RTT/2為周期,最小20ms(UDT設定是300ms)。一個NAK控制封包含有一個丢失封包的壓縮清單。是以,僅僅丢失的封包會被重傳。通過使用RTT/2作為NAK報告的周期,這會導緻丢失封包可能會被重傳一次以上,但是這樣會保持低延時在NAK封包丢失的情況下。

Too-Late-Packet-Drop: 封包太晚丢棄

這個特性在SRT1.0.5中開始有,允許發送端丢棄封包,如果其沒有機會及時發送。在SRT發送端,如果Too-Late-Packet-Drop使能,封包的時間戳比SRT最大延時的125%還要大,就會被認為太晚而不用在發送了,會被編碼器丢棄。IFrame尾部的封包就有可能被丢棄。

接收者(SRT>=1.1.0)可以不讓使能發送端的包丢棄,來防止發送端的産生bug。發送端(srt>-1.1.0)會保留封包至少1000ms,如果SRT的最大延時小于1000ms(對最大的RTT不夠的話)。

在接收端,大IFrame的尾部可能晚到,并且不會被SRT接收buffer緩沖到。接受buffer耗盡,如果有發現丢包發生,就沒有時間可以重傳。丢失的封包被接收者忽略。

Bidirectional Transmission Queues:雙向傳輸隊列

SRT也支援這樣的場景,接收者也有自己的發送隊列,發送着也有相應的接受隊列,支援雙向通信。

這是很有用的,能支援标準點到點的SRT會話,兩端都有發送/接受buffer。發送端的Tx buffer對應接收端的Rx buffer,而接收端的Tx buffer對應發送端的Rx buffer。和普通單方向的會話一樣,Tx/RX的延時互相比對。

在handshake封包中,發送端提供自己的Tx latency和假想對端的latency(接收端的Tx buffer值)。接收端也響應回複對應的參數。提議的latency值是在單個RTT周期内,雙方評估的結果(盡量選擇大一點的值)。

SRT協定翻譯SRT協定

ACKs, ACKACKs & Round Trip Time

Round Trip Time(RTT)是時間的度量,表示封包一個來回的耗時。SRT不能測量單方向的耗時,是以隻能用RTT/2來表示單方向耗時。一個ACK(從接收方)會觸發ACKACK(從發送方)的發送,幾乎不帶其他延時。ACK的發送時間與對應ACKACK收到時間的內插補點就是RTT。

SRT協定翻譯SRT協定

ACKACK告訴接收者停止發送對應便宜點的ACK,因為發送端已經知道接收端收到了。否則,ACK(帶有過時資訊)将被持續的周期發送。類似的,如果發送端沒有收到ACK,它自己也會周期發送沒有收到ACK的packet。

有兩種情況發送ACK。一個full ACK是基于10ms(ACK周期)發送。對于高bitrate的傳輸,一種"light ACK"就能被發送,期是多個packet的一個sequence。在10ms的間隔裡,經常有大量packet的發送和接收,以至于發送端ACK的偏移點不能夠快的移動。為了減輕這個問題,在收到64packets後(即使ACK發送周期還沒到),發送端發送一個light ACK。

SRT協定翻譯SRT協定

ACK動作像ping封包,而ACKACK像ping back回複,以此可以度量出RTT。每個ACK都有一個數值,而ACKACK也有相同的一個數值。接收方有一個ACK的清單去比對ACKACK。不像full ACK封包(包含目前的RTT和多個其他的控制資訊參數),light ACK包含sequence數值(如下表所示)。在接收端,所有控制消息被直接發送和處理,但是ACKACK的處理時間是微不足道的(因為它的處理時間被包括在RTT裡面)。

RTT是在接收端被計算出來的,并且發送下一個full ACK。注意,第一個ACK包含的RTT值預設是100ms,因為早期的計算可能不準确。

SRT協定翻譯SRT協定

發送端永遠都是通過接收端擷取到RTT。沒有一個方法來模拟ACK/ACKACK機制(舉例,不可能發送一個消息,這個消息不處理而立刻傳回)。

Dirft Management: 偏移管理

當發送方進入“連接配接”狀态,它就告訴上層應用有個socket interface接口已經ready可以發送了。在這個時間的,應用可以開始發送資料packet了。它以一定的輸入速率把packet加入到SRT發送方的buffer,通過這個buffer,packet以規定的時間發送到接收者。

同步的時間是需要來保證,接收者/發送者buffer的登記,需要考慮到時間軸和RTT。考慮到加/減RTT,和可能的不同步的系統時間,一個都能認同的時間基準,每分鐘約幾個微秒的偏移。這樣的偏移累積起來可能需要幾天才能讓發送/接收的buffer耗盡或溢出,進而嚴重影響視訊品質。SRT有時間管理機制來補償這個偏移量。

當packet收到後,SRT能得出packet timestamp和期望timestamp之間的內插補點。時間戳timestamp的計算是在接收方進行。RTT告訴接收方封包要消耗多少時間。SRT在發送者buffer的延時視窗的邊緣時間和接收者對應時間之間維護一個參數。這樣能允許基于本地時間實時的能排程事件。

接收者采樣時間偏移資料,和周期的計算packet timestamp糾正參數,兩者就能用來對每個收到的data packet來調整封包間隔。

當一個packet收到後,不能馬上上送上層應用。當時間推移,接收者就能算出丢失封包預計的時間,并且可以用這些資訊去用特殊封包來填補這些“丢包的空洞”。

接收者用本地時間去排程事件—舉例,去決定是否現在上送一個packet。每個packet裡的timestamp都與會話開始時候有個內插補點。當收到一個packet(packet内帶有發送方的timestamp),接收者就用本地時間與會話開始時間之間的內插補點,來重新計算packet的timestamp。start time就是會話開始時的本地時間。packet timestamp就等于目前時間減去start time(packet_timestamp=now-start_time),start time就是socket的建立時刻。

Loss List

發送方通過NAK報告來建立lost packe list。當排程到發送,先看lost list中是否有封包需要發送,有的話先發送lost list中的。否則,就發送SndQ list中的。注意,當packet發送後,仍舊在buffer中保留以免對方沒有收到。

收到NAK封包後,就把其中的封包放入lost list。當延時視窗前移,packet将被移出send queue,需要檢查一下是否丢棄或重傳的packet在lost list中,以此來決定是否把這些封包移出lost list,因為它們沒有必要再重傳。在send queue和lost list的操作是通過ACKPOS決定。

SRT協定翻譯SRT協定

當ACKPOS前移到一個點,所有比這個點舊的packet都可以被移出send queue。

SRT協定翻譯SRT協定

當接收者遇到遇到這種情況,下一個應該被play的packet沒有收到,它就應該跳過這個packet,并且發送一個fake ACK。對于發送端,fake ACK就是真的ACK,也就是說發送端就認為這個packet真的被成功接收了。這個方法有利于幫助發送者和接收者之間的同步。實際上packet的丢失對于發送端是不知道的。跳過這個封包在接收端的統計statistics中有記錄。

當發送端收到NAK packet。也有個packet的計數器。如果packet沒有對應的ACK,它就在lost list中保留,有可能被多次發送。在lost list中的packet優先級更高一些。

如果在lost list中的packet持續的阻塞住send queue,在一些情況下就會造成send queue被填滿。當send queue滿了,發送端首先就丢棄packet而不是發送它們。編碼器(或上層應用)可能持續的生成packet,但是send queue沒有空間放入,是以packet會被直接丢棄。SRT本身不對未發送封包敏感的,其也不會在SRT statistics中顯示。

這種packet上層丢棄的情況幾乎不會發生。放在send buffer中packet的數量是基于配置延時參數的。舊的packet,沒有機會再被重傳或被play的,會被丢棄,為上層應用的新封包留白間。當低延時配置被配置,最小一秒的延時是被使能的。一秒的限制是來源于MPEG I-frame用SRT傳輸的情況。IFrame是比較大的(通常8倍于其他packet),需要更多的時間來發送。其太大而不能在延時視窗中保留,可能會造成queue中的封包丢棄。為了避免這種情況,SRT應用在丢棄packet前,最少有1秒等等(或延時變量值)。這就可以當應用最小延時變量,仍可以應用到IFrame中。

SRT Packet Pacing: SRT按速率發送packet

UDT用最大帶寬設定來控制packet輸出速率。這個statics設定對于動态的輸入不太友好,特别當你改變編碼器的編碼bitrate的時候。SRT控制packet速率基于輸入速率,和重傳的負荷(這些都基于輸出來計算)。

早期,SRT用配置的輸入速率作為編碼器的輸出速率(根據packet的音頻和最高的bitrate)。但是有時對于編碼器經常會輸出過高的速率。在低速率輸出時,編碼器有時太過于樂觀,就會輸出超過預期過高的bitrate。在這些情況下,SRT packet就不會足夠快的輸出,因為SRT會最終被過低的錯誤配置影響到。

這可以通過計算bitrate來緩解這個問題。SRT檢測到要發送的packet,并且計算出它的平均移動bitrate。然而,這樣的操作可能會有一些延時。也就是說,如果編碼器遇到黑屏或者靜幀,它就會大幅度的降低bitrate,就會降低SRT bitrate。而當編碼器輸出突然增大,SRT也不會立刻增大很快。packet可能會延時,解碼器收到就會晚,進而造成問題。

一個提議的解決方案是,讓SRT把編碼器的input rate配置,和測量實際input rate,使用這兩者的中最大值。

輸出是通過控制packet周期(兩個packet之間的間隔)。對于一個指定的bitrate,SRT計算出一個packet的平均大小。packet的間隔是通過比較持續packet中的timestamp來定義。packet的輸出是通過packet size和間隔來排程。

SRT協定翻譯SRT協定

傳輸速度是通過packet之間的定時器來控制的。在老的代碼中,packet周期是通過擁塞控制子產品來調整的。基于從網絡的回報,packet間隔可以突然減小來加速,或突然增加來減速。但是這在SRT的直播模式中并不适合。音視訊流bitrate是在mpegts packet形成,修改出口packet pace病不能影響到接收方單個的流rate–它會影響到解碼。早期SRT是在一個周期裡,輸出rate與輸入input相當。預設情況下,SRT測量input流的bitrate,根據這個來調整packet period。

SRT需要一個确定的足夠帶寬(比預想的帶寬略高),為了有空間插入更多的重發packet,而不影響SRT發送者的主流輸出速度太多而導緻packet不能正确發送。唯一的辦法是通過network的回報來降低擁塞,來控制編碼器的輸出(SRT的輸入)。不太可能對已經打包到預想bitrate的packet進行調整,因為這個預設定的速度已經是解碼器想要的速度了。

這裡有3個配置項:INPUTBW, MAXBW 和 OVERHEAD(%)。

SRT協定翻譯SRT協定

設定輸入帶寬(INPUTBW)參數為0,意味着用内部測量值(smpinpbw)來設定packet周期,同時與output的overhead最大配置配合來完成。

一個絕對的最大帶寬(MAXBW)能被配置成一個能力極限值。設定MAXBW為0的話,就是隻用INPUTBW來調整輸出。

這裡有個情況是SRT需要考慮的。問題就是測量輸入帶寬的方法有一個延後問題,這個測量是平均值。是以如果輸入速率突然降為0(舉例,因為可能會有黑屏在視訊流中),測量結果就會掉入低值的rate。但是當視訊速率突然增長,input rate就突然增長。SRT的輸出速率就會落後于編碼器的輸入速率。封包就會累計在SRT發送者的buffer中,因為SRT要花時間來測量速度。如果packet太晚輸出,就會導緻問題。

SRT協定翻譯SRT協定

為了解決這個問題,SRT的發送方的輸出是通過視訊編碼器的速率來配置的。因為可能通過編碼器配置的bitrate來配置SRT的bitrate,任何修改都能被直接copy到SRT的配置中。這個是全局的。

SRT協定翻譯SRT協定

如下表所示,SRT的發送者bitrate因為黑屏而降低,但是不會一直降低。

SRT協定翻譯SRT協定

但是這個解決方案有它自己的弱點。在低bitrate,SRT從編碼器來的輸入速率經常會超過預先配置的bitrate。因為SRT發送方的輸出是基于配置編碼器的bitrate來調整,輸入突然過高會導緻packet再send buffer中的堆積。buffer的堆積比packet的發送更快。但是SRT輸出還會依賴配置的速度,但是被累積的packet不得不逾時發送。它們會在buffer中累計,不會即使的輸出,最後導緻一些packet會被發送過晚。

SRT協定翻譯SRT協定

圖中橘黃色線以上表示,基于延時需要利用overhead space進行重傳的pakets。橘黃色線表示的區域是丢失packet的數量。這些packet不得不加入到圖表的上部,實時直播流不得不一直維護這些資訊。

基于這個原則,packet之間的空間決定重傳packet在什麼地方插入,overhead代表可以提供的邊界。有個經驗的計算,定義packet之間的間隔進而得出輸出bitrate。它是負載的功能(負載包含音頻/視訊)。

SRT嘗試基于解碼器輸出來重新定義發送者的輸入帶寬,重發packet是透明的,就好像它們從來沒被重傳過。當到達一個臨界點,但是一旦packet pacing下降,有很大的累積在send buffer。它突然變滿,并且不能足夠快的清空,到某個時間點packet就開始丢包。

SRT版本1.3合并了兩種packet pacing的方法。輸入rate的檢測,但是如果其掉速太多,SRT發送者輸出的配置bitrate是公認的。如果測量低于配置速率,它并不遵循測量速率(如果完全沒有packet發送,SRT就不發送)。然而,如果編碼器輸入速率大于配置速率,它就遵循編碼器配置速率,越快越去遵循。綁定這兩種方法來克服各自的問題。

SRT協定翻譯SRT協定

理論上,帶寬能力是帶寬overhead的值。如果有太多packdet而不能發出,SRT不能發出。但是帶寬能力的機制不能正常工作。帶寬限制就被輕易的擊潰。

另外一個SRT版本1.3的變化,是加了一個配置option,叫OUTPACEMODE,其使能其他pacing項的組合。設定MAXBW模式就是以絕對帶寬容量值,其并不随編碼器的輸入而波動。設定MAXBW為0,意味着使用INPUTBW。相反的,設定INPUTBW為0意味着完全使用内部測量值。

SRT 1.3版本用這些技術的捆綁來作為配置輸入,而不是隻用測量值,或使用兩者間的最大值。OUTPACEMODE是用來使能其他配置項的合并使用。它定義了MAXBW,INPUTBW,和兩者的合并,或兩者都不使能(不限制)。

SRT packet pacing總結如下。預設,直播模式下的輸出rate是基于輸入rate的(也就是流的輸出)。輸入rate(sendmsg API)是内部測量到的,輸出rate是動态調整的,包括配置overhead(25%),其被加到重傳packet的迸發rate中。

Packet Probes

當SRT用很多技術方法在流控上,但有很多限制在于無法準确的計算鍊路的帶寬容量。這裡的Packet probe技術是每16個packet封包間隔發送一次“packet probe”其沒有封包間隔的延時。如果這兩個連着的packet到達接收者是有間隔的,意味着網絡有影響的背景流量,其也意味着足夠的網絡帶寬有所下降。這也幫助去測量網絡帶寬能力。但是在packet之間的空間的計算是無法控制的,也就是說足夠的帶寬量是很難定義出來的。

SRT協定翻譯SRT協定

繼續閱讀