1. RTP协议基础:RTP/RTCP协议栈概述、RTP数据包头部结构详解、RTP载荷类型与时钟频率、RTP时间戳与序列号的作用

各位同学,咱们直接进入正题。RTP协议,全称是实时传输协议。说白了,它就是为音视频数据在网络上传输而生的。你想想看,视频通话、直播、在线会议,这些场景背后都离不开RTP。

我刚开始接触RTP时,也觉得很抽象。后来在做一个视频会议项目时,发现画面卡顿、声音对不上,才真正意识到——不懂RTP,你连问题出在哪都找不到。所以这一章,咱们把地基打牢。

RTP/RTCP协议栈概述

RTP通常和RTCP(RTP控制协议)成对出现。RTP负责传数据,RTCP负责传控制信息。你可以把RTP想象成快递员,RTCP就是快递单上的追踪号——一个送东西,一个告诉你送得怎么样。

它们俩都跑在UDP之上。为什么不用TCP?因为实时性要求高,TCP的重传机制反而会引入延迟。丢几个包,总比等重传导致画面卡死要好。

核心关系:RTP传媒体数据(音频/视频),RTCP传质量反馈(丢包率、抖动、延迟)。两者配合,才能实现流畅的实时通信。

下面这张图,是我个人习惯用来向新人解释RTP/RTCP在协议栈中位置的。你看一眼就明白了。

RTP/RTCP 协议栈位置 应用层(音视频编码) RTP RTCP 传输层(UDP) 网络层(IP) RTP和RTCP共用UDP端口,通常RTP用偶数端口,RTCP用下一个奇数端口

RTP数据包头部结构详解

RTP头部是固定12字节。别被吓到,其实结构很清晰。我当年第一次抓包看RTP头部时,对着RFC 3550一行行对,才搞明白每个字段的意义。

咱们直接看头部结构:

偏移(字节) 字段 长度(位) 说明
0 V(版本) 2 当前版本为2
0 P(填充) 1 为1时尾部有填充字节
0 X(扩展) 1 为1时头部后有扩展头
0 CC(CSRC计数) 4 表示CSRC标识符的数量
1 M(标记) 1 应用自定义,常用于标记帧边界
1 PT(载荷类型) 7 标识编码格式
2-3 序列号 16 每发一个包递增1
4-7 时间戳 32 采样时刻,单位由时钟频率决定
8-11 SSRC 32 同步源标识符,唯一标识数据源
12+ CSRC列表 32×CC 贡献源列表,混音时使用

我的经验:抓包时,我最先看的就是SSRC和序列号。SSRC能帮你区分不同的音视频流,序列号能快速判断有没有丢包。有一次线上问题,就是靠序列号跳变定位到网络设备丢包的。

RTP载荷类型与时钟频率

载荷类型(PT)告诉接收端:这个包里的数据是用什么编码格式压缩的。比如PT=0是PCMU音频,PT=96是动态分配的H.264视频。

时钟频率这个概念,很多人容易搞混。它和时间戳的单位直接相关。音频的时钟频率通常是8000Hz或48000Hz,视频是90000Hz。为什么视频用90000Hz?因为要支持更高的时间精度,比如30fps的帧间隔是3000个时钟单位。

我整理了一份常用载荷类型表,建议你收藏:

PT值 编码格式 时钟频率(Hz) 类型
0 PCMU 8000 音频
3 GSM 8000 音频
8 PCMA 8000 音频
10 L16 44100 音频
26 JPEG 90000 视频
31 H.261 90000 视频
34 H.263 90000 视频
96-127 动态分配 协商确定 音/视频

注意:动态PT值(96-127)需要通过SDP协商才能确定具体编码。我曾经遇到过一个坑:发送端用PT=96表示H.264,接收端却以为是VP8,结果画面全是马赛克。所以一定要确保双方PT映射一致。

RTP时间戳与序列号的作用

这两个字段,是解决音画同步的关键。咱们分开说。

序列号:每发送一个RTP包,序列号就加1。接收端用它来检测丢包和恢复包序。比如你收到了序列号100、101、103,那102肯定丢了。嗯,这里要注意:序列号是16位的,溢出后会回绕到0。代码里处理回绕时,千万别用简单的比较大小,要用模运算。

时间戳:它反映的是媒体数据的采样时刻。音频每采样一次,时间戳增加一个时钟单位。视频每采集一帧,时间戳增加一个帧间隔对应的时钟单位。

举个例子:8kHz的音频,每20ms打包一次。那么每个包的时间戳增量就是 8000 × 0.02 = 160。所以第一个包时间戳是0,第二个是160,第三个是320,以此类推。

为什么时间戳对音画同步这么重要?因为播放器需要根据时间戳来安排音频和视频的播放时刻。如果音频时间戳和视频时间戳的基准不一致,就会出现嘴型对不上的问题。

关键点:序列号保证包的顺序和完整性,时间戳保证播放的时刻正确。两者缺一不可。

下面这张图,展示了时间戳和序列号在音视频流中的配合关系:

时间戳与序列号配合示例 音频流 SN:100 TS:0 SN:101 TS:160 SN:102 TS:320 SN:103 TS:480 SN:104 TS:640 视频流 SN:200 TS:0 SN:201 TS:3000 SN:202 TS:6000 SN:203 TS:9000 音频每包TS增量160(8kHz×20ms),视频每帧TS增量3000(90kHz÷30fps) 播放器根据TS对齐音视频,实现唇音同步

最后,分享一个我踩过的坑。有一次做直播项目,音频和视频的SSRC不同,时间戳基准也不同。音频时间戳从0开始,视频时间戳从随机值开始。结果播放器以为两者相差很大,一直缓冲等待,导致延迟越来越高。后来我强制让音视频时间戳使用同一个基准,问题就解决了。

所以记住:时间戳的基准必须统一。要么都用NTP时间,要么都用同一个起始点。否则音画不同步是必然的。