WebRTC中SDP是怎樣的
WebRTC中SDP是怎樣的,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
WebRTC 是 Web Real-Time Communication,即網頁實時通信的縮寫,是 RTC 協議的一種 Web 實現,項目由 Google 開源,并和 IETF 和 W3C 制定了行業標準。在國內 WebRTC 已經獲得了越來越多廠商的支持,應用前景變得更加廣闊,所以我們也開設專欄,分享阿里云內部的 WebRTC 研究工作。

Overview
狹義的說 WebRTC 是指瀏覽器端,瀏覽器端如何直接交換數據呢?肯定是沒法完全獨立完成的,必須得依靠服務器。一般依賴幾種服務器:
Signaling 信令服務器,也就是交換房間和會議的媒體信息,以及會議期間的消息,媒體描述使用的是 SDP 協議,也就是本文剖析的重點。
ICE 服務器,可以分為幫助兩個客戶端打洞建立 P2P 連接的 STUN 服務器,還有如果連不通就直接轉發的 TURN 服務器。ICE 的信息叫 Candidate,可以通過 SDP 交換,或者通過 Trickle。
SFU 或 MCU 服務器,如果多個人開會,每個端都向其他參會的端直接發送數據叫 MESH,但是 MESH 明顯有局限性,SFU 就是轉發可以讓客戶端只上行一路流轉給其他客戶端,而 MCU 更強大,可以上下行都只有一路流。
Note: WebRTC 除了傳輸,還有一個重要特性就是安全性,也就是 DTLS,而 DTLS 有些信息就是通過 SDP 傳遞的,后面會有相關的技術文章來介紹 DTLS。
下面,我們正式介紹 SDP 協議。
What's SDP
本文開篇的 SDP 關鍵屬性圖,已經幫助我們以全局的視角一窺 SDP 的模樣。SDP 描述了媒體會話,網絡信息、安全特性、傳輸策略等,圖中的每一個 SDP 屬性都在不同的應用場景下發揮著不同的作用,不可小覷。
接下來,我們進一步給出 SDP 的官方定義:SDP(Session Description Protocol) 是一種會話描述協議,基于文本,其本身并不屬于傳輸協議,需要依賴其它的傳輸協議(比如 SIP 和 HTTP)來交換必要的媒體信息,用于兩個會話實體之間的媒體協商。
WebRTC 的 Offer 和 Answer 包含了 SDP。相關的 RFC 包括:
1998, RFC2327
2006, RFC4566
一個不錯的 WebRTC 的 SDP 例子分析
Offer and Answer
WebRTC 使用 Offer-Answer 模型交換 SDP,Offer 中有 SDP,Answer 中也有。例如 Alice 和 Bob 通過 WebRTC 通信:
// Alice Offer
v=0
o=- 2397106153131073818 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE video
a=msid-semantic: WMS gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS
m=video 9 UDP/TLS/RTP/SAVPF 96 97
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:l5KU
a=ice-pwd:+Sxmm3PoJUERpeHYL0HW4/T9
a=ice-options:trickle
a=fingerprint:sha-256 7C:93:85:40:01:07:91:BE:DA:64:A0:37:7E:61:CB:9D:91:9B:44:F6:C9:AC:3B:37:1C:00:15:4C:5A:B5:67:74
a=setup:actpass
a=mid:video
a=sendrecv
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=ssrc-group:FID 2527104241
a=ssrc:2527104241 cname:JPmKBgFHH5YVFyaJ
a=ssrc:2527104241 msid:gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS c7072509-df47-4828-ad03-7d0274585a56
a=ssrc:2527104241 mslabel:gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS
a=ssrc:2527104241 label:c7072509-df47-4828-ad03-7d0274585a56
// Bob Answer
v=0
o=- 5443219974135798586 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE video
a=msid-semantic: WMS uiZ7cB0hsFDRGgTIMNp6TajUK9dOoHi43HVs
m=video 9 UDP/TLS/RTP/SAVPF 96 97
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:MUZf
a=ice-pwd:4QhikLcmGXnCfAzHDB++ZjM5
a=ice-options:trickle
a=fingerprint:sha-256 2A:5A:B8:43:66:05:B3:6A:E9:46:36:DF:DF:20:11:6A:F6:11:EA:D9:4E:26:E3:CE:5A:3A:C6:8D:03:49:7B:DE
a=setup:active
a=mid:video
a=sendrecv
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=ssrc-group:FID 3587783331
a=ssrc:3587783331 cname:INxZnBV2Sty1zlmN
a=ssrc:3587783331 msid:uiZ7cB0hsFDRGgTIMNp6TajUK9dOoHi43HVs a3b297e7-cdbe-464e-a32c-347465ace055
a=ssrc:3587783331 mslabel:uiZ7cB0hsFDRGgTIMNp6TajUK9dOoHi43HVs
a=ssrc:3587783331 label:a3b297e7-cdbe-464e-a32c-347465ace055
Remark: 用 Chrome 瀏覽器,先打開 webrtc-internals,然后打開 Alice 頁面點 Share 按鈕,接著打開 Bob 頁面點 Share,看到上面的 Offer 和 Answer。
交換完 SDP 后,會交換 Candidate:
// Alice Candidate
candidate: candidate:1912876010 1 udp 2122260223 30.2.220.94 52832 typ host generation 0 ufrag l5KU network-id 1 network-cost 10
candidate: candidate:1015535386 1 tcp 1518280447 30.2.220.94 9 typ host tcptype active generation 0 ufrag l5KU network-id 1 network-cost 10
// Bob Candidate
candidate:1912876010 1 udp 2122260223 30.2.220.94 51551 typ host generation 0 ufrag MUZf network-id 1 network-cost 10
最后 Alice 和 Bob 通信的 Candidate pair,選擇的是 UDP 通道:

Alice 發送的 Video 的信息:

Alice 收到的 (Bob 的) Video信息:

一般來說,推流方先發起 Offer,接收方給 Answer。比如客戶端推流到 SFU,客戶端發起 Offer 推流,SFU 給客戶端 Answer,客戶端將流推到 SFU,SFU 再轉發給其他客戶端。Licode 和 Janus 都是這種做法,這種方式下,如果客戶端需要拉取其他的客戶端的流,一般需要使用另外的 PeerConnection,接收 SFU 的 Offer,生成 Answer 后回應給 SFU。
不過,推流方發起 Offer 不是必須的,接收方也可以給 Offer,推流方給 Answer。比如 MediaSoup 這種 SFU,客戶端先給一個 Offer 給 SFU,SFU 只是檢查這個 Offer 中的媒體特性,然后 SFU 會生成 Offer(包含會議中的其他客戶端的流,如果沒有人則沒有 SSRC)給客戶端,客戶端發送 Answer 給 SFU。這種方式的好處是其他客戶端加入,以及流的變更(比如關閉視頻打開視頻時),都可以使用 Reoffer,也就是統一由 SFU 發起新的 Offer,客戶端響應,SFU 和客戶端的交互模式只有一種。
SDP Structure
SDP 描述分為兩部分,分別是會話級別的描述(session level)和媒體級別的描述(media level),其具體的組成可參考 RFC4566,帶星號 (*) 的是可選的。常見的內容如下:
Session description(會話級別描述)
v= (protocol version)
o= (originator and session identifier)
s= (session name)
c=* (connection information -- not required if included in all media)
One or more Time descriptions ("t=" and "r=" lines; see below)
a=* (zero or more session attribute lines)
Zero or more Media descriptions
Time description
t= (time the session is active)
Media description(媒體級別描述), if present
m= (media name and transport address)
c=* (connection information -- optional if included at session level)
a=* (zero or more media attribute lines)
對照 Alice 的 Offer(只包含了視頻沒有開啟音頻):
// Session description
v=0
o=- 2397106153131073818 2 IN IP4 127.0.0.1
s=-
c=IN IP4 0.0.0.0
// Time description
t=0 0
// Session Attributes
a=group:BUNDLE video
a=msid-semantic: WMS gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS
// Media description
m=video 9 UDP/TLS/RTP/SAVPF 96 97
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:l5KU
a=ice-pwd:+Sxmm3PoJUERpeHYL0HW4/T9
a=ice-options:trickle
a=fingerprint:sha-256 7C:93:85:40:01:07:91:BE:DA:64:A0:37:7E:61:CB:9D:91:9B:44:F6:C9:AC:3B:37:1C:00:15:4C:5A:B5:67:74
a=setup:actpass
a=mid:video
a=sendrecv
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=ssrc-group:FID 2527104241
a=ssrc:2527104241 cname:JPmKBgFHH5YVFyaJ
a=ssrc:2527104241 msid:gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS c7072509-df47-4828-ad03-7d0274585a56
a=ssrc:2527104241 mslabel:gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS
a=ssrc:2527104241 label:c7072509-df47-4828-ad03-7d0274585a56
SDP Line 是順序相關的,比如 a=rtpmap:96
后面的都是它相關的設置,直到下一行是a=rtpmap
或者其他屬性。
SDP Line 沒有統一的 Schema 描述,也就是沒有一個固定的規則能解析所有 Line,SDP Grammer 只是描述了 SDP 相關的屬性,具體每個屬性的表達需要根據屬性定義,定義在 RFC 4566,例如:
a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
SDP 解析時,每個 SDP Line 都是以 key=...
形式,解析出 key 是 a 后,可能有兩種方式,可參考 RFC4566:
a=<attribute>
a=<attribute>:<value>
比如 c=IN IP4 0.0.0.0,key 為 c。 比如 a=rtcp-mux,key 為 a,attribute 為 rtcp-mux,沒有 value。 比如 a=rtpmap:96 VP8/90000,key 為 a,attribute 為 rtpmap,value=96 VP8/90000。
有時候并非冒號 (:) 就一定是 <attribute>:<value>
,實際上 value 里面也會有冒號,比如:
a=fingerprint:sha-256 7C:93:85:40:01:07:91:BE
a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=ssrc:2527104241 msid:gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS
Session Level Field
會話級別的 SDP 描述字段包括:v、o、s、c、b、t。
v(version) SDP 協議版本,值固定為 0。
o(origin) 代表會話的發起者。
s(session name) 會話的名稱,每個 SDP 中有且僅能有一個 s 描述,其值不能為空。
c(connection data) 攜帶了會話的連接信息,其實就是 IP 地址。 SDP 的會話級別描述可以包含該字段,每一個媒體級別的描述也可以包含該字段,如果會話級別和媒體級別都有 c line,那么以媒體級別的 c line 為準。 因為 WebRTC 使用 ICE candidate 交換地址信息,所以不會用到 c line,不過這并不代表 c line 沒有用,在 SIP 視頻會議場景中,c line 就必不可少了,文末會再次介紹該字段。
b (bandwidth) 表示會話或媒體使用的建議帶寬。
t(timing) 指定了會話的開始和結束時間,如果開始和結束時間都為 0,那么意味著這次會話是永久的。
關于會話級別字段的更詳細的描述,請參考 RFC 4566。
Media Codecs
會話級別描述完成后,后面就是零到多個媒體級別描述,比如:
// Session Description
v=0
......
// Audio Media Description
m=audio 9 UDP/TLS/RTP/SAVPF 111
......
// Video Media Description
m=video 9 UDP/TLS/RTP/SAVPF 96 97
......
這個 SDP 描述了一個音頻和一個視頻,它的格式參考 RFC4566:
m=<media> <port> <proto> <fmt> ...
其中,后面的一串數字 111
和 96 97
就是 fmt,分別代表音頻和視頻的 Media Codec,后面會跟著 rtpmap、rtcp-fb、fmtp 這些屬性來做進一步的詳細的描述。
m=audio 9 UDP/TLS/RTP/SAVPF 111
a=mid:audio
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
m=video 9 UDP/TLS/RTP/SAVPF 96 97
a=mid:video
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
Remark: 當然,M line 的類型不是只有 audio 和 video,還有 application(bfcp)、text 等媒體類型。
Remark: a=mid 屬性可以認為是每個 M 描述的唯一 ID。比如 a=mid:audio,那么 audio
這個字符串就是這個 M 描述的 ID。有的時候 mid 屬性值也可以用數字表示,比如 a=mid:0,那么 0 也是這個 M 描述的 ID。mid 值一般和 grouping 傳輸屬性的 BUNDLE 策略結合來用,比如 a=group:BUNDLE audio video,代表本次會話將對 mid 為 audio
和 video
的 M 描述進行復用傳輸。
Remark: M line 的數字 9 代表該媒體類型的傳輸端口,在 RTC 場景中都是使用 ICE candidate 的地址信息進行數據傳輸,所以 M line 的 port 并沒有用到。不過,在 SIP 的場景下,M line 的 port 就十分重要了,此時,port 代表 RTP 端口,而且必須是偶數。結合 SDP 會話級別描述中的 C line 中的 IP 地址,我們就可以知道 SIP 的這路媒體流的傳輸地址。
Remark: RTX 表示是重傳,比如 video 的 97,就是 apt=96 的重傳。也就是說如果用的是 97 這個編碼格式,它是在 96(VP8) 基礎上加了重傳功能。
而一共有多少媒體流,則是通過 SSRC 指定的:
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
a=ssrc:2582129002 cname:8Y1pmIKBijmWeALu
a=ssrc:2582129002 msid:34fD1qguf2v79436S1khLkth8Nb6LbedcF9H bab38910-40cd-4581-9a20-e3f558abb397
a=ssrc:2582129002 mslabel:34fD1qguf2v79436S1khLkth8Nb6LbedcF9H
a=ssrc:2582129002 label:bab38910-40cd-4581-9a20-e3f558abb397
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 123 127 122 125 107 108 109 124
a=ssrc:565530905 cname:8Y1pmIKBijmWeALu
a=ssrc:565530905 msid:34fD1qguf2v79436S1khLkth8Nb6LbedcF9H 2c533cfe-b6bf-41a8-93f0-1ca031436702
a=ssrc:565530905 mslabel:34fD1qguf2v79436S1khLkth8Nb6LbedcF9H
a=ssrc:565530905 label:2c533cfe-b6bf-41a8-93f0-1ca031436702
Remark: SSRC 就包含了需要發送的媒體流,另外 Offer 和 Answer 中都可以包含 SSRC。比如客戶端和 MediaSoup 通信時,MediaSoup 總是給客戶端發 Offer,MediaSoup 的 Offer 包含了 MediaSoup 要發送(轉發其他客戶端的流給客戶端)的媒體流 SSRC,同時客戶端的 Answer 中也包含了自己要推送的 SSRC 流,他們的類型都是 sendrecv。
Remark: msid 對應了NetStream.id,也就是代表了不同的媒體源,這些 SSRC 可以是不同的媒體源。
如何確定最后的編碼?對方會在 Answer 中給出,比如上面 Offer 給出了多個編碼,在 Answer 中會選擇一個:
m=audio 9 UDP/TLS/RTP/SAVPF 111
m=video 9 UDP/TLS/RTP/SAVPF 100 102 127 125 108 124
a=rtpmap:100 H264/90000
a=rtpmap:102 H264/90000
a=rtpmap:127 H264/90000
a=rtpmap:125 H264/90000
a=rtpmap:108 red/90000
a=rtpmap:124 ulpfec/90000
雖然 Video 編碼有 100 到 125,但是他們都是 H.264,而 108 和 124 則是 FEC,基于 H.264。
PlanB and UnifiedPlan
上面的 MediaCodecs 中,沒有規定如何指定多條流。實際上 Audio 和 Video 都有多個 SSRC,每個 SSRC 的編碼可能相同但也可能不同。比如互聯網視頻會議,用移動端接入時,編碼可能都是 H.264,但是和其他終端接入時可能會有其他編碼。
如果 SSRC 的編碼不相同,那么將這些 SSRC 放在同一個 M 描述就會有問題,這就是 PlanB 和 UnifiedPlan 的關鍵所在。對于 PlanB 只有一個 M(audio) 和 M(video),他們的編碼要相同,當有多路媒體流時,則根據 SSRC 去區分。UnifiedPlan 則可以有多個 M(audio) 和 M(video),每路流都有自己的 M 描述,這樣就可以支持不同的編碼。
PlanB 和 UnifiedPlan 其實就是 WebRTC 在多路媒體源(multi media source)場景下的兩種不同的 SDP 協商方式。如果引入 Stream 和 Track 的概念,那么一個 Stream 可能包含 AudioTrack 和 VideoTrack,當有多路 Stream 時,就會有更多的 Track,如果每一個 Track 唯一對應一個自己的 M 描述,那么這就是 UnifiedPlan,如果每一個 M line 描述了多個 Track(track id),那么這就是 Plan B。
Note: 當只有一路音頻流和一路視頻流時,Plan B 和 UnifiedPlan 的格式是相互兼容的。
Remark: Chrome 早期支持的是 PlanB,目前最新版本也支持了 UnifiedPlan,參考 Need to implement WebRTC "Unified Plan" for multistream。
PlanB 參考下圖:

UnifiedPlan 參考下圖:

Candidate
Candidate 就是傳輸的候選人,客戶端會生成多個 Candidate,比如有 host 類型的、有 relay 類型的、有 UDP 和 TCP 的,如下圖所示:
sdpMid: audio, sdpMLineIndex: 0, candidate:2213672593 1 udp 2122260223 30.2.228.19 51068 typ host
sdpMid: video, sdpMLineIndex: 1, candidate:2213672593 1 udp 2122260223 30.2.228.19 55061 typ host
sdpMid: audio, sdpMLineIndex: 0, candidate:3446803041 1 tcp 1518280447 30.2.228.19 9 typ host
sdpMid: video, sdpMLineIndex: 1, candidate:3446803041 1 tcp 1518280447 30.2.228.19 9 typ host
sdpMid: video, sdpMLineIndex: 1, candidate:150963819 1 udp 41885439 182.92.80.26 54400 typ relay raddr 42.120.74.91 rport 37714
sdpMid: audio, sdpMLineIndex: 0, candidate:150963819 1 udp 41885439 182.92.80.26 59241 typ relay raddr 42.120.74.91 rport 49618
Remark: 我們去掉了后面的屬性,比如 generation 0 ufrag kce9 network-id 1 network-cost 10
,這些屬于 Candidate 的描述,和連通性檢查等相關。
客戶端自己生成了 6 個 Candidates,3 個 Audio 和 3 個 Video,2 個 TCP 和 4 個 UDP,4 個 host 和 2 個 relay。當然對方也會有很多 Candidate,接下來就是自己的 Candidates 和對方的 Candidates 匹配連通(ICE Connectivity Checks),形成 CandidatePair 也就是傳輸通道。Candidate 還附帶了網絡屬性,比如network-cost 會在 ICE Connectivity Checks 時用到。
Remark: 關于 Candidate 的類型,還有 srflx 以及 prflx,關于這兩種 Candidate 類型的定義以及區分,后面會在 ICE 相關的技術文章中介紹。
Remark: 關于 ICE Connectivity Checks 我們會在后面給出詳細的分析,涉及到了STUN協議。下面會總結出 ICE 相關的 SDP 信息。
SDP 和 Candidate 都是通過信令交換的。如果對方只給了 relay 的 Candidate,例如:
sdpMid: audio, sdpMLineIndex: 0, candidate:150963819 1 udp 41885439 182.92.80.26 51542 typ relay raddr 42.120.74.91 rport 56380
這種情況下,肯定最后連通的 CandidatePair 是 Relay 對 Relay,如下圖所示:


從這個圖中能看出來這個傳輸通道的發送和接收碼率、包的個數、RTT 和丟包率等信息。
實際上,由于我們這個客戶端還有 host 類型的 Candidate,所以它會嘗試直接用 host 的這個 Candidate 和對方的 relay 直接連接:
sdpMid: audio, sdpMLineIndex: 0, candidate:2213672593 1 udp 2122260223 30.2.228.19 51068 typ host
Statistics Conn-audio-1-1
googActiveConnection false

當然,由于沒有連通所以這個 CandidatePair 就不可用。
Remark: WebRTC 是具備在多個 Candidate 之間切換的能力的,具體在 ICE Connectivity Checks 中我們再分析。
上面的 Candidates 自己生成了 2 個 Relay 的 Candidates,一個是 audio 的一個是 video 的,為何只用到了audio 的呢?這就是下面的 BUNDLE 涉及的了。
Bundle and RTCP-MUX
傳輸時,可以復用媒體通道,一種是音頻和視頻的復用,一種是 RTCP 和 RTP 的復用。
RTCP 和 RTP 復用,表示 Sender 使用一個傳輸通道(單一端口)發送 RTP 和 RTCP:
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
a=rtcp-mux
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 123 127 122 125 107 108 109 124
a=rtcp-mux
此時,Receiver 必須準備好在 RTP 端口上接收 RTCP 數據,并需要預留一些資源,比如 RTCP 帶寬。
音頻和視頻復用時,最后只會用一個 Candidate 傳輸,比如客戶端自己的 SDP Offer,和兩個 relay 的Candidates:
a=group:BUNDLE audio video
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
a=mid:audio
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 123 127 122 125 107 108 109 124
a=mid:video
sdpMid: video, sdpMLineIndex: 1, candidate:150963819 1 udp 41885439 182.92.80.26 54400 typ relay raddr 42.120.74.91 rport 37714
sdpMid: audio, sdpMLineIndex: 0, candidate:150963819 1 udp 41885439 182.92.80.26 59241 typ relay raddr 42.120.74.91 rport 49618
這表示最終 audio 和 video 盡管可能有獨立的 Candidate,但是如果對方也是 BUNDLE,那么最終只會用一個 Candidate。例如,如果對方的 Answer 是:
a=group:BUNDLE audio video
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
a=mid:audio
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 123 127 122 125 107 108 109 124
a=mid:video
sdpMid: audio, sdpMLineIndex: 0, candidate:150963819 1 udp 41885439 182.92.80.26 51542 typ relay raddr 42.120.74.91 rport 56380
最后它們只會用一個 Candidate 傳輸。如下圖所示:

rtcp-mux 將 RTP 和 RTCP 復用到單一的端口進行傳輸,這簡化了 NAT traversal,而 BUNDLE 又將多路媒體流復用到同一端口進行傳輸,這不僅使 candidate harvesting 等 ICE 相關的 SDP 屬性變得簡單,而且又進一步簡化了 NAT traversal。
rtcp-mux 是與 RTC 傳輸相關的重要的 SDP 屬性,關于它的 SDP 協商的原則如下:
如果 Offer 攜帶 rtcp-mux 屬性,并且 Answer 方希望復用 RTP 和 RTCP 到單一端口,那么 Answer 必須也要攜帶該屬性。
如果 Offer 沒有攜帶 rtcp-mux 屬性,那么 Answer 也一定不能攜帶 rtcp-mux 屬性,而且 Answer 方禁止 RTP 和 RTCP 復用單一端口。
rtcp-mux 的協商和使用必須是雙向的。
舉個例子??蛻舳巳ビ嗛喎掌鞯牧?,客戶端的 Offer 沒有攜帶 rtcp-mux 屬性,那么服務器會認為客戶端不支持 rtcp-mux,也不會走 rtcp 復用的流程。相反,服務器會分別創建 RTP 和 RTCP 兩個傳輸通道,只有當兩個通道的 ICE 和 DTLS 都成功,才會認為本次訂閱的傳輸通道建立成功,繼而向客戶端發流。
試想,如果因為你的疏忽導致 Offer 漏掉了 rtcp-mux 屬性,那么你將永遠等不到服務器 Ready 的那一天。所以,SDP 看似只是一些文本,很簡單,但是只有在項目的實戰中,多遇到幾個坑,才能更深切的體會到 SDP 屬性的含義以及這些屬性是如何在 RTC 場景中去發揮作用的。
Remark: 關于 rtcp-mux 更詳細的協商細節請參考 RFC 8035。
Remark: 關于 rtcp-mux 場景下如何通過頭部字段區分 rtp 和 rtcp,請參考 RFC 5761。
ICE Connectivity
這里我們只說明 SDP 中和 ICE Connectivity Checks 相關的信息,具體的過程我們會在其他文章中單獨分析。
SDP 中和 ICE 相關的信息包括:
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
a=ice-ufrag:kce9
a=ice-pwd:M31WxfrwmrFvPws4+tPdbsCE
a=ice-options:trickle
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 123 127 122 125 107 108 109 124
a=ice-ufrag:kce9
a=ice-pwd:M31WxfrwmrFvPws4+tPdbsCE
a=ice-options:trickle
ufrag 和 pwd 就是 ICE short-term 認證算法用到的用戶名和密碼。而 trickle 說明 SDP 中沒有包含 candidate 信息,Candidate 是通過信令單獨交換的,這樣可以做到 Connectivity checks 和 Candidate harvesting 并行處理,提高會話建立的速度。
DTLS
国产第一页屁屁影院,免费看A片无码不卡福利视频,国产在视频线在精品视频2020,屁屁影院WWW免费版