一、RTP
1.1 RTP協議介紹
在 WebRTC 中,RTP(Real-time Transport Protocol,實時傳輸協議)是音視頻媒體數據傳輸的核心協議,負責實時數據的封裝、傳輸與解封裝,為實時交互提供時序、同步、分片重組等關鍵能力。它基于 UDP 傳輸(兼顧實時性),但自身不保證可靠性,而是通過與 RTCP(實時傳輸控制協議)配合,實現丟包反饋、碼率調整等功能。
WebRTC 的實時音視頻通話(如 P2P 通話、多人會議)中,音視頻數據(經編碼后,如 VP8/VP9/H.264 視頻、OPUS 音頻)需通過 RTP 封裝后再由 UDP 傳輸,核心作用包括:
- 分片與重組:解決大幀(如視頻 I 幀)超過以太網 MTU(約 1500 字節)的問題,通過分片傳輸,接收端重組為完整幀;
- 時序與排序:通過序號和時間戳保證數據的正確順序和播放時序;
- 媒體類型區分:通過載荷類型標識音頻 / 視頻及具體編解碼器;
- 流標識:通過同步源(SSRC)區分同一端的不同媒體流(如音頻流和視頻流)。
1.2 RTP報文格式
RTP 協議頭遵循 RFC 3550 標準,WebRTC 使用版本 2(V=2),核心字段如下(按功能分類):
1. 基礎控制字段
- V(版本):2 位,固定為 2(WebRTC 唯一支持的版本)。
- P(填充位):1 位,標識載荷末尾是否有填充數據(用于加密時對齊塊大小,如 AES 加密)。
- X(擴展位):1 位,標識是否有擴展頭部。WebRTC 廣泛使用擴展頭部傳輸額外信息(如音頻電平、視頻方向等)。
- CC(CSRC 計數):4 位,標識后續 CSRC 列表的長度(用于混音場景,如多方通話中標識音頻來源)。
2. 媒體標識與邊界字段
- M(標記位):1 位,用于標識幀的邊界。例如:
- 視頻中,M=1 表示當前 RTP 包是一幀的最后一個分片;
- 音頻中,M=1 表示一個完整音頻幀的結束(如 OPUS 幀的邊界)。
- PT(載荷類型):7 位,標識載荷的媒體類型及編解碼器。WebRTC 中多為動態值(96-127),需通過 SDP 協商確定具體映射:
- 例如:
a=rtpmap:96 VP8/90000
表示 PT=96 對應 VP8 視頻,時鐘頻率 90000Hz(視頻常用); a=rtpmap:111 OPUS/48000/2
表示 PT=111 對應 OPUS 音頻,48kHz 采樣率,雙聲道。
- 例如:
3. 時序與排序字段
- Sequence Number(序號):16 位,按發送順序遞增,用于:
- 接收端檢測丟包(序號不連續則可能丟包);
- 分片重組(同一幀的分片序號連續)。
- Timestamp(時間戳):32 位,用于同步和時序控制:
- 同一幀的所有分片時間戳相同(區分幀邊界);
- 不同幀的時間戳不同(按編解碼器時鐘頻率遞增,如視頻 90kHz:每 1/90000 秒遞增 1);
- 接收端通過時間戳計算播放順序(解決網絡亂序問題)。
4. 流標識字段
- SSRC(同步源):32 位,唯一標識一個媒體流(如同一設備的視頻流或音頻流)。例如:
- 視頻流可能用 SSRC=2345,音頻流用 SSRC=888(如用戶提供的示例),接收端通過 SSRC 區分音視頻流;
- 若流中斷重連,SSRC 會重新生成,避免沖突。
- CSRC(貢獻源):0-15 個 32 位字段,標識混音場景中參與混音的原始音頻源(如多方通話中,一個音頻包可能包含多個說話人的 CSRC)。
1.3 RTP協議重點特性
1. 動態 PT 的協商(SDP 交互)
WebRTC 支持多種編解碼器(如 VP8/VP9/H.264 視頻,OPUS/G.711 音頻),但 RTP 的 PT 值(尤其是 96-127)是動態分配的,需通過 SDP(會話描述協議)協商:
- 發送端在 SDP 的
m=video
或m=audio
行中列出支持的 PT 值; - 通過
a=rtpmap
屬性映射 PT 值與編解碼器(如a=rtpmap:96 VP8/90000
); - 雙方協商后,確定本次通話使用的 PT 與編解碼器對應關系。
2. 大幀分片與重組
視頻 I 幀(關鍵幀)數據量大(可達幾十 KB),遠超 MTU(1500 字節),WebRTC 通過 RTP 分片傳輸:
- 發送端將 I 幀拆分為多個 RTP 包,每個包的時間戳相同,序號連續,最后一個包的
M=1
(標記幀結束); - 接收端收集相同時間戳的 RTP 包,按序號排序重組為完整 I 幀,再交給解碼器。
3. RTP 擴展頭部(WebRTC 增強功能)
WebRTC 通過 RTP 擴展頭部傳輸額外控制信息,提升實時性和用戶體驗,常見擴展包括:
- 絕對發送時間(Absolute Send Time):標識包的發送時間,輔助接收端計算網絡延遲;
- 音頻電平(Audio Level):標識音頻能量,用于說話人檢測(如會議中高亮當前說話人);
- 視頻方向(Video Orientation):標識視頻幀的旋轉角度(如手機橫屏 / 豎屏切換);
- 擴展通過 SDP 的
a=extmap
字段協商(如a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
)。
4. 安全性:SRTP 加密
WebRTC 要求媒體傳輸加密,使用SRTP(Secure RTP) 對 RTP 包進行加密和認證:
- 加密算法:通常用 AES-128,防止數據被竊聽;
- 認證算法:HMAC-SHA1,防止數據被篡改;
- 密鑰通過 DTLS(數據報傳輸層安全)協議協商,確保密鑰安全交換。
5. 與 RTCP 的協同
RTP 負責傳輸媒體數據,RTCP 負責控制與反饋,兩者協同保證傳輸質量:
- 接收端通過 RTCP 的 RR(接收報告)反饋丟包率、抖動等信息;
- 發送端根據 RTCP 反饋調整碼率(如丟包率高則降低視頻碼率)、重傳策略等,實現自適應比特率(ABR)。
1.4 RTP協議解析
知道了上面這些字段的含義后,下面我們還是來看一個具體的例子吧!假設你從網上接收到一組音視頻數據,假設 PT=98 是視頻數據,PT=111 是音頻數據,如下:
{V=2,P=0,X=0,CC=0,M=0,PT:98,seq:13,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:14,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=0,PT:98,seq:14,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:15,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=0,PT:98,seq:15,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:16,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=0,PT:98,seq:16,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:17,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=0,PT:98,seq:17,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:18,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=0,PT:98,seq:18,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:19,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=0,PT:98,seq:19,ts:1122334455,ssrc=2345}, {V=2,P=0,X=0,CC=0,M=0,PT:111,seq:20,ts:1122334455,ssrc=888}, {V=2,P=0,X=0,CC=0,M=1,PT:98,seq:20,ts:1122334455,ssrc=2345},
解析結果如下:
V=2
:版本號為 2,符合 WebRTC 唯一支持的 RTP 版本標準;P=0
:無填充數據(載荷末尾沒有額外填充字節);X=0
:無擴展頭部(未攜帶額外擴展信息,如音頻電平、絕對發送時間等);CC=0
:無 CSRC 列表(非混音場景,媒體流來自單一源)。- PT=98:標識為視頻數據(根據前提,PT=98 對應視頻);
- ssrc=2345:唯一標識該視頻流(同一設備的視頻源);
- ts=1122334455:所有包的時間戳相同,說明它們屬于同一視頻幀的分片;
- seq=13~20:序號連續遞增,說明是同一幀的連續分片(無丟包,按順序傳輸);
- M=0→M=1:前 7 個包
M=0
(非幀末尾),最后一個包M=1
(標記為該視頻幀的最后一個分片)。
RTP更多資料參考我的博客: RTP協議介紹
二、RTCP
2.1 RTCP協議介紹
RTCP(RTP 控制協議)是 WebRTC 實現實時音視頻傳輸的核心控制協議,其核心目標是通過網絡質量反饋和傳輸策略優化,確保在復雜網絡環境下的流暢通信:
- 網絡狀態監控:通過周期性交換 SR(發送方報告)和 RR(接收方報告),實時統計丟包率、抖動、往返時間(RTT)等關鍵指標。
- 媒體同步:利用 SR 報文中的 NTP 時間戳,實現音頻與視頻流的精確同步。
- 傳輸優化:根據 RTCP 反饋動態調整編碼參數(如分辨率、幀率)、重傳策略(如 NACK、FEC)和擁塞控制算法(如 GCC)。
- 會話管理:支持 BYE 報文結束會話、SDES 報文描述參與者信息,以及 FIR 報文請求關鍵幀同步。
2.2 RTCP報文格式
-
RTCP 有兩個最重要的報文:RR(Reciever Report)和 SR(Sender Report),通過這兩個報文的交換,各端就知道自己的網絡質量到底如何了
-
RTCP 報文基于 UDP 傳輸,通常以復合包形式發送(多個 RTCP 報文合并為一個 UDP 包),且第一個報文必須為 SR 或 RR
1. SR
-
用途:發送方周期性發送(默認 5 秒一次),報告自身發送數據的統計信息,同時包含作為接收方時的網絡質量反饋。
-
結構與字段:
- Header:包含版本(V=2)、填充位(P)、接收報告塊數(RC)、報文類型(PT=200)和長度。
- Sender Info:
- NTP 時間戳:絕對時間(1900 年 1 月 1 日起的秒數),用于音視頻同步。
- RTP 時間戳:與媒體時鐘對齊,用于計算幀率和時間偏移。
- Packet Count:會話開始后發送的 RTP 包總數。
- Octet Count:會話開始后發送的負載字節總數。
- Report Block(多個):
- SSRC:報告對應的媒體流源。
- 丟包率:累計丟包數與期望接收包數的比值(24 位有符號整數)。
- Interarrival Jitter:相鄰包到達時間的差異,反映網絡抖動。
- LSR/DLSR:最后一次收到對端 SR 的時間及間隔,用于計算 RTT。
示例場景:發送方通過 SR 報文告知接收方:“我已發送 1000 個視頻包,總大小 2MB,當前接收對端音頻流的丟包率為 5%,抖動為 20ms。”
SR的報文由四部分組成:
SR 報文 = Header (8B) + Sender Info (20B) + [Report Block (24B) × RC] + [Padding]
(1)Header 頭部(8 字節)
字段 | 長度 | 說明 |
---|---|---|
V | 2 bit | 版本號,固定為 2 (WebRTC 唯一支持的版本)。 |
P | 1 bit | 填充位,若為 1 ,報文末尾包含填充字節(最后一個字節的值表示填充數)。 |
RC | 5 bit | 接收報告塊(Report Block)的數量(最多 31 個)。 |
PT | 8 bit | 報文類型,固定為 200 (SR 報文標識)。 |
Length | 16 bit | 報文總長度(以 32 位字為單位,含頭部和填充,需減 1)。 |
SSRC | 32 bit | 發送者的同步源標識符(唯一標識該媒體流)。 |
(2)Sender Info 發送者信息(20 字節)
字段 | 長度 | 說明 |
---|---|---|
NTP Timestamp | 64 bit | 絕對時間戳(1900 年 1 月 1 日起的秒數),用于音視頻同步。 |
RTP Timestamp | 32 bit | 與 NTP 時間戳對應的 RTP 時間戳(媒體時鐘對齊)。 |
Packet Count | 32 bit | 會話開始后發送的 RTP 包總數(SSRC 變更時重置)。 |
Octet Count | 32 bit | 會話開始后發送的負載字節總數(不含 RTP 頭和填充)。 |
(3)Report Block 接收報告塊(每個 24 字節)
字段 | 長度 | 說明 |
---|---|---|
SSRC_n | 32 bit | 被報告的媒體流源的 SSRC 標識符。 |
Fraction Lost | 8 bit | 最近一個統計周期內的丟包率(0-255 ,實際值為 字段值 / 256 )。 |
Cumulative Lost | 24 bit | 累計丟包數(期望接收包數 - 實際接收包數)。 |
Extended Highest Seq | 32 bit | 接收的最大序列號(低 16 位為序列號,高 16 位為循環計數)。 |
Interarrival Jitter | 32 bit | 相鄰包到達時間的抖動(方差估計值)。 |
LSR(Last SR) | 32 bit | 接收來自 SSRC_n 的最后一個 SR 報文的 NTP 時間戳中間 32 位。 |
DLSR(Delay since LSR) | 32 bit | 自接收 SSRC_n 的 SR 報文以來的延遲(單位:1/65536 秒)。 |
示例場景:
發送者通過 SR 報文告知接收者:“我已發送 1000 個視頻包(Packet Count
),總大小 2MB(Octet Count
),當前接收對端音頻流的丟包率為 5%(Fraction Lost = 12.8
),抖動為 20ms(Interarrival Jitter
)。”
2 RR
- 用途:接收方發送,報告從多個 SSRC 接收數據的統計信息,用于發送方評估網絡質量。
- 結構與字段:
- Header:與 SR 類似,但 PT=201。
- Report Block:
- SSRC:報告對應的媒體流源。
- Extended Highest Sequence Number:接收的最大序列號,用于計算丟包數。
- Fraction Lost:最近一個統計周期內的丟包率(0-255)。
- Interarrival Jitter:與 SR 中的定義相同。
示例場景:接收方通過 RR 報文反饋:“從 SSRC=2345(視頻流)接收的包中,最近 100 個包丟失 5 個,抖動為 30ms,RTT 為 150ms。”
RR報文由三部分組成:
RR 報文 = Header (8B) + [Report Block (24B) × RC] + [Padding]
(1)Header 頭部(8 字節)
字段 | 長度 | 說明 |
---|---|---|
V | 2 bit | 版本號,固定為 2 。 |
P | 1 bit | 填充位,含義同 SR。 |
RC | 5 bit | 接收報告塊(Report Block)的數量(最多 31 個)。 |
PT | 8 bit | 報文類型,固定為 201 (RR 報文標識)。 |
Length | 16 bit | 報文總長度(以 32 位字為單位,含頭部和填充,需減 1)。 |
SSRC | 32 bit | 接收者的同步源標識符(標識該接收端)。 |
(2)Report Block 接收報告塊(每個 24 字節)
字段 | 長度 | 說明 |
---|---|---|
SSRC_n | 32 bit | 被報告的媒體流源的 SSRC 標識符。 |
Fraction Lost | 8 bit | 最近一個統計周期內的丟包率(0-255 ,實際值為 字段值 / 256 )。 |
Cumulative Lost | 24 bit | 累計丟包數(期望接收包數 - 實際接收包數)。 |
Extended Highest Seq | 32 bit | 接收的最大序列號(低 16 位為序列號,高 16 位為循環計數)。 |
Interarrival Jitter | 32 bit | 相鄰包到達時間的抖動(方差估計值)。 |
LSR(Last SR) | 32 bit | 接收來自 SSRC_n 的最后一個 SR 報文的 NTP 時間戳中間 32 位。 |
DLSR(Delay since LSR) | 32 bit | 自接收 SSRC_n 的 SR 報文以來的延遲(單位:1/65536 秒)。 |
示例場景:
接收者通過 RR 報文反饋:“從 SSRC=2345(視頻流)接收的包中,最近 100 個包丟失 5 個(Fraction Lost = 12.8
),抖動為 30ms(Interarrival Jitter
),RTT 為 150ms(DLSR
計算得出)。”
3. FIR
- 用途:強制發送方生成關鍵幀(如 H.264 的 IDR 幀或 VP8 的關鍵幀),用于解決新用戶加入時的解碼初始化問題或關鍵幀丟失后的同步。
- 結構與字段:
- Header:PT=206(PSFB 類型),子類型 = 4。
- FCI(Feedback Control Information):
- SSRC:請求的媒體流源。
- Seq Nr:FIR 報文序列號(8 位),用于去重和排序。
- 多用戶場景:FIR 可包含多個 FCI 字段,每個對應一個參與者的 SSRC,實現批量關鍵幀請求。
示例場景:新用戶加入房間后發送 FIR 報文:“請 SSRC=2345(用戶 A)、SSRC=888(用戶 B)立即發送 IDR 幀。”
2.3 RTCP重點特性
網絡質量評估與動態優化
-
帶寬評估:
- 接收方通過 RR 報文反饋丟包率和抖動,發送方結合 SR 中的發送統計,使用 GCC(Google Congestion Control)算法動態調整碼率。
- 例如:若丟包率超過 10%,GCC 觸發降碼率;若 RTT 穩定且帶寬充足,則提升碼率。
-
重傳策略:
- NACK(Negative Acknowledgment):接收方通過 RTCP FB 報文請求重傳丟失的包,適用于非關鍵幀恢復。
- FEC(Forward Error Correction):發送方預先計算冗余包(如 XOR 異或包),接收方可通過冗余數據恢復丟失的媒體幀。
關鍵幀同步與解碼初始化
-
FIR 報文的觸發場景:
- 新用戶加入房間時,主動發送 FIR 報文請求所有參與者的 IDR 幀,確保解碼器初始化。
- 接收方檢測到連續丟包導致解碼失敗時,通過 FIR 強制發送方生成新關鍵幀。
-
IDR 幀的重要性:IDR 幀包含完整圖像信息,是解碼后續 P 幀、B 幀的基礎。若接收方未收到 IDR 幀,后續所有幀將無法解碼。
多流協同與會話管理
- SSRC 標識:每個媒體流(如視頻、音頻)通過唯一 SSRC 區分,RTCP 報告塊通過 SSRC 關聯具體流的統計信息。
- BYE 報文:參與者退出時發送 BYE 報文,其他參與者收到后釋放資源并更新會話列表。
- SDES 報文:攜帶參與者的 CNAME(規范名),確保 SSRC 沖突或程序重啟時仍能正確關聯媒體流。
RTCP 與 RTP 的協作機制
- 復用 UDP 端口:RTP 和 RTCP 通常使用相鄰端口(如 RTP 用 5000,RTCP 用 5001),但 WebRTC 支持通過 SDP 協商端口分配。
- 統計信息共享:
- RTP 發送模塊在打包時記錄序列號、時間戳等信息,供 RTCP 生成 SR 報文。
- RTP 接收模塊在解包時統計丟包、抖動等數據,作為生成 RR 報文的依據。
- 周期性發送:RTCP 報文的發送頻率根據參與者數量動態調整(如 10 人時每 5 秒發送一次),確保控制信息不超過總帶寬的 5%。
三、SDP
3.1 SDP 協議介紹
在 WebRTC 中,兩個客戶端(如瀏覽器、移動設備)建立通信前,必須通過信令服務器交換 SDP 信息:
- 讓雙方知曉彼此支持的音視頻編解碼器(如 VP8、H.264、OPUS)、編解碼參數(如采樣率、聲道數);
- 明確傳輸協議(如 RTP/RTCP over UDP)、網絡信息(如 IP、端口);
- 協商安全機制(如 DTLS 加密)和服務質量策略(如丟包重傳、帶寬控制)。
最終通過對比雙方 SDP 的 “交集”,確定實際通信中使用的參數。
SDP交換
下面是 1 對 1 WebRTC 處理過程圖:
-
如上圖所示,兩個客戶端 / 瀏覽器進行 1 對 1 通話時,首先要進行信令交互,而交互的一個重要信息就是SDP 的交換。
-
交換 SDP 的目的是為了讓對方知道彼此具有哪些能力,然后根據雙方各自的能力進行協商,協商出大家認可的音視頻編解碼器、編解碼器相關的參數(如音頻通道數,采樣率等)、傳輸協議等信息。
-
如上圖所示,Amy 與 Bob進行通訊,它們先各自在 SDP 中記錄自己支持的音頻參數、視頻參數、傳輸協議等信息,然后再將自己的 SDP 信息通過信令服務器發送給對方。
-
當一方收到對端傳來的 SDP 信息后,它會將接收到的 SDP 與自己的 SDP 進行比較,并取出它們之間的交集,這個交集就是它們協商的結果,也就是它們最終使用的音視頻參數及傳輸協議了。
3.2 SDP報文格式
SDP 是純文本協議,由一系列<type>=<value>
格式的行組成(=
兩側無空格),其中<type>
為單個字符,<value>
為具體描述內容。
例如:
v=0 // 版本號
o=- 123456 2 IN IP4 192.168.1.1 // 會話發起者信息
m=audio 9 UDP/TLS/RTP/SAVPF 111 // 音頻媒體描述
a=rtpmap:111 opus/48000/2 // 負載類型111對應OPUS編碼(48kHz采樣率,雙聲道)
SDP 分為會話級描述和媒體級描述兩層,層級關系決定參數的作用范圍:
1. 會話級描述(Session Level)
作用域為整個會話,從首行v=
開始,到第一個m=
(媒體描述)結束。包含會話全局信息,如會話發起者、時間等。若媒體級未重新定義,會話級參數為媒體的默認值。
v=<version>
:必選,SDP 版本號(WebRTC 中固定為 0)。o=<username> <session-id> <version> <nettype> <addrtype> <address>
:必選,會話發起者信息。username
:用戶名(可省略為-
);session-id
:唯一標識(通常用 NTP 時間戳);nettype
:網絡類型(固定為IN
,表示互聯網);addrtype
:地址類型(如IP4
);address
:發起者 IP。
s=<session-name>
:必選,會話名稱(WebRTC 中常為-
)。t=<start> <stop>
:必選,會話活躍時間(0 0
表示持久會話)。
2. 媒體級描述(Media Level)
作用域為單個媒體流(如一路音頻或視頻),從m=
開始到下一個m=
結束。每個媒體流(音頻、視頻)對應一個媒體級描述。
-
m=<media> <port> <transport> <fmt-list>
:必選,媒體基本信息。<media>
:媒體類型(audio
/video
);<port>
:傳輸端口(WebRTC 中常為9
,實際通過 ICE 協商確定);<transport>
:傳輸協議(如UDP/TLS/RTP/SAVPF
,表示加密的 RTP 傳輸);<fmt-list>
:支持的負載類型列表(如111 103
,對應具體編解碼器)。
-
a=<attribute>
:可選,媒體屬性,用于補充描述媒體細節(WebRTC 中擴展了大量屬性)
WebRTC 對SDP的擴展
標準 SDP 主要描述基礎媒體信息,而 WebRTC 為滿足實時通信的安全、網絡適配和質量需求,擴展了大量專屬屬性,按功能分為 5 大類:
- Session Metadata,會話元數據
- Network Description,網絡描述
- Stream Description,流描述
- Security Descriptions,安全描述
- Qos Grouping Descriptions, 服務質量描述
1. 會話元數據(Session Metadata)
對應標準 SDP 的會話級描述,包含v=
、o=
、s=
、t=
等,用于標識會話全局信息。
2. 網絡描述(Network Description)
描述網絡傳輸相關信息,確保雙方能建立網絡連接(依賴 ICE 協議)。核心屬性:
c=<nettype> <addrtype> <address>
:會話級默認 IP 地址(WebRTC 中常為0.0.0.0
,實際通過 ICE 候選地址協商)。a=candidate:<foundation> <component> <transport> <priority> <ip> <port> ...
:ICE 候選地址(如本地 IP、中繼服務器 IP 等,用于 NAT 穿透)。
3. 流描述(Stream Description)
描述音視頻流的編解碼能力,是媒體協商的核心。核心屬性:
a=rtpmap:<payload> <encoding>/<clock-rate>[/<params>]
:映射負載類型到編解碼器。
例:a=rtpmap:96 VP8/90000
表示負載類型 96 對應 VP8 視頻編碼(時鐘頻率 90000Hz,RTP 視頻的標準時鐘)。a=fmtp:<payload> <params>
:編解碼器的具體參數。
例:a=fmtp:111 minptime=10;useinbandfec=1
表示 OPUS 編碼(負載 111)的最小打包時長為 10ms,啟用內置前向糾錯。a=sendrecv
/a=sendonly
/a=recvonly
:媒體流的方向(發送、接收或雙向)。
4. 安全描述(Security Descriptions)
WebRTC 強制加密傳輸,安全描述用于身份認證和加密協商,核心屬性:
a=ice-ufrag:<value>
/a=ice-pwd:<value>
:ICE 協商的用戶名和密碼(用于驗證 ICE 候選地址的合法性)。a=fingerprint:<hash> <value>
:DTLS 指紋(基于公鑰生成,用于驗證對方身份,防止中間人攻擊)。a=crypto:<tag> <crypto-suite> <key-params>
:加密套件(如AES_CM_128_HMAC_SHA1_80
)。
5. 服務質量描述(QoS & Grouping Descriptions)
確保音視頻傳輸的穩定性和質量,核心屬性:
a=rtcp-fb:<payload> <feedback>
:RTCP 反饋機制(用于質量控制)。
例:a=rtcp-fb:96 nack
表示支持丟包重傳;a=rtcp-fb:96 goog-remb
啟用 Google 的帶寬估算算法(動態調整發送碼率)。a=rtcp-mux
:RTP 和 RTCP 復用同一端口(節省端口資源)。a=group:<semantics> <mid-list>
:將關聯的媒體流分組(如音視頻同步)。
3.3 SDP協議解析
以下是一個簡化的 WebRTC SDP 示例,包含音頻和視頻流的完整描述:
//============= 會話描述(Session Level):作用于整個會話,包含全局信息 ====================
v=0 // SDP版本號,WebRTC中固定為0(遵循標準SDP規范)
o=- 7017624586836067756 2 IN IP4 127.0.0.1 // 會話發起者信息// -:忽略用戶名;7017624586836067756:會話唯一標識(NTP時間戳);2:會話版本(修改后遞增)// IN:網絡類型(互聯網);IP4:地址類型;127.0.0.1:發起者本地IP(實際通過ICE協商真實地址)
s=- // 會話名稱,WebRTC中簡化為“-”(無實際業務含義)
t=0 0 // 會話活躍時間,0 0表示“持久會話”(實時通信無固定結束時間)
... // 其他會話級擴展字段//================ 媒體描述(Media Level):按音頻、視頻分別定義 =================
//================ 音頻媒體描述 =================
/*
* 音頻媒體基礎信息:定義傳輸協議、端口和支持的負載類型
* 1024:傳輸端口(實際由ICE協商確定,此處為占位符)
* UDP/TLS/RTP/SAVPF:傳輸協議鏈(UDP底層,TLS建立DTLS,RTP傳媒體,SRTP加密+反饋)
* 111、103...:支持的音頻負載類型(對應不同編解碼器)
*/
m=audio 1024 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 126//============== 音頻網絡描述 ==================
// 接收/發送音頻的IP地址,WebRTC中被ICE候選地址覆蓋,此處為占位
c=IN IP4 0.0.0.0
// RTCP控制報文的地址和端口,WebRTC中通常與RTP復用端口(a=rtcp-mux),此處無效
a=rtcp:9 IN IP4 0.0.0.0
... // 其他網絡擴展字段(如ICE候選地址a=candidate)//============== 音頻安全描述 ================
// ICE協商的安全驗證信息(防止惡意接入)
a=ice-ufrag:khLS // ICE用戶名(用于驗證候選地址合法性)
a=ice-pwd:cxLzteJaJBou3DspNaPsJhlQ // ICE密碼(與用戶名配合驗證)
// DTLS指紋(基于公鑰生成,用于對端身份驗證,防止中間人攻擊)
a=fingerprint:sha-256 FA:14:42:3B:C7:97:1B:E8:AE:0C2:71:03:05:05:16:8F:B9:C7:98:E9:60:43:4B:5B:2C:28:EE:5C:8F3:17
... // 其他安全擴展字段(如加密套件a=crypto)//============== 音頻流媒體描述(編解碼器信息) ================
// 映射負載類型111到OPUS編碼:48000=采樣率(Hz);2=雙聲道
a=rtpmap:111 opus/48000/2
// OPUS編碼參數:minptime=10(最小打包時長10ms,減少延遲);useinbandfec=1(啟用內置前向糾錯,抗丟包)
a=fmtp:111 minptime=10;useinbandfec=1
... // 其他OPUS擴展參數
// 映射負載類型103到ISAC編碼(16kHz采樣率,單聲道)
a=rtpmap:103 ISAC/16000
// 映射負載類型104到ISAC編碼(32kHz采樣率,單聲道)
a=rtpmap:104 ISAC/32000
// 映射負載類型9到G722編碼(8kHz采樣率)
a=rtpmap:9 G722/8000
... // 其他音頻編解碼器描述//================= 視頻媒體描述 =================
// 視頻媒體基礎信息:9=端口占位符;100、101...=支持的視頻負載類型
m=video 9 UDP/TLS/RTP/SAVPF 100 101 107 116 117 96 97 99 98
... // 其他視頻基礎擴展字段//================= 視頻網絡描述 =================
// 視頻接收/發送IP地址,同音頻,被ICE候選地址覆蓋
c=IN IP4 0.0.0.0
// 視頻RTCP地址和端口,同音頻,無效
a=rtcp:9 IN IP4 0.0.0.0
... // 其他視頻網絡擴展字段(如ICE候選地址)//================= 視頻安全描述 =================
// 與音頻共享ICE憑證和DTLS指紋(同一會話安全參數一致)
a=ice-ufrag:khLS
a=ice-pwd:cxLzteJaJBou3DspNaPsJhlQ
a=fingerprint:sha-256 FA:14:42:3B:C7:97:1B:E8:AE:0C2:71:03:05:05:16:8F:B9:C7:98:E9:60:43:4B:5B:2C:28:EE:5C:8F3:17
... // 其他視頻安全擴展字段//================ 視頻流描述 ===============
a=mid:video // 媒體ID(用于區分音頻/視頻流,如mid:audio對應音頻)
... // 其他視頻流擴展字段(如方向a=sendrecv)
// 映射負載類型100到VP8視頻編碼:90000=時鐘頻率(視頻RTP標準時鐘,與幀率無關)
a=rtpmap:100 VP8/90000 //================ 視頻服務質量描述(QoS):通過RTCP反饋控制傳輸質量 ===============
// 支持完整幀請求(FIR):解碼器初始化或出錯時,請求發送方生成關鍵幀(如IDR幀)
a=rtcp-fb:100 ccm fir
// 支持否定確認(NACK):接收方發現丟包時,請求重傳丟失的RTP包
a=rtcp-fb:100 nack // 參考rfc4585
// 支持圖片丟失指示(PLI):類似FIR,用于請求關鍵幀
a=rtcp-fb:100 nack pli
// 啟用Google帶寬估計(REMB):接收方通過RTCP告知可用帶寬,發送方動態調整碼率
a=rtcp-fb:100 goog-remb
// 啟用傳輸擁塞控制(Transport-CC):通過RTCP反饋包到達時間,估算擁塞并調整發送策略
a=rtcp-fb:100 transport-cc
... // 其他視頻QoS擴展字段
-
從上面這段 SDP 中你應該可以總結出:SDP 是由一個會話層和多個媒體層組成的,而對于每個媒體層,WebRTC 又將其細劃為四部分,即媒體流、網絡描述、安全描述和服務質量描述。
-
并且在上面的例子中有兩個媒體層——音頻媒體層和視頻媒體層,而對于每個媒體層,也都有對應的媒體流描述、網絡描述、安全描述及服務質量描述
四、Candidate
4.1 Candidate 介紹
在 WebRTC 中,ICE Candidate(ICE 候選者) 是實現端到端連接的核心網絡信息載體,用于描述通信雙方可能的網絡連接端點(包含 IP、端口、協議等關鍵信息)。ICE(Interactive Connectivity Establishment,交互式連接建立)協議通過收集、排序和驗證這些候選者,最終建立高效且可靠的連接
4.2 ICE Candidate 結構
ICE Candidate 是 WebRTC 用于標識 “通信端點” 的結構化信息,包含建立網絡連接所需的全部關鍵參數
字段 | 含義 |
---|---|
IP | 通信使用的 IP 地址(IPv4 或 IPv6),如內網 IP(host 類型)、外網 IP(srflx 類型)等。 |
port | 傳輸端口(UDP 為主,WebRTC 默認優先 UDP)。 |
type | 候選者類型,分為host (主機)、srflx (服務器反射)、relay (中繼)。 |
priority | 優先級數值(整數),用于排序連接嘗試順序(值越高優先級越高)。 |
protocol | 傳輸協議(通常為 UDP,部分場景支持 TCP)。 |
usernameFragment | 用于 ICE 驗證的用戶名片段(與ice-ufrag 配合,防止惡意連接)。 |
foundation | 候選者的基礎標識(同一網絡接口的候選者可能共享該值)。 |
WebRTC 將 Candidate 分為三類,按優先級從高到低排序,確保優先使用高效連接(如局域網), fallback(降級)到可靠連接(如中繼)。
1. host
類型(主機候選者)
- 含義:本機內網的 IP 地址和端口,直接綁定到本地網卡(如
192.168.1.100:5000
)。 - 來源:WebRTC 啟動時自動掃描本機所有網卡(有線、無線、虛擬機等),收集所有活躍的內網 IP 和隨機端口(通常為 UDP 端口)。
- 優先級:最高(通常優先級數值在
1.2e9
左右)。 - 適用場景:通信雙方在同一局域網(如同一 WiFi 下的兩臺設備),可直接通過內網 IP 建立連接,延遲最低(通常 < 10ms)。
2. srflx
類型(服務器反射候選者)
- 含義:內網主機通過 NAT(網絡地址轉換)映射后的外網 IP 和端口(如
203.0.113.5:6000
,對應內網192.168.1.100:5000
)。 - 來源:通過STUN 協議(RFC5389)從公網 STUN 服務器獲取:
- 內網主機向 STUN 服務器發送
Binding Request
請求; - STUN 服務器收到請求后,提取其公網側的 IP 和端口(即 NAT 映射后的地址),通過
Binding Response
返回給主機; - 主機解析響應,得到
srflx
類型候選者。
- 內網主機向 STUN 服務器發送
- 優先級:次高(通常優先級數值在
1e9
左右)。 - 適用場景:通信雙方處于不同內網(跨 NAT),但可通過 NAT 打洞(P2P 穿越)直接通信。例如,家庭 WiFi 內的設備與公司內網設備通過各自的
srflx
候選者建立 P2P 連接,避免中繼帶來的延遲。
STUN 協議
srflx 類型的 Candidate 實際上就是內網地址和端口經NAT映射后的外網地址和端口。如下圖所示:
-
你應該知道,如果主機沒有公網地址,是無論如何都無法訪問公網上的資源的。例如你要通過百度搜索一些信息,如果你的主機沒有公網地址的話,百度搜索到的結果怎么傳給你呢?
-
而一般情況下,主機都只有內網 IP 和端口,那它是如何訪問外網資源的呢?實際上,在內網的網關上都有 NAT (NetAddress Transport) 功能,NAT 的作用就是進行內外網的地址轉換。這樣當你要訪問公網上的資源時,NAT 首先會將該主機的內網地址轉換成外網地址,然后才會將請求發送給要訪問的服務器服務器處理好后將結果返回給主機的公網地址和端口,再通過 NAT 最終中轉給內網的主機。
-
知道了上面的原理,你要想讓內網主機獲得它的外網 IP 地址也就好辦了,只需要在公網上架設一臺服務器,并向這臺服務器發個請求說: “Hi!伙計,你看我是誰?”對方回: “你不是那 xxxx 嗎?”這樣你就可以知道自己的公網 IP了,是不是很簡單?
-
實際上,上面的描述已經被定義成了一套規范,即 RFC5389 ,也就是 STUN 協議,我們只要遵守這個協議就可以拿到自己的公網 IP 了
這里我們舉個例子,看看通過 STUN 協議,主機是如何獲取到自己的外網 IP 地址和端口的:
-
首先在外網搭建一個 STUN 服務器,現在比較流行的 STUN 服務器是coturn,你可以到 GitHub 上自己下載源碼編譯安裝。
-
當 STUN 服務器安裝好后,從內網主機發送一個 binding request 的 STUN 消息到 STUN 服務器。
-
STUN 服務器收到該請求后,會將請求的 IP 地址和端口填充到 binding response 消息中,然后順原路將該消息返回給內網主機。此時,收到 binding response 消息的內網主機就可以解析 binding response 消息了,并可以從中得到自己的外網 IP 和端口。
3. relay
類型(中繼候選者)
- 含義:中繼服務器(TURN 服務器)的 IP 和端口,用于中轉通信數據(如
167.71.240.3:7000
)。 - 來源:通過TURN 協議(RFC5766,基于 STUN 擴展)從 TURN 服務器獲取:
- 內網主機向 TURN 服務器發送
Allocation Request
請求,申請中繼資源; - TURN 服務器分配一個專屬端口,用于中轉該主機的所有數據,并將該端口的 IP 和端口通過響應返回;
- 主機解析響應,得到
relay
類型候選者。
- 內網主機向 TURN 服務器發送
- 優先級:最低(通常優先級數值在
2e8
左右)。 - 適用場景:當
host
和srflx
候選者均無法建立連接(如對稱型 NAT 之間無法打洞),則通過 TURN 服務器中轉數據,確保連通性(代價是延遲較高,通常比 P2P 高 50-200ms)。
TURN 協議
這里需要說明一點,relay 服務是通過 TURN 協議實現的。所以我們經常說的 relay 服務器或 TURN 服務器它們是同一個意思,都是指中繼服務器。
知道了內網主機如何通過 STUN 協議獲取到 srflx 類型的候選者后,那么中繼類型候選者,即 relay型的 Candidate 又是如何獲取的呢?下面我們就來看一下:
-
首先你要清楚,relay 型候選者的優先級與其他類型相比是最低的,但在其他候選者都無法連通的情況下,relay 候選者就成了最好的選擇。因為它的連通率是所有候選者中連通率最高的。
-
其實,relay 型候選者的獲取也是通過 STUN 協議完成的,只不過它使用的 STUN 消息類型與獲取 srflx 型候選者的STUN 消息的類型不一樣而已。
-
RFC5766 的 TURN 協議描述了如何獲取 relay 服務器(即 TURN 服務器)的 Candidate 過程。其中最主要的是Allocation 指令。通過向 TURN 服務器發送 Allocation 指令,relay 服務就會在服務器端分配一個新的 relay 端口,用于中轉 UDP 數據報。
不過這里我只是簡要描述了下,如果你對這塊感興趣的話,可以直接查看 RFC5766 以了解更多的細節。
NAT 打洞 /P2P 穿越
當收集到 Candidate 后,WebRTC 就開始按優先級順序進行連通性檢測了:
-
它首先會判斷兩臺主機是否處于同一個局域網內,如果雙方確實是在同一局域網內,那么就直接在它們之間建立一條連接。
-
但如果兩臺主機不在同一個內網,WebRTC 將嘗試NAT 打洞,即 P2P 穿越。在 WebRTC 中,NAT 打洞是極其復雜的過程,它首先需要對 NAT 類型做判斷,檢測出其類型后,才能判斷出是否可以打洞成功,只有存在打洞成功的可能性時才會真正嘗試打洞。
WebRTC 將 NAT 分類為 4 種類型,分別是:
- 完全錐型 NAT
- IP 限制型 NAT
- 端口限制型 NAT
- 對稱型 NAT
需要記住的是,對稱型 NAT 與對稱型 NAT 是無法進行 P2P 穿越的;而對稱型 NAT 與端口限制型 NAT 也是無法進行 P2P 連接的
ICE
ICE 就是上面所講的獲取各種類型 Candidate 的過程,也就是:
- 在本機收集所有的 host 類型的 Candidate
- 通過 STUN 協議收集 srflx 類型的 Candidate
- 通過 TURN 協議收集 relay 類型的 Candidate。
在整個過程中,WebRTC 使用優先級的方法去建立連接,即局域網內的優先級最高,其次是 NAT 穿越,再次是通過中繼服務器進行中轉,這樣就巧妙地實現了“既要高效傳輸,又能保證連通率”這個目標。
更多資料:https://github.com/0voice