运行流程
本文定位
本文以一条主线串起国标监控的完整运行过程——从平台与设备配置、设备注册接入,到应用端调用后端接口与媒体出图,再到部署要点、事件机制与调试排查。SIP 报文格式见 通信协议,领域模型见 核心概念,业务场景见 交互场景。
一、运行流程总览
二、设备端接入(GB28181 IPC / NVR)
国标监控是协议接入,设备端通常无需开发,只在 web 管理界面填写 SIP 参数即可。
1. 平台准备(运维操作)
通过平台管理后台或运维直连数据库,为目标租户创建一条 SIP 平台配置:
| 字段 | 含义 |
|---|---|
server_id | 平台 SIP 服务器 ID(国标 20 位编码) |
domain | SIP 域(国标 10 位编码) |
password | 设备 Digest 鉴权默认密码 |
signal_node_id | (可选)绑定的信令节点编码;多实例分片部署时指定设备归属节点,单实例留空即用本实例信令地址 |
2. 设备配置(以海康 IPC 为例)
| 字段 | 填写值 |
|---|---|
| SIP 服务器 ID | 与平台 server_id 一致 |
| SIP 服务器域 | 与平台 domain 一致 |
| SIP 服务器地址 | 平台所绑信令节点的对外信令地址(在【国标平台】页只读查看) |
| SIP 服务器端口 | 5060 |
| SIP 用户名 | 设备国标编号(20 位) |
| SIP 用户认证 ID | 同上 |
| 密码 | 与平台 password 一致 |
| 注册有效期 | 3600(秒) |
| 心跳周期 | 60(秒) |
| 心跳超时次数 | 3 |
大华 / 宇视 / 华为 / 天地伟业等设备的字段名略有差异,但参数语义一致。配置完成保存重启,设备会自动 REGISTER。
3. 验证接入成功
接入成功后:
- 平台日志会出现「国标设备注册成功」信息(含 deviceId / tenantId / ip / port / transport / expires)
- 设备表
online_status变为ONLINE,register_time与keepalive_time持续更新
接入失败常见原因:
- 设备 SIP 参数与平台配置不匹配
- 设备 IP 无法连通平台 5060 端口(防火墙 / NAT)
- 密码错误(查后端 401 日志)
三、应用端接入(后端接口)
国标监控模块对外提供完整 REST 接口,统一前缀 /blade-iot/vms/。
后端接口一览
| 资源 | 路径 | 主要端点 |
|---|---|---|
| 平台 | /platform | submit / detail / list / sip-info(只读回填 SIP 监听信息) |
| 媒体节点 | /media-node | save / remove / detail / list(租户级 ZLM 节点 + 自动负载) |
| 设备 | /device | save(手动注册)/ detail / list / sync-catalog / remove / query-info / query-status / query-config / query-result / sync-time / reboot / record-start / record-stop / subscribe / unsubscribe |
| 通道 | /channel | detail / list / list-by-device / page-by-group / search / by-channel-id / reset-civil-code / reset-parent-id / ptz-type(人工覆盖云台类型) |
| 流会话 | /stream | start(+streamType) / stop / detail / list |
| 回放 | /playback | records/query / records/result / start / control(PLAY/PAUSE/SCALE/SEEK) |
| 云台 | /ptz | control / stop / preset(call/set/remove) / fi / cruise / scan / auxiliary / home-position / drag-zoom |
| 抓图 | /snapshot | snapshot / detail / list / url(返回 OSS 外链 JSON,前端优先)/ file(302 重定向 OSS) |
| 录像 | /record | download / download/list / download/url(外链 JSON,前端优先)/ download/file(302)/ manual/start / manual/stop(手动录像)/ plan/save / plan/update / plan/submit / plan/remove / plan/list / archive/list / archive/url(外链 JSON,前端优先)/ archive/file(302)/ archive/remove |
| 分组 | /group | save / update / submit / remove / tree / assign / unassign(按分组查通道走 /channel/page-by-group) |
| 预置位 | /preset | query / list |
| 级联 | /cascade | save / remove / detail / list / register / unregister |
| 视频墙看板 | /live | save / list / remove(分屏布局 JSON 按用户私有存取) |
| 报警(设备日志) | /alarm | list(按设备 / 告警方式 / 级别 / 时间段分页) |
| 设备地图 | /device/map | location / update-location / reset-location / find-within-radius / find-within-name / sync-geo / clear-geo / count-geo-devices |
| 流媒体 Webhook | /webhook | on_publish / on_stream_changed / on_stream_none_reader / on_server_keepalive(节点心跳)(流媒体回调,启动期强制 hook-secret) |
| 信令节点 | /signal-node | detail / list / binding-options(平台绑定下拉) / rename / enable / disable / remove / owned-devices(均超级管理员) |
1. 启动实时点播
POST /blade-iot/vms/stream/start?channelId=34020000001320000003&streamType=mainchannelId(必填)与 streamType(选填,默认 main)均为 query 参数,不接收 JSON 请求体。
响应:
{
"code": 200,
"data": {
"sessionId": "5e7b2c8a-...",
"ssrc": "0345670001",
"sessionStatus": "WAITING"
}
}前端轮询 GET /stream/detail?sessionId=...,sessionStatus=RUNNING 后取播放地址(wsFlvUrl / flvUrl / m3u8Url / rtmpUrl / rtcUrl)播放;rtcUrl 为 WebRTC(浏览器需 https 或 localhost 安全上下文),WS-FLV 走 Jessibuca / flv.js。
2. PTZ 控制
POST /blade-iot/vms/ptz/control?channelId=34020...&action=RIGHT&speed=100支持 11 种动作:8 方向(UP / DOWN / LEFT / RIGHT + 对角 UP_LEFT / UP_RIGHT / DOWN_LEFT / DOWN_RIGHT)+ ZOOM_IN / ZOOM_OUT,外加 STOP,速度 0-255(0=停止,默认 100)。
停止:POST /blade-iot/vms/ptz/stop?channelId=...(等效 action=STOP)。 预置位:POST /blade-iot/vms/ptz/preset/call / set(@RequestBody preset 实体) / remove。 扩展云台:/ptz/fi(聚焦/光圈)、/ptz/cruise(巡航)、/ptz/scan(扫描)、/ptz/auxiliary(辅助开关,如雨刷)、/ptz/home-position(看守位)、/ptz/drag-zoom(拉框缩放 / 3D 定位)。
对角(斜向)方向原生支持
对角方向(UP_LEFT 等)在 GB28181-2016 附录 A.3 的 8 字节控制码里同时置位水平 + 垂直方向 bit、水平/垂直速度一并生效。本实现协议层原生支持,前端可直接传 UP_LEFT / DOWN_RIGHT 等,无需拆成两路单方向指令。
3. 异步查询设备(轮询模式)
POST /blade-iot/vms/device/query-info?id=<设备主键>
→ 返回 { "code": 200, "data": 12345 } ← data 即 SN 标量,直接用于后续 query-result
GET /blade-iot/vms/device/query-result?sn=12345
→ pending: { "code": 200, "data": null }
→ ready: { "code": 200, "data": { "manufacturer": "...", "model": "...", ... } }
query-info/query-status/query-config入参均为数据库主键id(服务端据此取国标 deviceId),返回的data即异步任务 SN。
前端典型实现:1s 轮询,最多 30 次(30s 超时)。响应在 vms.query.cache-ttl-ms(默认 60s)内可重复读取,避免轮询窗口期内缓存被踢出。
4. 抓图 + 下载
POST /blade-iot/vms/snapshot/snapshot?channelId=...
→ 返回抓图记录 { id, storageUrl, fileSize }
GET /blade-iot/vms/snapshot/url?id=xxx ← 推荐:返回 { "url": "<OSS 外链>" } JSON
→ 前端拿外链直接作为 <img> src 显示 / window.open 下载
GET /blade-iot/vms/snapshot/file?id=xxx
→ HTTP 302 重定向到 OSS 外链(平台不中转流量)前端优先用 `*/url` 而非 `*/file`
*/file 端点 302 跳转到 OSS。若前端用 XHR / blob 直拉,浏览器会自动跟随 302 并把平台 Authorization 头一并发往第三方 OSS 域(凭证泄漏)。抓图(/snapshot/url)、录像下载(/record/download/url)、录像归档(/record/archive/url)均提供返回 JSON 外链的 */url 端点;前端取得外链后直接用作图片 src 或经 window.open 跳转下载,不对 OSS 域发起带平台凭证的请求。
5. 录像计划
POST /blade-iot/vms/record/plan/save
{
"channelId": "34020...",
"cronExpression": "0 0 0 ? * SAT",
"durationSeconds": 28800,
"retainDays": 30,
"enabled": 1
}平台后台任务 VmsRecordPlanExecutorTask 每 60s 扫描 next_fire_time ≤ now 的计划。命中后阶段 1 同步起实时取流(s=Play,VmsStreamType.RECORD 独占会话,录制当前实时画面而非回放历史录像)→ 等流就绪 → ZLM startRecord;阶段 2 异步由 executor.schedule 在 duration+5s 后回调 → stopRecord → 从 ZLM 拉取 MP4 直传 OSS → 尽力删除 ZLM 端录像文件 → 归档行转 DONE。
6. 开启订阅(增量推送 + GPS)
POST /blade-iot/vms/device/subscribe?id=<设备主键>&type=CATALOG
POST /blade-iot/vms/device/subscribe?id=<设备主键>&type=ALARM
POST /blade-iot/vms/device/subscribe?id=<设备主键>&type=POSITION入参仅 id(设备主键)与 type;POSITION 订阅的上报间隔为服务端常量 60s(DEFAULT_POSITION_INTERVAL_SEC),不可由请求传入。订阅有效期 1h(DEFAULT_EXPIRES_SEC=3600),约在有效期 80%(即创建后约 48min、距过期约 12min)触发续约,优先走 in-dialog SUBSCRIBE refresh(RFC 6665 §4.1.2.1),失败回退为新建订阅。设备 REGISTER 时自动重发该设备所有 ACTIVE 订阅,避免设备视角订阅丢失。
四、关键配置项
完整 yaml 配置(SIP / ZLM·媒体节点 / 抓图 / 录像 / OSS 的全量字段及默认值)统一维护在 配置详解 §一·配置全景;各字段语义按域分述——SIP 见 配置详解 §二,媒体(ZLM / 媒体节点)见 配置详解 §三。本文后续各节(部署、事件、排查)涉及的配置项,均可在该清单中查到。
五、流媒体部署要点
| 项 | 要点 |
|---|---|
| 部署形态 | 单节点或多节点;节点以 iot_vms_media_node 表为准,按租户隔离、按并发自动负载(详见「配置详解」) |
| 节点编码绑定 | 每个 ZLM 的 general.mediaServerId 必须等于其在媒体节点表中的「节点编码」node-id,否则心跳与会话回查命中不到节点 |
| 与平台关系 | 流媒体独立进程,平台通过 REST API + Hook 双向通信 |
| RTP 收流端口 | 由媒体节点 rtp_port 决定单端口 / 多端口收流,直接影响 Docker 放行:单端口仅放行该固定端口(须与 ZLM [rtp_proxy] port 一致),多端口放行整个 RTP 端口段。机制详见 配置详解 §3.5 |
| Hook 配置 | 流媒体配置文件配置四个回调 on_publish / on_stream_changed / on_stream_none_reader / on_server_keepalive,均指向 http://平台地址/blade-iot/vms/webhook/<hook 名>?secret=<hook-secret> |
| Hook 安全 | 必须设置 hook-secret,平台启动期 fail-fast 校验非空;可选 allowed-hook-ips CSV 进一步限制源 IP |
| 录像存储 | 录像去本地化:ZLM 录到自身磁盘 mp4_save_path(须在其 downloadRoot 之下),平台经 HTTP 拉流直传 OSS,无需 ZLM 与平台共享卷 |
| NAT / 防火墙 | 单端口模式放行 rtp_port 一个端口、多端口模式放行整个 RTP 端口段;public-host 是浏览器拉流域名 |
六、事件总线(进程内 Spring 事件)
告警与设备状态走进程内 Spring 事件,不依赖 Kafka 等外部消息队列。告警在协议层 AlarmMessageHandler 完成 XML 解析与 60s 去重后,交由 VmsAlarmUplinkAdapter:一边经 VmsBatchInserter 异步批量入库自有报警表 iot_vms_alarm,一边立即由 ApplicationEventPublisher 发布 VmsAlarmReceivedEvent(事件转发用内存报文、与本地入库刻意解耦);设备上下线发布 DeviceOnlineEvent / DeviceOfflineEvent。下游(级联上行转发、WebSocket 大屏推送等)用 @EventListener 在同进程消费。
| 事件 | 触发 | 典型消费者 |
|---|---|---|
VmsAlarmReceivedEvent | 告警去重通过即发布(与异步批量入库 iot_vms_alarm 解耦) | 级联上行转发、WebSocket 大屏推送 |
DeviceOnlineEvent | 设备注册 / 心跳判定上线 | 在线状态联动、大屏推送 |
DeviceOfflineEvent | 心跳超时 / 注销判定下线 | 离线状态联动、大屏推送 |
告警事件 pushData 示例:
{
"deviceId": "34020000001320000003",
"channelId": "34020000001320000003",
"alarmTime": "2026-05-26T10:00:00",
"alarmMethod": "5",
"alarmType": "6",
"eventType": "1",
"priority": 4,
"description": "区域入侵",
"longitude": 116.40739,
"latitude": 39.9042
}七、调试与排查
设备无法注册
| 检查项 | 排查方法 |
|---|---|
| 设备配置匹配 | 设备 web 界面 server-id / domain / port / password 与平台配置对齐 |
| 401 循环 | 检查 password 是否一致 |
| qop=auth 不兼容(级联场景) | 上级 401 携带 qop="auth",平台已支持自动适配;若仍失败抓包看 Authorization 头 |
| 防火墙 | 设备 IP → 平台 5060 UDP/TCP 必须连通 |
点播失败
| 检查项 | 排查方法 |
|---|---|
| INVITE 缺 Subject 头 | 严格按国标的设备会拒绝,检查平台 INVITE 报文是否含 Subject |
| 打开 RTP 端口失败 | 端口耗尽 / 流媒体不可达 |
| 设备 200 OK 后无 RTP | NAT 场景流媒体 public-host 配置错误,设备收到错误地址 |
| Hook 不到达 | 流媒体配置 hook URL 错 / 防火墙拦截 |
| 主子码流走错 | 通道不支持子码流时启动直播应传 main |
Catalog 同步缺通道
| 检查项 | 排查方法 |
|---|---|
| 分批 NOTIFY 丢包 | UDP 弱网常见,批间静默 15s 触发兜底自动完成(回收任务约 10s 一轮);持续丢包改 TCP 传输 |
| 设备 SumNum 不准 | 极个别厂商 bug,兜底按已收 items 完成 |
| 订阅模式 Event 字段未识别 | 平台已支持 ADD / DEL / UPDATE / ON / OFF / VLOST / DEFECT,检查报文是否真有 <Event> 节点 |
MobilePosition 收不到 NOTIFY
| 检查项 | 排查方法 |
|---|---|
| 设备无 GPS 硬件 | 固定摄像头 ≠ 移动单兵 / 车载,无 GPS 永远无响应 |
| Event 头不兼容 | 个别固件不接受默认的 presence,将 vms.gb28181.sip.mobile-position-event 改为 MobilePosition |
| Interval 太长 | 默认 60s 过长,首次订阅后 60s 才有第一条;改小观察 |
| 经纬度被拒 | WGS84 合理性校验拒绝越界坐标,看后端日志 |
CLOSE_PENDING 持续累积
| 检查项 | 排查方法 |
|---|---|
| 流媒体健康 | 流媒体进程是否在跑 / 关流接口是否返回成功 |
| 转 EXPIRED 是否生效 | 累积超 TTL 或单会话失败 5 次会转 EXPIRED |
上传 OSS 失败
| 检查项 | 排查方法 |
|---|---|
| OSS 配置 | endpoint / access-key / secret-key / bucket-name 是否正确 |
| 网络 | 平台是否能访问 OSS endpoint |
| 拉流/上传链路 | 平台能否经 HTTP 从 ZLM 拉取 MP4 并直传 OSS(录像已去本地化,无需 ZLM 与平台共享卷) |
八、约束与限制
| 项 | 限制 | 说明 |
|---|---|---|
| 录像下载 | 单次下载段 ≤ 6h | vms.record.max-range-seconds=21600 |
| 计划录制 | 单段 ≤ 24h | durationSeconds 上限 @Max 86400 |
| 手动录像 | 单次 ≤ 2h | vms.record.manual-max-seconds=7200 |
| 抓图频率 | 推荐 ≤ 1 次/秒/通道 | 高频会导致流媒体性能下降 |
| 字符集 | 默认 GB2312 | 部分上级要求 UTF-8,可改 vms.gb28181.sip.charset |
| 多租户 | 每租户 1 个 SIP 平台 + N 个 ZLM 媒体节点 | SIP 端口全局共享,按 server-id 区分租户;媒体节点按租户隔离 |
| 设备接入 | 自动接入(AUTO) / 手动注册(MANUAL 白名单) | 平台级 register-mode 决定;MANUAL 仅放行已登记设备(需先在【国标设备】登记) |
