什么是SDP
SDP(Session Description Protocol)是一種通用的會話描述協議,主要用來描述多媒體會話,用途包括會話聲明、會話邀請、會話初始化等。
WebRTC主要在連接建立階段用到SDP,連接雙方通過信令服務交換會話信息,包括音視頻編解碼器(codec)、主機候選地址、網絡傳輸協議等。
下面先簡單介紹下SDP的格式、常用屬性,然后通過WebRTC連接建立過程生成的SDP實例進行進一步講解。
協議格式說明
SDP的格式非常簡單,由多個行組成,每個行都是如下格式。
<type>=<value>
其中:
<type>
:大小寫敏感的一個字符,代表特定的屬性,比如v
代表版本;<value>
:結構化文本,格式與屬性類型有關,UTF8編碼;=
兩邊不允許存在空格;=*
表示是可選的;
常見屬性
以下面的SDP為例:
v=0
o=alice 2890844526 2890844526 IN IP4 host.anywhere.com
s=
c=IN IP4 host.anywhere.com
t=0 0
m=audio 49170 RTP/AVP 0
a=rtpmap:0 PCMU/8000
m=video 51372 RTP/AVP 31
a=rtpmap:31 H261/90000
m=video 53000 RTP/AVP 32
a=rtpmap:32 MPV/90000
協議版本號:v=
格式如下,注意,沒有子版本號。
v=0
會話發起者:o
格式如下,其中,username、session-id、nettype、addrtype、unicast-address 一起,唯一標識一個會話。
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地址。
會話名 s=
必選,有且僅有一個s=
字段,且不能為空。如果實在沒有有意義的會話名,可以賦一個空格,即s=
。
s=<session name>
連接數據:c=
格式如下:
c=<nettype> <addrtype> <connection-address>
每個SDP至少需要包含一個會話級別的c=
字段,或者在每個媒體描述后面各包含一個c=
字段。(媒體描述后的c=
會覆蓋會話級別的c=
)
- nettype:網絡類型,比如
IN
,表示 Internet。 - addrtype:地址類型,比如
IP4
、IP6
。 - connection-address:如果是廣播,則為廣播地址組;如果是單播,則為單播地址;
舉例01:
c=IN IP4 224.2.36.42/127
舉例02:
c=IN IP4 host.anywhere.com
媒體描述:m=
SDP可能同時包含多個媒體描述。格式如下:
m=<media> <port> <proto> <fmt> ...
其中:
- media:媒體類型。包括 video、audio、text、application、message等。
- port:傳輸媒體流的端口,具體含義取決於使用的網絡類型(在
c=
中聲明)和使用的協議(proto,在m=
中聲明)。 - proto:傳輸協議,具體含義取決於
c=
中定義的地址類型,比如c=
是IP4,那么這里的傳輸協議運行在IP4之上。比如:- UDP:傳輸層協議是UDP。
- RTP/AVP:針對視頻、音頻的RTP協議,跑在UDP之上。
- RTP/SAVP:針對視頻、音頻的SRTP協議,跑在UDP之上。
- fmt:媒體格式的描述,可能有多個。根據 proto 的不同,fmt 的含義也不同。比如 proto 為 RTP/SAVP 時,fmt 表示 RTP payload 的類型。如果有多個,表示在這次會話中,多種payload類型可能會用到,且第一個為默認的payload類型。
舉例,下面表示媒體類型是視頻,采用SRTP傳輸流媒體數據,且RTP包的類型可能是122、102...119,默認是122。
m=video 9 UDP/TLS/RTP/SAVPF 122 102 100 101 124 120 123 119
對於 RTP/SAVP,需要注意的是,payload type 又分兩種類型:
- 靜態類型:參考 RTP/AVP audio and video payload types。
- 動態類型:在
a=fmtp:
里進行定義。(a=
為附加屬性,見后面小節)
舉例,下面的SDP中:
- 對於audio,111 是動態類型,表示
opus/48000/2
。 - 對於video,122 是動態類型,表示
H264/90000
。
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 126
a=rtpmap:111 opus/48000/2
m=video 9 UDP/TLS/RTP/SAVPF 122 102 100 101 124 120 123 119
a=rtpmap:122 H264/90000
附加屬性:a=
作用:用於擴展SDP。
有兩種作用范圍:會話級別(session-level)、媒體級別(media-level)。
- 媒體級別:媒體描述(m=)后面可以跟任意數量的 a= 字段,對媒體描述進行擴展。
- 會話級別:在第一個媒體字段(media field)前,添加的 a= 字段是會話級別的。
有如下兩種格式:
a=<attribute>
a=<attribute>:<value>
格式1舉例:
a=recvonly
格式2舉例:
a=rtpmap:0 PCMU/8000
時間:t=
作用:聲明會話的開始、結束時間。
格式如下:
t=<start-time> <stop-time>
如果<stop-time>
是0,表示會話沒有結束的邊界,但是需要在<start-time>
之后會話才是活躍(active)的。如果<start-time>
是0,表示會話是永久的。
舉例:
t=0 0
WebRTC實例
下面例子來自騰訊雲WebRTC服務的遠端offer。
// sdp版本號為0
v=0
// o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>
// 用戶名為空,會話id是8100750360520823155,會話版本是2(后面如果有類似改變編碼的操作,sess-version加1),地址類型為IP4,地址為127.0.0.1(這里可以忽略)
o=- 7595655801978680453 2 IN IP4 112.90.139.105
// 會話名為空
s=-
// 會話的起始時間,都為0表示沒有限制
t=0 0
a=ice-lite
// 音頻、視頻的傳輸的傳輸采取多路復用,通過同一個RTP通道傳輸音頻、視頻,可以參考 https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-54
a=group:BUNDLE 0 1
// WMS是WebRTC Media Stram的縮寫,這里給Media Stream定義了一個唯一的標識符。一個Media Stream可以有多個track(video track、audio track),這些track就是通過這個唯一標識符關聯起來的,具體見下面的媒體行(m=)以及它對應的附加屬性(a=ssrc:)
// 可以參考這里 http://tools.ietf.org/html/draft-ietf-mmusic-msid
a=msid-semantic: WMS 5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV
// m=<media> <port> <proto> <fmt> ...
// 本次會話有音頻,端口為9(可忽略,端口9為Discard Protocol專用),采用UDP傳輸加密的RTP包,並使用基於SRTCP的音視頻反饋機制來提升傳輸質量,111、103、104等是audio可能采用的編碼(參見前面m=的說明)
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 126
// 音頻發送者的IP4地址,WebRTC采用ICE,這里的 0.0.0.0 可直接忽略
c=IN IP4 0.0.0.0
// RTCP采用的端口、IP地址(可忽略)
a=rtcp:9 IN IP4 0.0.0.0
// ice-ufrag、ice-pwd 分別為ICE協商用到的認證信息
a=ice-ufrag:58142170598604946
a=ice-pwd:71696ad0528c4adb02bb40e1
// DTLS協商過程的指紋信息
a=fingerprint:sha-256 7F:98:08:AC:17:6A:34:DB:CF:3B:EC:93:ED:57:3F:5A:9E:1F:4A:F3:DB:D5:BF:66:EE:17:58:E0:57:EC:1B:19
// 當前客戶端在DTLS協商過程中,既可以作為客戶端,也可以作為服務端,具體可參考 RFC4572
a=setup:actpass
// 當前媒體行的標識符(在a=group:BUNDLE 0 1 這行里面用到,這里0表示audio)
a=mid:0
// RTP允許擴展首部,這里表示采用了RFC6464定義的針對audio的擴展首部,用來調節音量,比如在大型會議中,有多個音頻流,就可以用這個來調整音頻混流的策略
// 這里沒有vad=1,表示不啟用這個音量控制
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
// 表示既可以發送音頻,也可以接收音頻
a=sendrecv
// 表示啟用多路復用,RTP、RTCP共用同個通道
a=rtcp-mux
// 下面幾行都是對audio媒體行的補充說明(針對111),包括rtpmap、rtcp-fb、fmtp
// rtpmap:編解碼器為opus,采樣率是48000,2聲道
a=rtpmap:111 opus/48000/2
// rtcp-fb:基於RTCP的反饋控制機制,可以參考 https://tools.ietf.org/html/rfc5124、https://webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02/
a=rtcp-fb:111 transport-cc
a=rtcp-fb:111 nack
// 最小的音頻打包時間
a=fmtp:111 minptime=20
// 跟前面的rtpmap類似
a=rtpmap:126 telephone-event/8000
// ssrc用來對媒體進行描述,格式為a=ssrc:<ssrc-id> <attribute>:<value>,具體可參考 RFC5576
// cname用來唯一標識媒體的數據源
a=ssrc:16864608 cname:YZcxBwerFFm6GH69
// msid后面帶兩個id,第一個是MediaStream的id,第二個是audio track的id(跟后面的mslabel、label對應)
a=ssrc:16864608 msid:5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV 128f4fa0-81dd-4c3a-bbcd-22e71e29d178
a=ssrc:16864608 mslabel:5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV
a=ssrc:16864608 label:128f4fa0-81dd-4c3a-bbcd-22e71e29d178
// 跟audio類似,不贅述
m=video 9 UDP/TLS/RTP/SAVPF 122 102 125 107 124 120 123 119
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:58142170598604946
a=ice-pwd:71696ad0528c4adb02bb40e1
a=fingerprint:sha-256 7F:98:08:AC:17:6A:34:DB:CF:3B:EC:93:ED:57:3F:5A:9E:1F:4A:F3:DB:D5:BF:66:EE:17:58:E0:57:EC:1B:19
a=setup:actpass
a=mid:1
a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:4 urn:3gpp:video-orientation
a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=sendrecv
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:122 H264/90000
a=rtcp-fb:122 ccm fir
a=rtcp-fb:122 nack
a=rtcp-fb:122 nack pli
a=rtcp-fb:122 goog-remb
a=rtcp-fb:122 transport-cc
a=fmtp:122 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtpmap:102 rtx/90000
a=fmtp:102 apt=122
a=rtpmap:125 H264/90000
a=rtcp-fb:125 ccm fir
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=rtcp-fb:125 goog-remb
a=rtcp-fb:125 transport-cc
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:107 rtx/90000
a=fmtp:107 apt=125
a=rtpmap:124 H264/90000
a=rtcp-fb:124 ccm fir
a=rtcp-fb:124 nack
a=rtcp-fb:124 nack pli
a=rtcp-fb:124 goog-remb
a=rtcp-fb:124 transport-cc
a=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032
a=rtpmap:120 rtx/90000
a=fmtp:120 apt=124
a=rtpmap:123 H264/90000
a=rtcp-fb:123 ccm fir
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
a=rtcp-fb:123 goog-remb
a=rtcp-fb:123 transport-cc
a=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
a=rtpmap:119 rtx/90000
a=fmtp:119 apt=123
a=ssrc-group:FID 33718809 50483271
a=ssrc:33718809 cname:ovaCctnHP9Asci9c
a=ssrc:33718809 msid:5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV 1d7fc300-9889-4f94-9f35-c0bcc77a260d
a=ssrc:33718809 mslabel:5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV
a=ssrc:33718809 label:1d7fc300-9889-4f94-9f35-c0bcc77a260d
a=ssrc:50483271 cname:ovaCctnHP9Asci9c
a=ssrc:50483271 msid:5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV 1d7fc300-9889-4f94-9f35-c0bcc77a260d
a=ssrc:50483271 mslabel:5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV
a=ssrc:50483271 label:1d7fc300-9889-4f94-9f35-c0bcc77a260d
寫在后面
SDP協議格式本身很簡單,難點一般在於應用層在不同場景下擴展出來的屬性,以及不同擴展屬性對應的含義。比如上面舉的例子,擴展屬性、屬性值的說明分散在數十個RFC里,查找、理解都費了一番功夫。
如有錯漏,敬請指出。
相關鏈接
SDP: Session Description Protocol
Annotated Example SDP for WebRTC