15、SSRC属性与RID:RID的SDP定义、Simulcast流标识、a=rid行解析
各位同学,今天我们来聊一个在WebRTC Simulcast场景下绕不开的话题——RID。说实话,我刚开始接触RID的时候,也被它和SSRC的关系搞得有点晕。但后来在项目中踩过几次坑,才真正理解了它的设计意图。
RID的全称是RestrictId,翻译过来就是“限制标识符”。嗯,这个名字其实挺抽象的。你想想看,它到底限制了什么?其实它限制的是——每个RTP流只能携带一个特定的RID值。说白了,RID就是给每个Simulcast层打的一个标签。
RID的SDP定义
我们先看看RID在SDP里长什么样。在WebRTC的SDP协商中,RID是通过a=rid行来定义的。我习惯把它理解为“流的身份证”。
a=rid:1 send recv
a=rid:2 send recv
a=rid:3 send recv
上面这个例子,定义了三个RID值:1、2、3。每个RID代表一个Simulcast层。注意这里的send和recv,它们表示这个RID是用于发送方向还是接收方向。
在实际项目中,我见过不少同学把RID和SSRC搞混。这里我给大家一个简单的区分方法:
- SSRC:是RTP层的同步源标识,每个RTP流一个,全局唯一
- RID:是应用层的流标识,用于区分Simulcast的不同层,同一个流的不同层可以有相同的SSRC空间
核心要点:RID是逻辑层的标识,SSRC是传输层的标识。RID告诉接收方“这是哪一层”,SSRC告诉接收方“这是哪个流”。
Simulcast流标识与a=rid行解析
我们来看一个完整的Simulcast SDP片段。这是我之前在一个视频会议项目中实际用过的配置:
a=group:BUNDLE 0 1 2
a=msid:example-msid
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98
a=rid:1 send recv
a=rid:2 send recv
a=rid:3 send recv
a=simulcast:send 1;2;3
a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:2 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
这里有几个关键点,我逐一解释:
- a=rid行:定义了三个RID值,分别是1、2、3。每个RID代表一个Simulcast层。通常RID值越小,分辨率或码率越低。
- a=simulcast行:声明了Simulcast的发送方向,
send 1;2;3表示发送端会发送三个层,RID分别为1、2、3。 - a=extmap行:定义了RTP头部扩展,用于在RTP包中携带RID信息。
rtp-stream-id就是RID的扩展头,repaired-rtp-stream-id是修复用的备用扩展头。
避坑指南:我曾经在一个项目中,只配置了a=rid行,但忘了加a=extmap。结果接收端虽然知道有三个层,但无法从RTP包中提取RID信息,导致无法正确路由。记住,a=extmap是必须的,它告诉接收端“RID信息放在RTP扩展头的哪个位置”。
RID与SSRC的映射关系
现在我们来画一张图,看看RID和SSRC在Simulcast场景下是如何配合工作的。
从这张图可以看出,每个RID层都对应一个独立的SSRC。但这里有个细节:RID是逻辑层的标识,而SSRC是传输层的标识。接收端通过RTP扩展头中的RID值,就能知道这个RTP包属于哪个层。
RID的扩展头定义
在RTP层面,RID是通过扩展头来传递的。标准定义了两个扩展头URI:
| 扩展头URI | 用途 | 长度 |
|---|---|---|
urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id |
主RID标识 | 1字节(最多255个字符) |
urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id |
备用RID标识(修复用) | 1字节 |
为什么需要两个?嗯,这里有个历史原因。早期的实现中,有些浏览器只支持repaired-rtp-stream-id,后来才统一到rtp-stream-id。我建议在SDP中两个都声明,兼容性更好。
注意事项:RID值在同一个媒体流中必须唯一。如果你有两个层都叫"1",接收端就分不清了。另外,RID值建议使用数字或简短字符串,不要超过255字节。
实际项目中的RID配置
最后,我分享一个我在项目中实际用过的RID配置模板。这个配置支持三层Simulcast,分别对应360p、720p和1080p:
// SDP中的RID配置示例
a=rid:0 send recv
a=rid:1 send recv
a=rid:2 send recv
a=simulcast:send 0;1;2
// RTP扩展头映射
a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
// 每个RID对应的编码参数(可选)
a=rid:0 send pt=96;max-width=640;max-height=360
a=rid:1 send pt=97;max-width=1280;max-height=720
a=rid:2 send pt=98;max-width=1920;max-height=1080
注意最后三行,我习惯在每个RID后面加上编码参数。这样接收端不用解析RTP包,光看SDP就知道每个层的分辨率范围。这在做自适应码率选择时特别有用。
好了,关于RID的SDP定义和Simulcast流标识,我们就讲到这里。记住,RID是Simulcast的核心,它让接收端能够智能地选择接收哪个层。下一节我们会深入SSRC的生成和冲突处理,到时候你会看到RID和SSRC是如何配合完成整个媒体协商的。