跳转到内容

RTP RFC 1889 — 让 UDP 也能跑实时音视频

是什么

RTP(Real-time Transport Protocol,实时传输协议)是给实时音视频包加一层时间戳和序号的协议。日常类比:你给一筐快递盒子贴标签,写上”第几件、几点几分发的”,收件人就能按发货时间排好播放,丢了哪件也一目了然。

RTP 自己不传东西,它跑在 UDP 上面,给每个 UDP 包前面加一个 12 字节的头。这个头里有 4 个关键字段:

  • 序号(16 bit):第几个包
  • 时间戳(32 bit):这一帧在发送端的”采样时刻”
  • SSRC(32 bit):这一路流的唯一标识
  • payload type(7 bit):里面装的是什么编码(PCMU 音频?H.261 视频?)

接收端拿到这些字段就能:丢包重组、抖动消除、多人会议分流、按编码解码。

为什么重要

不理解 RTP,下面这些事都没法解释:

  • 为什么 Zoom / 腾讯会议 / WebRTC / IP 电话不用 TCP——但又能保证语音连贯
  • 为什么视频会议里丢一个包听不出来,丢 TCP 包却会卡 2 秒
  • 为什么 WebRTC 的浏览器到浏览器音视频,底层包格式 30 年没换过——就是 RTP
  • 为什么实时流媒体的 NAT 穿透总是要单独配(STUN/ICE)——因为 RTP 自己不管

核心要点

三个基本设计选择

  1. 跑 UDP 不跑 TCP:TCP 像挂号信,丢了就重发,但晚到的语音重发也没用,反而把后面的全堵住(队头阻塞)。UDP 让丢的就丢,RTP 在上层补”知道丢了什么、知道何时播”。

  2. 时间戳 ≠ 墙上时间:时间戳按”采样率”走。音频 8 kHz 采样,每个 20 ms 包 +160;视频 90 kHz 时钟,每帧 +3000。接收端拿这个时间戳算”应该几点播”,消除网络抖动。

  3. 数据流和控制流分开:RTP 跑数据,配套的 RTCP(RTP Control Protocol)跑控制——每几秒互相汇报”我收到多少、丢多少、抖动多大”。两者占连续两个端口(偶数数据、奇数控制)。

12 字节头的全貌(简化)

0 1 2 3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+---------------+---------------+-------------------------------+
| timestamp |
+---------------------------------------------------------------+
| SSRC |
+---------------------------------------------------------------+
  • V=2 是版本号
  • M(marker)标”一帧的最后一个包”——视频解码器靠它知道”该刷屏了”
  • CC + 后续 CSRC:mixer 把多路合成一路时,把原始源标识列在这里

RTCP 报告和 5% 带宽规则

RTCP 包不能太多,否则吃带宽。RFC 规定 RTCP 最多占总带宽的 5%,发送间隔随会议人数自动拉长——50 个人开会时每人 5 秒发一次,500 个人时 50 秒发一次。这是个早期且优雅的拥塞自适应设计

实践案例

案例 1:一通 VoIP 电话的包流

你拨打 IP 电话,麦克风每 20 ms 采样一次。每 20 ms 你的客户端封装一个 RTP 包:

  • payload type = 0(PCMU,G.711 µ-law)
  • timestamp += 160(8000 Hz × 0.02 s)
  • sequence += 1
  • payload = 160 字节音频样本

接收端缓冲 60 ms(jitter buffer),按 timestamp 排序,按 20 ms 节奏取出播放。丢了一个包就塞静音或上一帧,听上去几乎察觉不到。

案例 2:5 人视频会议怎么分流

5 个人都往会议桥(mixer)发 RTP,每人一个独立的 SSRC:

Alice SSRC=0xAAAA →
Bob SSRC=0xBBBB → [mixer] → 每个参会者
Carol SSRC=0xCCCC →
...

mixer 可以选两种模式:

  • 转发:把 5 路原样转给每个人(每人收 4 路),客户端自己解 4 路混音
  • 混音:mixer 自己把 5 路解码混成 1 路再编码发出,CSRC 列表保留原始 SSRC,让客户端知道”刚刚那段声音是谁说的”

WebRTC 时代主流改成 SFU(Selective Forwarding Unit)——只转发,不混音,因为 CPU 便宜带宽贵。

案例 3:WebRTC 里你看不见但每天用的 RTP

打开 Chrome 的 chrome://webrtc-internals,开一个 Google Meet,你会看到:

  • 多路 RTP 流(音频一路、视频一路,可能还有屏幕共享)
  • SSRC、PT、丢包率、抖动、RTT——全是 RTCP 报告里的字段
  • 加了 SRTP 加密层(RFC 3711),但帧格式还是 RFC 1889 那 12 字节

30 年前的设计,今天每个浏览器都在跑。

踩过的坑

  1. 时间戳不是 Unix 时间:很多人第一次写 RTP 解析以为 timestamp 能直接转日期,结果发现是相对的、按采样率走。必须配合 RTCP 的 SR 报告里的 NTP 时间戳才能对齐到墙上时间。

  2. 序号 16 bit 会回卷:高码率视频几小时就把 65536 用完。接收端要追踪 cycle,常见 bug 是排序时把回卷的 0 当成”乱序很久的旧包”丢掉。

  3. RTP 自己不加密:RFC 1889 原版是明文。生产必须套 SRTP(RFC 3711),WebRTC 强制 DTLS-SRTP,否则浏览器拒绝建连。

  4. NAT 穿透不在 RTP 范围内:两端在 NAT 后面直接发 RTP 大概率到不了。要先用 STUN 探测公网映射,失败时走 TURN 中继,这套叫 ICE,是另外的协议族。

  5. RFC 1889 ≠ 最新版:2003 年 RFC 3550 取代了 1889,加了一些安全和 mixer 细节,但 12 字节头一字未改。看老代码里出现 1889 不要慌。

适用 vs 不适用场景

适用

  • 实时音视频通话(VoIP / 视频会议 / WebRTC)
  • 直播流媒体(早期 RTSP 拉流;今天大多换成 HLS/DASH,但内部转码仍可能用 RTP)
  • 多源同步(多路摄像头按时间戳对齐)

不适用

  • 文件传输 / 网页 / API 调用 → 必须可靠、不要实时 → 用 TCP / http-2 / quic
  • 海量并发直播(百万观众)→ HLS 切片走 CDN 比 RTP 划算
  • 严格实时控制(机械臂、自动驾驶 in-vehicle)→ 用 DDS / time-sensitive networking

历史小故事(可跳过)

  • 1992 年:Henning Schulzrinne 在 GMD-Fokus 提出最早的”音频包”草稿
  • 1996 年 1 月:RFC 1889 发布,作者四人是实时网络名宿——其中 jacobson-1988 的 Van Jacobson 同时还是 TCP 拥塞控制的奠基人
  • 2003 年:RFC 3550 取代 1889,是今天的”现行版”
  • 2011 年起:WebRTC 把 RTP 搬进浏览器,从协议变成 Web 标准的一部分

学到什么

  1. 协议分层不是越多越好:RTP 只做”序号+时间戳+源标识”三件事,刻意不做拥塞、加密、重传——这种克制让它撑了 30 年
  2. 数据面和控制面分离是经典手法:RTCP 占 5% 带宽这个”自适应汇报”设计今天看仍然漂亮
  3. 抖动 vs 丢包是实时网络的两件事:丢包靠 FEC / 重传补,抖动靠 jitter buffer 补,两条路独立
  4. RFC 是一种特殊文本:短、密、可执行——一份 RFC 就是一份能让全世界互通的”接口契约”

延伸阅读

关联

  • tcp —— 反例:可靠传输,但实时音视频用不了
  • quic —— UDP 上的现代可靠传输,与 RTP 一样选择不走 TCP
  • http-2 —— 多路复用思想可以对照 RTP 多 SSRC
  • saltzer-1984-e2e —— “端到端”原则让 RTP 敢于不做拥塞控制
  • jacobson-1988 —— Van Jacobson 是 RTP 共同作者
  • cerf-kahn-1974 —— TCP/IP 论文,整个 IP 协议栈的根