Catalog
  1. 1. SDP 语义成分
  2. 2. Offer/Answer 和 WebRTC
  3. 3. 字段及属性
    1. 3.1. a=ssrc
    2. 3.2. a=ice-ufrag:xxx , a=ice-pwd:xxx
  4. 4. 实际例子
SDP-WebRTC系列NO.5

在 WebRTC 框架中, SDP 被用于点与点之前的会话协商。协商基于 SDP 的 Offer/Answer 交换机制。SDP 包含了流信息, 以 Offers/Answers 的形式发送给对端。SDP 描述了多媒体会话,包括音视频,传真以及其他的流。它提供了一套标准用于全方位的描述多媒体会话,如媒体的功能,传输地址和相关的元信息。这些描述信息用于会话声明,会话邀请和参数协商。更加详细的信息参考 draft-ietf-rtcweb-sdp-12,我提取了部分内容分析并整理。

SDP 语义成分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
                                                +---------------------+
| v= |
+---------------------+
+---------------------+ +---------------------+
==== | Session Metadata | ===== | o= |
| +---------------------+ +----------------------
| +---------------------+
| | t= |
| +---------------------+
|
|
| +---------------------+
| | c= |
| +---------------------+
| +---------------------+
==== | Network Description | =====
| +---------------------+
| +---------------------+
| | a=candidate |
| +---------------------+
|
|
| +---------------------+
| | m= |
| +---------------------+
| +---------------------+ +---------------------+
==== | Stream Description | ===== | a=rtpmap |
| +---------------------+ +----------------------
| +---------------------+
| | a=fmtp |
| +---------------------+
| +---------------------+
| | a=sendrecv.. |
| +---------------------+
+---------------+
| SEMANTIC |
| COMPONENTS OF |
| SDP |
+---------------+
| +---------------------+
| | a=crypto |
| +---------------------+
| +---------------------+ +---------------------+
==== |Security Descriptions| =====| a=ice-frag |
| +---------------------+ +----------------------
| +---------------------+
| | a=ice-pwd |
| +---------------------+
| +---------------------+
| | a=fingerprint |
| +---------------------+
|
|
|
| +---------------------+
| | a=rtcp-fb |
| +---------------------+
| +---------------------+ +---------------------+
==== | Qos,Grouping | | |
| Descriptions | =====| a=group |
+---------------------+ +----------------------
+---------------------+
| a=rtcpmux |
+---------------------+
  • v= (protocol version) 协议版本
  • o= (originator and session identifier) 发起者和会话标识
  • s= (session name) 会话名称
  • i=* (session information) 会话信息
  • u=* (URI of description)
  • e=* (email address)
  • p=* (phone number)
  • c=* (connection information – not required if included in all media descriptions)
  • b=* (zero or more bandwidth information lines)
  • k=* (obsolete)
  • a=* (zero or more session attribute lines) 会话属性
  • t= (time the session is active) 会话时长
  • r=* (zero or more repeat times)
  • z=* (optional time zone offset line)
  • m= (media name and transport address) 媒体名称和通信地址
  • i=* (media title)
  • c=* (connection information – optional if included at session level)
  • b=* (zero or more bandwidth information lines) 带宽信息
  • k=* (obsolete)
  • a=* (zero or more media attribute lines) 媒体属性

Offer/Answer 和 WebRTC

最基本的形式是一个参与者发送一个初始 SDP Offer 包表示要建立一个多媒体通信会话。当另一个参与者接收到 Offer 后,他可能会生成一个 SDP Answer 包表示同意建立会话,也有可能拒绝这个 offer。在 WebRTC 场景下, Offer/Answer 模式定义了会话双方协商会话信息的状态机制。

字段及属性

a=ssrc

1
2
a = ssrc:<ssrc-id> <attribute>
a = ssrc:<ssrc-id> <attribute>:<value>

attribute:

  • msid: MediaStream id
  • mslabel:
  • label: Track id
  • fmtp

a=ice-ufrag:xxx , a=ice-pwd:xxx

用于传递用户名密码,保证 ICE 数据的可靠性。

实际例子

这是一个实测的例子,offer 是浏览器发起的, answer 是 Licode 搭建的服务器返回的。 注意看里面的部分注释。这是一个 PlanB 的 SDP,到目前为止 webrtc 已经支持 unified-plan。所以这个部分就权当了解一下吧。

offer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
v=0
o=- 6851282503962652110 2 IN IP4 127.0.0.1
s=-
t=0 0
// WMS(WebRTC Media Stream)
// 后面的串就是 msid
a=msid-semantic: WMS 9lt9jyVwtXNXn2959KBoSX85mftyFqvwVKrl
// 音视频绑定,使用同一个通道
a=group:BUNDLE audio video
// 音频流的一些信息,后面的数字是编解码类型, 下面有每个类型的详细信息。比如往下第二行,说明 111 是 opus 编解码,48000的采样率,双声道。
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
// 默认候选地址?
c=IN IP4 0.0.0.0
// rtpmap 编解码器参数
a=rtpmap:111 opus/48000/2
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:112 telephone-event/32000
a=rtpmap:113 telephone-event/16000
a=rtpmap:126 telephone-event/8000
// 采样间隔 10 ms, 使用内置的 fec, maxplaybackrate(指定采样率)
a=fmtp:111 minptime=10;useinbandfec=1
a=rtcp:9 IN IP4 0.0.0.0
// rtcp-fb rtcp 反馈机制
// 码率自适应
a=rtcp-fb:111 transport-cc
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=setup:actpass
a=mid:audio
a=sendrecv // 支持收发
// ice 用户名
a=ice-ufrag:SZFm
// ice 密码
a=ice-pwd:ety78r3qLBucXBcIlsp6kuBU
a=fingerprint:sha-256 0E:1E:A4:B2:0A:72:31:C6:6C:4C:5E:C9:D0:63:83:E1:E4:65:6A:BF:2D:3A:AF:0C:64:ED:D9:E4:62:22:37:33
// 使用 trickle ice (ice 的一种工作方式), 意为不必等到所有候选收集完成才开始建立通道
a=ice-options:trickle
a=ssrc:2305580648 cname:1KUJ6dmCj5e8D5XD
// 描述了 ssrc 和 AudioTrack 的关系, msid 后第一个字段是 stream-id,第二个字段是 track-id
a=ssrc:2305580648 msid:9lt9jyVwtXNXn2959KBoSX85mftyFqvwVKrl 50ba2594-797e-40a9-a62c-2e01d266f68e
// stream-id
a=ssrc:2305580648 mslabel:9lt9jyVwtXNXn2959KBoSX85mftyFqvwVKrl
// track-id
a=ssrc:2305580648 label:50ba2594-797e-40a9-a62c-2e01d266f68e
a=rtcp-mux // rtp/rtcp 共用一个通道
// 下面是视频流的一些信息,这里先不展开讲, 基本上套路都差不多,可能会有一些视频才有的媒体信息,比如关于关键帧之类的。
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114 115 116
c=IN IP4 0.0.0.0
a=rtpmap:96 VP8/90000
a=rtpmap:97 rtx/90000
a=rtpmap:98 VP9/90000
a=rtpmap:99 rtx/90000
a=rtpmap:100 VP9/90000
a=rtpmap:101 rtx/90000
a=rtpmap:102 H264/90000
a=rtpmap:122 rtx/90000
a=rtpmap:127 H264/90000
a=rtpmap:121 rtx/90000
a=rtpmap:125 H264/90000
a=rtpmap:107 rtx/90000
a=rtpmap:108 H264/90000
a=rtpmap:109 rtx/90000
a=rtpmap:124 H264/90000
a=rtpmap:120 rtx/90000
a=rtpmap:123 H264/90000
a=rtpmap:119 rtx/90000
a=rtpmap:114 red/90000
a=rtpmap:115 rtx/90000
a=rtpmap:116 ulpfec/90000
a=fmtp:97 apt=96
a=fmtp:98 profile-id=0
a=fmtp:99 apt=98
a=fmtp:100 profile-id=2
a=fmtp:101 apt=100
a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=fmtp:122 apt=102
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f
a=fmtp:121 apt=127
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=fmtp:107 apt=125
a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=fmtp:109 apt=108
a=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032
a=fmtp:120 apt=124
a=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
a=fmtp:119 apt=123
a=fmtp:115 apt=114
a=rtcp:9 IN IP4 0.0.0.0
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack // rtp 报文丢失重传
a=rtcp-fb:96 nack pli // pli (picture loss indication) 视频帧丢失重传
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 transport-cc
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
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=rtcp-fb:127 goog-remb
a=rtcp-fb:127 transport-cc
a=rtcp-fb:127 ccm fir
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=rtcp-fb:125 goog-remb
a=rtcp-fb:125 transport-cc
a=rtcp-fb:125 ccm fir
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=rtcp-fb:108 goog-remb
a=rtcp-fb:108 transport-cc
a=rtcp-fb:108 ccm fir
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=rtcp-fb:124 goog-remb
a=rtcp-fb:124 transport-cc
a=rtcp-fb:124 ccm fir
a=rtcp-fb:124 nack
a=rtcp-fb:124 nack pli
a=rtcp-fb:123 goog-remb
a=rtcp-fb:123 transport-cc
a=rtcp-fb:123 ccm fir
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
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:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:6 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://tools.ietf.org/html/draft-ietf-avtext-framemarking-07
a=extmap:9 http://www.webrtc.org/experiments/rtp-hdrext/color-space
a=setup:actpass
a=mid:video
a=sendrecv
a=ice-ufrag:SZFm
a=ice-pwd:ety78r3qLBucXBcIlsp6kuBU
a=fingerprint:sha-256 0E:1E:A4:B2:0A:72:31:C6:6C:4C:5E:C9:D0:63:83:E1:E4:65:6A:BF:2D:3A:AF:0C:64:ED:D9:E4:62:22:37:33
a=ice-options:trickle
//在webrtc中,重传包和正常包ssrc是不同的,上一行中前一个是正常rtp包的ssrc,后一个是重传包的ssrc
a=ssrc:1294953148 cname:1KUJ6dmCj5e8D5XD
a=ssrc:1294953148 msid:9lt9jyVwtXNXn2959KBoSX85mftyFqvwVKrl 61173a53-f5f6-41f6-8bb6-5ce4fef6c14b
a=ssrc:1294953148 mslabel:9lt9jyVwtXNXn2959KBoSX85mftyFqvwVKrl
a=ssrc:1294953148 label:61173a53-f5f6-41f6-8bb6-5ce4fef6c14b
a=ssrc:2605926894 cname:1KUJ6dmCj5e8D5XD
a=ssrc:2605926894 msid:9lt9jyVwtXNXn2959KBoSX85mftyFqvwVKrl 61173a53-f5f6-41f6-8bb6-5ce4fef6c14b
a=ssrc:2605926894 mslabel:9lt9jyVwtXNXn2959KBoSX85mftyFqvwVKrl
a=ssrc:2605926894 label:61173a53-f5f6-41f6-8bb6-5ce4fef6c14b
a=ssrc-group:FID 1294953148 2605926894
a=rtcp-mux

answer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
DEBUG:  processAnswer - Remote Description answer v=0
o=- 0 0 IN IP4 127.0.0.1
s=LicodeMCU
t=0 0
a=msid-semantic: WMS *
a=group:BUNDLE audio video
m=audio 9 UDP/TLS/RTP/SAVPF 111 // 音频编码支持 111, 也就是 opus。
c=IN IP4 0.0.0.0
a=rtpmap:111 opus/48000/2
a=rtcp:1 IN IP4 0.0.0.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=setup:active
a=mid:audio
a=recvonly // 仅接收
a=ice-ufrag:4f905505
a=ice-pwd:1b30842154fbbd4d26d73143ace8fa94
a=fingerprint:sha-256 F3:0C:05:EF:9E:52:29:A9:16:56:A5:D8:4F:56:3C:01:D6:77:2D:19:8B:78:71:6C:2C:76:C3:D3:D2:09:81:53
/* 候选信息字段说明
* "a=candidate:" 表示是候选信息
* 0 foundation ??
* 1 component id
* udp 通信协议
* 2130444543 优先级
* 94.191.48.15 48855 地址 & 端口
* typ 后面紧跟候选地址类型
* host 候选地址类型,这里表示是主机候选
* generation ??
* 0 ??
*/
a=candidate:0 1 udp 2130444543 94.191.48.15 48855 typ host generation 0 // 候选信息
a=end-of-candidates // 候选结束,因为不是获取完所有候选才 answer 的,所以有一个结束标识
a=rtcp-mux
// 下面是视频流相关
m=video 9 UDP/TLS/RTP/SAVPF 96
c=IN IP4 0.0.0.0
a=rtpmap:96 VP8/90000/2
a=rtcp:1 IN IP4 0.0.0.0
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 goog-remb
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:13 urn:3gpp:video-orientation
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
a=setup:active
a=mid:video
a=recvonly
a=ice-ufrag:4f905505
a=ice-pwd:1b30842154fbbd4d26d73143ace8fa94
a=fingerprint:sha-256 F3:0C:05:EF:9E:52:29:A9:16:56:A5:D8:4F:56:3C:01:D6:77:2D:19:8B:78:71:6C:2C:76:C3:D3:D2:09:81:53
a=candidate:0 1 udp 2130444543 94.191.48.15 48855 typ host generation 0
a=end-of-candidates
a=rtcp-mux

最后,这里只是简单的说了一些 SDP 和 SDP 在 WebRTC 场景下的一些内容,实际上 SDP 涉及到非常广的内容,有兴趣的可以参考我在文章前面贴出的 IETF 文档。目前我先研究到这里,因为后续还有很多其他的技术点要去看,毕竟现在还是要以做项目为主,技术研究为辅,得到大概信息就可以开始实现功能,以后有机会再来深入的研究。

Author: 42
Link: http://blog.ikernel.cn/2019/11/14/SDP/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.

Comment