
搞流媒体的谁敢说自己没跟RTP、RTCP打过交道我最早被这两个缩写折腾得够呛是在调一个国标接入平台的预览画面时平台日志里直接甩出一行“start preview failed maybe rtp session false or preview links num”当时一脑门子问号。后面又是抓包又是查SDP才发现自己连RTP的包头结构都没吃透排查起来自然一步一个坑。今天把RTP/RTCP这些基础但关键的知识系统梳理一遍从协议定位、核心字段到用ffmpeg和Wireshark怎么模拟、怎么分析再到国标平台预览失败的排查思路一次讲清楚。适合刚接触音视频传输、想搞懂抓包里那些RTP报文在说什么的开发者也适合被各种“rtp session false”日志难住的运维和集成工程师。1. 先搞清RTP/RTCP在实时流里的角色1.1 为什么实时音视频不用HTTP那套方案如果你只是做点播HTTPFTP那套足够舒服文件整体放服务器上客户端断点续传网络差顶多多缓冲几秒。但实时音视频完全不是一个逻辑摄像头画面是持续产生的播放端要边收边播延迟要求通常在几百毫秒以内。你用HTTP拉一个正在录制的流先不谈头部请求的开销光“请求-响应-收完再播”这个模式就卡死了实时性。RTPReal-time Transport Protocol实时传输协议就是把音频、视频这些实时数据切成小包以固定节奏持续往对端送。它不负责文件完整传输只负责“把这一个时刻的一块媒体数据尽快送到对方手里”。配合RTCPRTP Control Protocol实时传输控制协议一边传数据一边周期性地报告“你发的东西我收到多少、丢了多少、延迟抖动什么样”让通信双方能动态感知链路质量。简单类比RTP相当于快递员在一条环路上不停送货RTCP则是每隔一段路就回传一次“上一批货损坏了几件、路上堵了多久”的报告。数据面和控制面分开走互不干扰这是这套协议最核心的设计。1.2 承载在UDP上但补了TCP没有的“救急”能力RTP的默认承载协议是UDP。原因并不神秘TCP为了保证可靠传输会做重传和拥塞控制一旦网络抖动TCP会主动降低发送速度、等待丢失包重传这对实时媒体是致命的——视频通话里画面卡一下可以但为了等丢掉的旧数据把新数据堵住那体验直接崩了。UDP的哲学是“能送多少送多少丢了拉倒”时延低适合实时媒体。但纯UDP也有个致命缺陷它不带序号也没法给包标注时间。网络里包顺序乱了怎么办乱序和丢包怎么区分播放器哪个包在前哪个包在后这些全靠RTP在UDP之上补齐。RTP为每个包写了序号乱序时可以重排丢了能数出来丢多少又写入了时间戳让接收端知道这个包对应的采样时刻从而控制播放节奏、做音画同步。RTCP则专门负责反馈帮发送端知道丢包率、抖动、往返时延。值得注意RTP本身不保证服务质量它只提供恢复服务质量所需的信息。真正干活的还是应用层发送端收到RTCP反馈后决定要不要降码率、要不要重传这些策略由上层比如WebRTC、GB/T 28181网关实现。1.3 别搞混游戏里的“RTP”和流媒体里的“RTP”不是一回事搜“RTP”的时候很容易被另一个RTP干扰——RPG Maker VX Ace这类游戏提到的“RTP”是Run Time Package运行时资源包也就是游戏运行需要的素材库和DLL组件。遇到“RPGVX RTP is not found”的报错装一个对应的RTP运行库就能解决跟网络传输协议半毛钱关系没有。搜索引擎把这两类内容混在一起是因为缩写撞车了。技术排查时一定要先分清语境你是看到一个安装程序的报错还是在Wireshark里看到协议列写着RTP。如果是后者那才跟本文接下来要讲的内容相关。2. RTP核心拆解一个包头上写的全是“时间”和“顺序”2.1 RTP固定包头逐字段看懂RTP包由固定包头12字节起、可能的扩展头、载荷组成。前12字节是所有实现都必须处理的字段含义是排查一切RTP问题的起点。表格化整理如下字段长度含义V2 bit版本号目前固定为2P1 bit填充标志置1表示包尾有填充字节X1 bit扩展头标志置1表示包头后有扩展CC4 bitCSRC计数器说明后面跟了几个CSRCM1 bit标记位通常用于帧边界标记视频里常标I帧PT7 bit载荷类型标识音频/视频编码格式sequence number16 bit序号每个RTP包加1接收端用它测丢包、排序timestamp32 bit时间戳反映媒体采样时刻SSRC32 bit同步源标识每个发送源一个唯一编号CSRC可选每项32 bit贡献源列表混音场景里列出原始音源排错时最常用的就是序号和时间戳这两个字段。序号跳变说明丢包时间戳长期不动但Seq在涨多半是对方填充了冗余数据或者参数配置不对。2.2 时间戳和序号音画同步的地基序号好理解每发一个RTP包就加1接收端通过序号连续性判断丢包用序号差值就能算出实际丢了几个包。但时间戳要复杂一些。时间戳的单位不是秒而是“采样周期”。音频场景里如果采样率是8000Hz那么同一个音频流每个采样周期为1/8000秒RTP时间戳每增加1就代表经过了一个采样周期视频场景通常用90000Hz作为时钟频率因为90kHz是视频采样频率的标准值能保证常见的帧率25fps、30fps、60fps都被整数时间戳表示。时间戳的作用有两个一是让接收端以正确的节奏播放网络抖动导致包到达不均匀时播放器按时间戳而不是到达时间来安排播放时机二是音画同步——音频流和视频流的时间戳基于同一参考时钟时播放器可以根据时间戳关系把画面和声音对齐。你在Wireshark里看到视频流时间戳增量不是固定值是因为帧与帧之间的生成时间本来就不是等间隔的。注意RTCP里的SR报文会携带NTP时间戳和RTP时间戳的对应关系这是接收端做音画同步的“参照表”。很多同步问题排查到最后都是因为RTCP SR里的映射关系算错了单位。2.3 SSRC识别一个媒体流的“身份证”SSRCSynchronization Source是随机生成的32位标识符用来唯一标识一个RTP会话里的某个发送源。一个参与者发送多个媒体流时通常每个流有自己的SSRC。接收端依据SSRC区分“谁在说话”统计丢包时也是按SSRC分别统计的。SSRC会冲突吗理论上有因为32位随机数在大量会话时可能碰撞。RTP标准有冲突检测机制发现自己的SSRC被别人占用时接收端会发送RTCP BYE然后更换SSRC重新加入。实际排查中如果你在多路流汇聚的平台上看到画面串流、统计错乱可以怀疑一下是不是网关没有正确处理SSRC冲突。CSRC则用于混音场景。比如多方通话时RTP包里的语音可能是多个源头混出来的CSRC列表就列出这些原始SSRC。普通点对点视频通话中CSRC基本用不到。2.4 载荷类型PT协商出来的编解码PT字段标识RTP载荷的编码格式。RFC 3551规定了一些静态PT0是PCMUG.711 µ-law、8是PCMAG.711 A-law、4是G.722、9是G.722等。而视频编码H.264、H.265通常使用动态PT范围是96到127。动态PT本身没有固定含义全靠会话建立阶段通过SDP协商。SDP里会有类似这样一行mvideo 5004 RTP/AVP 96 artpmap:96 H264/90000意思就是视频流在端口5004使用RTP承载动态PT 96对应的编码是H.264时钟频率90000Hz。收到RTP包时要根据SDP协商结果来解释PT取值否则你看到PT96根本不知道包里是什么编码。很多“花屏”“无法解码”的问题都出在两端SDP里对PT的协商不一致。排查时先确认SDP的rtpmap再看RTP实际包头里的PT字段两者对不上播放端肯定罢工。3. RTCP媒体流的“体检报告”和“点名机制”3.1 RTCP的五大类报文分别负责什么RTCP报文和RTP走同一个传输通道一般也走UDP但端口通常是RTP端口1奇数端口。它不携带媒体数据只管质量反馈、会话成员管理。常见报文一共有五类类型名称作用SRSender Report发送者报告由发送端发出包含发送包数、字节数、NTP时间戳与RTP时间戳映射RRReceiver Report接收者报告由接收端发出反馈丢包率、累计丢包、抖动、往返时延SDESSource Description源描述携带CNAME等会话参与者身份信息BYEGoodbye离开会话通知告诉对方我这路流结束了APPApplication-defined应用自定义扩展实际抓包时最常见的组合是“SRSDES”“RRSDES”。SDES里的CNAME通常就是“userhost”这种全局唯一标识接收端靠CNAME在多个媒体流之间关联同一发送者。3.2 SR/RR里的关键统计量多少丢包、抖动多大、时延多高先拿RR来说它里面有三组数字最值得看丢包率从上次报告到这次报告之间接收端期望收到的包数和实际收到的包数之差除以期望包数得出一个小数。累计丢包整个会话开始至今丢失的包总数数据一直在累积只看差值容易误判。抖动两次包到达时间间隔的变化程度。它是用相邻包到达间隔的差值的平均偏差算出来的单位是RTP时间戳刻度除以90000就换算成秒。视频流抖动超过50ms基本就能肉眼看见卡顿。发送端真正要用的是往返时延RTT。RTP里的时间戳大部分是单向不可比的所以测RTT要借助SR和RR的配合发送端A在SR报文里写了一个NTP时间戳记为t1。接收端B收到SR后在RR报文里记录了LSR收到SR时的NTP时间戳和DLSR从收到SR到发出RR之间经过的时间。发送端A收到RR后用“当前时间 - LSR - DLSR”就得到单向往返时延。这套机制在WebRTC里也被大量使用。你在排查视频链路时如果发现RTT稳定在200ms以上就不要去纠结什么编解码参数了先把网络路径找出来。3.3 RTCP的发送节奏别把控制流量变成风暴RTCP不能想发就发RFC 3550对RTCP的发送频率有明确建议RTCP流量原则上不要超过会话总流量RTPRTCP的5%。其中发送者指发过RTP流的成员分到25%的带宽接收者分到剩下的75%并且发送间隔是随机化的避免大量参与者同时发送RTCP造成突发拥塞。实际工程里这个5%是“建议上限”很多系统会调小。比如GB/T 28181网关内部每秒只发一个RTCP SR能满足心跳和数据统计需求又不至于浪费带宽。如果你自己实现RTCP发送逻辑记得遵守“带随机性定时器”的要求否则多路流同时启动时RTCP报文会重叠在一起接收端统计全部错乱。4. 实操本地起一路RTP流抓包把每个字段看明白4.1 环境准备ffmpeg几分钟搭好一个RTP推流端抓包分析最怕没有真实流量。用ffmpeg在本地模拟一档RTP流非常简单先准备一个测试视频源比如用lavfi生成测试画面ffmpeg -re -f lavfi -i testsrcsize640x480:rate30 \ -c:v libx264 -b:v 1M -preset veryfast \ -payload_type 96 -ssrc 123456 \ -f rtp rtp://127.0.0.1:5004这里-re让ffmpeg按实时速率读取源-payload_type 96指定动态PT-ssrc 123456固定同步源方便抓包过滤输出目标是本机5004端口的RTP流。更推荐的做法是让ffmpeg生成SDP文件方便ffplay直接拉流ffmpeg -re -f lavfi -i testsrcsize640x480:rate30 \ -c:v libx264 -b:v 1M -preset veryfast \ -payload_type 96 -ssrc 123456 \ -f rtp rtp://127.0.0.1:5004 \ -sdp_file test.sdp生成出来的test.sdp里就有视频流的m描述、rtpmap映射可以用ffplay test.sdp验证播放。注意这是本地回环丢包基本为零适合熟悉流程真想体会丢包可以用tc命令在回环接口上加延迟和丢包率sudo tc qdisc add dev lo root netem delay 50ms loss 5%分析完后别忘删掉规则sudo tc qdisc del dev lo root4.2 Wireshark里怎么快速锁定RTP包打开Wireshark启动抓包过滤写udp.port 5004再运行上面的ffmpeg命令。你可能发现一个问题Wireshark并不会自动把包识别为RTP而是显示成UDP。原因是RTP没有固定端口必须通过SDP或解码器配置告诉Wireshark这是RTP。处理方式很简单选中任意一个UDP包右键“Decode As”把UDP端口5004的解析协议改成RTPWireshark会立刻按RTP结构解析整条流。此时你能在协议树里看到版本号、PT、Seq、时间戳、SSRC等字段。进一步分析整条RTP流的丢包和抖动可以走菜单“Telephony - RTP - RTP Streams”双击某条流能看到图形化统计序列号是否连续、到达时间是否均匀、抖动曲线什么样。操作一遍之后前面讲的序号、时间戳、SSRC就都有了直观认知。4.3 在抓包里找RTCP报告验证链路参数rtp://127.0.0.1:5004的RTCP端口是5005。抓包过滤器改成udp.port 5004 or udp.port 5005RTP流正常跑起来后你会在5005端口看到周期性的RTCP报文。先看SR报文里的包计数和字节计数跟RTP流实际发出去的包数比对再看RR报文——前提是你用ffplay播放过这条流接收端才会产生RR反馈。本地测试时RR里的丢包率接近0但如果你加了前面说的50ms抖动RR里的抖动字段就会明显变大这就是网络上视频卡顿的原因之一。小技巧RTP和RTCP使用相邻端口是约定俗成但并非强制。有些设备会把RTCP放在完全另外一个端口。抓到RTCP报文却不知道对应的RTP流时看RTCP包里的SSRC再去RTP流里匹配相同SSRC即可。5. 实战排查国标平台“start preview failed maybe rtp session false”怎么解5.1 先拆解这行日志到底在说什么国标GB/T 28181平台在拉流预览失败时经常会给出类似“start preview failed maybe rtp session false or preview links num”的提示。拆开看rtp session falseRTP会话没有成功建立媒体收流侧没有进入等待RTP包的状态。preview links num预览链路数量异常可能是0也可能超过上限。这个报错指向的是“信令通了媒体没通”的典型故障场景。SIP信令层面INVITE、200 OK可能已经完全正常但媒体平面没衔接上平台就报出这句话。5.2 从SIP信令到RTP媒体流的完整链路逐步确认排查思路是沿着协议栈一层层往下看SIP信令是否成功确认INVITE请求有收到200 OK。这一步不过说明设备侧注册或会话建立有问题后面都不用看。SDP里的媒体描述是否完整找到200 OK响应体里的SDP看有没有mvideo行、c连接地址、artpmap媒体属性。SDP缺失或不完整RTP会话就无从谈起。媒体地址和端口是否可达SDP里写的是设备或下级平台的收流IP和端口。拿这个IP和端口做一次网络连通性测试确认UDP端口没有被防火墙拦掉。NAT或网关映射是否正确多级平台级联时SDP里的IP地址经常是内网地址经过NAT后需要映射成公网或平台可达地址。SDP里地址不可达是最常见的“信令正常、RTP收不到”原因。RTP包是否真的到达收流端口在媒体服务器端抓包过滤目标端口看有没有RTP包进来。一条都没有回到第3、4步查网络有包但不识别看PT、SSRC是否和SDP协商一致。这五步走完九成问题都能定位。容易踩的坑是把所有精力放在SIP信令上却忽略了SDP响应体里的媒体信息——很多平台日志惨不忍睹但有包分析远比猜日志有用。5.3 高频故障清单和快速处置表现象直接原因处置信令200 OK但收流端口一个RTP包都收不到防火墙拦截UDP端口放通媒体UDP端口或修改SDP端口映射SDP里是内网IP上级平台回推内网地址NAT映射缺失在网关/NAT设备配置端口映射开启ALG或手动映射RTP到了但解析不了画面黑屏PT类型不匹配编解码协商不一致对照SDP rtpmap统一H.264/H.265 PT值预览数量超过平台license链接数上限释放空闲预览或提升授权数时通时断SSRC频繁变化对端会话异常重启查看对端媒体服务日志检查是否响应BYE/超时释放媒体通道这里要特别提一句“国标平台”这个场景的复杂性上级平台和下級平台之间往往有两级或三级级联每一级都可能改SDP内容。排查时光在当前平台抓包不够最好在信令链路两端分别抓包对比两端的SDP差异谁改的谁知道。6. 收藏向RTP/RTCP高频问题速查与经验补充6.1 高频问题速查表症状大概率原因怎么查播放器花屏、马赛克RTP丢包或H.264关键帧丢失后无后续I帧看RTP流的Seq跳变统计丢包率检查是否为关键帧间隔过长画面卡顿但码率正常网络抖动大接收缓冲不足看RTCP RR里的jitter字段调整接收端缓冲音画不同步RTCP SR时间戳映射错误或音视频流参考时钟不同源对比SR里的NTP和RTP时间戳换算关系ffmpeg输出“RTP missed X packets”抓包丢包或发送端和接收端编码速率不匹配确认抓包是否有丢弃检查时间戳增量是否均匀多路流串画面SSRC冲突未处理抓包看两个流的SSRC是否重合检查网关处理逻辑RTP包被Wireshark识别成UDP未正确配置解码规则Decode As指定端口为RTP6.2 我踩过的几个“不写进文档”的坑第一别指望RTCP丢包率一定能反映真实体验。接收端缓存一两秒再播放即使网络丢包1%用户也可能毫无感知反过来RTCP报告没丢包但播放器延迟抖动缓冲设置太小照样卡成PPT。排查要结合发送端、网络、接收端三层看。第二SSRC不能拍脑袋固定死。上面我给的ffmpeg例子是为了抓包方便固定SSRC但生产环境中多路流汇聚时固定的SSRC反而容易冲突。真正的网关实现应该用随机SSRC并做好冲突检测。第三GB /T 28181平台预览失败的报错很多并不是RTP本身出了问题而是SDP里端口写法和实际收流端口对不上。遇到“rtp session false”不要死磕RTP字段先回看SDP的媒体描述是不是你预期的样子。好多次排查到最后发现是上一次会话没有正常释放媒体端口被残留会话占着。6.3 关于“RTP over TCP”的一个补充弱网环境下你也会见到RTP不再走UDP而是封装在RTSP的TCP连接里传输也就是常说的TCP interleaved模式。这是为了穿透某些防火墙、规避UDP被丢。这种模式在Wireshark里看起来不是独立的RTP流而是RTSP报文里内嵌的二进制数据。用Wireshark一样能解析但统计丢包时要小心TCP重传会导致应用层看到重复的RTP序号直接按序号差值算丢包会误判。检测到TCP重传先排除重传影响再算真实丢包。我在实际调流媒体系统的过程中最深的体会是RTP/RTCP的门槛不在报文格式背得多熟而在遇到问题时能不能快速定位是哪一层断了。协议字段是死知识但排查思路是活经验。如果你现在正在被某个“preview failed”折腾不妨按第5章的链路排查法走一遍把SIP、SDP、UDP、RTP这四层拉通问题多半不会藏太久。