RTP 实战与排错 — Wireshark 解码、ffmpeg 推流与音视频故障定位

Wireshark 分析 RTP 流与播放音频、ffmpeg/gstreamer/sngrep 命令、单向语音与花屏排错 / 应用层 / UDP

这篇你能学到

  • 怎么让 Wireshark 认出"没有固定端口"的 RTP(抓信令 / 启发式 / Decode As),以及怎么用 RTP Streams、RTP Player 直接听出杂音断续。
  • ffmpeg/ffplay/gst-launch/sngrep/tcpdump 怎么发流、收流、看 SIP 通话质量,防火墙/NAT 怎么放行与穿透。
  • “单向语音 / 杂音爆音 / 花屏 / 唇音不同步 / SSRC 突变 / RTSP 拉不到流"的排错思路,以及 RTP vs RTSP vs HLS vs SRT 的选型。

1. 抓包观察

1.1 让 Wireshark 认出 RTP(第一步,必看)

这一步能干什么:RTP 没有固定端口,Wireshark 默认把它当普通 UDP,所以排错第一步是教它识别 RTP——否则后面所有过滤式都无从谈起。

RTP 没有固定端口,Wireshark 默认把它显示为普通 UDP。三种解决办法:

方法操作
① 抓上信令(最佳)同时抓 SIP/RTSP/SDP,Wireshark 会自动从 SDP 学到端口并解码
② 启用启发式解析Analyze → Enabled Protocols → 勾选 rtp_udp(Heuristic 项)
③ 手工指定右键任一 UDP 包 → Decode As… → 选 RTP

1.2 显示过滤式

这组过滤式能干什么:从海量 UDP 包里只挑 RTP/RTCP、按 SSRC 或负载类型定位某条流、看帧结束标记、看丢包/抖动超阈值、或切到 SIP/SDP/RTSP/加密 SRTP 视角。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
rtp # RTP 包
rtcp # RTCP 包
rtp.ssrc == 0xA1B2C3D4 # 指定流
rtp.p_type == 0 # PCMU(G.711 μ-law)
rtp.p_type == 8 # PCMA
rtp.p_type >= 96 # 动态负载类型(Opus/H.264/VP8)
rtp.marker == 1 # 帧结束(视频)/ 语音突发起始(音频)
rtp.seq == 1003 # 指定序号
rtp.timestamp
rtp.ext # 头部扩展(WebRTC 的 TWCC/abs-send-time)

rtcp.pt == 200 # SR 发送报告
rtcp.pt == 201 # RR 接收报告
rtcp.pt == 202 # SDES(看 CNAME)
rtcp.pt == 203 # BYE
rtcp.pt == 205 # RTPFB:NACK / TWCC
rtcp.pt == 206 # PSFB:PLI / FIR / REMB
rtcp.ssrc.fraction_lost > 0 # 有丢包上报
rtcp.ssrc.jitter > 100 # 抖动偏大

sip # 信令
sip.Method == "INVITE"
sdp # 会话描述(看协商出的端口与编码)
rtsp # RTSP 遥控
srtp # 加密的 RTP(WebRTC 场景,负载不可读)

1.3 Wireshark 的 RTP 分析利器

这张表能干什么:列出 Wireshark 里几个一键定位音视频问题的入口——尤其 RTP Player 能直接听出杂音,比看数字更快。

功能路径用途
RTP StreamsTelephony → RTP → RTP Streams列出所有流:SSRC、源/目的、PT、包数、丢包数与丢包率、最大抖动、平均抖动
Stream Analysis选中流 → Analyze逐包列出 delta、jitter、skew、标记乱序/丢失/错误时间戳
Play StreamsTelephony → RTP → RTP Player直接播放音频(G.711/G.722 等),一听就知道有无杂音断续
VoIP CallsTelephony → VoIP Calls列出 SIP 呼叫,可看流程图并一键播放媒体
Flow GraphStatistics → Flow Graph信令+媒体的时序图
IO GraphStatistics → I/O Graphrtp.ssrc==X 画码率曲线,看是否有突降

1.4 典型字段说明(一眼看出问题)

观察点正常异常判读
Sequence number严格 +1跳号 = 丢包;回退 = 乱序;重复 = 重传或环路
Timestamp按采样率规律递增(音频 20 ms 包 +160/+960,视频 30fps +3000)增量不规律 = 采集/编码卡顿;同帧多包应完全相同
Marker视频每帧最后一包 =1;音频突发起始 =1视频长时间无 M=1 → 帧未完整;音频频繁 M=1 → 静音抑制频繁
SSRC会话中稳定不变中途变化 = 发送端重启、媒体重协商,或SSRC 冲突;接收端会重建缓冲导致卡顿
Payload Type全程一致中途变化 = 编码切换(可能是带宽自适应),接收端需支持
包间隔≈ 打包间隔(如 20 ms)忽大忽小 = 网络抖动;成串到达 = 缓冲/整形
RTCP fraction lost0~2/256> 13/256(约 5%) 语音质量明显下降
RTCP jitter音频 8 kHz 下 < 240(30 ms)过大需加深抖动缓冲,或链路有问题
RTCP SR 是否存在每 ~5 秒一次完全没有 RTCP → 唇音同步失效、无质量反馈、部分设备判定超时挂断
RTP 流数量通话应有双向两条流只有单向 = 经典的"单通"问题(见 §3.1)

1.5 命令行抓包

这组命令能干什么:在无 GUI 的服务器上用 tcpdump/tshark 抓 SIP+RTP、统计 RTP 流、看 RTCP 反馈、提 SDP,或用 sngrep 交互式看 SIP 通话流程图。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 抓 SIP + RTP(信令与媒体一起,方便自动解码)
sudo tcpdump -i any -nn -s0 'udp portrange 10000-20000 or port 5060' -w rtp.pcap

# 用 tshark 统计 RTP 流
tshark -r rtp.pcap -q -z rtp,streams
tshark -r rtp.pcap -d 'udp.port==49170,rtp' -Y rtp -T fields \
  -e frame.time_relative -e rtp.ssrc -e rtp.seq -e rtp.timestamp -e rtp.p_type -e rtp.marker

# 查看 RTCP 反馈
tshark -r rtp.pcap -Y 'rtcp' -T fields \
  -e rtcp.pt -e rtcp.ssrc.fraction_lost -e rtcp.ssrc.cum_nr -e rtcp.ssrc.jitter

# 提取 SDP 看协商结果
tshark -r rtp.pcap -Y 'sdp' -V | grep -E '^\s+(Media Description|Media Attribute)'

# 实时观察 SIP 通话(VoIP 排错神器)
sudo sngrep # 交互式 SIP 流程图 + RTP 统计
sudo sngrep -r rtp.pcap

2. 常用命令 / 配置

2.1 ffmpeg / ffplay 收发 RTP

这组命令能干什么:用 ffmpeg 把音视频推成 RTP 流、用 ffplay 按 SDP 收流播放/录制,或从 RTSP 摄像头拉流(内部就是 RTP)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 推 RTP 音频(G.711 μ-law)
ffmpeg -re -i input.wav -acodec pcm_mulaw -ar 8000 -ac 1 \
       -f rtp rtp://192.168.1.20:49170

# 推 RTP 视频(H.264)
ffmpeg -re -i input.mp4 -an -c:v libx264 -preset ultrafast -tune zerolatency \
       -f rtp rtp://192.168.1.20:5004

# 推音视频(两条 RTP 流 + 生成 SDP)
ffmpeg -re -i input.mp4 \
  -c:v libx264 -tune zerolatency -f rtp rtp://192.168.1.20:5004 \
  -c:a libopus -ar 48000 -f rtp rtp://192.168.1.20:5006 \
  -sdp_file stream.sdp

# 接收播放(需要 SDP 文件描述编码与端口)
ffplay -protocol_whitelist file,udp,rtp -i stream.sdp
ffplay -protocol_whitelist file,udp,rtp -fflags nobuffer -flags low_delay -i stream.sdp

# 录制 RTP 到文件
ffmpeg -protocol_whitelist file,udp,rtp -i stream.sdp -c copy out.mp4

# 从 RTSP 摄像头拉流(内部用 RTP 传媒体)
ffplay -rtsp_transport tcp rtsp://admin:pass@192.168.1.64:554/Streaming/Channels/101
ffmpeg -rtsp_transport udp -i rtsp://192.168.1.64:554/live -c copy -t 30 clip.mp4
ffprobe -v error -show_streams rtsp://192.168.1.64:554/live # 查看流信息

典型 SDP 文件(stream.sdp):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
v=0
o=- 0 0 IN IP4 127.0.0.1
s=Test Stream
c=IN IP4 192.168.1.20
t=0 0
m=video 5004 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1
m=audio 5006 RTP/AVP 111
a=rtpmap:111 opus/48000/2

2.2 GStreamer(更细粒度控制)

这组命令能干什么:用 GStreamer 精细化控制 RTP 收发(含抖动缓冲、带 RTCP 的完整 rtpbin 会话),适合做更贴近真实媒体的联调。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 发送:H.264 over RTP
gst-launch-1.0 videotestsrc ! x264enc tune=zerolatency ! rtph264pay config-interval=1 pt=96 \
  ! udpsink host=192.168.1.20 port=5004

# 接收:带抖动缓冲
gst-launch-1.0 udpsrc port=5004 caps="application/x-rtp,media=video,encoding-name=H264,payload=96" \
  ! rtpjitterbuffer latency=200 ! rtph264depay ! avdec_h264 ! autovideosink

# 音频 Opus
gst-launch-1.0 audiotestsrc ! opusenc ! rtpopuspay pt=111 ! udpsink host=192.168.1.20 port=5006
gst-launch-1.0 udpsrc port=5006 caps="application/x-rtp,media=audio,encoding-name=OPUS,payload=111" \
  ! rtpjitterbuffer ! rtpopusdepay ! opusdec ! autoaudiosink

# 带 RTCP 的完整会话(rtpbin 自动处理 SR/RR 与同步)
gst-launch-1.0 -v rtpbin name=rtpbin \
  videotestsrc ! x264enc tune=zerolatency ! rtph264pay ! rtpbin.send_rtp_sink_0 \
  rtpbin.send_rtp_src_0 ! udpsink host=192.168.1.20 port=5004 \
  rtpbin.send_rtcp_src_0 ! udpsink host=192.168.1.20 port=5005 sync=false async=false \
  udpsrc port=5007 ! rtpbin.recv_rtcp_sink_0

2.3 VoIP / WebRTC 诊断

这组命令能干什么:在服务器侧看 SIP 通话质量、Asterisk/FreeSWITCH 的每路丢包抖动、用 mtr/iperf3/ping 测 UDP 路径基线,以及浏览器端用 webrtc-internals 看实时曲线、代码里取 getStats。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# SIP 通话实时监控(含 RTP 质量统计)
sudo sngrep -c # 只显示呼叫流
sudo sngrep host 192.168.1.10

# Asterisk / FreeSWITCH
asterisk -rx "rtp set debug on"
asterisk -rx "sip show channelstats" # 查看每路的丢包与抖动
fs_cli -x "show channels"
fs_cli -x "sofia status profile internal"

# 网络质量基线(RTP 对丢包/抖动敏感)
mtr -u -P 49170 192.168.1.20 # UDP 模式路径质量
iperf3 -c 192.168.1.20 -u -b 1M -t 30 # UDP 丢包与抖动测试(输出即 jitter/lost)
ping -i 0.2 -c 100 192.168.1.20 # 看 RTT 波动

WebRTC 端诊断(浏览器):

1
2
chrome://webrtc-internals/ # 实时曲线:packetsLost、jitter、RTT、bitrate、framesDropped
about:webrtc # Firefox
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 代码内获取统计
const stats = await pc.getStats();
stats.forEach(r => {
  if (r.type === 'inbound-rtp' && r.kind === 'video') {
    console.log('丢包', r.packetsLost, '抖动', r.jitter,
                '解码帧', r.framesDecoded, '关键帧请求', r.pliCount, 'NACK', r.nackCount);
  }
  if (r.type === 'candidate-pair' && r.state === 'succeeded') {
    console.log('RTT', r.currentRoundTripTime, '可用带宽', r.availableOutgoingBitrate);
  }
});

2.4 防火墙与 NAT 配置

这段配置能干什么:放行 RTP 端口范围与 SIP 信令端口,处理 SIP ALG(多数情况应关闭),并测试 STUN/TURN 穿透。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 放行 RTP 端口范围(示例:Asterisk 默认 10000-20000)
sudo firewall-cmd --permanent --add-port=10000-20000/udp
sudo firewall-cmd --permanent --add-port=5060/udp
sudo firewall-cmd --reload
sudo ufw allow 10000:20000/udp

# 加载 SIP 连接跟踪(帮助 NAT 自动开洞,但常与 SBC 冲突)
sudo modprobe nf_conntrack_sip
# 很多场景下应当**关闭** SIP ALG(它会错误改写 SDP 导致单通)
sudo modprobe -r nf_nat_sip nf_conntrack_sip

# 测试 STUN 穿透
stunclient stun.l.google.com 19302
turnutils_uclient -v -u user -w pass turn.example.com

3. 常见故障与排错

3.1 单向语音(“单通”)—— VoIP 头号故障

先记住结论:单通几乎总是 NAT / 防火墙 / ALG 三类问题——SDP 写了私网地址、RTP 端口范围没放行、或路由器的 SIP ALG 改错了 SDP。抓包看 RTP Streams 是否只有单向,是定位第一步。

现象:A 能听见 B,B 听不见 A(或反之)。

排查顺序

1
2
3
# ① 抓包确认 RTP 流方向:应有双向两条流
tshark -r call.pcap -q -z rtp,streams
# 只有一条 → 某方向根本没发或没到
原因判断解决
NAT 后 SDP 写了私网地址SDP 的 c=IN IP4 192.168.x.x 是内网地址,对端往私网发SIP 客户端配置外网地址;部署 SBC 或启用 STUN
防火墙未放行 RTP 端口范围出方向有包,入方向无包放行 UDP 10000-20000(或实际范围)
SIP ALG 错误改写路由器 SIP ALG 改了 SDP 但改错关闭路由器的 SIP ALG(最常见的"玄学"根因)
对称 NAT / 端口预测失败STUN 返回不同端口使用 TURN 中继兜底
单向路由/ACLmtr -u 一侧不通检查网络设备策略
编码不匹配SDP answer 中没有共同编码检查 a=rtpmap 交集

3.2 声音断续、杂音、机器人音

先记住结论:规律断续多因丢包,忽快忽慢爆音多因抖动过大,金属/机器人音多因编码不匹配或转码劣化——先用 RTP Streams 看丢包率与 RR 中的 jitter,再决定加 FEC/RED、加深缓冲还是统一编码。

现象原因定位处理
规律性断续丢包Wireshark RTP Streams 看丢包率>1% 需处理:查链路、启 FEC/RED、降码率
忽快忽慢、爆音抖动过大RR 中 jitter 值 / Stream Analysis加深抖动缓冲;QoS 给 EF 标记优先转发
金属音/机器人音编码不匹配或转码劣化抓包看 PT 与 SDP统一编码,避免多次转码
单侧回声回声消除(AEC)失效检查设备 AEC、降低扬声器音量、用耳机
完全静音但有 RTP 包PT 与实际负载不符 / 静音抑制Wireshark Play Stream 试听核对 a=rtpmap;关闭 VAD/DTX 测试

QoS 标记(有效缓解抖动):

1
2
3
# 给 RTP 打 DSCP EF (46)
sudo iptables -t mangle -A OUTPUT -p udp --dport 10000:20000 -j DSCP --set-dscp-class EF
# 交换机侧需信任 DSCP 并配置优先队列

3.3 视频花屏 / 灰屏 / 长时间黑屏

先记住结论:花屏多半是丢了 P 帧、等不到下一个关键帧;持续花屏是 IDR 关键帧丢失且没 PLI 机制;一直黑屏是 SPS/PPS 没传或没周期重发。处理围绕"关键帧策略"展开。

现象原因处理
花屏后自行恢复丢了 P 帧,等到下一个关键帧才恢复缩短 GOP(关键帧间隔);启用 NACK 重传;接收端主动发 PLI
持续花屏不恢复关键帧(IDR)丢失且无 PLI 机制rtcp.pt==206 确认有无 PLI;服务端需响应 PLI 立即出 I 帧
一直黑屏无画面SPS/PPS 未传或未周期重发ffmpeg 加 -x264opts repeat-headers=1;GStreamer rtph264pay config-interval=1
大量马赛克码率不足或丢包严重启用带宽估计(REMB/TWCC)自适应降码率
画面卡住但音频正常视频流 SSRC 变化或解码器异常抓包看 rtp.ssrc 是否跳变
1
2
3
# 让 H.264 周期性重发 SPS/PPS(关键!否则中途加入者永远解不出画面)
ffmpeg -i in.mp4 -c:v libx264 -x264-params keyint=60:scenecut=0:repeat-headers=1 \
       -f rtp rtp://host:5004

3.4 唇音不同步(Lip Sync 失准)

先记住结论:唇音不同步几乎都是"没有 RTCP"或"CNAME 对不上”——要么防火墙只放了 RTP 偶数端口漏了 RTCP 奇数端口,要么两条流 CNAME 不一致,要么时间戳生成用错了时钟。先抓 rtcp.pt==200rtcp.pt==202 确认锚点和关联。

根因排查

1
2
3
4
# ① 有没有 RTCP SR?没有 SR 就没有同步锚点
tshark -r call.pcap -Y 'rtcp.pt==200' | wc -l # 应 > 0
# ② 音视频流的 CNAME 是否相同?不同则无法关联
tshark -r call.pcap -Y 'rtcp.pt==202' -V | grep -i cname
原因处理
RTCP 被防火墙阻断(只放行了 RTP 偶数端口,漏了 RTCP 奇数端口)放行 RTP 端口 +1;或启用 rtcp-mux
音视频流 CNAME 不一致检查发送端实现,同一参与者应用相同 CNAME
时间戳生成错误(用墙上时间而非采样时钟)修正打包逻辑:时间戳必须按采样数递增
音视频抖动缓冲深度差异大统一同步策略,以慢的一方为准
采集设备时钟漂移定期重采样对齐

3.5 RTP 流中断 / SSRC 突变

先记住结论:SSRC 突变一般是发送端重启/重协商或 SSRC 冲突后按 RFC 3550 重选;流突然停多为收到 BYE 或 NAT 映射老化(保活不足)。定位看 SSRC 是否跳变、序号是否大跳。

现象原因
SSRC 中途改变发送端重启、重新协商(re-INVITE)、或 SSRC 冲突后按 RFC 3550 重选
序号大跳但 SSRC 不变长时间静音抑制(DTX),或网络长时间中断
流突然停止收到 RTCP BYE(正常挂断);或 NAT 映射老化(保活不足
NAT 映射老化UDP NAT 表项典型 30~180 秒;静音期不发包会被回收 → 启用 RTCP 保活或 STUN binding 保活、或关闭 DTX

3.6 RTSP 摄像头拉不到流

先记住结论:RTSP 信令通但收不到 RTP,多半是 UDP 被防火墙/NAT 挡了,改用 -rtsp_transport tcp 走 RTP over RTSP 单端口即可绕开;401/404 则是认证或 URL 路径问题。

1
2
3
4
5
# 分步排查
nc -zv 192.168.1.64 554 # ① TCP 554 通吗
curl -v rtsp://192.168.1.64:554/live 2>&1 | head -20 # ② 有无 401(认证)
ffprobe -rtsp_transport tcp rtsp://admin:pass@192.168.1.64:554/live # ③ 用 TCP 交织传输
tshark -i any -Y rtsp -V | grep -E 'DESCRIBE|SETUP|PLAY|Transport' # ④ 看协商细节
问题处理
RTSP 信令通但收不到 RTPUDP 被防火墙/NAT 阻断 → 改用 -rtsp_transport tcp(RTP over RTSP interleaved,单端口)
401 Unauthorized用户名密码;注意特殊字符需 URL 编码(@%40
404 Not FoundURL 路径错误,查厂商文档(海康 /Streaming/Channels/101,大华 /cam/realmonitor?channel=1&subtype=0
拉流几秒后断keepalive 未发;ffmpeg 加 -stimeout 5000000
延迟很大-fflags nobuffer -flags low_delay -probesize 32 -analyzeduration 0

3.7 排错思路总览

先记住结论:音视频问题排错是一条"有没有流 → 单向还是双向 → 丢包还是抖动 → 有没有 RTCP → SSRC/时间戳稳不稳 → 视频关键帧策略"的漏斗;抓包是一切的起点。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
音视频有问题?
├─ 抓包:有 RTP 流吗?
│ ├─ 没有 → 信令失败(SIP/SDP/RTSP)、防火墙、NAT
│ ├─ 只有单向 → 单通问题:SDP 私网地址 / SIP ALG / 防火墙
│ └─ 双向都有 → 继续
├─ RTP Streams 看丢包率与抖动
│ ├─ 丢包 >1% → 链路质量、拥塞、无线干扰 → FEC/NACK/降码率
│ ├─ 抖动大 → 加深抖动缓冲 + QoS DSCP EF
│ └─ 正常 → 继续
├─ 有 RTCP 吗?
│ ├─ 没有 → 唇音不同步、无自适应 → 放行 RTCP 端口或启 rtcp-mux
│ └─ 有 → 看 fraction_lost / jitter / RTT
├─ SSRC 稳定吗? 突变 → 发送端重启或冲突
├─ 时间戳规律吗? 不规律 → 采集/编码卡顿
└─ 视频花屏 → 关键帧策略(GOP、repeat-headers、PLI 响应)

4. 与其他协议对比

维度RTP/RTCPRTSPHLS / DASHSRTWebRTC
定位媒体数据传输信令/遥控基于 HTTP 的分段流安全可靠传输完整实时通信栈
规范RFC 3550/3551RFC 2326 / 7826RFC 8216 / MPEG-DASHHaivision 开源W3C + IETF
端口动态 UDPTCP 554TCP 80/443UDP 可配动态 UDP(ICE)
承载UDP(可 TCP/DTLS/QUIC)TCPHTTP/TCPUDPDTLS-SRTP over UDP
延迟20~200 ms依赖底层 RTP2~30 s100~500 ms50~300 ms
可靠性不可靠(配 NACK/FEC)信令可靠TCP 可靠ARQ 重传不可靠 + NACK/FEC
方向双向控制信令单向拉流单/双向双向
加密需 SRTP可 RTSPSHTTPS + AES-128内建 AES强制 DTLS-SRTP
NAT 穿透需 STUN/TURN/SBC一般天然友好(HTTP)较好内建 ICE
CDN 分发优秀需 SFU/MCU
典型场景VoIP、会议、监控摄像头/流媒体控制大规模直播、点播广电级远距离传输浏览器音视频通话

关系而非竞争

  • RTSP 与 RTP 是搭档:RTSP 负责"播放/暂停/定位",RTP 负责传媒体。
  • WebRTC 内部就是 RTP:SRTP = 加密的 RTP,RTCP-FB = 增强的 RTCP。
  • HLS 与 RTP 是不同赛道:前者牺牲延迟换取 CDN 可扩展性与穿透性,后者牺牲可扩展性换取低延迟与双向互动。

5. 速查表 / 常见面试题

5.1 RTP 头字段速查

字段位宽记忆点
V2恒为 2
P1有填充
X1有头部扩展
CC4CSRC 个数 0~15
M1视频=帧尾,音频=突发起始
PT7编码类型,动态 96~127
Seq16每包 +1,初值随机
Timestamp32采样时钟单位,初值随机
SSRC32源标识
CSRC0~15×32混音器填
固定头12 字节记住这个数

5.2 时间戳增量速查

编码时钟率20 ms 增量备注
PCMU/PCMA (G.711)8000160PT=0 / 8
G.7298000160PT=18
G.7228000(名义)160实际采样 16 kHz,历史坑
Opus48000960动态 PT,常用 111
所有视频9000030fps→3000 / 25fps→3600 / 60fps→1500统一 90 kHz

5.3 RTCP 包类型速查

PT名称关键内容
200SRNTP↔RTP 映射、发包数、字节数
201RR丢包率、累计丢包、抖动、LSR、DLSR
202SDESCNAME(关联同一参与者的多条流)
203BYE离开会话
204APP自定义
205RTPFBNACK(fmt=1)、TWCC(fmt=15)
206PSFBPLI(1)、FIR(4)、REMB(15)
207XR扩展质量报告

5.4 高频面试题

Q1:RTP 为什么建立在 UDP 而不是 TCP 之上? A:实时媒体的核心诉求是低延迟且延迟稳定。TCP 的重传、队头阻塞、拥塞退避会造成不可预测的延迟累积,而迟到的媒体数据等于无用数据——重传一个 300 ms 前的音频帧不如直接丢弃做丢包隐藏。UDP 的"发出即忘"配合应用层的抖动缓冲、FEC、选择性 NACK,能在丢包与延迟之间做更精细的权衡。

Q2:RTP 头里的序列号和时间戳分别解决什么问题?为什么不能只要一个? A:序列号解决乱序与丢包检测(每包 +1);时间戳解决播放时序恢复(记录采样时刻,驱动抖动缓冲)。二者不可互相替代:同一视频帧被分成 10 个包时,时间戳完全相同但序号递增 10 次——只有序号无法知道何时播放,只有时间戳无法知道包是否丢了或乱了。

Q3:RTP 时间戳的单位是什么?为什么视频统一用 90000 Hz? A:单位是媒体采样时钟周期,不是毫秒。90000 Hz 是 25/30/50/60 fps 等常见帧率的公倍数(90000/30=3000、/25=3600、/50=1800、/60=1500 均为整数),能精确表示各种帧率而无累积舍入误差,同时精度足够(11.1 μs)。

Q4:SSRC 和 CSRC 有什么区别? A:SSRC 是当前 RTP 包的同步源——“这个包是谁发出来的”,32 位随机且会话内唯一。CSRC贡献源列表,只有经过 **Mixer(混音器)**时才出现:混音器把 N 路流合成 1 路,用自己的新 SSRC 发送,并把原始 N 个源的 SSRC 填入 CSRC 列表(最多 15 个),让接收端知道"这段混音里有谁在说话"。

Q5:没有 RTCP 会怎样? A:① 无法做音视频同步——音频与视频是独立的 RTP 流,时间戳基准各自随机,只有 RTCP SR 提供的 (NTP, RTP timestamp) 映射才能对齐;② 无质量反馈——发送端不知道丢包率与 RTT,无法码率自适应;③ 无 NACK/PLI——视频花屏无法恢复;④ 无 CNAME——无法判断多条流属于同一参与者;⑤ 部分设备因收不到 RTCP 判定对端超时而挂断。

Q6:RTP 和 RTSP 是什么关系? A:RTSP 是遥控器,RTP 是电视信号。RTSP(TCP 554)是应用层信令协议,提供 DESCRIBE/SETUP/PLAY/PAUSE/TEARDOWN 等方法控制媒体会话;实际的音视频数据由 RTP 传输(可以是独立 UDP,也可以用 RTSP interleaved 在同一 TCP 连接上交织)。二者配合,而非替代。

Q7:RTP 如何应对丢包? A:按延迟预算分层选择:① PLC 丢包隐藏(音频用前后帧外推,零带宽成本);② NACK 重传(RTCP RTPFB,RTT 小时有效);③ FEC 前向纠错(发冗余包直接恢复,代价是 20~100% 额外带宽,适合高 RTT);④ RED 冗余编码(新包捎带上一帧副本);⑤ 视频丢关键帧时发 PLI/FIR 请求立即出 I 帧;⑥ SVC/Simulcast 分层编码降级。

Q8:抖动是怎么计算的?抖动缓冲深度怎么定? A:D(i-1,i) = (R_i - R_{i-1}) - (S_i - S_{i-1})(到达间隔差减采样间隔差),再一阶指数平滑 J = J + (|D| - J)/16。缓冲深度是延迟与流畅的权衡:太浅会欠载断续,太深则延迟大。现代实现(如 WebRTC 的 NetEQ)用自适应缓冲,根据实测抖动动态调整,并在静音期悄悄伸缩以避免可听失真。ITU-T G.114 建议单向延迟 ≤150 ms。

Q9:Marker 位在音频和视频里含义相同吗? A:不同,由 Profile 定义。音频(RFC 3551):M=1 表示语音突发的第一个包(静音抑制后恢复发声),提示接收端可能需要调整缓冲;视频(如 RFC 6184 H.264):M=1 表示一帧的最后一个 RTP 包,接收端据此判断帧已完整可送解码。

Q10:WebRTC 里的 RTP 有什么不同? A:本质仍是 RTP,但强化了:① 强制 SRTP(DTLS-SRTP 协商密钥,RFC 5764);② rtcp-mux(RTP 与 RTCP 复用同一端口,NAT 只需打一个洞);③ BUNDLE(音频/视频/DataChannel 全部复用一个传输通道);④ 大量 RTCP 反馈扩展(NACK、PLI、REMB、TWCC)支撑 GCC 拥塞控制;⑤ RFC 8285 头部扩展携带 abs-send-time、audio-level、TWCC 序号;⑥ ICE/STUN/TURN 做 NAT 穿透。

Q11:为什么 RTP 一般用偶数端口,RTCP 用奇数端口?现在还这样吗? A:RFC 3550 的传统约定:RTP 用偶数端口 N,RTCP 用 N+1,便于隐式推导。现在有两种改进:SDP 用 a=rtcp:<port> 显式指定;或用 rtcp-mux(RFC 5761)把 RTP 与 RTCP 复用到同一端口,靠 PT 值区分(RTCP 的 PT 为 200207,因此 RTP 保留 7276 不使用)。WebRTC 默认启用 rtcp-mux。

Q12:VoIP 单向语音(单通)最常见的原因是什么? A:NAT 相关问题。典型是 SDP 中的 c= 行写了私网地址,对端把 RTP 发往不可达的内网 IP;或路由器的 SIP ALG 错误改写了 SDP;或防火墙只放行了信令端口 5060 而没放行 RTP 的 UDP 端口范围。排查方法:抓包看 RTP Streams 是否只有单向,检查 SDP 中的地址与端口,关闭路由器 SIP ALG,必要时部署 SBC 或 STUN/TURN。