WebRTC多媒体开发

SDP[RFC3264]

2018-04-18  本文已影响47人  耦耦

SDP协议


概述

SDP(会话描述协议),用于两个会话实体之间的媒体协商,并达成一致,属信令语言族,采用文本(字符)描述形式。

SDP(session description Protocal)会话描述协完全是一种会话描述格式 ― 它不属于传输协议 ― 它只使用不同的适当的传输协议,包括会话通知协议(SAP)、会话初始协议(SIP)、实时流协议(RTSP)、MIME 扩展协议的电子邮件以及超文本传输协议(HTTP)。SDP协议是也是基于文本的协议。SDP 不支持会话内容或媒体编码的协商,所以在流媒体中只用来描述媒体信息。媒体协商这一块要用RTSP来实现.

JSEP将客户端之间传递的信令分为两种:offer信令和answer信令。他们主要内容的格式都遵循会话描述协议(Session Description Protocal,简称SDP)。

SDP协议格式:SDP描述由许多文本行组成,文本行的格式为<类型>=<值>

注意:协议的等号前后不可有空格!!!type: 该字节为单字节(如: v,o, m等)区分大小写

<type>=< value > [CRLF]

其实可以将其简化一下,它就是一个在点对点连接中描述自己的字符串,我们可以将其封装在JSON中进行传输,在PeerConnection建立后将其通过服务器中转后,将自己的SDP描述符和对方的SDP描述符交给PeerConnection就行了。(暂时没试过)

常见的fields有:

通过offer和answer交换SDP描述符


大致上在两个用户(甲和乙)之间建立点对点连接流程应该是这个样子(这里不考虑错误的情况,RTCPeerConnection简称PC):

webRTC参考图.png
  1. 甲和乙(也就是图中的A和B)各自建立一个PC实例
  2. 甲通过PC所提供的createOffer()方法建立一个包含甲的SDP描述符的offer信令
  3. 甲通过PC所提供的setLocalDescription()方法,将甲的SDP描述符交给甲的PC实例
  4. 甲将offer信令通过服务器发送给乙
  5. 乙将甲的offer信令中所包含的的SDP描述符提取出来,通过PC所提供的setRemoteDescription()方法交给乙的PC实例
  6. 乙通过PC所提供的createAnswer()方法建立一个包含乙的SDP描述符answer信令
  7. 乙通过PC所提供的setLocalDescription()方法,将乙的SDP描述符交给乙的PC实例
  8. 乙将answer信令通过服务器发送给甲
  9. 甲接收到乙的answer信令后,将其中乙的SDP描述符提取出来,调用setRemoteDescripttion()方法交给甲自己的PC实例

通过在这一系列的信令交换之后,甲和乙所创建的PC实例都包含甲和乙的SDP描述符了,完成了两件事的第一件。我们还需要完成第二件事——获取连接两端主机的网络地址,这里可以参考P2P的链接过程,此处不赘述。

SDP协议分析 RFC4566


会话描述

示例:o = - 6311806030512608073 2 IN IP4 127.0.0.1  

<username>是用户在始发主机上的登录名,或者如果始发主机不支持用户标识的概念,则为“ - ” 。<username>不能包含空格。

<sess-id>是一个数字字符串,使得<username>,<sess-id>,<nettype>,<addrtype>和<unicast-address>的元组形成会话的全局唯一标识符。

<sess-version> 是此会话描述的版本号。

<nettype> 网络类型。是一个给出网络类型的文本字符串。最初“IN”被定义为具有“Internet”的含义,但其他值可以在将来注册。

 <addrtype> 地址类型 IP4和IP6。

 <unicast-address>是创建会话的机器的地址。

时间描述

如果<stop-time>设置为零,则会话不受限制,尽管直到<开始时间>之后它才会变为活动状态。如果<开始时间>也为零,则该会话被认为是永久的。

如果一个会话在多个不规则间隔时间激活,可以使用多个“t =”行; 每个额外的“t =”行指定了会话活动的额外时间段。如果会话在正常时间处于活动状态,则应在“t =”行之外和之后使用“r =”行 -- 在这种情况下,“t =”行指定开始和重复序列的停止时间。

一个或更多时间描述(如下所示):

媒体描述,如果有的话

SDP属性

如果没有任何属性“sendonly”,“recvonly”,“inactive”,和“sendrecv”时,应将“sendrecv”假定为非会议类型“broadcast”或“H332”(见下文)的会话的默认值。

SDP包括以下一些方面:

协议实例


Offer from localPeerConnection:

// SDP开头4个必填字段
- **v=0**   // SDP版本号,设置为0,这是当前使用的唯一SDP版本

- **o=**- 6976870941538595051 2 IN IP4 127.0.0.1
 // 来源包含一系列字段,其中包括用户、会话ID、版本ID、网络地址、地址类型和地址;这里的地址是一个环回地址(127.0.0.1)

- **s=-**  // 主题,会话名,没有的话使用-代替

- **t=0 0**     // 时间,两个值分别是会话的起始时间和结束时间,这里都是0代表没有限制

// 接下来是SDP的属性用于定义此SDP中使用的媒体流ID语义。
- **a=group:**BUNDLE audio video   // 需要共用一个传输通道传输的媒体,如果没有这一行,音视频,数据就会分别单独用一个udp端口来发送

- **a=msid-semantic:** WMS qovvqrAafFmIE8VZCxLsWvxdW7zQtcDpzzsb
//WMS是WebRTC Media Stream简称,这一行定义了本客户端支持同时传输多个流,一个流可以包括多个track,
//一般定义了这个,后面a=ssrc这一行就会有msid,mslabel等属性

// 接下来,此SDP提议包含三个用于建立数据通道的媒体行(m =)
- **m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126**
// 第一个音频媒体行列出了端口号(9,不会被使用,因为实际端口位于a = candidate字段中)、扩展的安全音频/视频配置文件( UDP/TLS/RTP/SAVPF),
//随后列出可能的编解码器(有效负载类型分别是111 103 104 9 0 8 106 105 13 110 112 113 126),用于发送DTMF
// PCM编解码器使用静态有效负载(0~95),而OPUS和telephone-event则使用动态有效负载(范围96~127)。
// 每个编码器都有一个a=rtpmap属性,但此属性对于静态有效负载而言为可选属性

- **c=**IN IP4 0.0.0.0   //媒体链接数据字段,设置了一个无效的IP地址(人们常说的“黑洞”地址0.0.0.0)
- **a=**rtcp:9 IN IP4 0.0.0.0   // 包括一个RTCP端口和IP地址属性,但后者却设置为无效的IP地址和端口,暂不清楚该属性的用途

- **a=**ice-ufrag:U8F/   //用户名片段
- **a=ice-pwd:**Hfo+6wYJCMeLWahO6CLPwbLZ    // ICE密码。每个m行,将包括不同的用户名和密码。使用时使用第一组
- **a=ice-options:**trickle
- **a=fingerprint:**sha-256 EF:BD:53:BB:A4:E9:28:87:74:A4:15:27:59:B8:2D:05:61:04:CA:76:C8:2D:1C:BF:F0:CC:12:D8:8A:CC:AD:49
// 用于建立DTLS链接的自签名证书的SHA-256散列,因此必须协商确定由哪一方开通链接

- **a=setup:actpass**     //以上这行代表本客户端在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多路复用属性指示将通过用于RTP的同一端口对RTCP进行多路传输
- **a=rtpmap:**111 opus/48000/2
- **a=rtcp-fb:**111 transport-cc
// 以上这行说明opus编码支持使用rtcp来控制拥塞,

- **a=fmtp:**111 minptime=10;useinbandfec=1
// 对opus编码可选的补充说明,minptime代表最小打包时长是10ms,useinbandfec=1代表使用opus编码内置fec特性

// 13个可能的编解码器的rtpmap属性
- 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:1815301143 cname:JsTxr0Ps83IbEYOT
//cname用来标识一个数据源,ssrc当发生冲突时可能会发生变化,但是cname不会发生变化,也会出现在rtcp包中SDEC中,
//用于音视频同步

- a=ssrc:1815301143 msid:qovvqrAafFmIE8VZCxLsWvxdW7zQtcDpzzsb 2e0529d2-d3bd-460f-a325-71d148367b1b
//以上这一行定义了ssrc和WebRTC中的MediaStream,AudioTrack之间的关系,msid后面第一个属性是stream-id,
//第二个是track-ida=ssrc:1815301143 mslabel:qovvqrAafFmIE8VZCxLsWvxdW7zQtcDpzzsb
- a=ssrc:1815301143 label:2e0529d2-d3bd-460f-a325-71d148367b1b
- **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:U8F/
- a=ice-pwd:Hfo+6wYJCMeLWahO6CLPwbLZ
- a=ice-options:trickle
- a=fingerprint:sha-256 EF:BD:53:BB:A4:E9:28:87:74:A4:15:27:59:B8:2D:05:61:04:CA:76:C8:2D:1C:BF:F0:CC:12:D8:8A:CC:AD:49
- 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
//ccm是codec control using RTCP feedback message简称,意思是支持使用rtcp反馈机制来实现编码控制,
//fir是Full Intra Request简称,意思是接收方通知发送方发送幅完全帧过来

- **a=rtcp-fb:**96 nack   // 支持关键帧丢包重传,参考rfc4585
- **a=rtcp-fb:**96 nack pli    // 支持关键帧丢包重传,参考rfc4585
- **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   // 支持使用rtcp包来控制发送方的码流
- **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 
  //h264编码可选的附加说明
- **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  
//h264编码可选的附加说明
- **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  
 //h264编码可选的附加说明
- **a=rtpmap:**122 rtx/90000
- **a=rtcp-fb:**122 apt=127
- **a=rtcp-fb:**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  
 //h264编码可选的附加说明
- **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
//以上两行是VP8编码的重传包rtp类型
- **a=rtpmap:**124 ulpfec/90000    //支持ULP FEC,参考rfc5109

- **a=ssrc-group:**FID 2893345836 1252482188     
// 在webrtc中,重传包和正常包ssrc是不同的,上一行中前一个是正常rtp包的ssrc,后一个是重传包的ssrc
- **a=ssrc:**2893345836 cname:JsTxr0Ps83IbEYOT
- **a=ssrc:**2893345836 msid:qovvqrAafFmIE8VZCxLsWvxdW7zQtcDpzzsb f10f7f49-dd82-4916-a517-a28547e2c2ff
- **a=ssrc:**2893345836 mslabel:qovvqrAafFmIE8VZCxLsWvxdW7zQtcDpzzsb
- **a=ssrc:**2893345836 label:f10f7f49-dd82-4916-a517-a28547e2c2ff
- **a=ssrc:**1252482188 cname:JsTxr0Ps83IbEYOT
- **a=ssrc:**1252482188 msid:qovvqrAafFmIE8VZCxLsWvxdW7zQtcDpzzsb f10f7f49-dd82-4916-a517-a28547e2c2ff
- **a=ssrc:**1252482188 mslabel:qovvqrAafFmIE8VZCxLsWvxdW7zQtcDpzzsb
- **a=ssrc:**1252482188 label:f10f7f49-dd82-4916-a517-a28547e2c2ff

**media之前的行是Session级别,也就是对会话的描述,而media及它后面的 a =行称作media行,属于media级别。**

注:

参考资料


1、使用WebRTC搭建前端视频聊天室——信令篇
2、做WebRTC,千万别把媒体和信令混在一起
3、webrtc进阶-信令篇-之三:信令、stun、turn、ice
4、SDP 协议分析
5、WebRTC56版本SDP详细解析
6、SDP协议介绍 有必要多看几遍!!

上一篇 下一篇

猜你喜欢

热点阅读