SDP里面内容虽然很多,但是条理很清楚。SDP值为字符串,通过换行符生成一行一行的SDP报文,所有行可分为三类:全局行、音频行、视频行
-
v - Version,版本,版本,应等于0
-
o - Origin,源,包含一个唯一ID,用于重新协商
-
s - Session Name,会话名称,应等于-
-
t - Timing,时间,应等于0 0
-
m - Media Description,媒体描述,下面有详细说明
-
a - Attribute,属性,一个自由文本字段,这是WebRTC中最常见的行
-
c - Connection Data,连接数据,应等于IN IP4 0.0.0.0
一、全局行
v=0
sdp版本号,一直为0,rfc4566规定
o=- 7017624586836067756 2 IN IP4 127.0.0.1
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=<session name>
会话名,没有的话使用 - 代替
t=0 0
它给出了开始和结束时间。 当它们被设置为0时,意味着会话不受特定时间限制,换句话说,它在任何时候都是永久有效的。
a=group:BUNDLE audio video
BUNDLE分组建立了SDP中包含的几个媒体线之间的关系,通常是音频和视频。在WebRTC中,它用于在相同的RTP会话中复用多个媒体流。 在这种情况下,浏览器提供多路复用音频和视频,但另一方也必须支持和接受。 如果没有这一行,音视频,数据就会分别单独用一个udp端口来发送
a=msid-semantic: WMS h1aZ20mbQB0GSsq0YxLfJmiYWE9CBfGch97C
WMS是WebRTC Media Stream简称,这一行定义了本客户端支持同时传输多个流,一个流可以包括多个track, 一般定义了这个,后面a=ssrc这一行就会有msid,mslabel等属性
二、视频行
2.1 媒体描述
m=video 60372 UDP/TLS/RTP/SAVPF 100 101 116 117 96
m=video说明本会话包含音频,60372代表视频使用端口60372来传输,但是在webrtc中一现在一般不使用,如果设置为0,代表不传输音频, UDP/TLS/RTP/SAVPF是表示用户来传输视频支持的协议,udp,tls,rtp代表使用udp来传输rtp包,并使用tls加密SAVPF代表使用srtcp的反馈机制来控制通信过程, 后台100 101 116 117 96表示本会话视频支持的编码。
m=<media> <port> <proto> <fmt> ...
【学习地址】:FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发
【文章福利】:免费领取更多音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击1079654574加群领取哦~
其中:
-
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
2.2 连接数据(c=)
c=IN IP4 217.130.243.155
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
2.3 属性(a=)
a=rtcp:64891 IN IP4 217.130.243.155
a=<attribute> | <attribute>:<value>
属性(attribute)是扩展SDP的主要手段,分为会话级属性和媒体级属性:
(a)会话级属性:添加在第一个媒体描述之前,传达的信息适用于整个会议而不是单个媒体。
-
a=group:BUNDLE audio video 通过mid标识符把多个媒体属性连接起来;
-
a=msid-semantic: WMS ma 表示是webrtc媒体流(Webrtc Media Streams);
(b)媒体级属性:媒体描述中添加有关媒体流的信息。
-
a=mid:audio 上述BUNDLE中用到的媒体标识;
-
a=msid:ma ta 连接不同的媒体描述,使用相同的MediaStreams;
-
a=sendonly 表示媒体发送端,其他类型:recvonly,sendrecv,inactive;
-
a=rtcp:9 IN IP4 0.0.0.0 用来传输rtcp地地址和端口;
-
a=rtcp-mux 表示rtp,rtcp包使用同一个端口来传输;
-
a=ice-xxx:xxx ice协商过程中的安全验证信息;
-
a=fingerprint:xxx 表示dtls协商过程中需要的认证信息;
-
a=setup:actpass 表示本客户端在dtls协商过程中,可以做客户端也可以做服务端;
-
a=rtpmap:111 opus/48000/2 负载类型111,编码格式opus,48000是时钟,2是通道数;
-
a=rtcp-fb:111 nack 支持丢包重传;
-
a=rtcp-fb:111 nack pli 支持关键帧丢包重传;
-
a=rtcp-fb:111 transport-cc 表示opus编码支持使用rtcp来控制拥塞;
-
a=fmtp:111 minptime=10;useinbandfec=1;maxplaybackrate=16000 对opus编码可选的补充说明,minptime代表最小打包时长是10ms,useinbandfec=1代表使用opus编码内置fec特性;
-
a=ssrc:1370113029 cname:NMediaAudio cname用来标识一个数据源,ssrc当发生冲突时可能会发生变化,但是cname不会发生变化,也会出现在rtcp包中SDEC中,用于音视频同步;
-
a=candidate:1 1 udp 2013266431 x.x.x.x 43342 typ host generation 0 表示候选人的传输地址,查看详情。
2.1 ICE候选者
a=candidate:1467250027 1 udp 2122260223 192.168.0.196 56143 typ host generation 0
2.2 ICE参数
a=ice-ufrag:Oyef7uvBlwafI3hT a=ice-pwd:T0teqPLNQQOf+5W+ls+P2p16
2.3 DTLS参数
a=fingerprint:sha-256 49:66:12:17:0D:1C:91:AE:57:4C:C6:36:DD:D5:97:D2:7D:62:C9:9A:7F:B9:A3:F4:70:03:E7:43:91:73:23:5E a=setup:actpass
2.4 Codec参数
a=rtpmap:100 VP8/90000
这条线表示VP8与有效载荷类型100对齐。这意味着此会话中包含VP8视频帧的RTP数据包的有效载荷类型字段的值将为100. 现在VP8是视频的MTI编解码器,未来可能会发生变化。
a=rtcp-fb:100 ccm fir
指明使用全内帧请求(Full Intraframe Request, FIR)
a=rtcp-fb:100 nack
此行请求使用RFC 4585中指示的否定ACK(nack)。这允许另一端知道数据包丢失。
a=rtcp-fb:100 nack pli
此行表明支持PLI NACK RTCP消息。 这允许在视频包丢失时向另一端点请求新的VP8关键帧。
a=rtcp-fb:100 goog-remb
它定义了RTCP消息对Receiver Estimated Maximum Bitrate的使用。前缀goog-意味着仍然只能由Google和非标准实现。
a=rtpmap:101 VP9/90000
Chrome支持版本48的VP9。您可以在Web M项目站点了解此视频编解码器的功能。 默认情况下,它在VP8之后显示为SDP中的第二个选项。
a=rtcp-fb:101 ccm fir a=rtcp-fb:101 nack a=rtcp-fb:101 nack pli a=rtcp-fb:101 goog-remb a=rtpmap:116 red/90000
该行请求使用RFC2198,其定义有效载荷格式以编码冗余媒体数据。在WebRTC中,这用于封装有效载荷VP8(视频有效载荷本身)和FEC(Forward Error Correction)。
a=rtpmap:117 ulpfec/90000
此行请求使用ULP FEC(在RFC5109中定义)。 FEC(前向纠错)允许通过基于原始分组发送冗余信息来纠正数据传输中的某种错误。 当丢包(在RTCP-RR数据包中报告)时使用FEC。
a=rtpmap:96 rtx/90000
参数rtx和apt在RFC4588中定义。 该RFC定义了RTP有效载荷格式,仅用于执行另一方尚未接收的分组的重传。 无法使用原始有效负载重新发送数据包,因为它会破坏RTP和RTCP机制,因此它们会在具有不同有效负载的重新传输流中重新传输。 90000指的是重传流的时钟速率,其与原始VP8流相同,原始VP8流与其他视频协议90000相同。
a=fmtp:96 apt=100
该行表示具有有效载荷96的RTP分组将传输那些已经在该SDP(VP8)中对有效载荷100进行了编码的编解码器的rtx消息。
2.5 SSRC参数
a=ssrc-group:FID 2231627014 632943048
此行声明SSRC 632943048是RFC5576中指定的2231627014的rtx修复流程
a=ssrc:2231627014 cname:4TOk42mSjXCkVIa6 a=ssrc:2231627014 msid:lgsCFqt9kN2fVKw5wg3NKqGdATQoltEwOdMS daed9400-d0dd-4db3-b949-422499e96e2d a=ssrc:2231627014 mslabel:lgsCFqt9kN2fVKw5wg3NKqGdATQoltEwOdMS a=ssrc:2231627014 label:daed9400-d0dd-4db3-b949-422499e96e2d
** 注:未特别说明,则与audio一致
三、音频行
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
这一行表示你要用来接收或者发送音频使用的IP地址,webrtc使用ice传输,不使用这个地址
a=rtcp:9 IN IP4 0.0.0.0
明确指定传输RTCP的IP和端口,而不是从基础媒体端口派生的。请注意,与SRTP的端口相同,因为支持RTCP Multiplex。webrtc中不使用。
a=mid:audio
在前面BUNDLE这一行中用到的媒体标识。如果我们有不同的媒体,我们每个都应该有不同的标识符。
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
此行定义将在RTP标头中使用的扩展,以便接收器可以正确解码并提取元数据。
a=sendrecv
上一行指出我是双向通信,另外几种类型是recvonly,sendonly,inactive。
a=rtcp-mux
指出rtp,rtcp包使用同一个端口来传输
3.1 ICE候选者
a=candidate:1467250027 1 udp 2122260223 192.168.0.196 46243 typ host generation 0
a=candidate:1467250027 2 udp 2122260222 192.168.0.196 56280 typ host generation 0
UDP上RTP的主机候选者 - 在此ICE行中,我们的浏览器为其主机候选者 - 浏览器正在计算机上监听的接口或接口的IP。 浏览器可以在该IP上接收/发送SRTP和SRTCP,以防远程对等端的候选者具有IP可见性。例如,如果另一台计算机位于同一LAN上,则将使用主机候选项。 协议(udp) - 2122260223之后的数字是候选者的优先级。请注意,宿主候选者的优先级高于其他候选者, 因为使用宿主候选者在资源使用方面更有效。第一行(component = 1)用于RTP,第二行(component = 2)用于RTCP。 请注意,浏览器不知道另一端是否支持rtcp-mux,因此它必须在要约中包含RTCP端口。
a=candidate:435653019 1 tcp 1845501695 192.168.0.196 0 typ host tcptype active generation 0
a=candidate:435653019 2 tcp 1845501695 192.168.0.196 0 typ host tcptype active generation 0
TCP上RTP的主机候选者 - 这些线路与之前的两条ICE线路相同,但是对于TCP流量。 请注意,优先级较低 - 即1845501695较大 - 因为TCP不是实时媒体传输的最佳选择。
a=candidate:1853887674 1 udp 1518280447 47.61.61.61 36768 typ srflx raddr 192.168.0.196 rport 36768 generation 0
a=candidate:1853887674 2 udp 1518280447 47.61.61.61 36768 typ srflx raddr 192.168.0.196 rport 36768 generation 0
UDP上RTP的自反性候选者(reflexive candidates) - 这里我们有服务器反身候选人。 请注意,它们的优先级低于主机候选者。 这些候选人是由STUN服务器发现的。
a=candidate:750991856 2 udp 25108222 237.30.30.30 51472 typ relay raddr 47.61.61.61 rport 54763 generation 0
a=candidate:750991856 1 udp 25108223 237.30.30.30 58779 typ relay raddr 47.61.61.61 rport 54761 generation 0
UDP上RTP的中继候选者(Relay candidates) - 接下来我们有中继候选。这些候选者是从TURN服务器获得的,必须在创建对等连接时进行配置。 请注意,此处的优先级低于主机和反射候选者(25108222更高),因此仅当主机和反射候选者之间没有IP连接时才使用中继。
3.2 ICE参数
a=ice-ufrag:khLS
a=ice-pwd:cxLzteJaJBou3DspNaPsJhlQ
以上两行是ice协商过程中的安全验证信息
3.3 DTLS参数
a=fingerprint:sha-256 FA:14:42:3B:C7:97:1B:E8:AE:0C2:71:03:05:05:16:8F:B9:C7:98:E9:60:43:4B:5B:2C:28:EE:5C:8F3:17
此指纹是DTLS-SRTP协商中使用的证书的哈希函数的结果。 此行在信令(应该是可信的)和DTLS中使用的证书之间创建绑定,如果指纹不匹配,则应拒绝会话。
a=setup:actpass
代表本客户端在dtls协商过程中,可以做客户端也可以做服务端
3.4 Codec参数
a=rtpmap:111 opus/48000/2
Opus是WebRTC的MTI音频编解码器之一。 它具有可变比特率(6kbps-510kbps),并且不受任何版税限制,因此可以在任何浏览器中自由实现。 Opus支持开始变得普遍,它已成为大多数WebRTC应用程序的关键。
a=fmtp:111 minptime=10; useinbandfec=1
此行包括Chrome支持的音频Opus编解码器的可选有效载荷格式特定参数。 minipitime = 10指定分组化时间的最低值(ptime:由单个分组传输的音频的毫秒数)。 useinbandfec = 1指定解码器能够利用Opus带内FEC(前向错误连接)。
a=rtpmap:103 ISAC/16000
ISAC(互联网语音音频编解码器)是用于高质量会议的宽带语音编解码器。 16000表示ISAC将以16kbps的速度使用。
a=rtpmap:104 ISAC/32000
32000表示ISAC将以32kbps的速度使用。
a=rtpmap:9 G722/8000
G722是一款工作频率为48,56和64 kbit/s的宽带音频编解码器,与G.711等窄带语音编码器相比,由于50-7000 Hz的语音带宽更宽,因此可提供更高的语音质量。
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
这是使用不同压扩法则的经典电信64kbps脉冲编码调制(PCM)编解码器。 0和8分别是PCMU和PCMA的静态有效载荷类型。从技术上讲,这些线路不存在,因为这些信息可以通过媒体线中的编解码器列表 - PCMU或PCMA来推断。
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
上面的动态RTP有效载荷类型(除了有效载荷类型13,它是静态的)表示舒适噪声(Comfort Noise, CN)将用于速率为48000,32000,16000和8000kbits/s的编解码器。
a=rtpmap:126 telephone-event/8000
此行表示浏览器支持RFC4733,允许它在RTP内发送DTMF,而不是通常的数字化正弦波,而是作为特殊有效载荷(在这种情况下,RTP数据包中有效载荷126)。 该DTMF机制确保DTMF将独立于音频编解码器和信令协议进行传输。
a=maxptime:60
maxptime指定可以封装在每个数据包中的最大媒体数量,以毫秒为单位表示。数据包的大小可能会对音频和BW的质量产生副作用。可以在SDP中修改此值。
3.5 SSRC参数
a=ssrc:3570614608 cname:4TOk42mSjXCkVIa6
cname源属性将媒体源与其Canonical端点标识符相关联,即使在发现冲突时ssrc标识符发生更改,该标准端点标识符也将保持RTP媒体流的常量。 这是媒体发送方将在其RTCP SDES数据包中放置的值。
a=ssrc:3570614608 msid:lgsCFqt9kN2fVKw5wg3NKqGdATQoltEwOdMS 35429d94-5637-4686-9ecd-7d0622261ce8
该线用于使用SDP信令通知SSRC的RTP概念与“媒体流”/“媒体流轨道”的WebRTC概念之间的关联。 第一个参数对应于媒体流(media stream)的id,第二个参数对应于媒体流轨道的if。这些ID在WebRTC API中处理。 第一个数字是SSRC标识符,它将包含在RTP数据包的SSRC字段中。
a=ssrc:3570614608 mslabel:lgsCFqt9kN2fVKw5wg3NKqGdATQoltEwOdMS
label属性指的是Media Stream对象的id。不推荐使用该参数,并将msid替换为该参数。标签是为了向后兼容而保留。
a=ssrc:3570614608 label:35429d94-5637-4686-9ecd-7d0622261ce8
label属性也被msid弃用,并在使用SDP的任意网络应用程序的上下文中携带指向RTP媒体流的指针。 此标签与WebRTC API中的Media Stream Track ID相对应,该ID包含在msid行中。
四、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
五、Uncaught (in promise) DOMException: Answer tried to set recv when offer did not set send
chrome 中可以播放,firefox报错
搜索一下,参考https://stackoverflow.com/questions/35166456
RFC 3264: " If a media stream is listed as recvonly in the offer, the answer MUST be marked as sendonly or inactive in the answer. "
这里可以参考SDP模型介绍,获取更详细的知识
1.情态动词术语解释
-
MUST必须、一定要;
-
MUST NOT禁止;
-
REQUIRED需要;
-
SHALL、SHOULD应该;
-
SHALL NOT、SHOULD NOT不应该;
-
RECOMMENDED推荐;
-
MAY可以
以上情态动词术语可参考RFC2119[3],这些动词要求我们在产品实现时,需要遵守或灵活变更约束。
2.初始协商的Offer请求
实体A <-> 实体B,实体首先发起Offer请求,内容如2节所示,对于作何一个媒体流/媒体通道,这时实体A必须:
-
如果媒体流方向标为recvonly/sendrecv,即a=recvonly或a=sendrecv,则A必须(MUST)准备好在这个IP和端口上接收实体B发来的媒体流;
-
如果媒体流方向标为sendonly/inactive,即a=recvonly或a=sendrecv,则A不需要进行准备。
3.Answer响应
实体B收到A的请求offer后,根据自身支持的媒体类型和编码策略,回复响应。
-
如果实体B回复的响应中的媒体流数量和顺序必须(MUST)和请求offer一致,以便实体A进行甄别和决策。即m行的数量和顺序必须一致,B不能(MUST NOT)擅自增加或删除媒体流。如果B不支持某个媒体流,可以在对应的端口置0,但不能不带这个m行描述。
-
对于某种媒体,实体B必须(MUST)从请求offer中选出A支持且自己也支持的该媒体的编码标识集,并且可以(MAY)附带自己支持的其它类型编码。
-
对于响应消息中各个媒体的方向: 如果请求某媒体流的方向为sendonly,那么响应中对应媒体的方向必须为recvonly; 如果请求某媒体流的方向为recvonly,那么响应中对应媒体的方向必须为sendonly; 如果请求某媒体流的方向为sendrecv,那么响应中对应媒体的方向可以为sendrecv/sendonly/recvonly/inactive中的一种; 如果请求某媒体流的方向为inactive,那么响应中对应媒体的方向必须为inactive;
-
响应answer里提供IP和端口,指示Offerer本端期望用于接收媒体流的IP和端口,一旦响应发出之后,Offerer必须(MUST)准备好在这个IP和端口上接收实体A发来的媒体流。
-
如果请求offer中带了ptime(媒体流打包间隔)的a行或带宽的a行,则响应answer也应该(SHOULD)相应的携带。
-
实体B Offerer应该(SHOULD)使用实体A比较期望的编码生成媒体流发送。一般来说对于m行,如m=video 0 RTP/AVP 31 34,排充越靠前的编码表示该实体越希望以这个编码作为载体,这里示例31(H261),34(H263)中H261为A更期望使用的编码类型。同理,当实体A收到响应answer后也是这样理解的。
4.实体收到响应后的处理
当实体A收到B回复的响应后,可以(MAY)开始发送媒体流,如果媒体流方向为sendonly/sendrecv,
-
必须(MUST)使用answer列举的媒体类型/编码生成媒体发送;
-
应该(SHOULD)使用answer中的ptime和bandwidth来打包发送媒体流;
-
可以(MAY)立即停止监听端口,该端口为offer支持answer不支持的媒体所使用的端口。
5.修改媒体流(会话)
修改媒体流的offer-answer操作必须基于之前协商的媒体形式(音频、视频等),不能(MUST NOT)对已有媒体流进行删减。
(a)删除媒体流 如果实体认定新的会话不支持之前媒商的某个媒体,新的offer只须对这种媒体所在m行的端口置0,但不能不描述这种媒体,即不带对应m行。当answerer收到响应之后,处理同初始协商一样。
(b)增加媒体流 如果实体打算新增媒体流,在offer里只须加上描述即可或者占用之前端口被置0的媒体流,即用新的媒体描述m行替换旧的。当answerer收到offer请求后,发现有新增媒体描述,或者过于端口被置0的媒体行被新的媒体描述替换,即知道当前为新增媒体流,处理同初始协商。
(c)修改媒体流 修改媒体注主要是针对初始协商结果,如果有变更即进入修改流程处理,可能的变更包括IP地址、端口,媒体格式(编码),媒体类型(音、视频),媒体属性(ptime,bandwidth,媒体流方向变更等)。
6.解决问题:
查看请求offer发送的Sdp,发现在没有设置的情况下,全是默认的recvonly。
m=audio ...
...
a=recvonly
...
m=video ...
a=recvonly
而服务器返回的
m=audio ...
...
a=recvonly
...
m=video ...
a=sendrecv
参照上述要求,可以将请求offer设置成sendrecv即可解决firefox中的报错
this.pc.addTransceiver("video", {
'direction': 'sendrecv'
});
this.pc.addTransceiver("audio", {
'direction': 'sendrecv'
});
7.Transceivers
Transceivers are for sending and receiving
Transceivers is a WebRTC specific concept that you will see in the API. What it is doing is exposing the ‘Media Description’ to the JavaScript API. Each Media Description becomes a Transceiver. Every time you create a Transceiver a new Media Description is added to the local Session Description.
Each Media Description in WebRTC will have a direction attribute. This allows a WebRTC Agent to declare ‘I am going to send you this codec, but I am not willing to accept anything back’. There are four valid values:
-
send
-
recv
-
sendrecv
-
inactive