RTP/RTCP 协议基础:RTP 包结构、RTCP SR/RR 报告、NACK 与 PLI
聊到 WebRTC 流控,RTP 和 RTCP 是绕不开的基石。说白了,RTP 负责把音视频数据从 A 点搬到 B 点,RTCP 则负责在背后打小报告——质量怎么样、丢了多少包、要不要重传。我刚开始接触 WebRTC 时,总觉得 RTCP 是可有可无的辅助协议,直到有一次线上会议频繁卡顿,抓包一看才发现 RTCP 报告里全是异常。嗯,从那以后我再也不敢小看它了。
3.1 RTP 包结构:数据搬运工的身份证
RTP(Real-time Transport Protocol)是实时传输的载体。每个 RTP 包都像快递包裹,头部信息就是快递单。你想想看,没有快递单,接收端怎么知道这包数据是视频第几帧、音频第几毫秒?
一个标准的 RTP 头部长这样:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
几个关键字段,我挑重要的说:
- V(版本号):固定为 2,目前主流版本。
- P(填充位):如果置 1,包尾有填充字节。我见过一些加密实现会用这个字段对齐块大小。
- X(扩展位):置 1 表示头部后面跟着扩展头。WebRTC 的 Transport-cc 扩展就在这里。
- CC(CSRC 计数):表示后面有多少个 CSRC 标识符。混音场景下会用,WebRTC 里很少见。
- M(标记位):视频里通常标记帧边界,音频里标记会话开始。
- PT(负载类型):告诉接收端这包数据是 H264、VP8、Opus 还是别的。WebRTC 动态协商 PT 值,范围 96-127。
- sequence number(序列号):16 位,每发一个包加 1。接收端靠它检测丢包、排序。我调试时最常看的就是这个字段——序列号跳变基本等于丢包。
- timestamp(时间戳):32 位,音频和视频的时钟频率不同。音频通常 48kHz,视频 90kHz。这个字段决定了播放时机。
- SSRC(同步源标识符):32 位随机数,唯一标识一个 RTP 流。同一个会话里,每个音视频流都有自己的 SSRC。
3.2 RTCP SR/RR 报告:收发双方的质量体检单
RTCP(RTP Control Protocol)周期性发送控制包。它不像 RTP 那样每帧都发,而是按带宽比例分配——我建议你记住这个比例:RTCP 流量通常控制在会话总带宽的 5% 以内。
RTCP 有好几种类型,流控里最核心的是 SR(Sender Report) 和 RR(Receiver Report)。
3.2.1 SR 包:发送端自报家门
SR 由数据发送方发出。它包含两部分:
- 发送端信息:NTP 时间戳(绝对时间)、RTP 时间戳(相对时间)、发送包计数、发送字节计数。
- 报告块:针对每个接收端的质量统计,包括丢包率、累计丢包数、最高序列号、抖动、延迟等。
SR 包结构大致如下:
+-------------------------------+
| 头部 (V=2, P, RC, PT=200) |
+-------------------------------+
| SSRC of sender |
+-------------------------------+
| NTP timestamp (most significant)|
+-------------------------------+
| NTP timestamp (least significant)|
+-------------------------------+
| RTP timestamp |
+-------------------------------+
| sender's packet count |
+-------------------------------+
| sender's octet count |
+-------------------------------+
| 报告块 1 (针对接收端 A) |
| 报告块 2 (针对接收端 B) |
| ... |
+-------------------------------+
关键指标解读:
- 丢包率(fraction lost):8 位,表示上一个报告周期内的丢包比例。值 0-255,对应 0%-100%。我一般看到超过 10%(约 25)就认为网络质量较差。
- 累计丢包数(cumulative lost):24 位,从会话开始到现在的总丢包数。这个值只增不减,适合看长期趋势。
- 抖动(interarrival jitter):32 位,表示包到达时间的统计方差。抖动大说明网络不稳定,jitter buffer 需要调整。
- 延迟(LSR/DLSR):LSR 是上次收到 SR 的 NTP 时间,DLSR 是从收到 SR 到发出 RR 的延迟。两者结合可以算出 RTT。
3.2.2 RR 包:接收端反馈实况
RR 包由数据接收方发出。它和 SR 的报告块格式完全一样,只是没有发送端信息部分。RR 包告诉发送方:我这边收到了多少、丢了多少、抖动多大、延迟多长。
我举个例子。有一次线上会议,用户反馈声音断断续续。我抓包发现 RR 报告里的丢包率从 2% 突然跳到 15%,同时抖动值飙升。这说明网络瞬间恶化,jitter buffer 来不及适应。后来我们加了 NACK 重传,情况才好转。
| 字段 | 长度 | 说明 |
|---|---|---|
| fraction lost | 8 bit | 上一个周期丢包比例,0-255 |
| cumulative lost | 24 bit | 累计丢包数 |
| highest seq no. | 32 bit | 收到的最高序列号 |
| interarrival jitter | 32 bit | 到达时间抖动 |
| LSR | 32 bit | 上次收到 SR 的 NTP 时间 |
| DLSR | 32 bit | 从收到 SR 到发出 RR 的延迟 |
3.3 NACK 与 PLI:丢包后的急救措施
RTP 是 UDP 传输,天生不可靠。丢包了怎么办?WebRTC 提供了两种反馈机制:NACK 和 PLI。
3.3.1 NACK:精准补包
NACK(Negative ACKnowledgment)是 RTCP 的一种反馈包(PT=205),FMT=1。接收端发现某个序列号丢了,就发 NACK 告诉发送端:把第 X 号包重传给我。
NACK 包结构:
+-------------------------------+
| 头部 (V=2, P, FMT=1, PT=205) |
+-------------------------------+
| SSRC of sender |
+-------------------------------+
| SSRC of media source |
+-------------------------------+
| 丢失的序列号 (PID) |
| 位掩码 (BLP) |
+-------------------------------+
- PID(Packet ID):丢失的起始序列号。
- BLP(Bitmask of Lost Packets):16 位掩码,表示 PID 之后哪些包也丢了。位 0 表示 PID+1,位 1 表示 PID+2,以此类推。
一个 NACK 包最多可以报告 17 个丢包(1 个 PID + 16 个掩码位)。我调试时经常用 Wireshark 过滤 rtcp.nack,看丢包模式是零星丢包还是连续丢包。
3.3.2 PLI:关键帧请求
PLI(Picture Loss Indication)是另一种 RTCP 反馈(PT=206,FMT=1)。它不要求重传某个包,而是要求发送端立即生成一个关键帧(I 帧)。
什么时候用 PLI?
- 接收端刚加入会话,没有参考帧。
- 连续丢包导致参考帧损坏,解码器无法恢复。
- 视频画面突然花屏,解码器请求重置。
PLI 包结构很简单:
+-------------------------------+
| 头部 (V=2, P, FMT=1, PT=206) |
+-------------------------------+
| SSRC of sender |
+-------------------------------+
| SSRC of media source |
+-------------------------------+
没有额外字段,就是一个信号:给我一个关键帧。
3.4 知识体系总览
下面这张图把 RTP/RTCP 的核心关系串起来了。我建议你多看几遍,理解数据流和反馈流是怎么配合的。
这张图里,RTP 是单向数据流,RTCP 是双向控制流。SR 从发送端到接收端,RR、NACK、PLI 从接收端到发送端。流控算法就是根据 RR 里的丢包率、抖动、RTT,以及 NACK 的频率,动态调整发送码率。
我个人习惯在调试时先确认 RTCP 报告是否正常到达。如果接收端不发 RR,发送端就不知道网络状况,只能盲目发送。这种情况我遇到过好几次——最后发现是防火墙阻断了 RTCP 端口。