共计 7169 个字符,预计需要花费 18 分钟才能阅读完成。
什么是 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