关于云计算:WebRTC-SDP-详解和剖析

56次阅读

共计 17644 个字符,预计需要花费 45 分钟才能阅读完成。

WebRTC 是 Web Real-Time Communication,即网页实时通信的缩写,是 RTC 协定的一种 Web 实现,我的项目由 Google 开源,并和 IETF 和 W3C 制订了行业标准。在国内 WebRTC 曾经取得了越来越多厂商的反对,利用前景变得更加广大,所以咱们也开设专栏,分享阿里云外部的 WebRTC 钻研工作。

本篇是阿里云视频云 WebRTC 技术专栏系列文章的第一篇,作者将从 WebRTC SDP 例子和要害属性的角度为大家深度分析解读,其中也分享了阿里云技术专家的一些实践经验,心愿能对大家有所帮忙或者启发。后续 WebRTC 技术专栏系列将持续推出 WebRTC ICE/DTLS/SRTP/RTCP/TURN 的详解与分析,欢送关注咱们的公众号。

作者:
忘篱,阿里云高级技术专家,负责阿里云 RTC 服务器研发;
泰一,阿里云高级开发工程师,从事阿里云 RTC 服务器研发

Overview

广义的说 WebRTC 是指浏览器端,浏览器端如何间接替换数据呢?必定是没法齐全独立实现的,必须得依附服务器。个别依赖几种服务器:

  1. Signaling 信令服务器,也就是替换房间和会议的媒体信息,以及会议期间的音讯,媒体形容应用的是 SDP 协定,也就是本文分析的重点。
  2. ICE 服务器,能够分为帮忙两个客户端打洞建设 P2P 连贯的 STUN 服务器,还有如果连不通就间接转发的 TURN 服务器。ICE 的信息叫 Candidate,能够通过 SDP 替换,或者通过 Trickle。
  3. SFU 或 MCU 服务器,如果多集体散会,每个端都向其余参会的端间接发送数据叫 MESH,然而 MESH 显著有局限性,SFU 就是转发能够让客户端只上行一路流转给其余客户端,而 MCU 更弱小,能够上下行都只有一路流。

Note: WebRTC 除了传输,还有一个重要个性就是安全性,也就是 DTLS,而 DTLS 有些信息就是通过 SDP 传递的,前面会有相干的技术文章来介绍 DTLS。

上面,咱们正式介绍 SDP 协定。

What’s SDP

本文开篇的 SDP 要害属性图,曾经帮忙咱们以全局的视角一窥 SDP 的模样。SDP 形容了媒体会话,网络信息、平安个性、传输策略等,图中的每一个 SDP 属性都在不同的利用场景下施展着不同的作用,不可小觑。

接下来,咱们进一步给出 SDP 的官网定义:SDP(Session Description Protocol) 是一种会话形容协定,基于文本,其自身并不属于传输协定,须要依赖其它的传输协定(比方 SIP 和 HTTP)来替换必要的媒体信息,用于两个会话实体之间的媒体协商。

WebRTC 的 Offer 和 Answer 蕴含了 SDP。相干的 RFC 包含:

  1. 1998, RFC2327
  2. 2006, RFC4566

一个不错的 WebRTC 的 SDP 例子剖析

Offer and Answer

WebRTC 应用 Offer-Answer 模型替换 SDP,Offer 中有 SDP,Answer 中也有。例如 Alice 和 Bob 通过 WebRTC 通信:

// Alice Offer
v=0
o=- 2397106153131073818 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE video
a=msid-semantic: WMS gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS
m=video 9 UDP/TLS/RTP/SAVPF 96 97
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:l5KU
a=ice-pwd:+Sxmm3PoJUERpeHYL0HW4/T9
a=ice-options:trickle
a=fingerprint:sha-256 7C:93:85:40:01:07:91:BE:DA:64:A0:37:7E:61:CB:9D:91:9B:44:F6:C9:AC:3B:37:1C:00:15:4C:5A:B5:67:74
a=setup:actpass
a=mid:video
a=sendrecv
a=rtcp-mux
a=rtcp-rsize
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
a=ssrc-group:FID 2527104241
a=ssrc:2527104241 cname:JPmKBgFHH5YVFyaJ
a=ssrc:2527104241 msid:gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS c7072509-df47-4828-ad03-7d0274585a56
a=ssrc:2527104241 mslabel:gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS
a=ssrc:2527104241 label:c7072509-df47-4828-ad03-7d0274585a56

// Bob Answer
v=0
o=- 5443219974135798586 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE video
a=msid-semantic: WMS uiZ7cB0hsFDRGgTIMNp6TajUK9dOoHi43HVs
m=video 9 UDP/TLS/RTP/SAVPF 96 97
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:MUZf
a=ice-pwd:4QhikLcmGXnCfAzHDB++ZjM5
a=ice-options:trickle
a=fingerprint:sha-256 2A:5A:B8:43:66:05:B3:6A:E9:46:36:DF:DF:20:11:6A:F6:11:EA:D9:4E:26:E3:CE:5A:3A:C6:8D:03:49:7B:DE
a=setup:active
a=mid:video
a=sendrecv
a=rtcp-mux
a=rtcp-rsize
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
a=ssrc-group:FID 3587783331
a=ssrc:3587783331 cname:INxZnBV2Sty1zlmN
a=ssrc:3587783331 msid:uiZ7cB0hsFDRGgTIMNp6TajUK9dOoHi43HVs a3b297e7-cdbe-464e-a32c-347465ace055
a=ssrc:3587783331 mslabel:uiZ7cB0hsFDRGgTIMNp6TajUK9dOoHi43HVs
a=ssrc:3587783331 label:a3b297e7-cdbe-464e-a32c-347465ace055

Remark: 用 Chrome 浏览器,先关上 webrtc-internals,而后关上 Alice 页面点 Share 按钮,接着关上 Bob 页面点 Share,看到下面的 Offer 和 Answer。

替换完 SDP 后,会替换 Candidate:

// Alice Candidate
candidate: candidate:1912876010 1 udp 2122260223 30.2.220.94 52832 typ host generation 0 ufrag l5KU network-id 1 network-cost 10
candidate: candidate:1015535386 1 tcp 1518280447 30.2.220.94 9 typ host tcptype active generation 0 ufrag l5KU network-id 1 network-cost 10

// Bob Candidate
candidate:1912876010 1 udp 2122260223 30.2.220.94 51551 typ host generation 0 ufrag MUZf network-id 1 network-cost 10

最初 Alice 和 Bob 通信的 Candidate pair,抉择的是 UDP 通道:

Alice 发送的 Video 的信息:

Alice 收到的 (Bob 的) Video 信息:

一般来说,推流方先发动 Offer,接管方给 Answer。比方客户端推流到 SFU,客户端发动 Offer 推流,SFU 给客户端 Answer,客户端将流推到 SFU,SFU 再转发给其余客户端。Licode 和 Janus 都是这种做法,这种形式下,如果客户端须要拉取其余的客户端的流,个别须要应用另外的 PeerConnection,接管 SFU 的 Offer,生成 Answer 后回应给 SFU。

不过,推流方发动 Offer 不是必须的,接管方也能够给 Offer,推流方给 Answer。比方 MediaSoup 这种 SFU,客户端先给一个 Offer 给 SFU,SFU 只是查看这个 Offer 中的媒体个性,而后 SFU 会生成 Offer(蕴含会议中的其余客户端的流,如果没有人则没有 SSRC)给客户端,客户端发送 Answer 给 SFU。这种形式的益处是其余客户端退出,以及流的变更(比方敞开视频关上视频时),都能够应用 Reoffer,也就是对立由 SFU 发动新的 Offer,客户端响应,SFU 和客户端的交互模式只有一种。

SDP Structure

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)

对照 Alice 的 Offer(只蕴含了视频没有开启音频):

// Session description
v=0
o=- 2397106153131073818 2 IN IP4 127.0.0.1
s=-
c=IN IP4 0.0.0.0

// Time description
t=0 0

// Session Attributes
a=group:BUNDLE video
a=msid-semantic: WMS gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS

// Media description
m=video 9 UDP/TLS/RTP/SAVPF 96 97
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:l5KU
a=ice-pwd:+Sxmm3PoJUERpeHYL0HW4/T9
a=ice-options:trickle
a=fingerprint:sha-256 7C:93:85:40:01:07:91:BE:DA:64:A0:37:7E:61:CB:9D:91:9B:44:F6:C9:AC:3B:37:1C:00:15:4C:5A:B5:67:74
a=setup:actpass
a=mid:video
a=sendrecv
a=rtcp-mux
a=rtcp-rsize
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
a=ssrc-group:FID 2527104241
a=ssrc:2527104241 cname:JPmKBgFHH5YVFyaJ
a=ssrc:2527104241 msid:gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS c7072509-df47-4828-ad03-7d0274585a56
a=ssrc:2527104241 mslabel:gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS
a=ssrc:2527104241 label:c7072509-df47-4828-ad03-7d0274585a56

SDP Line 是程序相干的,比方 a=rtpmap:96 前面的都是它相干的设置,直到下一行是 a=rtpmap 或者其余属性。

SDP Line 没有对立的 Schema 形容,也就是没有一个固定的规定能解析所有 Line,SDP Grammer 只是形容了 SDP 相干的属性,具体每个属性的表白须要依据属性定义,定义在 RFC 4566,例如:

a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]

SDP 解析时,每个 SDP Line 都是以 key=... 模式,解析出 key 是 a 后,可能有两种形式,可参考 RFC4566:

a=<attribute>
a=<attribute>:<value>

比方 c=IN IP4 0.0.0.0,key 为 c。
比方 a=rtcp-mux,key 为 a,attribute 为 rtcp-mux,没有 value。
比方 a=rtpmap:96 VP8/90000,key 为 a,attribute 为 rtpmap,value=96 VP8/90000。

有时候并非冒号 (:) 就肯定是 <attribute>:<value>,实际上 value 外面也会有冒号,比方:

a=fingerprint:sha-256 7C:93:85:40:01:07:91:BE
a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=ssrc:2527104241 msid:gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS

Session Level Field

会话级别的 SDP 形容字段包含:v、o、s、c、b、t。

  • v(version)

SDP 协定版本,值固定为 0。

  • o(origin)

代表会话的发起者。

  • s(session name)

会话的名称,每个 SDP 中有且仅能有一个 s 形容,其值不能为空。

  • c(connection data)

携带了会话的连贯信息,其实就是 IP 地址。
SDP 的会话级别形容能够蕴含该字段,每一个媒体级别的形容也能够蕴含该字段,如果会话级别和媒体级别都有 c line,那么以媒体级别的 c line 为准。
因为 WebRTC 应用 ICE candidate 替换地址信息,所以不会用到 c line,不过这并不代表 c line 没有用,在 SIP 视频会议场景中,c line 就必不可少了,文末会再次介绍该字段。

  • b (bandwidth)

示意会话或媒体应用的倡议带宽。

  • t(timing)

指定了会话的开始和完结工夫,如果开始和完结工夫都为 0,那么意味着这次会话是永恒的。

对于会话级别字段的更具体的形容,请参考 RFC 4566。

Media Codecs

会话级别形容实现后,前面就是零到多个媒体级别形容,比方:

// Session Description
v=0
......

// Audio Media Description
m=audio 9 UDP/TLS/RTP/SAVPF 111
......

// Video Media Description
m=video 9 UDP/TLS/RTP/SAVPF 96 97
......

这个 SDP 形容了一个音频和一个视频,它的格局参考 RFC4566:

m=<media> <port> <proto> <fmt> ...

其中,前面的一串数字 11196 97 就是 fmt,别离代表音频和视频的 Media Codec,前面会跟着 rtpmap、rtcp-fb、fmtp 这些属性来做进一步的具体的形容。

m=audio 9 UDP/TLS/RTP/SAVPF 111
a=mid:audio
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1

m=video 9 UDP/TLS/RTP/SAVPF 96 97
a=mid:video
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

Remark: 当然,M line 的类型不是只有 audio 和 video,还有 application(bfcp)、text 等媒体类型。

Remark: a=mid 属性能够认为是每个 M 形容的惟一 ID。比方 a=mid:audio,那么 audio 这个字符串就是这个 M 形容的 ID。有的时候 mid 属性值也能够用数字示意,比方 a=mid:0,那么 0 也是这个 M 形容的 ID。mid 值个别和 grouping 传输属性的 BUNDLE 策略联合来用,比方 a=group:BUNDLE audio video,代表本次会话将对 mid 为 audiovideo 的 M 形容进行复用传输。

Remark: M line 的数字 9 代表该媒体类型的传输端口,在 RTC 场景中都是应用 ICE candidate 的地址信息进行数据传输,所以 M line 的 port 并没有用到。不过,在 SIP 的场景下,M line 的 port 就非常重要了,此时,port 代表 RTP 端口,而且必须是偶数。联合 SDP 会话级别形容中的 C line 中的 IP 地址,咱们就能够晓得 SIP 的这路媒体流的传输地址。

Remark: RTX 示意是重传,比方 video 的 97,就是 apt=96 的重传。也就是说如果用的是 97 这个编码格局,它是在 96(VP8) 根底上加了重传性能。

而一共有多少媒体流,则是通过 SSRC 指定的:

m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
a=ssrc:2582129002 cname:8Y1pmIKBijmWeALu
a=ssrc:2582129002 msid:34fD1qguf2v79436S1khLkth8Nb6LbedcF9H bab38910-40cd-4581-9a20-e3f558abb397
a=ssrc:2582129002 mslabel:34fD1qguf2v79436S1khLkth8Nb6LbedcF9H
a=ssrc:2582129002 label:bab38910-40cd-4581-9a20-e3f558abb397

m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 123 127 122 125 107 108 109 124
a=ssrc:565530905 cname:8Y1pmIKBijmWeALu
a=ssrc:565530905 msid:34fD1qguf2v79436S1khLkth8Nb6LbedcF9H 2c533cfe-b6bf-41a8-93f0-1ca031436702
a=ssrc:565530905 mslabel:34fD1qguf2v79436S1khLkth8Nb6LbedcF9H
a=ssrc:565530905 label:2c533cfe-b6bf-41a8-93f0-1ca031436702

Remark: SSRC 就蕴含了须要发送的媒体流,另外 Offer 和 Answer 中都能够蕴含 SSRC。比方客户端和 MediaSoup 通信时,MediaSoup 总是给客户端发 Offer,MediaSoup 的 Offer 蕴含了 MediaSoup 要发送(转发其余客户端的流给客户端)的媒体流 SSRC,同时客户端的 Answer 中也蕴含了本人要推送的 SSRC 流,他们的类型都是 sendrecv。

Remark: msid 对应了 NetStream.id,也就是代表了不同的媒体源,这些 SSRC 能够是不同的媒体源。

如何确定最初的编码?对方会在 Answer 中给出,比方下面 Offer 给出了多个编码,在 Answer 中会抉择一个:

m=audio 9 UDP/TLS/RTP/SAVPF 111
m=video 9 UDP/TLS/RTP/SAVPF 100 102 127 125 108 124
a=rtpmap:100 H264/90000
a=rtpmap:102 H264/90000
a=rtpmap:127 H264/90000
a=rtpmap:125 H264/90000
a=rtpmap:108 red/90000
a=rtpmap:124 ulpfec/90000

尽管 Video 编码有 100 到 125,然而他们都是 H.264,而 108 和 124 则是 FEC,基于 H.264。

PlanB and UnifiedPlan

下面的 MediaCodecs 中,没有规定如何指定多条流。实际上 Audio 和 Video 都有多个 SSRC,每个 SSRC 的编码可能雷同但也可能不同。比方互联网视频会议,用挪动端接入时,编码可能都是 H.264,然而和其余终端接入时可能会有其余编码。

如果 SSRC 的编码不雷同,那么将这些 SSRC 放在同一个 M 形容就会有问题,这就是 PlanB 和 UnifiedPlan 的关键所在。对于 PlanB 只有一个 M(audio) 和 M(video),他们的编码要雷同,当有多路媒体流时,则依据 SSRC 去辨别。UnifiedPlan 则能够有多个 M(audio) 和 M(video),每路流都有本人的 M 形容,这样就能够反对不同的编码。

PlanB 和 UnifiedPlan 其实就是 WebRTC 在多路媒体源(multi media source)场景下的两种不同的 SDP 协商形式。如果引入 Stream 和 Track 的概念,那么一个 Stream 可能蕴含 AudioTrack 和 VideoTrack,当有多路 Stream 时,就会有更多的 Track,如果每一个 Track 惟一对应一个本人的 M 形容,那么这就是 UnifiedPlan,如果每一个 M line 形容了多个 Track(track id),那么这就是 Plan B。

Note: 当只有一路音频流和一路视频流时,Plan B 和 UnifiedPlan 的格局是互相兼容的。

Remark: Chrome 晚期反对的是 PlanB,目前最新版本也反对了 UnifiedPlan,参考 Need to implement WebRTC “Unified Plan” for multistream。

PlanB 参考下图:

UnifiedPlan 参考下图:

Candidate

Candidate 就是传输的候选人,客户端会生成多个 Candidate,比方有 host 类型的、有 relay 类型的、有 UDP 和 TCP 的,如下图所示:

sdpMid: audio, sdpMLineIndex: 0, candidate:2213672593 1 udp 2122260223 30.2.228.19 51068 typ host
sdpMid: video, sdpMLineIndex: 1, candidate:2213672593 1 udp 2122260223 30.2.228.19 55061 typ host

sdpMid: audio, sdpMLineIndex: 0, candidate:3446803041 1 tcp 1518280447 30.2.228.19 9 typ host
sdpMid: video, sdpMLineIndex: 1, candidate:3446803041 1 tcp 1518280447 30.2.228.19 9 typ host

sdpMid: video, sdpMLineIndex: 1, candidate:150963819 1 udp 41885439 182.92.80.26 54400 typ relay raddr 42.120.74.91 rport 37714
sdpMid: audio, sdpMLineIndex: 0, candidate:150963819 1 udp 41885439 182.92.80.26 59241 typ relay raddr 42.120.74.91 rport 49618

Remark:咱们去掉了前面的属性,比方 generation 0 ufrag kce9 network-id 1 network-cost 10,这些属于 Candidate 的形容,和连通性查看等相干。

客户端本人生成了 6 个 Candidates,3 个 Audio 和 3 个 Video,2 个 TCP 和 4 个 UDP,4 个 host 和 2 个 relay。当然对方也会有很多 Candidate,接下来就是本人的 Candidates 和对方的 Candidates 匹配连通(ICE Connectivity Checks),造成 CandidatePair 也就是传输通道。Candidate 还附带了网络属性,比方 network-cost 会在 ICE Connectivity Checks 时用到。

Remark: 对于 Candidate 的类型,还有 srflx 以及 prflx,对于这两种 Candidate 类型的定义以及辨别,前面会在 ICE 相干的技术文章中介绍。

Remark: 对于 ICE Connectivity Checks 咱们会在前面给出具体的剖析,波及到了 STUN 协定。上面会总结出 ICE 相干的 SDP 信息。

SDP 和 Candidate 都是通过信令替换的。如果对方只给了 relay 的 Candidate,例如:

sdpMid: audio, sdpMLineIndex: 0, candidate:150963819 1 udp 41885439 182.92.80.26 51542 typ relay raddr 42.120.74.91 rport 56380

这种状况下,必定最初连通的 CandidatePair 是 Relay 对 Relay,如下图所示:

从这个图中能看进去这个传输通道的发送和接管码率、包的个数、RTT 和丢包率等信息。

实际上,因为咱们这个客户端还有 host 类型的 Candidate,所以它会尝试间接用 host 的这个 Candidate 和对方的 relay 间接连贯:

sdpMid: audio, sdpMLineIndex: 0, candidate:2213672593 1 udp 2122260223 30.2.228.19 51068 typ host

Statistics Conn-audio-1-1
googActiveConnection    false

当然,因为没有连通所以这个 CandidatePair 就不可用。

Remark: WebRTC 是具备在多个 Candidate 之间切换的能力的,具体在 ICE Connectivity Checks 中咱们再剖析。

下面的 Candidates 本人生成了 2 个 Relay 的 Candidates,一个是 audio 的一个是 video 的,为何只用到了 audio 的呢?这就是上面的 BUNDLE 波及的了。

Bundle and RTCP-MUX

传输时,能够复用媒体通道,一种是音频和视频的复用,一种是 RTCP 和 RTP 的复用。

RTCP 和 RTP 复用,示意 Sender 应用一个传输通道(繁多端口)发送 RTP 和 RTCP:

m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
a=rtcp-mux

m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 123 127 122 125 107 108 109 124
a=rtcp-mux

此时,Receiver 必须筹备好在 RTP 端口上接管 RTCP 数据,并须要预留一些资源,比方 RTCP 带宽。

音频和视频复用时,最初只会用一个 Candidate 传输,比方客户端本人的 SDP Offer,和两个 relay 的 Candidates:

a=group:BUNDLE audio video

m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
a=mid:audio

m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 123 127 122 125 107 108 109 124
a=mid:video
sdpMid: video, sdpMLineIndex: 1, candidate:150963819 1 udp 41885439 182.92.80.26 54400 typ relay raddr 42.120.74.91 rport 37714
sdpMid: audio, sdpMLineIndex: 0, candidate:150963819 1 udp 41885439 182.92.80.26 59241 typ relay raddr 42.120.74.91 rport 49618

这示意最终 audio 和 video 只管可能有独立的 Candidate,然而如果对方也是 BUNDLE,那么最终只会用一个 Candidate。例如,如果对方的 Answer 是:

a=group:BUNDLE audio video

m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
a=mid:audio

m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 123 127 122 125 107 108 109 124
a=mid:video
sdpMid: audio, sdpMLineIndex: 0, candidate:150963819 1 udp 41885439 182.92.80.26 51542 typ relay raddr 42.120.74.91 rport 56380

最初它们只会用一个 Candidate 传输。如下图所示:

rtcp-mux 将 RTP 和 RTCP 复用到繁多的端口进行传输,这简化了 NAT traversal,而 BUNDLE 又将多路媒体流复用到同一端口进行传输,这不仅使 candidate harvesting 等 ICE 相干的 SDP 属性变得简略,而且又进一步简化了 NAT traversal。

rtcp-mux 是与 RTC 传输相干的重要的 SDP 属性,对于它的 SDP 协商的准则如下:

  1. 如果 Offer 携带 rtcp-mux 属性,并且 Answer 方心愿复用 RTP 和 RTCP 到繁多端口,那么 Answer 必须也要携带该属性。
  2. 如果 Offer 没有携带 rtcp-mux 属性,那么 Answer 也肯定不能携带 rtcp-mux 属性,而且 Answer 方禁止 RTP 和 RTCP 复用繁多端口。
  3. rtcp-mux 的协商和应用必须是双向的。

举个例子。客户端去订阅服务器的流,客户端的 Offer 没有携带 rtcp-mux 属性,那么服务器会认为客户端不反对 rtcp-mux,也不会走 rtcp 复用的流程。相同,服务器会别离创立 RTP 和 RTCP 两个传输通道,只有当两个通道的 ICE 和 DTLS 都胜利,才会认为本次订阅的传输通道建设胜利,继而向客户端发流。

试想,如果因为你的忽略导致 Offer 漏掉了 rtcp-mux 属性,那么你将永远等不到服务器 Ready 的那一天。所以,SDP 看似只是一些文本,很简略,然而只有在我的项目的实战中,多遇到几个坑,能力更深切的领会到 SDP 属性的含意以及这些属性是如何在 RTC 场景中去发挥作用的。

Remark: 对于 rtcp-mux 更具体的协商细节请参考 RFC 8035。

Remark: 对于 rtcp-mux 场景下如何通过头部字段辨别 rtp 和 rtcp,请参考 RFC 5761。

ICE Connectivity

这里咱们只阐明 SDP 中和 ICE Connectivity Checks 相干的信息,具体的过程咱们会在其余文章中独自剖析。

SDP 中和 ICE 相干的信息包含:

m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
a=ice-ufrag:kce9
a=ice-pwd:M31WxfrwmrFvPws4+tPdbsCE
a=ice-options:trickle

m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 123 127 122 125 107 108 109 124
a=ice-ufrag:kce9
a=ice-pwd:M31WxfrwmrFvPws4+tPdbsCE
a=ice-options:trickle

ufrag 和 pwd 就是 ICE short-term 认证算法用到的用户名和明码。而 trickle 阐明 SDP 中没有蕴含 candidate 信息,Candidate 是通过信令独自替换的,这样能够做到 Connectivity checks 和 Candidate harvesting 并行处理,进步会话建设的速度。

DTLS

这里咱们只阐明 SDP 中对于 DTLS 的信息,具体的 DTLS 握手过程会在 DTLS 相干的技术文章中独自剖析。

SDP 中和 DTLS 相干的信息包含:

m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126B0:A2:B3:AB:0B:A3:44:22:B1:C8:69:52:ED:04:E8:5A:A4:C3:7A:A6:55:F3:BA:76:62:26:4B:F7:9F:DD:F1:BD
a=setup:actpass

m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 123 127 122 125 107 108 109 124
a=fingerprint:sha-256 B0:A2:B3:AB:0B:A3:44:22:B1:C8:69:52:ED:04:E8:5A:A4:C3:7A:A6:55:F3:BA:76:62:26:4B:F7:9F:DD:F1:BD
a=setup:actpass

其中 fingerprint 是 DTLS 过程中的 Certificate 证书的签名,避免客户端和服务器的证书被篡改。

另外,setup 指的是 DTLS 的角色,也就是谁是 DTLS Client(active),谁是 DTLS Server(passive),如果本人两个都能够那就是 actpass。这里咱们是 actpass,那么就要由对方在 Answer 中确定最终的 DTLS 角色:

m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
a=fingerprint:sha-256 B1:FD:D6:2D:94:4E:33:A1:8C:9D:EF:ED:EB:AC:CC:2D:E2:37:15:9B:24:8C:BF:F2:7D:6A:B3:81:23:AA:13:54
a=setup:active

对方是 active,也就是 DTLS Client,那么本人就只能是 DTLS Server,会由对方发动 DTLS ClientHello 开始 DTLS 过程。

Stream Direction

媒体流的方向有四种,别离是 sendonly、recvonly、sendrecv、inactive,它们既能够呈现在会话级别形容中也能够呈现在媒体级别的形容中。

  • sendonly 示意只发送数据,比方客户端推流到 SFU,那么会在本人的 Offer(or Answer) 中携带 senonly 属性
  • revonly 示意只接收数据,比方客户端向 SFU 订阅流,那么会在本人的 Offer(or Answer) 中携带 recvonly 属性
  • sendrecv 示意能够双向传输,比方客户端退出到视频会议中,既要公布本人的流又要订阅他人的流,那么就须要在本人的 Offer(or Answer) 中携带 sendrecv 属性
  • inactive 示意禁止发送数据,比方在基于 RTP 的视频会议中,主持人临时禁掉用户 A 的语音,那么用户 A 的对于音频的媒体级别形容应该携带 inactive 属性,示意不能再发送音频数据。

NOTE: RFC 4566: senonly 和 recvonly 属性仅利用于媒体,不用于媒体管制相干的协定。比方在基于 RTP 的媒体会话中,即便是 recvonly 模式,也依然要发送 RTCP 包,即便是 senonly 模式,也仍然会接管并失常解决 RTCP 包。

媒体流方向的四个属性很重要,在组装 SDP 时要认真校验,保障流方向的正确性。

举个例子,客户端去订阅服务器的流。如果此时客户端的 Offer 携带的属性并不是 recvonly 而是 sendonly,那么即便在信令层面确实是订阅的语义,然而因为某些服务器对 SDP 各属性的校验是非常全面和严格的(本该如此),这种场景下,服务器将不会发送媒体流到客户端,而且服务器回复的 Answer 可能基本不会携带 SSRC。

RTCP Feedback

上面,咱们聊一下 rtcp-fb 这个媒体级别的 SDP 属性,它能通知咱们媒体会话可能对哪些 RTCP 音讯进行反馈,是一个和 QoS 相干的重要的 SDP 属性。

m=video 9 UDP/TLS/RTP/SAVPF 96
a=mid:video
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack pli

如上 SDP 信息,这是一个视频的 M 形容,VP8 编码,payload type 是 96。最初的 3 个 rtcp-fb 属性则阐明了对于 96 这个 media codec 来讲,在网络拥塞管制方面反对 twcc;在 ARQ 方面反对 nack 解决,可能重传失落的 RTP 包;在关键帧方面反对 fir 和 pli 解决,有能力进行关键帧的发送。

在做 SIP 的时候,遇到过一个坑:向某台型号的 SIP 设施发送 PLI 申请后,并没有收到关键帧,通过一番折腾,最初发现,这台设施的 rtcp-fb 形容如下:

m=video 16402 RTP/AVP  34
a=rtpmap:34 H263/90000
a=fmtp:34 CIF4=1;CIF=1;QCIF=1;SQCIF=1
a=sendrecv
a=rtcp-fb:* ccm tmmbr
a=rtcp-fb:* ccm fir

也就是说这台设施只反对 FIR 申请,没有解决 PLI 申请的能力(PS: 为什么没能早一些查看 SDP 的 rtcp 反馈能力,泪目)。在此也想着重强调一下:对于一些很业余谨严的零碎或者设施而言,SDP 齐全体现了它们所领有的能力,也能够让咱们发现其不具备的能力。SDP 的每一个属性都是有其存在意义的,万万不可疏忽。

Note: rtcp-fb 不能用于会话级别的形容中,只能用于媒体级别的形容,而且其 M 形容的 proto 字段肯定要指定 AVPF。

Note: 存在这种格局,a=rtcp-fb:* ccm fir,星号是一个通配符,示意该 M 形容下的所有类型的 media codec 都反对 fir 的解决和关键帧的反馈。

Compare with SIP SDP

RTC 场景与 SIP 场景下的 SDP 形容的不同体现在传输、媒体、信令三个层面。

Transmission Level

  1. 建连流程。RTC 场景下的音视频媒体流建连流程个别是 ICE + DTLS,而 SIP 场景下没有这套建连流程,所以也没有 ICE/DTLS 相干的 SDP 属性,比方 ufrag、pwd、setup、fingerprint 等。
  2. 端口复用。RTC 场景下个别都是音视频流以及 RTP/RTCP 复用繁多端口,通过 SSRC 辨别每一路流,通过数据包的头部字段值来辨别 RTP/RTCP,而 SIP 场景下不会复用端口,因而没有 rtcp-mux 属性,也没有 grouping 相干的属性,比方 BUNDLE,且音视频的 RTP 和 RTCP 都是独立端口进行传输,共有四个,所以人造能够应用端口来区分流以及 RTP/RTCP,因而也没有 SSRC 属性。
  3. 链路探测。RTC 场景下个别通过 ICE 的 STUN 探测环节来发现对端通过 NAT 映射之后的进口地址,称为 srflx,而 SIP 场景下须要本人实现对端地址发现的性能,以获取到 SIP 设施通过 NAT 映射之后的进口地址。
  4. 地址信息。RTC 场景下通过 SDP 的 candidate 替换对端地址信息,SIP 场景下通过 C line 的 ip 以及 M line 的端口来替换对端地址信息。
// RTC 场景
a=candidate:1 1 udp 2013266431 30.27.136.138 14306 typ host

// SIP 场景
c=IN IP4 30.41.5.131
m=audio 2352 RTP/AVP 107 108 114 104 105 9 18 8 0 101 123
m=video 2374 RTP/AVP 97 126 96 34 123

Media Level

  1. 屏幕共享。SIP 场景下通过 BFCP 协定来进行屏幕共享的协商,通过 a=content 属性来辨别支流(main)和共享流(slides),而 RTC 场景下通过内部 / 业务信令来进行屏幕共享的协商,支流和共享流的 SDP 形容统一,不会辨别。
  2. Media Codec。目前,RTC 场景下的音视频编码广泛是 Opus + H.264/VP8,SIP 场景下,对于音频编码,有很多 SIP 设施并不反对 Opus,而采纳比拟古老的音频编码,比方 G722、PCMA、PCMU,对于视频编码,广泛反对 H.264,个别不反对 VP8。

Signaling Level

  1. SDP 替换。都是 Offer/Answer 模型,RTC 场景下次要通过 HTTP/TCP 协定替换 SDP,个别是在 HTTP body 中携带 SDP 信息。SIP 场景下能够通过 UDP/TCP/TLS 协定替换 SDP,在 INVITE 和 200 OK 中携带 SDP 信息。

Summary

其实,SDP 文本化的协定格局自身很简略,其难点在于不同的利用场景(比方传统 SIP 视频会议或者 RTC 场景)下扩大出的纷繁复杂的属性及其含意,这些 SDP 属性散落在泛滥的 RFC 以及草案之中,不下肯定的功夫是很难做到全面了解与把握的(PS:每当说到此处,心里总是一万个马奔腾,WebRTC 的 RFC 太多了而且相互关联相互援用,看完这些 RFC 要筹备好视力降落 0.2 度)。

下一篇,咱们会重点讲一下 WebRTC ICE,包含连通性检测、状态切换、trickle 以及 nomination。感激浏览。

阿里云视频云技术公众号分享视频云行业和技术趋势,打造“新内容”、“新交互”。

正文完
 0