webrtc依赖的服务有如下几种
SDP协议:
1998-RFC2327
2006-RFC4566
例子(https://webrtchacks.com/sdp-anatomy/?spm=ata.13261165.0.0.41035c8c9sVCVD)
SDP是通过offer和answer来交互的
type: offer, sdp: 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 98 99 100 101 102 123 127 122 125 107 108 109 124
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=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=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
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=rtpmap:98 VP9/90000
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=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtpmap:100 H264/90000
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=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtpmap:102 H264/90000
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=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:123 rtx/90000
a=fmtp:123 apt=102
a=rtpmap:127 H264/90000
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=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032
a=rtpmap:122 rtx/90000
a=fmtp:122 apt=127
a=rtpmap:125 H264/90000
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=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
a=rtpmap:107 rtx/90000
a=fmtp:107 apt=125
a=rtpmap:108 red/90000
a=rtpmap:109 rtx/90000
a=fmtp:109 apt=108
a=rtpmap:124 ulpfec/90000
a=ssrc-group:FID 2527104241 4186960130
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
a=ssrc:4186960130 cname:JPmKBgFHH5YVFyaJ
a=ssrc:4186960130 msid:gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS c7072509-df47-4828-ad03-7d0274585a56
a=ssrc:4186960130 mslabel:gLzQPGuagv3xXolwPiiGAULOwOLNItvl8LyS
a=ssrc:4186960130 label:c7072509-df47-4828-ad03-7d0274585a56
type: answer, sdp: 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 98 99 100 101 102 123 127 122 125 107 108 109 124
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=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=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
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=rtpmap:98 VP9/90000
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=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtpmap:100 H264/90000
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=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtpmap:102 H264/90000
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=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:123 rtx/90000
a=fmtp:123 apt=102
a=rtpmap:127 H264/90000
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=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032
a=rtpmap:122 rtx/90000
a=fmtp:122 apt=127
a=rtpmap:125 H264/90000
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=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
a=rtpmap:107 rtx/90000
a=fmtp:107 apt=125
a=rtpmap:108 red/90000
a=rtpmap:109 rtx/90000
a=fmtp:109 apt=108
a=rtpmap:124 ulpfec/90000
a=ssrc-group:FID 3587783331 4235118392
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
a=ssrc:4235118392 cname:INxZnBV2Sty1zlmN
a=ssrc:4235118392 msid:uiZ7cB0hsFDRGgTIMNp6TajUK9dOoHi43HVs a3b297e7-cdbe-464e-a32c-347465ace055
a=ssrc:4235118392 mslabel:uiZ7cB0hsFDRGgTIMNp6TajUK9dOoHi43HVs
a=ssrc:4235118392 label:a3b297e7-cdbe-464e-a32c-347465ace055
一般来说,推流方先发起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描述分为两部分,分别是会话级别的描述(session level)和媒体界别的描述(media level),其具体的组成可参考RFC4566
Session description
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)
b=* (zero or more bandwidth information lines)
One or more time descriptions ("t=" and "r=" lines; see below)
z=* (time zone adjustments)
k=* (encryption key)
a=* (zero or more session attribute lines)
Zero or more media descriptions
Time description
t= (time the session is active)
r=* (zero or more repeat times)
Media description, if present
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=* (encryption key)
a=* (zero or more media attribute lines)
SDP Line是顺序相关的,比如a=rtpmap:96后面的都是和它相关的设置,直到下一行是a=rtpmap或者其他属性。
会话级别的描述包括:v、o、s、c、b、t
v:版本号,固定为0
o:代表会话的发起者
s:会话的名称,每个SDP中有且仅有一个s描述,其值不能为空
c:携带了会话的连接信息,其实就是IP地址。SDP的会话级别描述可以包含该字段,每一个媒体级别的描述也可以包含该字段,如果会话级别和媒体级别都有c line,那么以媒体级别的c line为准,因为WebRTC使用ICE candidate交换地址信息,所以不会用到c line,不过这并不代表c line没有用,在SIP视频会议场景中,c line就必不可少,文末会再次介绍该字段。
b:表示会话或媒体使用的建议带宽。
t:制定了会话和结束时间,如果开始和结束时间都为0,那么意味着这次会话是永久的。
会话级别描述完成后,后面会跟着0个或多个媒体级别的描述。
m line的类型不只有audio和video,还有application、text等媒体类型
a=mid属性可以认为是每个M描述的唯一ID。比如a=mid:audio,那么audio这个字符串就是这个M描述的ID。有时候mid属性值也可以用数字表示,比如a=mid:0,那么就是这个M描述的ID。mid值一般和grouping传输属性的bundle策略结合来使用,比如a=group:BUNDLE audio video,代表本次会话将mid为audio和video的M描述进行复用传输。
m line的数字9代表媒体类型的传输端口,在RTC场景下都是使用ICE candidate的地址信息进行数据传输,所以m line的port没有用到。不过在sip的场景下是需要的
rtx代表重传
ssrc,一共有多少媒体流,通过ssrc指定。ssrc包含了需要发送的媒体流,另外offer和answer中都可以包含ssrc。比如客户端和mediaSoup通信时,mediaSoup总是给客户端发offer,mediaSoup的offer包含了MediaSoup要发送(转发其它客户端的流给客户端)的媒体流ssrc,同时客户端的answer中也包含了自己要推送的ssrc流,他们的类型都是sendrecv
上面的SDP的例子,没有规定如何指定多条流。实际上audio和video都可有有多个ssrc,每个ssrc的编解码可能相同但也可能不相同。如果ssrc编解码不相同,那么将这些ssrc放在同一个M中描述就会有问题,这就是PlanB和unifiedPlan的关键所在。对于PlayB只能有一个M(audio)和M(video),如果有多个ssrc,他们的编解码也必须相同。unifiedPlan则可以多个M(audio)和M(video),每路流都有自己的M描述,这样就可以支持不同的编码。
PlanB和unifiedPlan其实就是WebRTC在多路媒体源场景下的两种不同的SDP协商方式。如果引入stream和track的概念,那么一个stream可能包含audio track和video track,当有多路stream时,就会有更多的track,如果每个track唯一对应一个自己的M描述,那么就是unifiedplan,如果每个M描述多个track,那么就是playB。
candidate就是传输的候选人,客户端会生成多个candidate,比如有host类型的,relay类型的,有udp和tcp的。两端都会通过SDP交换自己的多个candidate,然后通过ICE connectivity check,形成candidate pair也就是传输通道了。
a=rtcp-mux
===
a=group:BUNDLE audio video
m=....
a=mid:audio
m=....
a=mid:video
rtcp-mux将rtp和rtcp复用到单一的端口进行传输,BUNDLE将多路媒体流复用到同一个端口进行传输,这可以简化nat协商。
rtcp-mux的sdp协商原则为:
rtcp-mux更详细协商细节参见rfc 8035,rtcp-mux场景下如何通过头部字段区分rtp和rtcp,参考rfc5761
m=xxx
a=ice-ufrag:kce9
a=ice-pwd:xxxxx
a=ice-options:trickle
ufrag和pwd就是ICE short-term认证算法用到的用户名和密码。而trickle说明SDP中没有包含candidate信息,candidate信息是通过信令单独交换的,这样可以做到connectivity checks和candidate harvesting并行处理,提高会话建立的速度。
m=audio xxx
a=setup:actpass
m=video xxx
a=fingerprint:sha-256 B1:ff:......
a=setup:active
其中fingerprint是DTLS过程中的certificate证书的签名,防止客户端和服务器的证书被篡改。
另外,setup指的是DTLS的角色,active表示DTLS client,passive表示DTLS server,如果自己两个都是就是actpass。都是有client端发起DTLS clientHello开始DTLS过程。
媒体流的方向包括,sendonly,recvonly,sendrecv,inactive。
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
rtcp-fb这个是媒体级别的SDP属性,它能告诉我们媒体会话能够对哪些RTCP消息进行反馈,是一个和QoS相关的重要的SDP属性,如上面SDP信息,这是一个视频M描述,VP8编码,payload type是96。最后3个rtcp-fb属性则说明关于96这个media codec来讲在网络拥塞控制方面的支持twcc;在ARQ方面支持nack处理,能够重传丢失的RTP包;在关键帧方面支持fir和pli处理,有能力进行关键帧的发送。
rtcp-fb不能用于会话级别的描述,只能用于媒体级别的描述,而且M描述的proto字段一定要指定AVPF。
存在这种格式a=rtcp-fb:* ccm fir,*是一个通配符,表示该M描述下的所有类型的media codec都支持fir的处理和关键帧的反馈。