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中,编解码器的优先级通过rtpmap和fmtp属性的顺序来体现。排在前面的,优先级更高。
// 典型的视频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 协商流程的完整链路
我把整个媒体协商的流程画了张图,方便你理解:
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参数配置决定了传输的质量和稳定性。这三者缺一不可。