WebRTC 中的 SDP 协议

课程地址:零声学院 WebRTC入门与提高 https://ke.qq.com/course/435382?tuin=137bb271

技术支持QQ群:782508536

SDP 完全是一种会话描述格式 ― 它不属于传输协议 ― 它只使用不同的适当的传输协议,包括会话通知协议(SAP)、会话初始协议(SIP)、 实时流协议(RTSP)、 MIME 扩展协议的电子邮件以及超文本传输协议(HTTP)。SDP协议是也是基于文本的协议,这样就能保证协议的可扩展性比较强,这样就使其具有广泛的应用范围。SDP 不支持会话内容或媒体编码的协商,所以在流媒体中只用来描述媒体信息。媒体协商这一块要用 RTSP 来实现.

当发起多媒体电话会议,IP语音呼叫时,流媒体视频或其他会话,需要传达媒体细节,传输地址和其他会话描元数据给参与者。SDP 为此类信息提供了标准。SDP纯粹是会话描述的格式,它不包含传输协议。

WebRTC 会话就是由 SDP 描述的。对于 WebRTC 来说,最重要的是 SDP 中的媒体和传输信息。

媒体信息包括:

媒体类型(视频,音频)
传输协议(RTP/UDP/IP,H.320等)
媒体格式(H.261视频,MPEG视频等)

传输信息包括:

媒体的远程地址
媒体的远程传输端口

该地址和端口取决于媒体和传输协议定义。但需要注意的是,因为存在网络地址转换(NAT)和防火墙,所以传输过程比较复杂,在 SDP 中没有定义相关的实现。WebRTC 中使用 ICE 协议来解决 NAT 的问题。

SDP 格式

SDP会话描述是由多行文本组成表格。由会话级部分(session-level)和多个媒体级(media-level)部分组成。会话级部分以”v =”行开始,到第一个媒体级部分结束。每个媒体级部分以”m =”行开始,持续到下一个媒体级。

下面是所有的字段描述,可选项目标有”*”。

v =(协议版本)
o =(发起者和会话标识符)
s =(会话名称)
i = *(会话信息)
u = *(描述的URI)
e = *(电子邮件地址)
p = *(电话号码)
c = *(连接信息 - 如果包含在内,则不需要所有媒体)
b = *(零个或多个带宽信息行)
一个或多个时间描述("t ="和"r ="行;见下文)
z = *(时区调整)
k = *(加密密钥)
a = *(零个或多个会话属性行)零个或多个媒体描述
t =(会话活动时间)
r = *(零个或多个重复次数)
m =(媒体名称和传输地址)
i = *(媒体标题)
c = *(连接信息 - 如果包含在内,则为可选项会话级别)
b = *(零个或多个带宽信息行)
k = *(加密密钥)
a = *(零个或多个媒体属性行)

下面是一个基本的 SDP 描述:

o=- 3925575362227037542 2 IN IP4 127.0.0.1 t=0 0 a=group:BUNDLE audio video a=msid-semantic: WMS 735174861 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 a=rtcp:9 IN IP4 0.0.0.0 a=ice-ufrag:KZ8M a=ice-pwd:NZ1R3TFbpF9ZqEyg5PNSoM85 a=fingerprint:sha-256 7B:0B:B7:6C:C2:82:77:D2:70:18:3F:DD:18:98:AB:22:07:0E:5D:5B:6D:30:C0:05:42:50:C0:D7:53:AF:3E:9F a=setup:active a=mid:audio a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level a=sendrecv 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=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 a=ssrc:889008008 cname:JQsS3I1VR6oT0wUw a=ssrc:889008008 msid:735174861 6446c8d1-1db2-4024-b0bd-1e03304810fe a=ssrc:889008008 mslabel:735174861 a=ssrc:889008008 label:6446c8d1-1db2-4024-b0bd-1e03304810fe m=video 9 UDP/TLS/RTP/SAVPF 98 96 100 127 99 97 101 c=IN IP4 0.0.0.0 a=rtcp:9 IN IP4 0.0.0.0 a=ice-ufrag:KZ8M a=ice-pwd:NZ1R3TFbpF9ZqEyg5PNSoM85 a=fingerprint:sha-256 7B:0B:B7:6C:C2:82:77:D2:70:18:3F:DD:18:98:AB:22:07:0E:5D:5B:6D:30:C0:05:42:50:C0:D7:53:AF:3E:9F a=setup:active a=mid:video 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:98 H264/90000 a=rtcp-fb:98 ccm fir a=rtcp-fb:98 nack a=rtcp-fb:98 nack pli a=rtcp-fb:98 goog-remb a=rtcp-fb:98 transport-cc a=fmtp:98 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f a=rtpmap:96 VP8/90000 a=rtcp-fb:96 ccm fir a=rtcp-fb:96 nack a=rtcp-fb:96 nack pli a=rtcp-fb:96 goog-remb a=rtcp-fb:96 transport-cc a=rtpmap:100 red/90000 a=rtpmap:127 ulpfec/90000 a=rtpmap:99 rtx/90000 a=fmtp:99 apt=98 a=rtpmap:97 rtx/90000 a=fmtp:97 apt=96 a=rtpmap:101 rtx/90000 a=fmtp:101 apt=100 a=ssrc-group:FID 687692313 4175760292 a=ssrc:687692313 cname:JQsS3I1VR6oT0wUw a=ssrc:687692313 msid:735174861 54bc6a42-f281-4d75-ac41-ab709717abdb a=ssrc:687692313 mslabel:735174861 a=ssrc:687692313 label:54bc6a42-f281-4d75-ac41-ab709717abdb a=ssrc:4175760292 cname:JQsS3I1VR6oT0wUw a=ssrc:4175760292 msid:735174861 54bc6a42-f281-4d75-ac41-ab709717abdb a=ssrc:4175760292 mslabel:735174861 a=ssrc:4175760292 label:54bc6a42-f281-4d75-ac41-ab709717abdb 会话名,没有的话使用-代替

a=group
需要共用一个传输通道传输的媒体,如果没有这一行,音视频,数据就会分别单独用一个udp端口来发送
在同一个RTP会话中多路复用几个媒体流,也就是在后面以”m =”开始的媒体段

a=msid-semantic
WMS是WebRTC Media Stream简称,这一行定义了本客户端支持同时传输多个流,一个流可以包括多个track。
在PeerConnection生命周期内为 WebRTC Media Stream (WMS) 定义一个唯一的标识符,用于确定其他独立的RTP媒体流(下面以”m = “开始的媒体段)属于该 WMS。
接下来是三个以 “m = “开始的媒体段,分别是audio、video、application。

后面跟着四个参数
是媒体类型,包括audio, video, text, application, message
是发送媒体流的传输端口
是传输协议
是媒体格式说明,有效负载类型

有效负载类型可以看 这篇文档。其中0-95是静态负载类型,96-127是动态负载类型,需要使用”a = rtpmap:”属性指定格式参数。

m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 126
m=audio说明本会话包含音频,9代表音频使用端口9来传输,但是在webrtc中一现在一般不使用,如果设置为0,代表不传输音频,UDP/TLS/RTP/SAVPF是表示用户来传输音频支持的协议,udp,tls,rtp代表使用udp来传输rtp包,并使用tls加密
SAVPF代表使用srtcp的反馈机制来控制通信过程,后台111 103 104 9 0 8 106 105 13 126表示本会话音频支持的编码,后台几行会有详细补充说明

c=IN IP4 0.0.0.0
c 字段中包含了连接数据,但这一个地址不会被实际使用,只有 ICE 候选项中的 IP 地址和端口才会用于建立对话。

a=rtcp:9 IN IP4 0.0.0.0
用来传输rtcp地地址和端口,webrtc中不使用

a=ice-ufrag
a=ice-pwd
指定了用于ICE的用户名片段和密码,不同的媒体段会使用不同的用户名和密码。

a=fingerprint
指纹是用于建立DTLS连接的自签名证书的SHA-256散列,这行是dtls协商过程中需要的认证信息

a=setup:active
以上这行代表本客户端在dtls协商过程中,可以做客户端也可以做服务端,参考rfc4145 rfc4572

a=mid:audio
在前面BUNDLE这一行中用到的媒体标识

a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
上一行指出我要在rtp头部中加入音量信息,参考 rfc6464

a=sendrecv
上一行指出我是双向通信,另外几种类型是recvonly,sendonly,inactive

a=rtcp-mux
上一行指出rtp,rtcp包使用同一个端口来传输

a = rtpmap
参数为 <payload type> <encoding name> / <clock rate> [/ <encoding parameters>]
对于 a=rtpmap:111 opus/48000/2 ,就是对应”m =”中的有效负载111,使用Opus编解码器,采样频率48kHz,立体声。
一般每个媒体段会有多条”a=rtpmap”字段,位于前面的编解码器具有较高的优先级

a=fmtp:111 minptime=10;useinbandfec=1
这里讲一下a=fmtp:参数设置,这里讲音频的
将有效负载111,即 Opus 数据包的最短分时时间设置为10ms,且使用in-band FEC(前向纠错编码)

a=rtcp-fb:111 transport-cc
以上这行说明opus编码支持使用rtcp来控制拥塞,参考https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01

a=rtcp-fb
反馈消息,接收方向发送方发送的反馈消息

a=ssrc
同步源标识符,用于在使用多个源时表示不同源的属性

a=extmap
RTP 扩展项,接收者可以自己解码获取里面的数据

a=rtcp-mux
支持对RTP的同一端口多路复用RTCP

该属性在上面没有列出,可以自己添加
格式为<bwtype>:<bandwidth>
可以为CT或AS,CT是所有媒体的总带宽上限,AS是指定单个媒体的带宽

a=ssrc:18509423 cname:sTjtznXLCNH7nbRw
cname用来标识一个数据源,ssrc当发生冲突时可能会发生变化,但是cname不会发生变化,也会出现在rtcp包中SDEC中,用于音视频同步

a=ssrc:18509423 msid:h1aZ20mbQB0GSsq0YxLfJmiYWE9CBfGch97C 15598a91-caf9-4fff-a28f-3082310b2b7a
以上这一行定义了ssrc和WebRTC中的MediaStream,AudioTrack之间的关系,msid后面第一个属性是stream-d,第二个是track-id

m=video 9 UDP/TLS/RTP/SAVPF 98 96 100 127 99 97 101
是对视频的编码设置,在这里,你可以指定是使用H264编码还是使用VP8编码。如96代表VP8编码,98代表H264编码,如果你要指定编码方式为VP8就将96放在前面,指定H264,就将98放在前面

a=rtpmap:98 H264/90000
每个codec都有类似的描述都有以下类似的描述

a=rtcp-fb:98 ccm fir
ccm是codec control using RTCP feedback message简称,意思是支持使用rtcp反馈机制来实现编码控制,fir是Full Intra Request
简称,意思是接收方通知发送方发送幅完全帧过来

a=rtcp-fb:98 nack
支持丢包重传,参考rfc4585

a=rtcp-fb:98 nack pli
支持关键帧丢包重传,参考rfc4585

a=rtcp-fb:98 goog-remb
支持使用rtcp包来控制发送方的码流

a=rtcp-fb:98 transport-cc
参考上面opus

  • 由于H264的rtp中不能区分视频流中是否每一帧的图像都连续,对于丢帧的情况无法处理,所以fec+nack会导致fec包丢失后,nack去申请重传fec的包.造成带宽的浪费。
  • WebRTC对FEC的冗余度计算是动态的, 会根据丢包情况和网络带宽估计(BWE)的结果动态调整冗余度,
    内部会维护一个静态的冗余度表. 冗余度范围: 0-255.(255相当于100%冗余度)
  • ULPFEC: Uneven Level Protection FEC.
    将需要保护的媒体流按照重要性分成若干区域(section),