天天看點

[WebRTC架構分析] WebRTC 實作的 RFC 知多少?(RTP/RTCP/FEC 相關)

https://zhuanlan.zhihu.com/p/87879447

前言

WebRTC 作為一個多媒體實時通信系統,實作了很多 RFC 标準,并且針對 WebRTC 本身也制定了相關的标準。要想對 WebRTC 做深入的了解,參考相關标準文獻是必不可少的,否則一頭紮進源碼去分析具體實作邏輯,很難達到預期的效果。如果閱讀了相關文獻,從基礎理論上有一個宏觀上的認識,那麼再去分析相關源碼,你會時不時有“原來是這樣”的感歎。

本人在分析源碼的過程中參考一系列的 RFC 文檔,計劃通過幾篇文章對相關 RFC 文檔做一個整理、分類,并且做出簡要介紹。

歸納起來,WebRFC 實作參考的 RFC 标準分如下幾類:

  • ICE 協定相關部分,媒體描述,offer/answer 通信過程。
  • P2P 穿越相關部分,建立一對一通信鍊路。
  • DTLS 相關部分,主要是網絡傳輸相關标準。
  • RTP/RTCP/FEC 相關部分,主要是多媒體傳輸相關标準。

另外,WebRTC 是作為浏覽器核心釋出的,對外提供的是 JavaScript 接口,是以有一套 JSEP 規範,暫且沒有分析計劃。

第一篇我們就介紹 RTP/RTCP/FEC 相關部分。

RFC 1889

此協定主要是描述了 RTP real-time transport protocol。RTP 協定主要是用于多人音視訊會議的應用場景下。協定内定義了 RTP、RTCP 的基本封包格式和最初的算法。

連結:https://tools.ietf.org/html/rfc1889

RFC 3550

RFC 3550 是在 RFC 1889 的基礎上進行了改進, 對 RTP 標頭,RTCP 的 SR、RR、SDES、APP、BYE 做了介紹,對 RTCP 封包的收發算法、RTT 的計算做了規定。

連結:https://tools.ietf.org/html/rfc3550

RFC 3551 RTP/AVP

RFC 3551 叫做 RTP Audio visual profile,是 RFC 3550 的補充,主要展現在以下幾方面:

  1. 對 RTP/RTCP 頭沒有變化。對 RTCP 資料包發送時間周期做了補充說明。
  2. 對 AV codec 對應的 payload type 做了說明,曆史上采用靜态 payload type 并且和 name 綁定,後來發現 payload type 空間很有限,是以鼓勵用動态 payload type,範圍是 96-127。
  3. 對音頻、視訊 codec 做了一個說明,這些都是比較老的格式。

連結:https://tools.ietf.org/html/rfc3551

rfc 4585 RTP/AVPF

RFC 4585 叫做 RTP/RTCP Audio visual profile based feedback。在 RFC 3550 和 RFC 3551 的基礎上,提供了回報消息的機制(Feedback message)。

  • 提出了回報基于三個層面的概念:
  1. Transport layer feedback RTPFB 205
  2. Payload-specific feedback PSFB 206
  3. Application layer feedback
  • 定義了回報消息的通用格式如下。
  • 定義了基于 Transport layer 的 NACK 回報機制。
  • 定義了基于 Payload-specific
  1. PLI(Picture Loss Indication) 丢幀請求。
  2. SLI(Slice Loss Indication) 丢片請求。
  3. RPSI(Reference Picture Selection Indication) 參考幀選擇訓示器。

對消息在 SDP 中的屬性也做了說明。屬性表示是 “a=rtcp-fb:”,比如:

a=rtcp-fb:101 nack
a=rtcp-fb:101 nack pli
           

連結:https://tools.ietf.org/html/rfc4585

RFC 5104

RFC 4885 中隻是定義了簡單的回報機制,比如 NACK。是适合于 P2P 通信模式,或者是小方多人會議模式。

RFC 5104 制定了更适合多人通信模式的相關回報機制。

連結:https://tools.ietf.org/html/rfc5104

RFC 5285

定義 RTP 中的擴充頭。其實 RFC 3550 中也提供了擴充頭規範,但是隻能有一種擴充頭類型,不夠靈活。而 RFC 5285 支援多種類型擴充頭。

連結:https://tools.ietf.org/html/rfc5285

RFC 5761

解決 rtp 和 rtcp 共用同一個端口,資料包解複用的問題。這是通過 payload type 來解決。

連結:https://tools.ietf.org/html/rfc5761

WebRTC 識别 RTCP 的方法,是按照 RFC 訓示做的,如下:

// Check the RTP payload type. If 63 < payload type < 96, it's RTCP.
// For additional details, see http://tools.ietf.org/html/rfc5761.
bool IsRtcpPacket(const char* data, size_t len) {
  if (len < 2) {
    return false;
  }
  char pt = data[1] & 0x7F;
  return (63 < pt) && (pt < 96);
}
           

RFC 6184

此 RFC 主要是講述了将 H.264 NALU 打包成 RTP 的規範。

webrtc 中實作了 single 模式和 STAP-A 模式。

也實作了将一個 NALU 分片的機制。

連結:https://tools.ietf.org/html/rfc6184

RFC 2198

連結:https://tools.ietf.org/html/rfc2198

此 RFC 主要講述音頻備援。通過實踐來看,網絡擁塞、帶寬限制等都會造成網絡丢包,丢包是網際網路音視訊通信音頻差的主要原因。引入備援可以讓接收端根據備援資料恢複丢失的資料。

音頻備援相對簡單,主要思想就是:發送的時候,一個目前要發送的新包(primary packet)攜帶幾個已經發過的包(即,備援包),組成的一個大包;接收端,收到此包以後,可以解開,得到多個包,如果其中的一個備援包剛好是之前發送丢掉的,那麼此時馬上可以恢複出來,達到備援效果。

帶備援的音頻包,RTP 頭還是目前新包的頭,在 RTP 頭後面加入備援標頭,備援標頭後面是備援資料。注意,primary packet 的資料是在備援資料的後面。

備援標頭格式如下:

0                   1                    2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3  4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |F|   block PT  |  timestamp offset         |   block length    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           

F: 一個bit,1表示後面還有備援包,0 表示最後一個備援頭。

block PT: 備援包 payload type

timestamp offset:相對于 primary 包的時間戳偏移量。

block length: 資料長度。

帶備援資料包的一個特點是:所有資料包的時間戳,不應該相同。因為相同毫無意義吧!

RFC 2733

連結:https://tools.ietf.org/html/rfc2733

此文檔主要是講 FEC :Generic Forward Error Correction

文中讨論了 FEC 的主要解決的問題。如何通過原始媒體資料生成 FEC 資料包,FEC 資料包格式,如何通過 FEC 來恢複丢失的媒體包。

FEC 主要是采用 xor 運算來實作。

RFC 5109

連結:https://tools.ietf.org/html/rfc5109

此文也是讨論 FEC,理念是基于 RFC 2733,可以說是一個改進版本。

unequal error protection

Uneven Level Protection

後記

WebRTC rtp_rtcp 子產品實作了大多數 RTP/RTCP/FEC 相關規範。是以學習本文整理的規範是進一步 rtp_rtcp 子產品的基礎。後續跟進情況,再決定是否更新。