
1. 从一个实际对接问题说起为什么SDP值得单独拎出来讲做过视频监控平台对接的人大概率都经历过这样的场景设备侧信令看着都通了INVITE发出去也有200 OK回来但画面就是黑的或者只有单向音频。抓包一看SDP里的IP写的是内网地址媒体端口对不上又或者asetup、aconnection这些属性跟对端预期完全不一致。这类问题排查起来非常折磨人因为信令层看起来成功了问题全藏在SDP这个文本块里。SDP全称Session Description Protocol会话描述协议它本身不传输媒体也不负责协商它只是一份格式化的说明书用纯文本告诉对方我这边媒体流打算怎么发、发到哪、用什么编码、什么方向。真正干活的是它背后的offer/answer模型。而GB28181作为国内视频监控联网的核心标准把SDP用在了设备注册、实时点播、历史回放、语音对讲、报警联动等几乎所有媒体交互环节并且对标准SDP做了一些自己的约定和裁剪。这篇内容我打算把两件事讲透一是SDP本身的字段结构、offer/answer机制、常见属性到底怎么读怎么写二是GB28181在SDP上到底加了哪些私货、有哪些强制字段、哪些坑是标准里没写清楚但实际对接必须处理的。适合正在做平台对接、设备接入、流媒体网关开发或者被SDP问题卡住的工程师参考。不管你是刚接触信令的新手还是已经调过几套平台的老手我都尽量把为什么这么设计讲清楚而不是只丢一张字段表。2. SDP整体结构与字段设计逻辑拆解2.1 SDP的本质一份有严格顺序的文本清单SDP不是二进制协议也不是XML/JSON它就是一行一行的typevalue文本。别看它简单顺序是有强约束的。一个标准SDP由会话级描述和零到多个媒体级描述组成会话级在前媒体级在后每个媒体段以m开头。一个典型的SDP长这样v0 o- 1234567890 1234567890 IN IP4 192.168.1.10 sPlay cIN IP4 192.168.1.10 t0 0 mvideo 6000 RTP/AVP 96 97 98 artpmap:96 PS/90000 artpmap:97 MPEG4/90000 asendonly这里每一行的含义我后面会逐个拆。先记住一个核心原则SDP的字段顺序不能乱尤其是v必须是第一行o第二s第三t必须在所有媒体段之前。很多设备解析器是顺序敏感的你少一个t或者把c放到m后面对方可能直接拒绝。2.2 会话级字段描述这场会话是谁、什么时候、在哪会话级字段是所有媒体段共享的上下文。逐个说v协议版本目前永远是0。别改。o所有者/会话标识格式是ousername sess-id sess-version nettype addrtype address。这里的sess-id和sess-version在GB28181里经常被用来做会话唯一标识后面会细讲。s会话名称。标准里说不能为空但实际很多实现写-或者Play。GB28181里常见的是Play、Playback、Download、Talk。c连接信息格式cIN IP4 地址。这是最容易出问题的地方因为它决定了媒体流往哪发。会话级c可以被媒体级c覆盖。t时间描述tstart stop。实时流一般写t0 0表示永久会话。a属性行会话级和媒体级都能出现是SDP最灵活也最容易踩坑的部分。我个人的经验是排查SDP问题第一步就是看c和m里的端口第二步看a里的方向属性和编码映射。80%的对接故障都出在这两块。2.3 媒体级字段描述这条流是什么、怎么收媒体级从m开始格式是mmedia port proto fmt list。以mvideo 6000 RTP/AVP 96 97 98为例video媒体类型还有audio、application、text等。6000端口。注意这里可以是单端口也可以是起始端口/端口数的形式比如mvideo 6000/2 RTP/AVP 96。RTP/AVP传输协议明文RTP。如果是加密的会是RTP/SAVP。96 97 98payload type列表具体编码靠后面的artpmap解释。媒体级下面通常跟着这些属性artpmap:pt encoding/clock rate[/channels]把payload type映射到具体编码。比如artpmap:96 PS/90000表示96号负载是PS流时钟频率90000。afmtp:pt parameters编码的附加参数比如H264的profile-level-id、sprop-parameter-sets。asendonly/arecvonly/asendrecv/ainactive媒体方向。这个在GB28181里极其关键。asetup:DTLS角色active/passive/actpass加密场景用。aconnection:new表示新建连接GB28181里常见。2.4 offer/answer模型SDP不是单向广播是双向协商很多人误以为SDP就是我告诉你我怎么发其实完整流程是offer/answer主叫方在INVITE里带一个offer SDP描述自己能收什么、想发什么。被叫方在200 OK里带一个answer SDP从offer的能力集合里挑一个子集确认最终参数。answer必须是对offer的合法子集不能凭空加offer里没有的编码。这个模型的意义在于双方能力可能不对称通过一次往返确定交集。GB28181虽然简化了很多但基本遵循这个模型。理解这一点你才能明白为什么有时候设备回的SDP跟你发的不一样——它在做answer不是简单复读。3. GB28181对SDP的具体规定与字段约束3.1 GB28181为什么需要自己的SDP约定标准SDP是通用的但视频监控场景有几个特殊需求设备编码固定、媒体流以PS封装为主、需要区分实时/回放/下载/对讲、需要携带SSRC做流标识。所以GB28181在RFC 4566基础上做了一层行业profile规定了哪些字段必填、哪些值固定、哪些属性必须带。如果你拿一个通用SIP客户端的SDP直接去跟GB28181设备对接大概率会失败因为设备侧解析器对字段的预期是写死的。3.2 实时点播Play的SDP规定实时点播是最常见的场景。GB28181规定INVITE的offer SDP里s字段应为Play媒体描述通常是v0 o设备编码 0 0 IN IP4 媒体服务器IP sPlay cIN IP4 媒体服务器IP t0 0 mvideo 端口 RTP/AVP 96 artpmap:96 PS/90000 arecvonly ySSRC几个关键点o里的username通常是设备编码或者平台编码sess-id和sess-version很多实现写0。sPlay是约定值回放是Playback下载是Download对讲是Talk。mvideo的payload type固定用96编码固定PS/90000。虽然理论上可以协商但实际设备基本只认PS。arecvonly表示平台只收不发。如果是语音对讲方向会变成sendrecv或者双向。y是GB28181特有的SSRC行格式y十位十进制SSRC用来唯一标识一路流。这个字段标准SDP里没有是GB28181加的。注意y字段的SSRC必须是10位十进制数字前几位有编码规则比如第一位表示实时/回放具体规则各厂商实现略有差异对接时要跟设备文档确认。3.3 历史回放Playback与下载Download的差异回放和下载的SDP结构跟Play几乎一样区别在s字段和t字段回放sPlaybackt通常写具体时间段比如t1600000000 1600003600表示回放这个时间区间。下载sDownload同样是时间段但语义是文件下载而非流式回放。实际对接中我发现很多设备对t的解析并不严格真正决定回放区间的是INVITE里携带的XML消息体含StartTime/EndTimeSDP里的t更多是形式上的。但为了兼容性还是建议按规范填。3.4 语音对讲与广播的SDP特点对讲场景的SDP跟点播最大的区别是媒体方向。平台要同时发和收所以会出现maudio 端口 RTP/AVP 8 artpmap:8 PCMA/8000 asendrecv音频编码通常是PCMAG.711Apayload type 8时钟8000。有些设备支持PS封装的音频但纯对讲一般用裸RTP音频。这里要注意对讲的双向流可能用同一个端口也可能用不同端口取决于设备实现SDP里m的端口号必须跟实际监听端口一致。3.5 GB28181 SDP字段速查表字段是否必填GB28181约定值说明v必填0固定o必填设备/平台编码username常用编码s必填Play/Playback/Download/Talk区分业务类型c必填媒体服务器IP决定流发往哪t必填0 0 或时间段实时用0 0mvideo点播必填端口 RTP/AVP 96PS流artpmap必填96 PS/90000固定映射arecvonly点播必填-平台只收y必填10位SSRC流标识maudio对讲必填端口 RTP/AVP 8PCMAasendrecv对讲必填-双向这张表是我对接多套平台后整理的基本覆盖了90%的场景。剩下10%是加密、组播等特殊场景后面单独说。4. 实操过程从抓包到构造一份能用的SDP4.1 抓包定位SDP问题的标准流程遇到媒体不通我的排查顺序是这样的抓信令包找到INVITE和200 OK把两边的SDP都导出来。对比c地址offer里的地址是不是平台真实可达的IP如果平台有多网卡很容易填错。对比m端口answer里的端口是不是设备实际监听的有些设备回200 OK时端口跟offer不一致这是合法的但平台要按answer的端口发流。检查artpmappayload type和编码是否匹配。曾经遇到设备回artpmap:96 PS/90000但实际发的是H264裸流这种就是设备实现问题。检查ySSRC是否一致不一致会导致流被丢弃。最后看a方向recvonly和sendonly搞反是经典错误。这个流程走下来大部分问题都能定位。真正难的是设备行为不规范比如回了个语法正确但语义错误的SDP那就得靠日志和对比测试。4.2 构造offer SDP的参数计算假设平台媒体服务器IP是10.0.0.5要拉一路实时流本地准备用端口30000收流SSRC规划为0100000001第一位0表示实时后面是序号。那么offer SDP可以这样写v0 o34020000001320000001 0 0 IN IP4 10.0.0.5 sPlay cIN IP4 10.0.0.5 t0 0 mvideo 30000 RTP/AVP 96 artpmap:96 PS/90000 arecvonly y0100000001端口选择有个经验不要用1024以下的特权端口也不要用设备可能占用的常用端口。我一般从30000往上选避开RTP常见的5000-6000区间减少冲突。SSRC的规划要全局唯一否则多路流会串。4.3 解析answer SDP并调整收流参数设备回的200 OK里answer SDP可能是v0 o34020000001320000001 0 0 IN IP4 10.0.0.5 sPlay cIN IP4 10.0.0.5 t0 0 mvideo 30000 RTP/AVP 96 artpmap:96 PS/90000 asendonly y0100000001注意方向变成了sendonly因为设备是发流方。平台收到这个answer后要在30000端口起监听等待RTP包。如果设备回的端口不是30000比如回了30002那平台就得在30002收而不是坚持用自己offer的端口。这是offer/answer模型的核心answer说了算。4.4 一个完整的对接时序记录我拿一次实际对接的过程举例设备用虚构代称某型号编码器平台发INVITE带offer SDPc10.0.0.5mvideo 30000y0100000001。设备回100 Trying然后回200 OKanswer SDP里c10.0.0.5mvideo 30000asendonlyy0100000001。平台回ACK同时在30000端口起RTP监听。设备开始发PS流平台收到RTP包解出PS再解出H264。平台发BYE结束会话设备停止发流。整个过程看起来简单但第2步到第4步之间如果设备延迟发流或者平台监听起晚了会丢前几个包表现为画面开头花屏。解决办法是在发ACK之前就把监听端口准备好别等ACK之后再起。5. 常见问题与排查技巧实录5.1 SDP相关故障速查表现象可能原因排查方法解决信令通但无流c地址不可达ping/telnet测试改成正确IP有流但花屏端口不一致对比offer/answer端口按answer端口收单向音频方向属性错误检查sendrecv修正a方向流被丢弃SSRC不匹配对比y字段统一SSRC编码不识别rtpmap错误检查payload type修正映射回放时间不对t字段错误检查XML消息体以XML为准对讲无声音音频编码不匹配检查PCMA/8000统一编码5.2 几个标准里没写但实际会遇到的坑坑一设备回的SDP里c是内网地址。这在跨网段对接时特别常见。设备注册时上报的是内网IPSDP里也填内网IP平台在外网根本收不到流。解决办法是平台侧做地址替换或者要求设备配置公网映射。这个不是SDP语法问题是网络部署问题但表现就是媒体不通。坑二m行端口写成0。有些设备在拒绝某路媒体时会把端口写0表示这个媒体不启用。如果你没判断直接往0端口发流肯定失败。解析时要先判断端口是否为0。坑三artpmap的时钟频率写错。PS流标准是90000但偶尔遇到设备写8000导致时间戳计算全乱播放器表现为快放或慢放。这种只能靠抓包对比发现。坑四多路流SSRC冲突。平台同时拉多路流时如果SSRC规划不当两路流用了同一个SSRC收流端会混淆。我的做法是SSRC里嵌入通道号和序号保证全局唯一。坑五SDP里的o字段被忽略但影响会话匹配。有些平台用o里的sess-id做会话关联如果设备每次回的sess-id都变平台可能匹配不上。对接时要确认双方对o的依赖程度。5.3 我的独家排查心得抓包工具我习惯用通用的网络协议分析工具过滤条件直接写sip or rtp。看SDP的时候我有个小技巧把offer和answer的SDP并排贴到文本编辑器里逐行diff。人眼对比容易漏diff一下差异一目了然。特别是c、m、a这三类行差异往往就是问题所在。另外遇到设备行为诡异时别急着改代码先用一个最简单的SDP去测。比如只保留必填字段去掉所有可选属性看设备能不能正常回。如果能再逐个加回属性定位是哪个属性导致的问题。这种二分法排查比读文档快得多。6. 进阶场景加密、组播与扩展属性6.1 加密媒体的SDP变化当媒体需要加密时m行的协议从RTP/AVP变成RTP/SAVP并且需要额外的密钥协商属性。常见的有acrypto:SDES方式的密钥格式acrypto:tag crypto-suite key-params。afingerprint:DTLS证书指纹。asetup:DTLS角色。GB28181早期版本对加密支持较弱新版本逐步引入了这些。对接加密场景时acrypto的tag必须双方一致密钥参数要匹配否则解密失败。这块比明文复杂得多建议单独做测试用例。6.2 组播场景的SDP写法组播时c行填的是组播地址比如cIN IP4 239.1.1.1m行的端口是组播端口。平台不需要主动发流而是加入组播组收流。SDP里通常还会带agroup或者amulticast相关属性。组播的好处是一路流多端接收节省带宽但要求网络设备支持组播转发配置不当会导致收不到流。6.3 扩展属性与厂商私有字段除了y有些厂商还会加自己的私有属性比如assrc:、ax-...。这些字段标准SDP允许但对方不一定认。对接时如果看到不认识的a行先别删保留着因为可能是对方必需的。我遇到过设备依赖某个私有属性判断会话类型删了就回错误码。7. 写在最后几个能直接抄的实践建议如果你正在做GB28181对接下面这几条是我踩坑后总结的可以直接用第一SDP构造和解析都写成独立的模块别散落在信令代码里。SDP字段多、变体多独立模块方便单元测试和复用。第二offer里只放你真正支持的编码。别为了兼容性塞一堆payload type设备可能挑一个你不支持的反而出问题。第三answer解析要宽容offer构造要严格。对端回的SDP可能有各种不规范解析时尽量容错自己发的SDP要严格按规范减少对端解析失败的概率。第四SSRC和端口做好全局规划别随机生成。多路并发时规划好的编号能省掉大量排查时间。第五日志里把完整的SDP打出来别只打摘要。出问题时完整的SDP是唯一能还原现场的东西。这套东西我前后对接过好几套平台和多种型号设备SDP这块的坑基本都集中在地址、端口、方向、SSRC这四个维度。把这四个维度盯死大部分问题都能快速定位。剩下的就是耐心抓包、对比、验证没有捷径但有了清晰的排查框架效率会高很多。