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数据包头部结构详解
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,以此类推。
为什么时间戳对音画同步这么重要?因为播放器需要根据时间戳来安排音频和视频的播放时刻。如果音频时间戳和视频时间戳的基准不一致,就会出现嘴型对不上的问题。
关键点:序列号保证包的顺序和完整性,时间戳保证播放的时刻正确。两者缺一不可。
下面这张图,展示了时间戳和序列号在音视频流中的配合关系:
最后,分享一个我踩过的坑。有一次做直播项目,音频和视频的SSRC不同,时间戳基准也不同。音频时间戳从0开始,视频时间戳从随机值开始。结果播放器以为两者相差很大,一直缓冲等待,导致延迟越来越高。后来我强制让音视频时间戳使用同一个基准,问题就解决了。
所以记住:时间戳的基准必须统一。要么都用NTP时间,要么都用同一个起始点。否则音画不同步是必然的。