參考:
- rfc4566
- https://segmentfault.com/a/1190000038272539
- https://www.cnblogs.com/chyingp/p/sdp-in-webrtc.html
1. 概述
SDP(Session Description Protocol,會話描述協議) 的具體標准定義在了 rfc4566 中。本篇文章主要以 rfc4566 為基礎,通過 webrtc offer/answer 協商中的 sdp 為例進行記錄,然后會對比與 sip 呼叫中 sdp 的一些異同。
2. 結構
sdp 是一行一行的文本,每一行之間使用 \n 或者 \r\n 來分割,所以如果要解析 sdp,那么代碼需要兼容這兩種分割方式。除開分隔符,其他都是可打印字符。
每一行中,采用 type=value 的結構,即使用 = 號進行分割。其中,type 必須為單個字符,而 value 則較為復雜,可以有多種不同格式,= 號之間不能存在空格。
2.1 總體結構
sdp 多個行之間會一起描述一個結構功能,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)
2.2 會話級別描述(Session description level)
會話描述總是在 sdp 的開頭,是必須存在的結構。以下面的會話描述為例,說明常見的每個字段:
v=0
o=- 1044094566052576507 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1
a=msid-semantic: WMS g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp
2.2.1 v(protocol version)
會話協議版本,rfc4566 固定了版本號為 0,即:
v=0
2.2.2 o(originator and session identifier)
會話發起者標識:
o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>
- username:發起者的用戶名,不允許存在空格,如果應用不支持用戶名,則為 -。
- sess-id:會話id,由應用自行定義,規范的建議是 NTP(Network Time Protocol) 時間戳。
- sess-version:會話版本,用途由應用自行定義,只要會話數據發生變化時(比如編碼),sess-version 隨着遞增就行。同樣的,規范的建議是 NTP 時間戳。
- nettype:網絡類型,比如 IN 表示 Internet。
- addrtype:地址類型,比如 IP4、IV6。
- unicast-address:域名,或者 IP 地址。
2.2.3 s(session name)
會話名,沒有具體設置可為 -:
s=-
2.2.4 t(timing)
聲明會話的開始時間和結束時間:
t=<start-time> <stop-time>
如果開始和結束時間都為 0,那么意味着這次會話是永久的。
2.2.5 a(attribute)
a 開頭的表示附加屬性,用於擴展 sdp,有如下兩種格式:
a=<attribute>
a=<attribute>:<value>
a 開頭的行不僅會出現在 session level 中,也會出現在 media level 中(后文將展示)。
2.3 媒體級別描述(Media description level)
會話描述結束后,接着是媒體描述。在sdp中,可能有多個媒體描述,每個媒體描述由 m= 行開始。不同於 session level,media level 中的一些不同行,會有明確的先后關系,不能亂序,而 session level 中的大部分行可以任意排列。以下面的媒體描述為例,說明常見的字段:
m=audio 9 UDP/TLS/RTP/SAVPF 111 103
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:Fyzi
a=ice-pwd:/NDZTbh8NX+BTFjRyZy7Heqc
a=ice-options:trickle
a=fingerprint:sha-256 60:DF:D2:8E:AC:1B:7C:DB:DA:36:39:57:AA:DD:1A:C2:43:58:36:09:80:56:CA:18:F4:85:6B:9F:B1:8F:78:13
a=setup:actpass
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=sendonly
a=msid:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp 13eb9491-262e-4982-9aea-1c6af9e8ef22
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:103 ISAC/16000
a=ssrc:724846199 cname:wJobAtYmVV7u5Y3x
a=ssrc:724846199 msid:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp 13eb9491-262e-4982-9aea-1c6af9e8ef22
a=ssrc:724846199 mslabel:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp
2.3.1 m=(Media Descriptions)
媒體描述起始行:
m=<media> <port> <proto> <fmt> ...
- media:媒體類型。支持包括 video、audio、text、application(bfcp) 等。
- port:流媒體傳輸端口。具體含義取決於使用的網絡類型(在 c= 中聲明)和使用的協議(proto,在 m= 中聲明)。
- proto:流媒體傳輸協議。具體含義取決於 c= 中定義的地址類型,比如 c= 是 IP4,那么這里的傳輸協議運行在 IP4 之上。以 UDP/TLS/RTP/SAVPF 為例:
- UDP:傳輸層協議是UDP。
- TLS:加密傳輸基於 DTLS 協議。
- RTP:使用 rtp 協議傳輸媒體。
- SAVPF:使用 SRTP 協議對 RTP 媒體負載進行加密。如果是 AVPF 或 AVP,表示不對 RTP 中的媒體負載進行加密。AVPF與AVP的區別,見 rfc4585 文檔(webrtc 一般用 AVPF,sip 一般用 AVP)。
- fmt:媒體格式的描述,可能有多個。根據 proto 的不同,fmt 的含義也不同。比如 proto 為 RTP/AVP 時,fmt 表示 RTP payload 的類型。如果有多個,表示在這次會話中,多種 payload 類型都可能會用到。
2.3.2 c=(Connection Data)
會話連接信息。此字段也可以只出現在 session level 中,或者只在 media level 中,也可以都出現:
c=<nettype> <addrtype> <connection-address>
- nettype:網絡類型,比如IN,表示 Internet。
- addrtype:地址類型,比如IP4、IP6。
- connection-address:如果是廣播,則為廣播地址組;如果是單播,則為單播地址。
2.4 group bundle 與 mid
在 webrtc 中,a=group:BUNDLE 行用於綁定不同的 media level,而每個 media level 都會有一個 mid 字段,用於媒體行標識:
// Session Description
a=group:BUNDLE 0 1
...
// Audio Media Description
a=mid 0
...
// Video Media Description
a=mid 1
...
每個媒體行都可以創建一個自己的網絡連接,用於傳遞音視頻和 rtcp 數據。會話綁定媒體行的意義是,不同媒體行可以復用同一個網絡連接進行數據傳輸。
2.5 ICE(Interactive Connectivity Establishment)
媒體協商完成后,webrtc 雙方要做的第一件事就是建立網絡連接,而 ice 協議(參考 rfc5245)定義了 webrtc 建立網絡連接的方式,反應在 sdp 中,有如下字段:
...
a=ice-ufrag:Fyzi
a=ice-pwd:/NDZTbh8NX+BTFjRyZy7Heqc
a=ice-options:trickle
a=ice-lite
...
- ice-ufrag 和 ice-pwd 用於 ice 中 stun 消息的認證
- ice-options:trickle 表明本端支持獨立發送 candidates 和 sdp,參考 https://tools.ietf.org/id/draft-ietf-ice-trickle-16.html
- ice-lite 表明本端不會做連通性檢查(本端只會回應 stun binding response)
這些 ice 字段可以出現在所有的 media level 中,如果 sdp 指定了 group:bundle,則綁定的 media level 中,ice 字段應該都相同。
2.5.1 candidate(地址候選項)
地址候選項可以出現在 sdp 中,也可以單獨通過 http、websocket 等類似發送 sdp 的方式發送給對端(來自 rfc5245 15.1,更改了排列格式,SP 表示空格):
candidate-attribute="candidate:" foundation SP component-id SP transport SP priority SP connection-address SP port SP "typ" SP cand-type [SP rel-addr] [SP rel-port] *(SP extension-att-name SP extension-att-value)
- foundation:多個 candidates 之間通過此字段來區分是否是同一種候選地址
- component-id:1 表示用於傳輸 rtp 的候選地址,2 表示用於傳輸 rtcp 的候選地址,如果啟用了 rtcp-mux,那么都為 1 即可
- transport:網絡傳輸類型,udp 或 tcp
- priority:此 candidate 的優先級,用於生成 check-list pair 的時候,誰最先發起連通性檢查
- connection-address:候選地址,可以是 ipv4、ipv6、域名(如果是域名,接收端需要進行 dns 解析)
- port:候選端口
- cand-type:host、srflx、prflx、relay 之一
- extension-att-name,extension-att-value:擴展屬性
如下是一個 sdp 中的 candidate 示例(只能出現在 media level 中,不能出現在 session level 中,多個不同 media level 中的 candidate 可以相同):
a=candidate:0 1 udp 2130706431 192.168.0.106 8090 typ host generation 0
- foundation 為 0
- component-id 為 1,表明是用於 rtp 傳輸的候選地址,如果 sdp 啟用了 rtcp-mux,則 rtcp 傳輸也復用這個候選地址
- 網絡傳輸使用 udp
- 優先級為 2130706431,詳細計算公式參考 rfc5245
- 候選 ipv4 地址為 192.168.0.106
- 候選 port 為 8090
- 候選地址類型為 host,這種地址要么本端擁有公網 ip,要么與對端在同一個局域網中
- generation 0 是擴展屬性
注意以下是一個 janus 通過信令發送的 trickle candidate 示例:
{"janus":"trickle","candidate":{"candidate":"candidate:3805835391 1 udp 2122260223 192.168.0.107 53792 typ host generation 0 ufrag icRG network-id 1","sdpMid":"0","sdpMLineIndex":0},"transaction":"jIToQHjOgntu","session_id":52}
其中,必須指明此 candidate 屬於哪個 media stream(這里通過 mid 和 m-line index 進行指定,顯然,即使是 ice trickle 模式,也必須先發送 sdp 然后再發送 local candidate,參考 https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-trickle-ice-02#section-9.2)。
2.6 DTLS
ICE 連接建立完成后,接着就是 DTLS 握手協商出用於 SRTP 媒體加密的密鑰,DTLS 握手在 sdp 中的字段如下:
a=fingerprint:sha-256 60:DF:D2:8E:AC:1B:7C:DB:DA:36:39:57:AA:DD:1A:C2:43:58:36:09:80:56:CA:18:F4:85:6B:9F:B1:8F:78:13
a=setup:actpass
其中,fingerprint 即握手中的指紋信息(用於自簽證書驗證),setup 表明本端在握手中的角色:
- active:主動發起 DTLS 握手。
- passive:被動等待接受 DTLS 握手消息。
- actpass:既可以主動發起,也可以被動接受。當 offer 一方為 actpass 時,answer 一方必須指定為 active 或 passive。
2.7 Stream Direction
此屬性在 a= 中,如 a=sendonly,在不同 media level 中,可以有不同,以表明不同的媒體收發支持:
- sendonly:本端只支持發送媒體,不接收媒體,因此對端返回的 sdp 可以不攜帶 ssrc 信息。
- recvonly:本端只支持接收媒體,不發送媒體,因此本端 sdp 可以不攜帶 ssrc 信息。
- sendrecv:本端支持收發媒體
- inactive:用在某個 media level 協商失敗的回應中
2.8 Codec Parameters(編解碼格式參數)
編解碼參數用於描述媒體編解碼格式信息(使用此格式進行編解碼),一個 media level 可以支持多個編解碼格式,具體最終使用哪個或哪些取決於媒體協商的結果。
offer 中的編解碼格式表明 offer 端支持發送接收帶這些媒體格式的 rtp 包,answer 中的編解碼格式只能從這些給定的編解碼格式中進行協商。
2.8.1 rtpmap
a=rtpmap 是編解碼格式參數的起始行:
a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
- payload type:rtp payload 值,必須是 m line 中支持的某個值
- encoding name:編解碼格式名稱,如 H264、opus、vpx 等
- clock rate:時鍾頻率
- encoding parameters:可選項
2.8.2 fmtp(format specific param)
用於對 rtpmap 指定的編碼格式做進一步描述:
a=fmtp:<format> <format specific parameters>
- format:等於其上最近一個 rtpmap 的 payload 值,所以 a=fmtp 行必須在 a=rtpmap 行的后面,有順序之分
- format specific parameters:對 rtpmap 編解碼格式的進一步描述
如對 h264 編解碼格式:
a=rtpmap:102 H264/90000
a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
- level-asymmetry-allowed:指定
- packetization-mode:
- profile-level-id:16進制
2.8.3 rtcp-fb(rtcp feedback)
rtpmap 編解碼格式支持的 rtcp 反饋消息類型,如:
a=rtcp-fb:102 goog-remb
a=rtcp-fb:102 transport-cc
a=rtcp-fb:102 ccm fir
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
- goog-remb:Receiver Estimated Max Bitrate 接收端碼率反饋,參考 https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03
- transport-cc:傳輸層擁塞控制,參考 https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01
- ccm fir:Full Intra Request,關鍵幀請求,主要用於發送端剛加入會議時,接收端傳遞此消息,讓發送端盡快發送關鍵幀。fir 在 rfc5104(新的定義,一般用這種)和 rfc2032(舊的定義,不加 ccm 標識) 中進行了定義
- nack:Negative Acknowledgement,nack 實際上分為 RTPFB 和 PSFB,在 rtcp 的 FMT 字段進行區分。這里指 rtp 包丟失重傳,參考 rfc4585
- nack pli:nack Picture Loss Indication,當丟 rtp 包太多時,接收端發送此消息,讓發送端盡快發送新的關鍵幀過來
2.8.4 rtx
當 rtp 丟包重傳時,可以直接重傳原始包,也可以將待重傳包的 rtp payload type 填入新的負載類型值,用於表明這是一個重傳包。新的負載類型值即 sdp 中的 rtx rtpmap。rtx 依賴於某個非重傳的 rtpmap 編解碼格式,表示此 rtx 專門用來重傳所屬的編解碼格式:
a=rtpmap:123 H264/90000
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
a=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f
a=rtpmap:118 rtx/90000
a=fmtp:118 apt=123
如上,重傳 rtpmap 的 encoding name 為 rtx,pt 值為 118,如何與其上的 rtpmap:123 H264 相關聯呢?答案是借助 a=fmtp:118 apt=123,apt= 的值即此 rtx 所屬的非重傳編解碼格式。
注意,rtx 不需要雙向協商,即只要本端的 sdp 中出現 rtx 即表明本端重傳 rtp 時,以 rtx 的方式重傳。
rtx 重傳包也會擁有自己獨立的 ssrc,rtx 的 ssrc 參見下文。
2.9 extmap
rtp 頭部擴展,參考 rfc5285:
a=extmap:<value>["/"<direction>] <URI> <extensionattributes>
如一個 audio level 支持的頭部擴展:
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
value 和 url 可以自定定義。如上,offer 中的 extmap 表明 offer 端支持發送接收帶這些擴展頭的 rtp 包,answer 中的 extmap 只能從這些給定的 extmap 進行協商。
2.10 ssrc
ssrc 即 media level 的源同步標識,參考 rfc5576:
a=ssrc:<ssrc-id> <attribute>
a=ssrc:<ssrc-id> <attribute>:<value>
ssrc-id 是一個在 [0, 2^32-1] 之間的隨機值,如某個 audio level 的 ssrc:
a=ssrc:724846199 cname:wJobAtYmVV7u5Y3x
a=ssrc:724846199 msid:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp 13eb9491-262e-4982-9aea-1c6af9e8ef22
a=ssrc:724846199 mslabel:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp
a=ssrc:724846199 label:13eb9491-262e-4982-9aea-1c6af9e8ef22
a=ssrc:724846199 出現了多次,但是 attribute 都不同。
2.10.1 ssrc-group
定義一組相關聯的 ssrc:
a=ssrc-group:<semantics> <ssrc-id> ...
- semantics:可以取值為 FID(Flow Identification)、FEC(Forward Error Correction)
- ssrc-id:可以有多個,表明是一組相關聯的 ssrc
在 rtx 的語義中,rtx 重傳包不僅有不同於被重傳包的 pt 值,也有不同的 ssrc 值,rtx ssrc 在 ssrc-group 字段中,如下是 video media level 示例:
a=ssrc-group:FID 3473705511 683075964
a=ssrc:3473705511 cname:wJobAtYmVV7u5Y3x
a=ssrc:3473705511 msid:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp 0befb6f8-46a8-4890-9955-b53689962daf
a=ssrc:3473705511 mslabel:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp
a=ssrc:3473705511 label:0befb6f8-46a8-4890-9955-b53689962daf
a=ssrc:683075964 cname:wJobAtYmVV7u5Y3x
a=ssrc:683075964 msid:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp 0befb6f8-46a8-4890-9955-b53689962daf
a=ssrc:683075964 mslabel:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp
a=ssrc:683075964 label:0befb6f8-46a8-4890-9955-b53689962daf
其中,semantics 為 FID,ssrc-id 有兩個,第一個是正常 media level 的 ssrc,第二個 ssrc 即 rtx 的重傳 ssrc。
2.11 示例解釋
下面是一個 offer 示例,將逐行解釋,前文沒有描述的字段,在這里進行描述:
// sdp版本號為0
v=0
// 用戶名為空,會話id是 1044094566052576507,會話版本是2(會話重協商 sess-version 應加 1),地址類型為 IP4,地址為 127.0.0.1(可忽略)
o=- 1044094566052576507 2 IN IP4 127.0.0.1
// 會話名為空
s=-
// 實時會話
t=0 0
// mid=0 和 mid=1 的 media track 多路復用同一個網絡連接
a=group:BUNDLE 0 1
// WMS 是 WebRTC Media Stram 的縮寫,這里給 Media Stream 定義了一個唯一的標識符。一個 Media Stream 可以有多個 track(video track、audio track),這些 track 就是通過這個唯一標識符關聯起來的,具體見下面的媒體行(m=)以及它對應的附加屬性(a=ssrc)
a=msid-semantic: WMS g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp
// 音頻媒體描述,端口為9(可忽略),采用 UDP 傳輸加密的 RTP 包,支持 RTCP 反饋,111、103 是 audio 可能采用的編碼格式 payload type 值
m=audio 9 UDP/TLS/RTP/SAVPF 111 103
// 音頻發送者的 IP4 地址,WebRTC 采用 ICE,這里的 0.0.0.0 可直接忽略
c=IN IP4 0.0.0.0
// RTCP 采用的端口、IP地址,因為下面的 a=rtcp-mux,這里可忽略
a=rtcp:9 IN IP4 0.0.0.0
// ice 協商認證字段
a=ice-ufrag:Fyzi
a=ice-pwd:/NDZTbh8NX+BTFjRyZy7Heqc
// 本端支持的 ice 類型是 trickle
a=ice-options:trickle
// dtls 握手指紋
a=fingerprint:sha-256 60:DF:D2:8E:AC:1B:7C:DB:DA:36:39:57:AA:DD:1A:C2:43:58:36:09:80:56:CA:18:F4:85:6B:9F:B1:8F:78:13
// dtls 握手角色,支持主動和被動
a=setup:actpass
// 本 audio 的 mid 為 0,對應前面的 a=group:BUNDLE 0 1
a=mid:0
// audio 支持的 rtp 擴展頭
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
// audio 只支持發送 rtp,不支持接收 rtp。但是注意,仍然支持接收 rtcp
a=sendonly
// msid后面帶兩個id,第一個是 Media Stream 的 id,第二個是 audio track 的 id
a=msid:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp 13eb9491-262e-4982-9aea-1c6af9e8ef22
// rtcp 多路復用 rtp 的網絡通道
a=rtcp-mux
// opus 的 pt 值為 111,clock rate 為 48000,2 聲道
a=rtpmap:111 opus/48000/2
// opus 編解碼格式支持 transport-cc rtcp 反饋,注意,transport-cc rtcp 反饋需要 a=extmap:3 擴展頭的支持
a=rtcp-fb:111 transport-cc
// 進一步描述 opus 編解碼格式,支持帶內 fec
a=fmtp:111 minptime=10;useinbandfec=1
// audio 也支持 ISAC 編解碼格式
a=rtpmap:103 ISAC/16000
// audio 的 ssrc,cname用來唯一標識媒體的數據源
a=ssrc:724846199 cname:wJobAtYmVV7u5Y3x
// msid 與前面的 a=msid 字段相同
a=ssrc:724846199 msid:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp 13eb9491-262e-4982-9aea-1c6af9e8ef22
// mslabel:audio track id
a=ssrc:724846199 mslabel:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp
// label:webrtc media stream id
a=ssrc:724846199 label:13eb9491-262e-4982-9aea-1c6af9e8ef22
// 從下面開始是 video track 的媒體描述
m=video 9 UDP/TLS/RTP/SAVPF 96 97 102 121
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:Fyzi
a=ice-pwd:/NDZTbh8NX+BTFjRyZy7Heqc
a=ice-options:trickle
a=fingerprint:sha-256 60:DF:D2:8E:AC:1B:7C:DB:DA:36:39:57:AA:DD:1A:C2:43:58:36:09:80:56:CA:18:F4:85:6B:9F:B1:8F:78:13
a=setup:actpass
// 本 video 的 mid 為 1,對應前面的 a=group:BUNDLE 0 1
a=mid:1
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:13 urn:3gpp:video-orientation
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:11 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
a=sendonly
a=msid:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp 0befb6f8-46a8-4890-9955-b53689962daf
a=rtcp-mux
a=rtcp-rsize
// 支持 vp8 編解碼格式
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
// 支持 h264 編解碼格式
a=rtpmap:102 H264/90000
a=rtcp-fb:102 goog-remb
a=rtcp-fb:102 transport-cc
a=rtcp-fb:102 ccm fir
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
// pt 值為 102 的 h264 編解碼格式支持 rtp 丟包重傳
a=rtpmap:121 rtx/90000
a=fmtp:121 apt=102
// video 發送媒體正常的 ssrc 和支持 rtx 重傳的 ssrc
a=ssrc-group:FID 3473705511 683075964
a=ssrc:3473705511 cname:wJobAtYmVV7u5Y3x
a=ssrc:3473705511 msid:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp 0befb6f8-46a8-4890-9955-b53689962daf
a=ssrc:3473705511 mslabel:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp
a=ssrc:3473705511 label:0befb6f8-46a8-4890-9955-b53689962daf
a=ssrc:683075964 cname:wJobAtYmVV7u5Y3x
a=ssrc:683075964 msid:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp 0befb6f8-46a8-4890-9955-b53689962daf
a=ssrc:683075964 mslabel:g4n21yfXiVM9K1CrtoSZMNxoNI7kBbY9rHgp
a=ssrc:683075964 label:0befb6f8-46a8-4890-9955-b53689962daf
3. 協商失敗
媒體協商可能失敗,answer 端會檢查每一個 media level,如果某個 media level 協商失敗,answer 中的 sdp 如何表明呢?有兩種方式:
- m 行中的 port 字段為 0,如 m=video 0 UDP/TLS/RTP/SAVPF 96 97 102 121
- media direction 字段為 inactive,如 a=inactive
4. PlanB and UnifiedPlan
webrtc 引入了 stream 和 track 的概念,一個 track 即一路音頻或視頻流,比如一個終端,可以發送屏幕共享一路流、攝像頭一路流、麥克風音頻一路流。每一路單獨流是一個 track,集合在一起形成了一個 stream,每一路流通過 ssrc 來進行區分。
兩路音頻流 planb 的 sdp 格式:
...
a=group:BUNDLE audio
a=msid-semantic: WMS stream-id-2 stream-id-1
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
...
a=mid:audio...
a=rtpmap:103 ISAC/16000
...
a=ssrc:10 cname:cname
a=ssrc:10 msid:stream-id-1 track-id-1
a=ssrc:10 mslabel:stream-id-1
a=ssrc:10 label:track-id-1
a=ssrc:11 cname:cname
a=ssrc:11 msid:stream-id-2 track-id-2
a=ssrc:11 mslabel:stream-id-2
a=ssrc:11 label:track-id-2
兩路音頻流的 UnifiedPlan 格式:
...
a=group:BUNDLE 0 1
a=msid-semantic: WMS
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
...
a=mid:0
...
a=sendrecv
a=msid:- track-id-1
...
a=rtpmap:103 ISAC/16000
...
a=ssrc:10 cname:cname
a=ssrc:10 msid: track-id-1
a=ssrc:10 mslabel:
a=ssrc:10 label:track-id-1
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
...
a=mid:1
...
a=sendrecv
a=msid:- track-id-2
...
a=rtpmap:103 ISAC/16000
...
a=ssrc:11 cname:cname
a=ssrc:11 msid: track-id-2
a=ssrc:11 mslabel:
a=ssrc:11 label:track-id-2
可見,planb 格式中,audio 只有一個 media level,media level 中有多個 track 時不同 track 通過 ssrc 進行區分,不同 track 必須使用同一種編解碼格式。
unified plan 格式中,audio 有兩個 media level,每個 media level 對應一個 track,也對應一個 ssrc 進行區分,不同 track 可以使用不同的編解碼格式。
planb 和 unified plan 格式的差異注意意義在於:不同音視頻流可以支持不同的編解碼格式。
當只有一路音頻流和一路視頻流時,兩則一樣。
5. sip 呼叫中的 sdp
sip 呼叫中的 sdp 與 webrtc 會有一些顯著的區別,下面分別稱述。
5.1 網絡傳輸上的區別
- sip 呼叫是一套完整的運行在 TCP/UDP 之上的協議,sdp 只是 sip 呼叫中的一部分;webrtc 中的 sdp 需要依賴其它協議(如 http、websocket等)由用戶自定義傳輸。
- webrtc 引入了 ICE 協議,致力於打通不同網絡之間(如兩個處於不同 NAT 下的設備)的連接;sip 呼叫則需要開發者根據網絡拓撲類型自定義呼叫方式(如經由一個網關),以實現不同網絡類型的互通,sip 協議本身帶來的跨網絡連接能力有限(如自帶 rport 功能)。
- webrtc 一般不同 tracks 之間會復用一個網絡鏈接;sip 中不同 tracks,每個 track 的 rtp、rtcp 都會有自己的網絡連接。
- webrtc 通過 candidates 傳遞網絡連接信息;sip 的網絡連接信息直接寫在 sdp 中
// RTC
a=candidate:1 1 udp 2013266431 192.168.2.106 12345 typ host
// SIP
c=IN IP4 192.168.2.106
m=audio 3262 RTP/AVP 107 108
m=video 3264 RTP/AVP 97 126
5.2 媒體流的區別
- webrtc 支持任意路音視頻流;sip 只支持一路音頻流和一路視頻流(通過 BFCP 協議可以擴展多一路屏幕共享視頻流)