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的機制在接收方新創建了重要的特性,極大的降低buffer的需要。這些機制是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中的報文結構變化。爲了提高早期版本的適應能力,新舊報文格式都在下面列出(大字節序)。

    在這裏插入圖片描述

  • 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一節專門用來解釋。
在這裏插入圖片描述

KM 錯誤反饋報文

Key Messge Error Response控制報文(‘packet type’ bit=1)是用來交換錯誤狀態消息。在加密一節中詳細介紹。
在這裏插入圖片描述

ACK報文

ACK控制報文(‘packet type’ bit=1) 是用來提供報文發送狀態和RTT信息的。在SRT數據傳輸和控制一節中詳細介紹。

在這裏插入圖片描述

Keep-alive報文

Keep-alive報文(‘packet type’ bit=1) 是用來每10ms交換信息,來保證SRT流在連接斷開後字段重連的。
在這裏插入圖片描述

NAK控制報文

NAK控制報文(‘packet type’ bit=1) 是用來報告失敗的報文傳輸。在SRT數據傳輸和控制一節中詳細介紹。
在這裏插入圖片描述

SHUTDOWN控制報文

shutdown控制報文(‘packet type’ bit=1) 用來發器關閉SRT連接。
在這裏插入圖片描述

ACKACK控制報文

ACKACK控制報文(‘packet type’ bit=1) 用來回復收到ACK報文,並且可以用來計算RTT。在SRT數據傳輸和控制一節中介紹。
在這裏插入圖片描述

擴展控制報文

擴展控制報文(‘packet type’ bit=1) 用來爲原始UDT用戶控制消息。它們被用在SRT擴展握手報文中,可以通過獨立的消息,或內嵌在HANDSHAKE中。

在這裏插入圖片描述

SRT數據交互

下表描述數據交互(包括控制數據)。注意,兩點間角色的變換。舉例,在會話過程中節點可以作爲發起者,和監聽者,然後也能成爲發送和接受者在數據傳輸過程中。
在這裏插入圖片描述

SRT數據傳輸和控制

本節介紹直播的音視頻中,如何處理控制/數據報文的關鍵思想。

Buffers

當應用(編碼器)提供數據給srt來發送,它們被放入一個環狀的發送buffer中。它們用seqid來編號。報文放在buffer中,直到收到對端的ack,萬一它們會需要被重傳。每個報文都有一個時間戳,其基於連接時間(其在handshake中定義,在第一個報文發送之前)。
StartTime是應用創建SRT socket的時刻。報文時間戳是介於StartTime和報文被加到send buffer之間。
在這裏插入圖片描述注意:這裏的時間是從左到右的,最新的報文在右邊。

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

在這裏插入圖片描述
時間戳是和連接關聯的。傳輸並不是基於絕對時間。調度執行時間應該是基於實際時鐘時間。時間的基準應該轉換每個報文的時間戳到本地時鐘時間。報文都是從發生方StartTime的便宜。任何時間相關參數都是基於本地StartTime來維護的,用來計算RTT,時間區和偏移,通過nanoseconds和其他。

Send Buffer Management

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

下表顯示出send buffer與SRT socket(CUDT)相關。SndQ包含socket引用,時間戳引用,本地索引信息(其是在SndQ中位置)。相關引用對象也是SndQ的對象的一部分。
在這裏插入圖片描述
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決定什麼報文能恢復,多少次被恢復。

在這裏插入圖片描述
在準確的時刻,接受者buffer釋放第一個報文給上層應用。當延時窗口滑向下一個報文間隔,接受者釋放第二個報文給上層應用,以此類推。

現在我們看一下如果packet沒有收到(packet#4)會發生什麼。當延時窗口滑動,packet就應該可以上送給上層應用,但是該packet不存在。這就會導致跳到下個packet。其不會被恢復,那麼它也將被移出丟棄list,並且永不會在要求重傳。
在這裏插入圖片描述
滑移延時窗口可以被認爲是一個區間,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講指向發送隊列尾部。

在這裏插入圖片描述
每個packet都有timestamp,依賴timestamp來確定何時發送。SndQ列表是用timestamp來排列的。如果發送線程決定socket 1發送bufer有報文ready,它就把packet放入SndQ的隊列中。如果SndQ隊列是空,packet就被放在隊列頭,並帶上自己的時間戳,其決定報文什麼時候該被處理。

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

在這裏插入圖片描述
帶有包間隔的時間戳決定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中移除。

在這裏插入圖片描述
在丟失的案例中,ACK(seq)就是丟失列表中的第一個報文,其就是最新收到報文的seq+1。

Packet Retransmission (NAKs)

如果packet 4到達了接受者的buffer,但是packet 3並沒有到達,NAK報文就需要發送給發送着。NAK被加到一個列表(週期的NAK報告),其週期的發送給發送方,以此避免NAK報文本身傳輸中丟失或延遲到達。

在這裏插入圖片描述
如果packet 2到達,但是packet 3沒有,那麼當packet 4到達後,NAK就應該按照規則發送來發起要求重傳。

在這裏插入圖片描述

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週期內,雙方評估的結果(儘量選擇大一點的值)。
在這裏插入圖片描述

ACKs, ACKACKs & Round Trip Time

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

在這裏插入圖片描述
ACKACK告訴接收者停止發送對應便宜點的ACK,因爲發送端已經知道接收端收到了。否則,ACK(帶有過時信息)將被持續的週期發送。類似的,如果發送端沒有收到ACK,它自己也會週期發送沒有收到ACK的packet。

有兩種情況發送ACK。一個full ACK是基於10ms(ACK週期)發送。對於高bitrate的傳輸,一種"light ACK"就能被髮送,期是多個packet的一個sequence。在10ms的間隔裏,經常有大量packet的發送和接收,以至於發送端ACK的偏移點不能夠快的移動。爲了減輕這個問題,在收到64packets後(即使ACK發送週期還沒到),發送端發送一個light ACK。
在這裏插入圖片描述
ACK動作像ping報文,而ACKACK像ping back回覆,以此可以度量出RTT。每個ACK都有一個數值,而ACKACK也有相同的一個數值。接收方有一個ACK的列表去匹配ACKACK。不像full ACK報文(包含當前的RTT和多個其他的控制信息參數),light ACK包含sequence數值(如下表所示)。在接收端,所有控制消息被直接發送和處理,但是ACKACK的處理時間是微不足道的(因爲它的處理時間被包括在RTT裏面)。

RTT是在接收端被計算出來的,並且發送下一個full ACK。注意,第一個ACK包含的RTT值默認是100ms,因爲早期的計算可能不準確。
在這裏插入圖片描述
發送端永遠都是通過接收端獲取到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決定。
在這裏插入圖片描述
當ACKPOS前移到一個點,所有比這個點舊的packet都可以被移出send queue。
在這裏插入圖片描述當接收者遇到遇到這種情況,下一個應該被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和間隔來調度。

在這裏插入圖片描述
傳輸速度是通過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(%)。

在這裏插入圖片描述
設置輸入帶寬(INPUTBW)參數爲0,意味着用內部測量值(smpinpbw)來設置packet週期,同時與output的overhead最大配置配合來完成。

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

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

在這裏插入圖片描述
爲了解決這個問題,SRT的發送方的輸出是通過視頻編碼器的速率來配置的。因爲可能通過編碼器配置的bitrate來配置SRT的bitrate,任何修改都能被直接copy到SRT的配置中。這個是全局的。
在這裏插入圖片描述
如下表所示,SRT的發送者bitrate因爲黑屏而降低,但是不會一直降低。
在這裏插入圖片描述
但是這個解決方案有它自己的弱點。在低bitrate,SRT從編碼器來的輸入速率經常會超過預先配置的bitrate。因爲SRT發送方的輸出是基於配置編碼器的bitrate來調整,輸入突然過高會導致packet再send buffer中的堆積。buffer的堆積比packet的發送更快。但是SRT輸出還會依賴配置的速度,但是被累積的packet不得不超時發送。它們會在buffer中累計,不會即使的輸出,最後導致一些packet會被髮送過晚。

在這裏插入圖片描述
圖中橘黃色線以上表示,基於延時需要利用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就不發送)。然而,如果編碼器輸入速率大於配置速率,它就遵循編碼器配置速率,越快越去遵循。綁定這兩種方法來克服各自的問題。

在這裏插入圖片描述理論上,帶寬能力是帶寬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之間的空間的計算是無法控制的,也就是說足夠的帶寬量是很難定義出來的。

在這裏插入圖片描述

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