ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

WVP-GB28181-pro 国标级联语音喊话全流程解析:从 SIP 信令到 RTP 转发

WVP-GB28181-pro 国标级联语音喊话全流程解析:从 SIP 信令到 RTP 转发 WVP-GB28181-pro 国标级联语音喊话全流程解析从 SIP 信令到 RTP 转发【免费下载链接】wvp-GB28181-pro基于GB28181-2016、部标808、部标1078标准实现的开箱即用的网络视频平台。自带管理页面支持NAT穿透支持海康、大华、宇视等品牌的IPC、NVR接入。支持国标级联支持将普通摄像机/直播流/直播推流转国标共享到国标平台。项目地址: https://gitcode.com/GitHub_Trending/wv/wvp-GB28181-pro本篇技术文章基于 WVP-GB28181-pro 的官方文档 级联语音喊话流程说明系统梳理国标级联场景下语音喊话Audio Broadcast的完整 SIP 信令时序、SDP 协商细节与底层转发动作。读完本文你将掌握上级平台如何通过INFO(Broadcast)命令驱动下级平台向设备发起喊话、下级平台又如何向上级发起INVITE(broadcast)接收推流以及broadcastForPlatform三种传输模式在 SDP 中的具体体现并能对照源码定位每个环节的实现在哪一层。一、级联语音喊话的完整信令时序在国标级联拓扑中上级平台发起喊话WVP-PRO 作为下级平台居中调度最终将语音流送到摄像机/NVR。文档给出的完整时序如下startuml 上级平台 - 下级平台: 1. 发起语音喊话请求 上级平台 -- 下级平台: 2. 200OK 上级平台 - 下级平台: 3. 回复Result OK 上级平台 -- 下级平台: 4. 200OK 下级平台 - 设备: 5. 发起语音喊话请求 下级平台 -- 设备: 6. 200OK 下级平台 - 设备: 7. 回复Result OK 下级平台 -- 设备: 8. 200OK 下级平台 - 设备: 9. invite(broadcast) 下级平台 -- 设备: 10. 100 trying 下级平台 -- 设备: 11. 200OK SDP 下级平台 -- 设备: 12. ack 上级平台 - 下级平台: 13. invite(broadcast) 上级平台 -- 下级平台: 14. 100 trying 上级平台 -- 下级平台: 15. 200OK SDP 上级平台 -- 下级平台: 16. ack 上级平台 - 下级平台: 17. 推送RTP 下级平台 - 设备: 18. 推送RTP enduml整个流程分为四个阶段INFO 命令下发阶段1-4上级平台向 WVP-PRO 发送CmdTypeBroadcast的 INFO 请求WVP-PRO 先回200 OK确认收到再以Result OK的 INFO 响应通知命令受理结果上级平台再回200 OK完成确认。设备侧建立阶段5-12WVP-PRO 向目标设备转发同样的喊话请求并收到Result OK随后主动向设备发起INVITESDP 中标明要接收设备回传的媒体流设备返回100 Trying→200 OK(SDP)→ WVP-PRO 回ACK建立会话。上级平台收流阶段13-16WVP-PRO 反过来向上级平台发起INVITE(broadcast)上级平台按 SDP 中指定的 ZLMediaKit 端口推送 RTP 语音流。RTP 双向流转阶段17-18上级平台的 RTP 到达 WVP-PRO 侧的 ZLMediaKit再被转发到设备的收流端口形成上级平台 → 下级平台 → 设备的语音链路。值得注意的两个设计点Result OK 的异步确认WVP-PRO 收到 INFO 后先回200 OK真正的执行结果通过独立的 INFO 响应Result: OK/ERROR异步回传。这与 GB/T 28181 协议中命令应答与结果通知分离的设计一致。双向 INVITE喊话链路需要两条 SIP 会话——一条对设备收设备的反馈/占用控制一条对上级平台收语音推流。WVP-PRO 在其中充当信令和媒体流的双枢纽。二、接收上级平台喊话命令BroadcastNotifyMessageHandler上级平台下发的 INFO 消息CmdTypeBroadcast由 BroadcastNotifyMessageHandler 处理该类通过afterPropertiesSet()将自身注册到 NOTIFY 消息处理器的Broadcast命令分支下。其handForPlatform()方法完整对应时序图中的 1-4 步关键处理逻辑如下参数校验解析 INFO 消息体中的SN消息序列号与TargetID目标通道国标编号任一缺失直接回400 BAD_REQUESTSourceID可选缺省时取TargetID的值。通道定位与类型校验通过channelService.queryOneWithPlatform(platform.getId(), targetId)在该级联平台共享的通道列表中定位通道若通道不存在回404 NOT_FOUND若通道数据类型不是 GB28181例如共享了 1078 或流媒体通道则回403 FORBIDDEN——源码注释明确只支持国标的语音喊话。200 OK 应答找到设备和通道后立即responseAck(request, Response.OK)对应时序第 2 步。占用检查调用playService.audioBroadcastInUse(device, deviceChannel)检查该设备语音通道是否已被占用若已占用则通过broadcastResultCmd向上级回复Result: ERROR避免并发喊话抢占同一语音通道。回复 Result OK 并触发后续流程commanderForPlatform.broadcastResultCmd(platform, channel, sn, true, ...)在 SIP MESSAGE 发送成功的回调中才调用platformService.broadcastInvite(...)向上级平台发起 INVITE。其中broadcastResultCmd的实现位于 SIPCommanderForPlatform它构造如下 XML 响应体对应时序第 3 步的 回复Result OK?xml version1.0 encodingGBK? Response CmdTypeBroadcast/CmdType SN消息序列号/SN DeviceID目标通道国标编号/DeviceID ResultOK 或 ERROR/Result /Response三、向上级平台发起 INVITE 接收推流SDP 消息体逐行解读platformService.broadcastInvite(...)的核心实现在 PlatformServiceImpl处理流程为复用已有会话先从 Redis 中查询该通道InviteSessionType.BROADCAST类型的旧InviteInfo。若旧流在 ZLMediaKit 中仍然存在isStreamReady为 true直接回调 hook 复用避免重复建流若流已不存在则清理 Redis 中的脏数据。打开收流端口receiveRtpServerService.openGbRTPServerForBroadcast(mediaServerItem, platform, channel, ...)在选中的 ZLMediaKit 节点上分配一个 RTP 收流端口与 SSRC端口打开失败时向上抛端口监听失败错误。写入会话状态构造InviteInfo状态ready写入 Redis供后续事件关联。发送 INVITE调用commanderForPlatform.broadcastInviteCmd(...)收到200 OK后构建SsrcTransaction类型InviteSessionType.BROADCAST放入sessionManager供 BYE 时按 Call-ID 或流标识定位会话。INVITE 的 SDP 消息体由broadcastInviteCmd拼装逐行对应如下这是理解时序第 13-16 步的关键SDP 字段内容示例说明v0-SDP 版本o平台国标编号 0 0 IN IP4 sdpIp发送方为下级平台的国标编号sdpIp取 MediaServer 的 SDP 对外地址sPlayPlay国标约定实时点播/喊话使用Play文档中点播流程第 2 步同样强调 s 字段为 Play 代表实时点播u通道国标编号:0目标用户被喊话通道cIN IP4 sdpIpRTP 接收地址maudio端口 UDP/TCP ... 8 96媒体端口即上一步打开的收流端口载荷 8 为 PCMA(G.711A)、96 为 PS 封装arecvonly-本方向只接收明确下级平台是收流方artpmap:8PCMA/8000G.711A 编码、8kHz 采样率ySSRC国标私用字段指定本流 SSRCfv/2/5/25/1/4096a/1/8/1国标私用媒体参数字段视频编码/分辨率/帧率/码率 音频编码/码率/采样率a/1/8/1表示 G.711、8kHz传输模式broadcastForPlatform配置项SDP 中m行与asetup行由配置项broadcastForPlatform决定该配置定义在 UserSetting默认值为UDP/** * 国标级联语音喊话发流模式 * UDP:udp传输 TCP-ACTIVEtcp主动模式 TCP-PASSIVEtcp被动模式 */ private String broadcastForPlatform UDP;三种模式在 SDP 中的差异见 SIPCommanderForPlatform#broadcastInviteCmdUDP默认maudio port RTP/AVP 8 96无 setup 行TCP-PASSIVEmaudio port TCP/RTP/AVP 8 96asetup:passiveaconnection:new由上级平台主动建立 TCP 连接适合下级平台在 NAT 之后的场景TCP-ACTIVEmaudio port TCP/RTP/AVP 8 96asetup:activeaconnection:new由下级平台主动连接上级。200 OK的后续处理在inviteOKHandler中完成先解析响应 SDP 中的y字段并与本端 SSRC 比对兼容上级未回传 SSRC 及上级自定义 SSRC 的情况若为 TCP-ACTIVE 模式则解析响应 SDP 中的音频端口调用connectRtpServer主动连接上级平台的媒体端口收流超时则回BYE并释放端口、SSRC 与 SSRC 会话streamByeCmdcloseRTPServersessionManager.removeByStream。四、收到上级推流后如何转发到设备时序第 17 步上级平台推送 RTP落到 WVP-PRO 侧后处理链如下ZLMediaKit on_publish 事件ZLM 收到上级推流后回调 WVP-PRO触发PlatformServiceImpl中openGbRTPServerForBroadcast注册的回调——此时先更新InviteInfo状态为okonPublishHandlerForBroadcast再把HookDataapp/stream/MediaServer交给BroadcastNotifyMessageHandler中预设的hookEvent。定位设备侧发送任务BroadcastNotifyMessageHandler用sendRtpServerService.queryByStream(hookData.getStream(), targetId)查找已存在的SendRtpInfo。若存在即设备侧会话已建立直接调用mediaServerService.startSendRtp(...)让 ZLM 把收到的流转发到设备收流端口——对应时序第 18 步。不存在则补发设备 INVITE若SendRtpInfo缺失说明设备侧会话尚未建立或已断开则重新调用playService.audioBroadcastCmd(device, deviceChannel, mediaServer, app, stream, 60, true, ...)以isFromPlatformtrue标记来自上级平台的喊话向设备重发 INVITE 并等待设备200 OK中携带的收流端口。并发占用兜底若此时audioBroadcastInUse返回 true例如本地网页恰好也在喊话同一设备说明设备侧会话已被占用则调用platformService.stopBroadcast(...)向上级回 BYE 并清理资源保证一条语音通道同时只服务一个喊话会话。五、本地喊话与级联喊话的复用关系级联喊话并非独立实现而是完全复用了本地Web/API 发起喊话的底层通道。从源码结构看本地喊话入口是 PlayController 的/api/play/broadcast/{deviceId}/{channelId}GET/POST 均可支持timeout、broadcastMode参数与/api/play/broadcast/stop/{deviceId}/{channelId}内部调用playService.audioBroadcast(...)设备/通道级统一入口由 SourceBroadcastServiceForGbImpl 实现startBroadcast纯广播与startTalk对讲带回流播放地址最终都落到同一个playService.audioBroadcast会话占用状态由 AudioBroadcastManager 基于ConcurrentHashMapchannelId, AudioBroadcastCatch维护exit()判断占用、get()/update()/del()管理生命周期流媒体侧转发由SendRtpInfo任务描述mediaServerService.startSendRtp/startSendRtpPassive按broadcastForPlatform模式选择推流方式。这也解释了为什么级联喊话与本地喊话互斥——两者共享同一个AudioBroadcastManager占用表任何一侧先建立会话另一侧都会被audioBroadcastInUse拦截。六、会话终止与资源回收喊话链路的拆除涉及三条清理动作均集中在 PlatformServiceImpl#stopBroadcastpublic void stopBroadcast(Platform platform, CommonGBChannel channel, String app, String stream, boolean sendBye, MediaServer mediaServerItem) { if (sendBye) { commanderForPlatform.streamByeCmd(platform, channel, app, stream, null, null); } finally { receiveRtpServerService.closeRTPServer(mediaServerItem, app, stream); // 清理 Redis 中的 InviteInfo inviteStreamService.removeInviteInfo(inviteInfo); sessionManager.removeByStream(app, stream); } }即向上级回 BYE释放对端会话→ 关闭 ZLM 收流端口 → 删除 Redis InviteInfo → 移除内存 SSRC 会话。触发时机包括上级平台主动 BYE、收流超时InviteInfo查询不到时自动回 BYE、设备侧异常导致的自动重建失败以及停止喊话 API。此外SIPCommanderForPlatform.streamByeCmd支持按 Call-ID 或app/stream双路定位SsrcTransaction保证即使一侧先收到 BYE 也能正确清理。七、关键要点小结信令顺序不可变INFO(Broadcast) → 200 OK → Result OK 是上级平台的触发链随后才是对设备与对上级平台各自的 INVITE/ACK 会话建立两条 INVITE 会话互相独立但共同支撑同一条 RTP 链路。SDP 三要素sPlay声明实时流类型y指定 SSRCarecvonlymaudio ... 8 96声明只接收 G.711A 语音f字段携带国标媒体参数a/1/8/1对应 G.711/8kHz。传输模式可配broadcastForPlatform支持UDP默认、TCP-PASSIVE、TCP-ACTIVE三种模式分别映射到 SDP 的m行协议与asetup行NAT 环境建议按网络位置选择被动或主动模式。单通道单会话AudioBroadcastManager保证一个设备语音通道同一时刻只有一个喊话会话级联喊话与本地喊话互相抢占检查。全链路资源回收BYE、收流超时、失败回调三条路径都会执行关端口 清 Redis 删 SSRC 会话的完整清理避免 ZLM 端口与 Redis 状态泄漏。如需进一步了解本地非级联语音对讲的媒体流转可参考 语音对讲原理图其中描述了 ZLMediaKit on_publish 回调驱动 WVP-PRO 向设备发 INVITE 的通用链路与本文级联场景共享同一套底层转发机制。【免费下载链接】wvp-GB28181-pro基于GB28181-2016、部标808、部标1078标准实现的开箱即用的网络视频平台。自带管理页面支持NAT穿透支持海康、大华、宇视等品牌的IPC、NVR接入。支持国标级联支持将普通摄像机/直播流/直播推流转国标共享到国标平台。项目地址: https://gitcode.com/GitHub_Trending/wv/wvp-GB28181-pro创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进