RTP 实战与排错 — Wireshark 解码、ffmpeg 推流与音视频故障定位
Wireshark 分析 RTP 流与播放音频、ffmpeg/gstreamer/sngrep 命令、单向语音与花屏排错 / 应用层 / UDP
Table of Contents
这篇你能学到
- 怎么让 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.3 Wireshark 的 RTP 分析利器
这张表能干什么:列出 Wireshark 里几个一键定位音视频问题的入口——尤其 RTP Player 能直接听出杂音,比看数字更快。
| 功能 | 路径 | 用途 |
|---|---|---|
| RTP Streams | Telephony → RTP → RTP Streams | 列出所有流:SSRC、源/目的、PT、包数、丢包数与丢包率、最大抖动、平均抖动 |
| Stream Analysis | 选中流 → Analyze | 逐包列出 delta、jitter、skew、标记乱序/丢失/错误时间戳 |
| Play Streams | Telephony → RTP → RTP Player | 直接播放音频(G.711/G.722 等),一听就知道有无杂音断续 |
| VoIP Calls | Telephony → VoIP Calls | 列出 SIP 呼叫,可看流程图并一键播放媒体 |
| Flow Graph | Statistics → Flow Graph | 信令+媒体的时序图 |
| IO Graph | Statistics → I/O Graph | 按 rtp.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 lost | 0~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 通话流程图。
| |
2. 常用命令 / 配置
2.1 ffmpeg / ffplay 收发 RTP
这组命令能干什么:用 ffmpeg 把音视频推成 RTP 流、用 ffplay 按 SDP 收流播放/录制,或从 RTSP 摄像头拉流(内部就是 RTP)。
| |
典型 SDP 文件(stream.sdp):
2.2 GStreamer(更细粒度控制)
这组命令能干什么:用 GStreamer 精细化控制 RTP 收发(含抖动缓冲、带 RTCP 的完整 rtpbin 会话),适合做更贴近真实媒体的联调。
| |
2.3 VoIP / WebRTC 诊断
这组命令能干什么:在服务器侧看 SIP 通话质量、Asterisk/FreeSWITCH 的每路丢包抖动、用 mtr/iperf3/ping 测 UDP 路径基线,以及浏览器端用 webrtc-internals 看实时曲线、代码里取 getStats。
| |
WebRTC 端诊断(浏览器):
| |
2.4 防火墙与 NAT 配置
这段配置能干什么:放行 RTP 端口范围与 SIP 信令端口,处理 SIP ALG(多数情况应关闭),并测试 STUN/TURN 穿透。
| |
3. 常见故障与排错
3.1 单向语音(“单通”)—— VoIP 头号故障
先记住结论:单通几乎总是 NAT / 防火墙 / ALG 三类问题——SDP 写了私网地址、RTP 端口范围没放行、或路由器的 SIP ALG 改错了 SDP。抓包看 RTP Streams 是否只有单向,是定位第一步。
现象:A 能听见 B,B 听不见 A(或反之)。
排查顺序:
| 原因 | 判断 | 解决 |
|---|---|---|
| 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 中继兜底 |
| 单向路由/ACL | mtr -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 标记(有效缓解抖动):
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 是否跳变 |
3.4 唇音不同步(Lip Sync 失准)
先记住结论:唇音不同步几乎都是"没有 RTCP"或"CNAME 对不上”——要么防火墙只放了 RTP 偶数端口漏了 RTCP 奇数端口,要么两条流 CNAME 不一致,要么时间戳生成用错了时钟。先抓 rtcp.pt==200 和 rtcp.pt==202 确认锚点和关联。
根因排查:
| 原因 | 处理 |
|---|---|
| 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 路径问题。
| 问题 | 处理 |
|---|---|
| RTSP 信令通但收不到 RTP | UDP 被防火墙/NAT 阻断 → 改用 -rtsp_transport tcp(RTP over RTSP interleaved,单端口) |
| 401 Unauthorized | 用户名密码;注意特殊字符需 URL 编码(@ → %40) |
| 404 Not Found | URL 路径错误,查厂商文档(海康 /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/时间戳稳不稳 → 视频关键帧策略"的漏斗;抓包是一切的起点。
| |
4. 与其他协议对比
| 维度 | RTP/RTCP | RTSP | HLS / DASH | SRT | WebRTC |
|---|---|---|---|---|---|
| 定位 | 媒体数据传输 | 信令/遥控 | 基于 HTTP 的分段流 | 安全可靠传输 | 完整实时通信栈 |
| 规范 | RFC 3550/3551 | RFC 2326 / 7826 | RFC 8216 / MPEG-DASH | Haivision 开源 | W3C + IETF |
| 端口 | 动态 UDP | TCP 554 | TCP 80/443 | UDP 可配 | 动态 UDP(ICE) |
| 承载 | UDP(可 TCP/DTLS/QUIC) | TCP | HTTP/TCP | UDP | DTLS-SRTP over UDP |
| 延迟 | 20~200 ms | 依赖底层 RTP | 2~30 s | 100~500 ms | 50~300 ms |
| 可靠性 | 不可靠(配 NACK/FEC) | 信令可靠 | TCP 可靠 | ARQ 重传 | 不可靠 + NACK/FEC |
| 方向 | 双向 | 控制信令 | 单向拉流 | 单/双向 | 双向 |
| 加密 | 需 SRTP | 可 RTSPS | HTTPS + 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 头字段速查
| 字段 | 位宽 | 记忆点 |
|---|---|---|
| V | 2 | 恒为 2 |
| P | 1 | 有填充 |
| X | 1 | 有头部扩展 |
| CC | 4 | CSRC 个数 0~15 |
| M | 1 | 视频=帧尾,音频=突发起始 |
| PT | 7 | 编码类型,动态 96~127 |
| Seq | 16 | 每包 +1,初值随机 |
| Timestamp | 32 | 采样时钟单位,初值随机 |
| SSRC | 32 | 源标识 |
| CSRC | 0~15×32 | 混音器填 |
| 固定头 | 12 字节 | 记住这个数 |
5.2 时间戳增量速查
| 编码 | 时钟率 | 20 ms 增量 | 备注 |
|---|---|---|---|
| PCMU/PCMA (G.711) | 8000 | 160 | PT=0 / 8 |
| G.729 | 8000 | 160 | PT=18 |
| G.722 | 8000(名义) | 160 | 实际采样 16 kHz,历史坑 |
| Opus | 48000 | 960 | 动态 PT,常用 111 |
| 所有视频 | 90000 | 30fps→3000 / 25fps→3600 / 60fps→1500 | 统一 90 kHz |
5.3 RTCP 包类型速查
| PT | 名称 | 关键内容 |
|---|---|---|
| 200 | SR | NTP↔RTP 映射、发包数、字节数 |
| 201 | RR | 丢包率、累计丢包、抖动、LSR、DLSR |
| 202 | SDES | CNAME(关联同一参与者的多条流) |
| 203 | BYE | 离开会话 |
| 204 | APP | 自定义 |
| 205 | RTPFB | NACK(fmt=1)、TWCC(fmt=15) |
| 206 | PSFB | PLI(1)、FIR(4)、REMB(15) |
| 207 | XR | 扩展质量报告 |
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。