6、媒体协商机制:媒体能力协商、编解码器优先级、RTP/RTCP参数配置

媒体协商,说白了就是两个端点坐下来,互相亮出自己会什么、不会什么,然后商量出一个双方都能接受的方案。我刚开始接触WebRTC时,觉得这步不就是交换个SDP嘛,有什么难的?后来踩了坑才明白——这里面的门道,远比想象中深。

6.1 媒体能力协商的本质

两个浏览器要建立通话,它们得先回答几个问题:

  • 你支持哪些编解码器?
  • 你的视频分辨率能到多少?
  • 你的音频采样率是多少?
  • 你支持哪些RTP扩展头?

这些信息都封装在SDP(Session Description Protocol)里。Offer端把自己的能力列出来,Answer端从中挑选自己能接受的,再返回给Offer端。这个过程就是媒体协商。

核心原则:协商的结果必须是双方能力的交集。如果一方只支持VP8,另一方只支持H.264,那视频就协商失败。

6.2 编解码器优先级

我遇到过这样一个场景:两个Chrome浏览器通话,视频编解码器列表里既有VP8也有H.264。到底选哪个?这就涉及到优先级的问题。

在SDP中,编解码器的优先级通过rtpmapfmtp属性的顺序来体现。排在前面的,优先级更高。

// 典型的视频SDP片段
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99
a=rtpmap:96 VP8/90000
a=rtpmap:97 H264/90000
a=rtpmap:98 VP9/90000
a=rtpmap:99 AV1/90000

这里VP8排在第一位,所以Offer端优先推荐VP8。Answer端如果也支持VP8,就会选择它。如果不支持,才会往下看H.264。

我的建议:在实际项目中,不要把VP8和H.264的优先级调得太死。我见过有人强制把H.264排第一,结果在移动端上兼容性出了问题。最好让浏览器自己根据硬件能力去选。

6.3 RTP/RTCP参数配置

协商完编解码器,还得商量RTP和RTCP的参数。这些参数直接影响音视频的传输质量。

6.3.1 RTP参数

RTP参数主要包括:

  • SSRC:同步源标识符,每个RTP流都有一个唯一的SSRC
  • Payload Type:负载类型,标识使用的编解码器
  • Sequence Number:序列号,用于检测丢包和排序
  • Timestamp:时间戳,用于播放同步

这些参数在SDP中是这样体现的:

a=ssrc:1234567890 cname:{user-id}
a=ssrc:1234567890 msid:{stream-id} {track-id}
a=ssrc:1234567890 mslabel:{stream-label}
a=ssrc:1234567890 label:{track-label}

6.3.2 RTCP参数

RTCP负责传输控制信息,比如:

  • SR/RR:发送者/接收者报告,包含丢包率、抖动等统计
  • SDES:源描述,包含CNAME等信息
  • BYE:通知对方自己即将离开

RTCP的发送间隔也很关键。默认情况下,RTCP每5秒发送一次。但在实际项目中,这个间隔太长了。

我曾经踩过的坑:有一次做直播场景,RTCP间隔没调,结果丢包率统计滞后了十几秒。等发现网络质量下降时,画面已经卡成PPT了。后来我把RTCP间隔改成了1秒,问题才解决。

6.4 协商流程的完整链路

我把整个媒体协商的流程画了张图,方便你理解:

媒体协商完整流程 Offer端 (发起方) Answer端 (应答方) 1. 创建Offer SDP Offer (编解码器列表) 2. 解析并匹配能力 3. 创建Answer SDP Answer (选中的参数) 4. 设置远端描述 5. ICE连接建立 5. ICE连接建立 ICE候选者交换 6. RTP/RTCP媒体传输开始

6.5 实际项目中的参数调优

光知道理论还不够,我分享几个实际项目中的调优经验。

参数 默认值 推荐值 说明
RTCP间隔 5秒 1-2秒 直播场景建议1秒,普通通话2秒
RTP包大小 1400字节 1200-1400 避免IP分片,留出IP/UDP头空间
NACK重传次数 3次 2-5次 网络差时适当增加,但别太多
PLI请求间隔 无限制 最小500ms 防止频繁请求关键帧

一个小技巧:如果你在做视频会议,建议把max-bitrate在SDP里显式设置一下。我见过不少项目没设这个,结果浏览器自动分配了过高的码率,导致网络拥塞。

6.6 编解码器协商的细节

编解码器协商不只是选VP8还是H.264那么简单。同一个编解码器,还有不同的配置参数。

拿H.264来说,SDP里会有这样的参数:

a=fmtp:97 profile-level-id=42e01f;packetization-mode=1

这里profile-level-id=42e01f表示使用Baseline Profile,Level 3.1。packetization-mode=1表示支持非交错模式(Single NAL Unit模式)。

我遇到过一个问题:两个浏览器都支持H.264,但一个用的是Constrained Baseline,另一个用的是Main Profile。结果协商失败,视频就是出不来。后来我查了规范才发现,这两个profile虽然都是H.264,但互相不兼容。

注意:VP8和VP9的协商相对简单,因为它们没有那么多profile变种。如果你追求兼容性,VP8是个稳妥的选择。但如果你追求画质,H.264的High Profile能提供更好的压缩率。

6.7 扩展头协商

RTP扩展头(RTP Header Extension)也是协商的一部分。常见的扩展头有:

  • abs-send-time:绝对发送时间,用于带宽估计
  • transport-cc:传输拥塞控制
  • video-orientation:视频方向
  • playout-delay:播放延迟控制

这些扩展头在SDP中通过extmap属性声明:

a=extmap:1 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01

协商时,双方必须对扩展头的ID和URI达成一致。如果一方声明了某个扩展头,另一方不支持,那这个扩展头就不会被使用。

嗯,媒体协商这块内容确实不少。但说白了,它就是两个端点互相试探、互相妥协的过程。你只要理解了SDP的结构,掌握了编解码器优先级和RTP/RTCP参数的配置逻辑,大部分问题都能迎刃而解。

总结一下:媒体协商的核心是SDP的交换和匹配。编解码器优先级决定了选哪个编码方案,RTP/RTCP参数配置决定了传输的质量和稳定性。这三者缺一不可。

公众号:蓝海资料掘金营,微信deep3321