2. RTP协议基础
要解决音画不同步,必须先看懂 RTP 报文本身。RTP(Real-time Transport Protocol)并不负责“保证送达”,它负责的是把媒体采样按时间关系封装成一个个可被接收端重排、播放和同步的数据包。换句话说,RTP 头部里的每一个字段,几乎都对应着音画同步问题的一个线索:序列号告诉你包有没有丢、有没有乱序;时间戳告诉你这段媒体应该在什么时刻播放;SSRC 告诉你这包属于哪一路媒体流;载荷类型告诉你这是音频还是视频、用什么编码。理解这些字段,是后续排查抖动、丢包、时间戳跳变和音视频漂移的基础。
一、RTP 报文结构:固定头 + 扩展头 + 载荷
RTP 报文由固定头部、可选的 CSRC 列表、可选的扩展头和载荷组成。固定头部最小 12 字节,是所有 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 |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
固定头之后,如果 X=1,则存在扩展头;扩展头之后才是真正的媒体载荷。载荷可能是 Opus 音频帧、H.264 NAL 单元、VP8 分片等。RTP 本身不解释载荷内容,解释工作交给载荷类型和对应的编解码规范。
二、头部字段含义:每个字段都在回答一个同步问题
| 字段 | 长度 | 含义 | 与音画同步的关系 |
|---|---|---|---|
| V(Version) | 2 bit | RTP 版本,通常为 2 | 版本不一致会导致解析失败 |
| P(Padding) | 1 bit | 载荷末尾是否有填充字节 | 影响载荷边界计算 |
| X(Extension) | 1 bit | 是否有扩展头 | 扩展头常携带传输时间信息 |
| CC(CSRC Count) | 4 bit | CSRC 标识符数量 | 用于混音场景的源归属判断 |
| M(Marker) | 1 bit | 标记重要事件,如视频帧结束 | 帮助识别帧边界,影响播放节奏 |
| PT(Payload Type) | 7 bit | 载荷类型,标识编码格式 | 决定如何解码和时钟频率 |
| Sequence Number | 16 bit | 序列号,每发一个包递增 1 | 检测丢包、乱序、重复包 |
| Timestamp | 32 bit | 采样时刻,单位由时钟频率决定 | 音视频同步的核心依据 |
| SSRC | 32 bit | 同步源标识,标识一路媒体流 | 区分音频流和视频流 |
| CSRC | 32 bit × N | 贡献源列表,用于混音场景 | 追溯混音后的原始源 |
三、序列号、时间戳与 SSRC:同步的三根支柱
序列号是 16 位无符号整数,每发送一个 RTP 包递增 1。接收端通过序列号可以判断是否丢包、是否乱序、是否重复。例如收到 100、101、103,说明 102 丢失;收到 100、102、101,说明发生乱序。序列号本身不携带时间信息,但它决定了接收端能否把包按正确顺序交给抖动缓冲区和解码器。
时间戳是 32 位无符号整数,表示该包中第一个采样字节的采样时刻。它的单位不是秒,而是“采样时钟周期”。音频常用 8000 Hz、16000 Hz、48000 Hz,视频常用 90000 Hz。例如音频时钟频率为 48000 Hz,每包携带 20 ms 音频,则相邻包时间戳增量应为 960。时间戳是音画同步的核心:接收端用时间戳把音频和视频映射到同一条播放时间轴上。
SSRC 是 32 位同步源标识,用来区分同一会话中的不同媒体流。典型 WebRTC 会话中,音频流和视频流各有一个 SSRC。接收端通过 SSRC 把包归类到对应的流,再分别做抖动缓冲、解码和渲染。如果 SSRC 冲突或变化,接收端可能把两路流混在一起,导致播放异常。
CSRC 用于混音场景。当多个源经过混音器合并后,混音器会把自己的 SSRC 作为主 SSRC,把原始源的 SSRC 放入 CSRC 列表。这样接收端既能播放混音结果,又能知道声音来自哪些原始参与者。
核心记忆:序列号管“顺序”,时间戳管“时刻”,SSRC 管“哪一路”,PT 管“怎么解”,CSRC 管“混音来源”。音画不同步排查时,先看时间戳,再看序列号,最后确认 SSRC 和 PT 是否匹配。
四、载荷类型与时钟频率:同步计算的分母
载荷类型 PT 决定了解码方式和时钟频率。常见静态 PT 包括 PCMU(0,8000 Hz)、PCMA(8,8000 Hz)、G.722(9,8000 Hz)等。动态 PT 通常通过 SDP 协商,例如 Opus 常用 111,时钟频率 48000 Hz;H.264 常用 96~127 中的某个值,时钟频率 90000 Hz。时钟频率决定了时间戳增量的含义:同样增加 48000,在 48000 Hz 音频中代表 1 秒,在 90000 Hz 视频中只代表约 0.533 秒。因此,音视频同步计算必须使用各自的时钟频率,不能直接比较时间戳数值。
音频:PT=111 (Opus), clock=48000 Hz, 20ms/包
时间戳增量 = 48000 × 0.020 = 960
视频:PT=96 (H.264), clock=90000 Hz, 33.3ms/帧
时间戳增量 = 90000 × 0.0333 ≈ 3000
五、案例场景:一次典型的音画不同步排查
假设用户反馈“视频比音频慢半拍”。抓包后先看 RTP 头部:音频 SSRC 为 0x1A2B3C4D,视频 SSRC 为 0x5E6F7A8B,两者 PT 分别为 111 和 96,说明流区分正常。继续观察时间戳:音频时间戳每包增加 960,视频时间戳每帧增加 3000,增量符合 20 ms 和 33.3 ms 的预期,说明发送端节奏正常。再看序列号:视频序列号出现 100、101、104、105,说明中间丢了 102、103 两个包。视频丢包后,解码器等待后续帧或做错误隐藏,导致视频渲染时刻被推迟,而音频继续按时间戳播放,最终表现为视频滞后。此时解决方向不是调整时间戳,而是先处理视频丢包和抖动缓冲策略。
排查顺序建议:先确认 SSRC 是否稳定,再检查 PT 与时钟频率是否匹配,然后看序列号丢包/乱序,最后对比音视频时间戳映射到同一时间轴后的偏差。不要一上来就改时间戳,很多“不同步”其实是丢包或抖动造成的播放延迟。
六、常见误区与复盘
- 误区一:时间戳就是毫秒。时间戳单位是采样周期,必须除以时钟频率才能换算成秒。
- 误区二:序列号连续就没有丢包。序列号连续只能说明 RTP 层没丢,网络抖动仍可能导致到达时间不均匀。
- 误区三:音频和视频时间戳可以直接相减。两者时钟频率不同,必须先换算到同一时间单位。
- 误区四:SSRC 不重要。SSRC 变化会导致接收端重建流状态,可能引发播放中断或同步重置。
- 误区五:CSRC 只和混音有关,和同步无关。在混音场景中,CSRC 能帮助定位是哪个原始源的时间戳异常。
掌握 RTP 报文结构和头部字段,是后续理解 RTCP 发送者报告、NTP 时间戳映射、抖动缓冲和音画同步算法的基础。只有先能准确读出每个字段的含义,才能在真实抓包中快速定位问题,而不是凭感觉猜测。