4、RTCP协议详解:SR/RR报告、SDES、BYE、APP包类型及作用

聊完RTP,咱们得聊聊它的“好搭档”——RTCP。RTP负责把音视频数据扔出去,但扔得怎么样?对方收到了没?网络堵不堵?这些事儿RTP一概不管。这时候RTCP就登场了。

RTCP的全称是RTP Control Protocol,说白了就是RTP的控制面。它不传音视频数据,只传控制信息。我个人习惯把RTCP比作“快递回执”——你寄了个包裹,对方收到后给你回个条,告诉你“收到了,但箱子有点瘪”。

RTCP有几种核心包类型:SR、RR、SDES、BYE、APP。咱们一个一个拆开看。

4.1 SR(Sender Report)——发送端报告

SR包是发送端发的。谁在发RTP数据,谁就要定期发SR。它告诉接收端:“我发了多少数据,时间戳是多少,你拿这个去算同步。”

SR包里最重要的字段是NTP时间戳和RTP时间戳。NTP是绝对时间,RTP是采样时钟。有了这两个,接收端就能把音视频流对齐。我在项目中遇到过音画不同步的问题,查到最后就是SR包里的NTP时间戳没对齐。

SR包核心字段:
  • SSRC:发送端的同步源标识符
  • NTP时间戳:绝对时间(秒+微秒)
  • RTP时间戳:与NTP对应的RTP时钟
  • 发送包计数:从会话开始到现在的总包数
  • 发送字节计数:从会话开始到现在的总字节数

你想想看,如果没有SR,接收端只知道“我收到了一个RTP包”,但不知道这个包对应什么时间点。有了SR,接收端就能把RTP时间戳映射到真实时间,音视频同步才有基础。

4.2 RR(Receiver Report)——接收端报告

RR包是接收端发的。它告诉发送端:“我收到了多少包,丢了多少,抖动多大,延迟多少。” 说白了,这就是接收端给发送端的“反馈”。

RR包里最核心的是丢包率和往返时延(RTT)。发送端看到丢包率高了,就知道该降码率了;看到RTT大了,就知道网络拥塞了。WebRTC的拥塞控制算法,很大程度上依赖RR包里的这些数据。

RR报告块字段 含义 我踩过的坑
丢包率 从上次报告到现在的丢包比例 注意是比例,不是绝对值
累计丢包数 从会话开始到现在的总丢包数 这个值会溢出,要处理回绕
到达时间抖动 包到达时间的统计方差 抖动大不代表丢包,但说明网络不稳定
最后SR时间戳(LSR) 最近收到的SR中的NTP时间 用于计算RTT,必须精确
延迟自最后SR(DLSR) 从收到SR到发送RR的延迟 这个值不准,RTT就算不准
避坑指南: 我曾经在计算RTT时忘了减去DLSR,结果RTT算出来比实际大了一倍。正确的公式是:RTT = 当前时间 - LSR - DLSR。少一个都不行。

4.3 SDES(Source Description)——源描述包

SDES包用来描述RTP源的“身份信息”。它不参与流控,但参与会话管理。最常见的SDES项是CNAME(规范名称)。

CNAME是每个RTP源的唯一标识。为什么需要CNAME?因为同一个用户可能有多个SSRC(比如音频一个、视频一个),但CNAME是同一个。这样接收端就知道“这两个流来自同一个人”。

SDES还有其他项:NAME(用户名)、EMAIL(邮箱)、TOOL(工具名)。不过说实话,我在实际项目中只用CNAME,其他项基本没用过。WebRTC的实现里也只强制要求CNAME。

SDES常见项:
  • CNAME:规范名称,必须唯一
  • NAME:用户显示名
  • EMAIL:用户邮箱
  • TOOL:生成RTP流的工具名
  • NOTE:临时备注(很少用)

4.4 BYE(Goodbye)——离开通知

BYE包很简单,就是告诉对方:“我要走了,不发了。” 当参与者离开会话时,发送BYE包。接收端收到BYE后,就知道这个源不会再发数据了,可以清理资源。

BYE包里可以带一个可选的原因字段。比如“user left”或“session ended”。不过大多数实现里,原因字段都是空的。我建议至少填个简单的原因,方便调试时排查问题。

注意: BYE包不是必须的。如果参与者突然断网,BYE包可能发不出去。接收端需要靠超时机制来判断源是否离开。WebRTC里默认超时时间是30秒。

4.5 APP(Application-Defined)——应用自定义包

APP包是RTCP留给应用层的“扩展接口”。标准RTCP包不够用时,你可以用APP包定义自己的控制消息。APP包里有一个4字节的“名字”字段(ASCII字符),用来标识你的应用类型。

我在项目中用过APP包来传递自定义的QoS信息。比如发送端告诉接收端“当前编码器用了什么参数”,或者接收端告诉发送端“请切换到低分辨率”。这些信息标准RTCP包不提供,但APP包可以搞定。

不过要注意,APP包是应用层定义的,不同实现之间可能不兼容。如果你用了APP包,一定要在信令阶段协商好。

4.6 RTCP包结构总览

咱们用一张图来总结RTCP的包类型和它们之间的关系:

RTCP包类型与作用 RTCP复合包 SR 发送端报告 RR 接收端报告 SDES 源描述 BYE 离开通知 APP 应用自定义 复合包规则 • SR/RR必须放在复合包最前面 • SDES必须跟在SR/RR后面 • BYE可以单独发,但建议复合

4.7 RTCP的发送间隔与带宽控制

RTCP不能发得太频繁,否则会占用太多带宽。标准规定RTCP带宽通常占会话总带宽的5%。其中SR/RR占75%,SDES占25%。BYE和APP不单独分配带宽。

发送间隔的计算公式是:间隔 = 平均RTCP包大小 / (RTCP带宽 / 参与者数量)。参与者越多,间隔越长。这就是为什么大会议里RTCP报告来得慢——人太多了,每个人都要排队发。

经验之谈: 我在做多人会议时,发现默认的RTCP间隔太长(5秒以上),导致拥塞控制反应迟钝。后来我手动调整了RTCP带宽比例,从5%提到10%,反馈速度明显快了。但要注意,RTCP带宽不能太高,否则会挤占RTP的带宽。

4.8 实际项目中的RTCP处理

在WebRTC里,RTCP的处理是自动的。你不需要手动构造SR或RR包,libwebrtc会帮你搞定。但理解这些包的含义,对排查问题非常有帮助。

我记得有一次线上会议频繁卡顿,抓包一看,RR包里的丢包率高达15%。但网络工程师说网络没问题。后来发现是接收端的缓冲区太小,导致包被丢弃了。RR报告里的“丢包”不一定是网络丢包,也可能是应用层丢包。

所以,当你看到RR报告里的丢包率异常时,别急着怪网络。先检查一下接收端的缓冲区设置、CPU负载、解码器状态。这些因素都可能导致“假丢包”。

RTCP包类型速查表:
包类型 PT值 方向 核心作用
SR 200 发送端→接收端 报告发送统计和时间同步
RR 201 接收端→发送端 报告接收统计和QoS反馈
SDES 202 双向 源身份描述(CNAME)
BYE 203 双向 通知离开会话
APP 204 双向 应用自定义控制消息

RTCP是WebRTC流控的“眼睛”。没有它,发送端就是盲人摸象,不知道网络状况如何。理解了SR和RR,你就掌握了流控的反馈回路;理解了SDES和BYE,你就掌握了会话管理的基础;理解了APP,你就有了扩展的余地。