媒体信息
如前所述,在 SDP 中最重要的内容就是媒体信息。我们看一下 SDP 中媒体信息的具体格式,如下所示:
m=<media > <port >/<numbers > <transport > <fmt > …
其中,<media> 表示媒体类型,可以是 audio、video 等。<port>/<numbers> 表示该媒体使用的端口号。对于 WebRTC 而言,由于它不使用 SDP 中描述的网络信息,所以该端口号对它没任何意义。<transport> 表示使用的传输协议,可以是 UDP、TCP 等。<fmt> 表示媒体数据类型,一般为 PayloadType 列表,其具体含义需要使用 “a=rtpmap:” 属性做进一步阐述。
我们来看一个具体的例子,如代码 7.2 所示。从代码中可以看到,media 的值为 audio,表示该媒体的类型为音频;port 为 9,可以直接忽略,因为 WebRTC 不使用标准 SDP 中的网络信息,所以这里的端口也就失去了意义;transport 为 UDP/TLS/RTP/SAVFP,表示底层使用了哪些传输协议;fmtlist 的值为一串从 111 到 126 的数字,每个数字代表一个 PayloadType,不同的 PayloadType 表示媒体数据使用了不同的编解码器或编解码器参数。
上面提到的 UDP/TLS/RTP/SAVFP,其含义为:传输时底层使用 UDP;在 UDP 之上使用了 DTLS 协议来交换证书;证书交换好后,媒体数据由 RTP 进行传输(RTP 运行在 UDP 之上),保证传输的可靠性;媒体数据(音视频数据)的安全性是由 SRTP 负责的,即对 RTP 包中的 Body 部分进行加密。此外,传输时还使用 RTCP 的 feekback 机制对传输信息进行实时反馈(SAVPF),以便进行拥塞控制。
...
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
...
通过上面的介绍,我们已经清楚了 SDP 中的媒体信息是用来做什么的。不过媒体信息不只有上面的这些内容,它还有很多 “a=” 的属性用来对前面的信息做进一步解释,如每个 PayloadType 的详细参数就是由它们说明的。
音频媒体信息
音频媒体的描述前面已经介绍过了,但还有很多细节没有介绍。这些细节是无法通过一条 “m=” 行就能够描述清楚的,必须通过 “a=rtpmap” 对其做进一步解释才行。如代码 7.3 所示,在这段代码中,使用大量的 “a=rtpmap” 属性对 “m=” 行做进一步阐释。
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 …
...
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
...
这段代码中的第 1 行代码是对音频媒体的描述;第 3、6、7、8 行代码使用 “a=rtpmap” 解释了 PayloadType 使用的编解码器及其参数是什么;第 5 行代码 “a=fmtp” 属性指定了 PayloadType 的数据格式,即音频帧最小 10ms 一帧,使用带内 FEC。
在 WebRTC 的 SDP 中,“a=rtpmap”、“a=fmtp” 属性随处可见。无论是音频媒体中,还是视频媒体中,都使用它们对媒体做进一步的解释。
(1)“a=rtpmap” 属性
rtpmap(rtp map),通过字面含义可以知道它是一张 PayloadType 与编码器的映射表,每个 PayloadType 都对应一个编码器。其格式定义在 RFC4566 中,如下所示:
a=rtpmap:<payload type ><encoding name >/<clock rate >[/< encodingparameters >]
通过上面 rtpmap 的格式,可以很容易理解代码 7.3 中第 3 行代码的含义:Payload Type 值为 111 的编码器是 Opus,其时钟频率(采样率)为 48000,音频通道数为 2。同理,PayloadType 值为 103 的编码器是 ISAC,采样率为 16000;PayloadType 值为 104 的编码器也是 ISAC,只不过其采样率变成了 32000;PayloadType 值为 9 的编码器是 G722,采样率是 8000……
(2)“a=fmtp”属性
fmtp(format parameters)用于指定媒体数据格式。“a=fmtp” 属性的格式与 rtpmap 一样也是定义在 RFC4566 的第 6 节中,如下所示:
a=fmtp:<format > <format specific parameters >
现在再来看一下代码 7.3 中的第 5 行代码,它描述了 PayloadType 值为 111 的数据(Opus 数据):以 10ms 长的音频数据为一帧,并且数据是经 FEC 编码的。其中,“usein bandfec=1” 是 WebRTC 针对 Opus 增加的 fmtp 值。如果你想了解这些细节,可以看一下相关的草案。
视频媒体信息
与音频媒体信息相比,视频媒体信息要复杂一些,在 SDP 中视频相关的描述如代码 7.4 所示。
m=video 9 UDP/TLS/RTP/SAVPF 96 … 102 121 124 …
...
a=mid:1
...
a=rtpmap:96 VP8/90000
...
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
...
a=rtpmap:102 H264/90000
...
a=fmtp:102 level-asymmetry-allowed=1; packetization-mode=1; profile-level-id=42001f
a=rtpmap:121 rtx/90000
a=fmtp:121 apt=102
...
a=rtpmap:124 red/90000
a=rtpmap:119 rtx/90000
a=fmtp:119 apt=124
...
其中,第1行代码为视频的“m=”行,其与音频的“m=”行类似,区别在于两者的媒体类型不同:一个是“video”,另一个则是“audio”。此外,第1行中的PayloadType列表也发生了变化,这个很好理解,视频媒体使用的编码器本就与音频媒体使用的不同。第3行代码表明视频媒体的ID编号为1,而音频媒体的ID编号为0。如果有更多的媒体,编号会一直累加。第5∼18行代码是对不同PayloadType的解释,下面看一下它们是如何解释PayloadType的吧。
第5行代码,PT(PayloadType)值为96表示媒体数据使用的编码器是VP8,其时钟频率为90000。又因为其排在“m=”行PT列表的第一位,所以它还是视频的默认编码器。同理,代码第10行,PT值为102表示媒体数据使用的是H264编码器,时钟频率也是90000。
第7行代码,PT值为97表示的含义与之前PT值为96的情况有所不同,rtx表示的不再是编码器,而是丢包重传。要想弄明白第7行代码的含义,必须与第8行代码结合着一起看。在第8行代码中,apt(associated payload type)的值为96,说明96与97是关联在一起的,PT=97是PT=96的补充。因此第7行代码的含义是:当WebRTC使用的媒体数据类型(PayloadType)为96时,如果出现丢包需要重传,重传数据包的PayloadType为97。同理,第13∼14行代码指明121是PT=102重传包的PayloadType。
第16∼18行代码较为特殊,要想了解这三行代码的含义,你还需要了解一些额外知识:一是red,它是一种在WebRTC中使用的FEC算法,用于防止丢包;二是red编码流程,默认情况下WebRTC会将VP8/H264等编码器编码后的数据再交由red模块编码,生成带一些冗余信息的数据包,这样当传输中某个包丢了,就可以通过其他包将其恢复回来,而不用重传丢失的包。了解了上面这些内容后,第20∼22行代码的含义应该就清楚了,即PT值为124表示需要使用red对之前编码好的数据再进行red处理,119是PT=124重传数据包的PayloadType。如果用Wireshark等抓包工具抓取WebRTC媒体数据包时会发现它们都是red包,而在red包里装的是VP8/H264编码的数据。
再看一下与H264相关的fmtp内容。第12行代码,level-asymmetry-allowed=1指明通信双方使用的H264Level是否要保持一致:0,必须一致;1,可以不一致。packetization mode指明经H264编码后的视频数据如何打包,其打包模式有三种:0,单包;1,非交错包;2,交错包。三种打包模式中,模式0和模式1用在低延时的实时通信领域。其中模式0的含义是每个包就是一帧视频数据;模式1的含义是可以将视频帧拆成多个顺序的RTP包发送,接收端收到数据包后,再按顺序将其还原。profile-level-id由三部分组成,即profile_idc、profile_iop以及level_idc,每个组成部分占8位,因此可以推测出profile_idc=42、profile_iop=00、level_idc=1f。关于这几个值的具体含义,如果读者感兴趣,可以自行查看H264规范手册。
以上分析将SDP中视频媒体信息相关的内容及其含义讲解清楚了。音视频媒体信息是SDP中最为重要的内容,读者一定要牢牢掌握。
SSRC与CNAME
除了音频媒体信息和视频媒体信息外,媒体描述中还包括一项重要内容,就是 SSRC(Synchronization Source)。SSRC 是媒体源的唯一标识,每一路媒体流都有一个唯一的 SSRC 来标识它。
举一个具体的例子,如代码 7.5 所示,是一个视频媒体描述的 SDP 片段。
...
m=video ...
...
a=ssrc-group:FID 1531262201 2412323032 // 视频流的 SSRC
a=ssrc:1531262201 cname:Hmks0+2NwywExB+s
...
// 丢包重传流的 SSRC
a=ssrc:2412323032 cname:Hmks0+2NwywExB+s
...
从代码中可以看到,里边有两个不同的 SSRC,即第 6 行代码的 1531262201 和第 9 行代码的 2412323032。这里你可能会产生疑问,既然每路视频只能有唯一的 SSRC,那为什么这个视频媒体描述中却出现了两个视频源(SSRC)呢?要回答这个问题,就要从第 4 行代码说起了。第 4 行代码的 ssrc-group 指明两个 SSRC 是有关联关系的,后一个 SSRC(2412323032)是前一个 SSRC(1531262201)的重传流。也就是说,1531262201 是真正代表视频流的 SSRC,而 2412323032 是视频流(1531262201)丢包时使用的 SSRC,这就是为什么在同一个媒体描述中会有两个 SSRC。所以,虽然在同一个视频描述中有两个 SSRC,但对于该视频来说,仍然只有唯一的 SSRC 用来标识它。
此外,在代码第 6∼9 行,我们还能看到一个关键字 cname,而且 SSRC 为 1531262201 的 cname 名字与 SSRC 为 2412323032 的 cname 名字是一模一样的,它有什么含义呢?
cname(canonical name)通常称为别名,可以用在很多地方,其中广为人知的是用在域名解析中。当你想为某个域名起一个别名的时候,就可以使用它。如在直播推/拉流中,想将某个云厂商的推流地址 push.xxx.yun.xxx.com 换成你自己的地址 push.advancedu.com,就可以使用 cname。
cname 在 SDP 中的作用与域名解析中的作用是一致的,就是为媒体流起了一个别名。在同一个视频媒体描述中的两个 SSRC 后面都跟着同样的 cname,说明这两个 SSRC 属于同一个媒体流。关于 cname 更多的内容,将在 9.3.1 节中进一步介绍。