7.2.3 RTCP:质量反馈环与唇同步(RTCP: Feedback Loop & Lip Sync)
上一节结尾留下了一道难题:各路流的时间戳初值随机、速率各异,音视两条流的时间轴互不相认。与此同时,7.2.1 还挂着另一笔账:UDP 没有拥塞控制,发送端对网络状况一无所知,谈何适应。这两道难题,RTP 一个字段都没加——答案全部在孪生协议 RTCP(RTP Control Protocol) 里:一条与数据流并行的、低频的控制信道 [7]。
"低频" 是被明文限流的:RTCP 流量默认不得超过会话带宽的 5%,其中发送者合计约占 1/4、接收者约占 3/4——反馈信道天生纤瘦,设计者的潜台词很清楚:信道是用来传内容的,报告永远不许多嘴 [7]。
五种包型:各司其职
RTCP 的包型只有五种,一张表就能说全:
| PT | 名称 | 职责 |
|---|---|---|
| 200 | SR(Sender Report) | 发送方报告:时间戳对 + 发送统计 + 各源接收报告块 |
| 201 | RR(Receiver Report) | 接收方报告:只有接收报告块 |
| 202 | SDES | 源描述(CNAME 等身份信息) |
| 203 | BYE | 离会通告 |
| 204 | APP | 应用自定义扩展 |
主角是 SR 与 RR——它们共同构成那条反馈环。SR 的内部结构是标准的三段式:8 字节公共头、20 字节 sender info、随后每个被报告的源各挂一个 24 字节的 report block。两段戏分别藏在中段与末段里。
sender info:把两口的钟钉在一起
sender info 的 20 字节里,并排躺着一对时间戳:NTP timestamp(64 位) 与 RTP timestamp(32 位),外加累计发送的包数与字节数。
这对时间戳就是唇同步的全部机关。它的含义是:"当我的 RTP 时钟走到这个值时,真实世界(NTP 墙钟)的时刻是那个值"。发送端每隔一段时间(在那 5% 的预算内)广播一次这样的对应关系,接收端手里便有了每条流的 "RTP 时刻 → 墙钟时刻" 换算表——音频流一张、视频流一张。两条原本互不相认的时间轴,经由墙钟这口中立的天平,对齐到了一起:5.3.1 讨论的音视同步,在 RTP 体系里的标准机制就是这个 NTP-RTP 时间戳对 [7]。后来的 WebRTC 原样沿用了它(7.5 回收)。
report block:丢包与抖动的体检单
每个 report block 24 字节,是被报告源的一张体检单,关键字段四位:
- fraction lost(8 bit):自上一份报告以来的丢包比例
- cumulative packets lost(24 bit):会话开始以来的累计丢包数——一个是"最近一段"、一个是"有史以来",分析数据时切莫张冠李戴
- extended highest sequence number(32 bit):已收到的最高序号,高 16 位记录序号回绕次数
- interarrival jitter(32 bit):到达间隔抖动的估计值
其中抖动字段背后,站着 RTP 体系里唯一一条 RFC 强制要求所有实现必须采用 的算法。定义包 $i$ 与包 $j$ 的相对传输时间差:
其中 $S_i$ 为包 $i$ 的 RTP 时间戳(采样时刻),$R_i$ 为它的实际到达时刻(两者须换算到同一单位)。直觉很直白:发送间隔与到达间隔的差,就是网络引入的走走停停。抖动的估计值 $J$ 则按一阶滤波逐包递推:
增益取 1/16,是噪声抑制与跟踪速度之间权衡出的经验最优。为什么连一个估计器都要强制统一?规范说得坦率:只有这样,不同厂商的实现报出来的抖动才可横向比较——监控数据才有跨系统分析的价值 [7]。发送报告时,把当时的 $J$ 采样填入 report block 即可。
小结:双协议的完整闭环
至此,RTP 与 RTCP 的分工闭环成形:数据信道轻装上阵地冲,控制信道勒紧腰带地报;接收端用序号与时间戳恢复秩序,用 SR 的时间戳对对齐多路时钟,用报告块把网络的真实状况捎回发送端——丢包率与抖动,就是发送端调整码率、更换策略的仪表盘。7.2.1 留下的 "UDP 无拥塞控制" 之问,至此也有了着落:适应网络的不是协议本身,而是这条纤细却源源不断的反馈环。
不过,这套诞生于组播会议室的设计,放进今天的互联网还有两个明显的时代局限:它假设参与者彼此可达(NAT 与防火墙表示反对),也假设会话由人手工约定(浏览器表示不会)。补上这两块短板的,正是把 RTP 重新武装起来的 WebRTC——7.2.4,我们看这场跨越二十年的接力。