API 文档 v0.9.7

GBHub 国标视频平台 REST API 完整手册 · 认证鉴权 · ZLM/SIP 节点 · 流媒体 · 设备与通道 · 截图与云台 · 广播对讲 · 目录级联 · 代理 · 定时任务 · ONVIF · 移动端多用户 · 录像转录 · 通话绑定

← 返回首页

基本说明

GBHub 国标视频平台对外提供一套 REST API,覆盖认证鉴权、设备/通道管理、流媒体启停、截图/云台/广播对讲、目录推送、代理与级联、定时任务、ONVIF 发现、移动端多用户、通话绑定等能力。

基础地址

http://<服务器IP>:3002

请求头

请求头是否必需说明
Authorization是JWT Bearer Token(除登录接口外)
Content-Type写操作必需application/json
X-Internal-Token内部接口必需服务间调用鉴权
X-Node-Token节点上报/api/report-node-status 使用

关键约定

  • JWT 有效期:默认 7 天(JWT_EXPIRE_DAYS)
  • 通配符:统一使用 "*"(不再支持 "all")
  • 时间格式:YYYY-MM-DD HH:MM:SS 或 ISO8601
  • 分页:page/page_size 或 cursor/count

通用错误码

状态码 / code含义典型场景
200成功正常响应
401认证失败缺少或无效 JWT
403权限不足无对应权限
404资源不存在设备/通道/任务不存在
422请求体格式错误字段缺失或类型不符
500服务器内部错误存储/后端异常
code: 0业务成功响应 JSON 中 code 字段
code: -1业务错误响应 msg 中含具体原因

1. 认证与 Token 管理

所有管理 API(除登录接口外)均需在请求头中携带 JWT:Authorization: Bearer <token>。默认初始化超级管理员 root,密码由 ADMIN_INIT_PASSWORD 指定(默认 admin123)。

1.1 管理员登录

POST/api/admin/login管理员登录获取 JWT
参数类型必填说明
username*String是用户名
password*String是密码
curl -X POST http://127.0.0.1:3002/api/admin/login \
  -H "Content-Type: application/json" \
  -d '{"username":"root","password":"admin123"}'

响应示例

{"code":0,"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}

1.2 全局播放 / 推流 Token

全局 Token 由环境变量 PLAY_TOKEN / PUBLISH_TOKEN 控制,用于 ZLM 播放/推流鉴权,与管理 JWT 无关。

1.3 修改登录密码

POST/api/change-pwd修改管理员密码
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/change-pwd \
  -H "Content-Type: application/json" \
  -d '{"new_password":"new_password"}'

1.4 流专属 Token 管理

POST/api/stream-token设置/更新流 Token
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/stream-token \
  -H "Content-Type: application/json" \
  -d '{"app":"live","stream":"test","type":"play","token":"my_token","expire_seconds":3600}'
GET/api/stream-token?app=live&stream=test&type=play查询流 Token
DELETE/api/stream-token删除流 Token
GET/api/stream-tokens列出全部流 Token

2. ZLM 节点管理与 SIP 绑定

一个平台可挂载多台 ZLM 节点,每台 ZLM 的 hook 必须指向"管它设备的 SIP"。本节覆盖 ZLM 节点的增删改查、轮询、状态上报,以及 ZLM ↔ SIP 绑定。

2.1 获取节点列表

GET/api/zlm-servers列出全部 ZLM 节点
curl -H "Authorization: Bearer <token>" http://127.0.0.1:3002/api/zlm-servers

2.2 获取单个节点详情

GET/api/zlm-servers/{id}获取节点详情

2.3 更新节点

PUT/api/zlm-servers/{id}更新节点配置
字段类型说明
nameString节点名称
api_baseStringZLM API 地址
secretStringZLM API 密钥
http_fmp4_baseStringHTTP-FLV / fMP4 基地址
static_baseString静态资源基地址
record_virtual_pathString录像虚拟路径
media_ipString媒体 IP
curl -H "Authorization: Bearer <token>" -X PUT http://127.0.0.1:3002/api/zlm-servers/my-node-01 \
  -H "Content-Type: application/json" \
  -d '{"api_base":"http://new-api:9080","secret":"new-secret","http_fmp4_base":"http://192.168.28.252:9080/","static_base":"http://192.168.28.252:9080/","media_ip":"192.168.28.252"}'

2.4 删除节点

DELETE/api/zlm-servers删除节点
curl -H "Authorization: Bearer <token>" -X DELETE http://127.0.0.1:3002/api/zlm-servers \
  -H "Content-Type: application/json" -d '{"id":"my-node-01"}'

2.5 轮询获取在线节点

GET/api/zlm/round-robin轮询返回在线节点

2.6 节点状态上报

POST/api/report-node-statusZLM 定期上报状态
💡
鉴权请求头:X-Node-Token(对应环境变量 NODE_REPORT_TOKEN)。首次上报会创建节点并异步设置所有 hook。

2.7 绑定 SIP 节点

POST/api/zlm-servers/{id}/bind-sip绑定到指定 SIP
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/zlm-servers/my-node-01/bind-sip \
  -H "Content-Type: application/json" -d '{"sip_node_id":"sip-01"}'

2.8 解绑 SIP 节点

POST/api/zlm-servers/{id}/unbind-sip解绑 SIP

3. 流媒体列表

GET/api/zlm-media-list?node_id=my-node-01列出 ZLM 上所有流
curl -H "Authorization: Bearer <token>" \
  "http://127.0.0.1:3002/api/zlm-media-list?node_id=my-node-01"

4. 实时播放

4.1 开启直播

POST/api/start-live向设备请求直播
参数类型必填说明
device_id*String是设备 ID
channel_idString否通道 ID,不传则取设备第一个通道
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/start-live \
  -H "Content-Type: application/json" \
  -d '{"device_id":"34020000001320000001","channel_id":"34020000001310000001"}'

4.2 停止直播

POST/api/stop-live停止直播
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/stop-live \
  -H "Content-Type: application/json" \
  -d '{"stream":"34020000001320000001_34020000001310000001"}'

5. 录像回放

POST/api/start-playback发起设备录像回放
参数类型必填说明
device_id*String是设备 ID
channel_idString否通道 ID
start_time*String是开始时间
end_time*String是结束时间
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/start-playback \
  -H "Content-Type: application/json" \
  -d '{"device_id":"34020000001320000001","channel_id":"34020000001310000001","start_time":"2026-06-01T10:00:00","end_time":"2026-06-01T11:00:00"}'

6. 云端录像管理

6.1 查询云端录像

POST/api/records查询 ZLM 录像记录
💡
返回的录像记录包含 node_id 字段,记录该录像文件所在的 ZLM 节点 ID。
参数类型必填说明
channel_idString否通道 ID,不传则查全部通道
appString否应用名,默认 rtp
start*String是开始时间(支持多种格式)
end*String是结束时间
pageInteger否页码,默认 1
page_sizeInteger否每页数量,默认 20
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/records \
  -H "Content-Type: application/json" \
  -d '{"channel_id":"34020000001310000001","app":"rtp","start":"2026-06-01 00:00:00","end":"2026-06-04 00:00:00","page":1,"page_size":10}'

响应示例

{
  "code": 0,
  "data": {
    "records": [
      {
        "channel_id": "34020000001310000001",
        "app": "rtp",
        "start_time": "2026-07-21 09:02:06",
        "end_time": "2026-07-21 09:02:30",
        "file_path": "/etc/m/www/record/rtp/.../2026-07-21-17-02-06-0.mp4",
        "file_size": 3615230,
        "play_url": "http://192.168.28.252:9080/record/rtp/.../2026-07-21-17-02-06-0.mp4",
        "node_id": "1",
        "s3_url": null
      }
    ],
    "total": 290,
    "page": 1,
    "page_size": 10
  }
}

6.2 删除云端录像 DEPRECATED

DELETE/api/records按条目删除录像
⚠️
此接口已废弃:删除录像文件请使用定时清理任务(cleanup_media),它会自动清理本地文件、数据库记录和 Redis S3 缓存,保证数据一致性。

仅删除数据库元数据,不影响本地文件。

curl -H "Authorization: Bearer <token>" -X DELETE http://127.0.0.1:3002/api/records \
  -H "Content-Type: application/json" \
  -d '{"items":[{"channel_id":"34020000001310000001","app":"rtp","start_time":"2026-06-03T06:47:16","file_path":"/etc/.../xx.mp4"}]}'

7. 告警管理

7.1 查询告警记录

GET/api/alarms按条件查询告警
curl -H "Authorization: Bearer <token>" \
  "http://127.0.0.1:3002/api/alarms?device_id=34020000001320000001&start_time=2026-06-06%2000:00:00&end_time=2026-06-07%2000:00:00"

7.2 删除告警记录

DELETE/api/alarms按条目删除告警
curl -H "Authorization: Bearer <token>" -X DELETE http://127.0.0.1:3002/api/alarms \
  -H "Content-Type: application/json" \
  -d '{"items":[{"device_id":"34020000001320000001","channel_id":"34020000001310000001","alarm_time":"2026-06-06T12:30:00"}]}'

8. 设备管理

8.1 获取所有设备列表

GET/api/devices列出全部设备(不分页)

8.1.1 添加设备

POST/api/devices添加国标设备

在平台中注册一个新设备(NVR 或摄像头)。设备信息存储在 Redis 中,初始状态为离线(ip 和 port 为空),待设备主动注册或平台发起连接后更新。

参数类型必填说明
device_id*String是20 位国标设备编码(唯一)
passwordString否设备注册密码(不填则使用全局配置)
nameString否设备自定义名称(便于识别)
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/devices \
  -H "Content-Type: application/json" \
  -d '{"device_id":"34020000001320000001","password":"123456","name":"NVR-主楼"}'

成功响应

{"code": 0, "msg": "device added successfully"}

错误响应

HTTP响应内容说明
400{"code":-1,"msg":"device_id required"}缺少设备 ID
409{"code":-1,"msg":"device already exists"}设备 ID 已存在
500{"code":-1,"msg":"internal error"}Redis 操作失败
💡
默认行为:新添加的设备会自动设置 version=2016,传输协议为 tcp(推荐),同时创建空通道列表 device:{id}:channels = [],并加入全局集合 all_devices。设备上线后,ip 和 port 字段会被自动更新。

8.2 分页获取设备列表

GET/api/devices-paginated?cursor=0&count=200分页查询
参数类型必填说明
cursorInteger否游标,首次传 0,后续使用上一次返回的 next_cursor
countInteger否每页条数,默认 200

8.3 搜索设备

GET/api/devices/search?keyword=xxx按关键字搜索

智能判断:全数字按 ID 前缀匹配,否则按名称模糊匹配。

curl -H "Authorization: Bearer <token>" \
  "http://127.0.0.1:3002/api/devices/search?keyword=340200000013"

8.4 获取设备通道列表(分页)

GET/api/device-channels?device_id=xxx&cursor=0&count=100通道分页列表

8.5 获取设备详细信息

GET/api/device-info?device_id=xxx设备详情

8.6 刷新设备通道

POST/api/refresh-device-channels主动向设备查询通道
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/refresh-device-channels \
  -H "Content-Type: application/json" -d '{"device_id":"34020000001320000001"}'

8.7 修改设备配置

POST/api/device-config修改设备名称/密码/传输协议等
字段类型说明
device_id*String设备 ID(必填)
nameString设备名称
passwordStringSIP 密码。特例:"0" 表示跳过鉴权(调试用),空串表示使用全局密码
transportString媒体传输:udp / tcp。空/缺省时跟随注册上报的 auto_transport(推荐保留空,由设备自动探测)
check_ssrcBoolean是否启用 SSRC 校验,true/false,默认 false
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/device-config \
  -H "Content-Type: application/json" \
  -d '{"device_id":"34020000001320000001","name":"新名称","check_ssrc":"true","password":"新密码","transport":"tcp"}'
💡
媒体传输字段 transport:空/缺省时跟随设备注册上报的 auto_transport;信令传输由设备注册时自动检测,无需手动设置。修改后生效时机:下一次拉起流时生效(ensure_stream_online 缓存会失效 10s 内的旧值)。

8.8 删除设备

DELETE/api/devices删除设备
curl -H "Authorization: Bearer <token>" -X DELETE http://127.0.0.1:3002/api/devices \
  -H "Content-Type: application/json" -d '{"device_id":"34020000001320000001"}'

8.9 查询设备状态历史

GET/api/device-status-history?device_id=xxx&page=1&page_size=20设备上下线历史
参数类型必填说明
device_id*String是设备 ID
pageInteger否页码,默认 1
page_sizeInteger否每页条数,默认 20,最大 200
💡
数据仅记录状态变化(ON→OFF / OFF→ON),不会产生连续重复状态。若设备从未被同步任务记录过,items 为空。

8.10 搜索设备通道

GET/api/device-channels/search?device_id=xxx&keyword=yyy在设备通道中搜索

8.11 设备音频封装模式

设置设备在语音广播 / 双向对讲时使用的音频封装格式。ps 为默认(PT=96 + PS/90000),pcm 为 PCMA 裸流(PT=8 + PCMA/8000)。修改后下次发起广播/对讲时生效。

8.11.1 查询单通道当前配置

GET/api/device/audio-ps?device_id=...&channel_id=...查询音频封装
curl -H "Authorization: Bearer <token>" \
  "http://127.0.0.1:3002/api/device/audio-ps?device_id=34020000001320000001&channel_id=34020000001310000001"

8.11.2 设置音频封装模式

POST/api/device/audio-ps设置 ps / pcm
# PS 封装(默认,兼容性最好)
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/device/audio-ps \
  -H "Content-Type: application/json" \
  -d '{"device_id":"34020000001320000001","channel_id":"34020000001310000001","mode":"ps"}'

# PCMA 裸流(部分设备要求)
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/device/audio-ps \
  -H "Content-Type: application/json" \
  -d '{"device_id":"34020000001320000001","channel_id":"34020000001310000001","mode":"pcm"}'

8.11.3 重置为默认(PS)

DELETE/api/device/audio-ps删除配置回落到默认

9. 通道配置

9.1 查询单个通道配置

GET/api/channel-config?device_id=...&channel_id=...查询通道配置

9.2 修改单个通道配置

POST/api/channel-config修改通道配置
字段类型说明
device_id*String设备 ID
channel_id*String通道 ID
substreamBoolean是否使用子码流,默认 false(主码流)
zlm_nodeString绑定的 ZLM 节点 ID(覆盖默认节点选择)
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/channel-config \
  -H "Content-Type: application/json" \
  -d '{"device_id":"34020000001320000001","channel_id":"34020000001310000001","substream":"true"}'
💡
修改 substream 或 zlm_node 后,正在进行的流不会自动切换,需要 stop-live 后重新 start-live 才生效。

9.3 批量修改通道配置

POST/api/channel-configs/batch批量修改
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/channel-configs/batch \
  -H "Content-Type: application/json" \
  -d '{"channels":[{"device_id":"...","channel_id":"...","zlm_node":"node1"}]}'

10. 通道绑定与全局索引

10.1 获取绑定列表

GET/api/channels列出全部通道绑定

10.2 绑定通道(单条)

POST/api/channels添加通道绑定
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/channels \
  -H "Content-Type: application/json" -d '{"id":"34020000001310000001","stream":"test","app":"live"}'

10.3 删除绑定

DELETE/api/channels删除单条绑定

10.4 批量解绑

DELETE/api/channels/batch批量解除绑定

10.5 清空所有绑定

DELETE/api/channels/clear清空全部绑定

10.6 批量绑定

POST/api/channels/batch-bind支持全部设备 / 指定设备 / 显式列表
# 全部设备
curl -X POST "http://127.0.0.1:3002/api/channels/batch-bind" \
  -H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
  -d '{"device_id":"*","app":"rtp"}'

# 指定设备全部通道
curl -X POST "http://127.0.0.1:3002/api/channels/batch-bind" \
  -H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
  -d '{"device_id":"34020000001320000001","app":"rtp"}'

10.7 获取全部设备通道

GET/api/all-channels所有设备的通道

10.8 分页获取全部设备通道

GET/api/all-channels-paginated?cursor=0&count=200通道分页

10.9 通道自定义名称管理

POST/api/channel-name设置通道名称
DELETE/api/channel-name删除通道名称
GET/api/channel-names?device_id=...查询通道名称

10.10 手动刷新全局通道索引

POST/api/all-channels/rebuild-index重建索引
⚠️
全局通道索引不会自动维护。设备增删后需手动调一次。

11. 截图管理

11.1 请求设备截图(国标)

POST/api/snapshot向设备请求截图
参数类型必填说明
device_id*String是设备 ID
channel_idString否通道 ID;不传则取设备第一个通道
💡
两种流程(按设备的 version 字段自动选):
version=2022:后端发 CaptureCmd 让设备直接上传到 S3 或本地;返回后立即 ready 或 pending。
version=2016:后端发 Snapshot 查询,设备回 Base64 图片,后端保存到本地并返回 URL。
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/snapshot \
  -H "Content-Type: application/json" \
  -d '{"device_id":"34020000001320000001","channel_id":"34020000001310000001"}'

11.2 ZLM 截图

POST/api/zlm-snap从 ZLM 流截取画面
参数类型必填说明
device_idString条件与 app+stream 二选一
channel_idString条件—
appString条件代理应用名
streamString条件代理流 ID
zlm_nodeString否强制指定 ZLM 节点
countInteger否连拍次数,默认 1
asyncBoolean否走 ZLM 内部快速解码,默认 true

11.3 查询最新截图

GET/api/snapshot-query?device_id=...&channel_id=...查询该通道最新一张截图状态
参数类型必填说明
device_id*String是设备 ID
channel_id*String是通道 ID

响应示例

{
  "code": 0,
  "data": {
    "type": "file",
    "url": "/snapshots/dev/xxx/20260601/143015_12345.jpg",
    "sn": "12345",
    "status": "ready",
    "time": 1780300800
  }
}
status含义
pending抓拍命令已发出,等待设备上传(前端应轮询直到 ready)
ready已落盘/已上传 S3,URL 有效
none 或 data 缺失该通道从未截图

11.4 截图历史列表

GET/api/snapshot-list?device_id=...&channel_id=...&cursor=0&count=50分页查询截图历史
参数类型必填说明
device_id*String是设备 ID
channel_id*String是通道 ID
cursorInteger否游标(首次 0),默认 0
countInteger否每页数量,默认 50,最大 200

响应示例

{
  "code": 0,
  "data": {
    "items": [
      {
        "url": "/snapshots/dev/xxx/20260601/143015_12345.jpg",
        "date": "2026-06-01 14:30:15"
      }
    ],
    "next_cursor": 50,
    "total": 128
  }
}

11.5 删除截图

POST/api/snapshot-delete按 URL 删除单张截图
参数类型必填说明
url*String是截图 URL(相对或绝对均可,S3 URL 也支持)
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/snapshot-delete \
  -H "Content-Type: application/json" \
  -d '{"url":"/snapshots/dev/xxx/20260601/143015_12345.jpg"}'
⚠️
只删除文件本体,不会从 Redis 索引 snapshot_index:{device_id}:{channel_id} 移除条目(清理任务会兜底)。

11.6 批量截图

POST/api/batch-snap全量并发截图

12. 云台控制

通过 POST /api/ptz 接口向设备发送云台控制指令。指令以十六进制字符串形式传递,支持持续按住和单次操作两种模式。

POST/api/ptz发送云台控制指令
参数类型必填说明
device_id*String是设备 ID
channel_idString否通道 ID,不填则使用设备 ID
ptz_cmd*String是云台控制码(十六进制字符串),见下表
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/ptz \
  -H "Content-Type: application/json" \
  -d '{"device_id":"34020000001320000001","channel_id":"34020000001310000001","ptz_cmd":"A50F01084C4C4095"}'

响应示例

{"code": 0}

云台控制码

类型操作Cmd 字符串
方向控制(持续按住时触发)上A50F01084C4C4095
下A50F01044C4C4091
左A50F01024C4C408F
右A50F01014F4F4094
单次操作(点击触发)放大A50F01424C000043
缩小A50F01444C004445
停止A50F0100000000B5
⚠️
注意:方向控制指令通常由前端在用户按住按钮时循环发送,松开时发送停止指令;单次操作(如变倍)只需发送一次即可。发送频率建议不低于 200ms 间隔,避免设备处理不过来。

13. 预置位管理

GET/api/presets?device_id=...&channel_id=...查询预置位
POST/api/presets/query主动向设备查询预置位

14. 语音广播与对讲 v0.9.7

💡
前置条件:设备已注册、所属 SIP 节点在线、ZLM 节点已与该 SIP 绑定。
音源编码:PCMA / G.711 A-law / 8000 Hz / 单声道(payload type 8)。
音源流:stream 参数必须是 ZLM 上已存在的流(app=rtp)。
模式配置:BROADCAST_MODE = auto(默认)/ client / server。
并发控制:同一通道同时只允许一个用户,通过 broadcast_owner:{device_id}:{channel_id} Redis 锁控制,锁 TTL 90s,前端每 30s 心跳续期。

14.1 单向语音广播(喊话)

POST/api/audio-broadcast服务器向设备推流
参数类型必填说明
device_id*String是设备 ID(20 位)
channel_id*String是通道 ID(20 位)
stream*String是ZLM 上已存在的音源流(app=rtp)
owner*String是前端生成的客户端唯一标识(UUID),用于独占锁 + 心跳续期。建议使用 crypto.randomUUID(),localStorage 持久化
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/audio-broadcast \
  -H "Content-Type: application/json" \
  -d '{"device_id":"34020000001320000001","channel_id":"34020000001310000001","stream":"talk_src_xxx","owner":"61cf1137-3e14-4eee-82ec-3a82c3a61d2d"}'

成功响应

{
  "code": 0,
  "stream_id": "talk_34020000001320000001_34020000001310000001",
  "transport": "udp",
  "status": "ready",
  "answer_port": null,
  "mode": "client"
}
字段类型说明
stream_idString会话 ID,格式 talk_{device_id}_{channel_id},停止/心跳必须携带
transportStringtcp / udp,实际媒体传输方式
statusStringready = 已在推流;waiting_device = TCP passive 等待设备主动连接
answer_portInteger | nullTCP passive 监听端口;UDP 或 TCP active 为 null
modeStringclient = 设备主动 INVITE(设备自推流);server = 服务器主动 INVITE

14.1.1 心跳续期

POST/api/audio-broadcast-heartbeat前端每 30s 调用,续期独占锁
⚠️
必须实现心跳!独占锁 broadcast_owner:{device_id}:{channel_id} 的 TTL 是 90s,前端必须每 30s 调一次续期。
不调心跳的后果:90s 后锁过期,其他用户可抢占,自己的会话失效。
收到 423 时:说明锁已被别人抢走,前端应立即停止本地推流和播放。
参数类型必填说明
device_id*String是设备 ID
channel_id*String是通道 ID
owner*String是必须与启动时相同
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/audio-broadcast-heartbeat \
  -H "Content-Type: application/json" \
  -d '{"device_id":"34020000001320000001","channel_id":"34020000001310000001","owner":"61cf1137-3e14-4eee-82ec-3a82c3a61d2d"}'
code说明
0续期成功(锁是自己的或首次写入)
423锁已被其他用户抢(自己的锁已过期,别人抢到了)
-1参数缺失 / Redis 异常
# 成功
{"code":0}

# 锁被抢
{"code":423,"msg":"该通道已被其他用户占用","owner":"<current_owner>"}

14.1.2 停止广播

POST/api/audio-broadcast-stop停止广播 + 释放独占锁
参数类型必填说明
stream_id*String是启动时返回的 stream_id
device_id*String是设备 ID
channel_id*String是通道 ID
owner*String是必须与启动时相同,否则返回 423 拒绝释放
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/audio-broadcast-stop \
  -H "Content-Type: application/json" \
  -d '{"stream_id":"talk_xxx","device_id":"xxx","channel_id":"yyy","owner":"61cf1137-3e14-4eee-82ec-3a82c3a61d2d"}'

14.2 双向语音对讲

POST/api/audio-talk参数同广播,额外返回 recv_stream
参数类型必填说明
device_id*String是设备 ID
channel_id*String是通道 ID
stream*String是ZLM 上已存在的音源流
owner*String是独占锁 owner(与广播共用同一把锁)
{
  "code": 0,
  "stream_id": "talk_34020000001320000001_34020000001310000001",
  "recv_stream": "talk_recv_34020000001320000001_34020000001310000001",
  "transport": "udp",
  "status": "ready",
  "answer_port": 45012,
  "mode": "server"
}
💡
recv_stream 字段:仅当设备支持双向(SDP 含 a=sendrecv)时返回,前端应播放 recv_stream 以听到设备回传音频。
如果不支持双向:recv_stream 为空字符串,前端可以退化为播放设备原流(play_url)。

14.2.1 停止对讲

POST/api/audio-talk-stop参数同 audio-broadcast-stop

14.3 常见错误

code / HTTP响应 msg原因 / 解决
423该通道正在被其他用户使用独占锁冲突:别的用户正在广播/对讲。前端应提示并停止
-1device INVITE failed: src_stream 'xxx' not online in ZLM after 8s前端推流未成功(ZLM 上无此流)。检查 startPush 是否成功、麦克风权限、ZLM WebRTC 服务
-1startSendRtp failed: ... connection refused设备 SDP 是 TCP + a=setup:active,服务器无法主动连。改走 UDP 媒体
-1startSendRtp failed: can not find the source streamstream 不在 ZLM 上。先推流再调 API
-1client-only mode: device did not send INVITE设备未在 5s 内主动 INVITE。改用 BROADCAST_MODE=auto 或 server
-1device INVITE failed: ...(reason: zlm_start_send_rtp_failed)ZLM startSendRtp 失败。检查 ZLM 日志和 media_ip 配置
-1broadcast race unresolved: client result timeout设备 INVITE 处理超过 12s 仍未返回结果(罕见)。检查 server.rs 日志
-1device not found设备未注册 / 不在本 SIP 节点
-1no online zlm node无在线 ZLM 节点

14.4 前端实现要点

💡
推荐流程(无死锁):
1. startPush(stream) — 先推流(ZLM 上有流)
2. 轮询 ZLM getMediaList — 等流上线(可选,失败不阻塞)
3. POST /api/audio-broadcast — 推流就绪后再调 API
4. 收到 423 → 前端 stopPush 回滚
5. 每 30s 调 heartbeat — 续期锁
6. 停止 → POST stop + stopPush + close_streams
不推荐(会死锁):先调 API 再推流。因为后端 handle_incoming_invite 会等前端推流上线(8s),前端等 API 返回 → 死锁。

15. 平台信息

GET/api/platform-info获取平台基础信息

16. 目录与业务分组管理

16.1 - 16.3 行政区域名称

POST/api/admin-region-name设置
参数类型必填说明
code*String是行政区划代码
name*String是名称
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/admin-region-name \
  -H "Content-Type: application/json" -d '{"code":"340200","name":"芜湖市"}'
DELETE/api/admin-region-name删除
GET/api/admin-region-names?code=340200查询

16.4 - 16.6 业务分组名称

POST/api/biz-group-name设置
参数类型必填说明
code*String是业务分组编码
name*String是名称
DELETE/api/biz-group-name删除
GET/api/biz-group-names?code=...查询

16.7 - 16.9 通道业务分组

POST/api/channel-biz-group设置
DELETE/api/channel-biz-group删除
GET/api/channel-biz-groups?channel_id=...查询

17. 流代理管理

17.1 拉流代理

GET/api/stream-proxies列出拉流代理
POST/api/stream-proxies添加
参数类型必填说明
vhostString否默认 __defaultVhost__
appString否默认 live
stream*String是流 ID
url*String是拉流地址
on_demandBoolean否是否按需
zlm_nodeString否指定 ZLM 节点
enable_mp4Boolean否是否开启 MP4 录制
auto_closeBoolean否按需拉流无人观看自动关闭
DELETE/api/stream-proxies删除

17.2 推流代理

GET/api/stream-pusher-proxies列出推流代理
POST/api/stream-pusher-proxies添加
DELETE/api/stream-pusher-proxies删除

18. 录制控制

18.1 开始录制

POST/api/start-record开始录制
参数类型必填说明
app*String是应用名
stream*String是流 ID
type*Int是0=HLS, 1=MP4
customized_pathString否保存目录
max_secondInt否切片时长
POST/api/stop-record停止录制
POST/api/is-recording查询录制状态

19. 级联管理

用于管理下级平台与上级平台的级联连接,支持 UDP 和 TCP 两种传输方式。

19.1 获取级联列表

GET/api/servers级联列表
curl -H "Authorization: Bearer <token>" http://127.0.0.1:3002/api/servers

响应示例

{
  "code": 0,
  "data": [
    {
      "id": "182.92.251.233:6060",
      "device_id": "34020000002000000004",
      "realm": "3402000000",
      "sip_server": "182.92.251.233:6060",
      "local_addr": "0.0.0.0:5070",
      "transport": "TCP"
    }
  ]
}

19.2 添加级联服务器

POST/api/servers添加级联服务器

添加一个上级平台级联配置。

参数类型必填说明
device_id*String是下级设备 ID(用于 SIP 认证用户名)
realm*String是SIP 域
password*String是认证密码
sip_server*String是上级服务器地址(IP:端口)
local_addr*String是本地监听地址(IP:端口),TCP 模式下为 TCP 监听端口
transport*String是传输协议:UDP 或 TCP
versionString否GB/T 28181 协议版本,默认 "2022"
server_idString否上级平台 ID,不传时使用 device_id

UDP 模式示例

curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/servers \
  -H "Content-Type: application/json" \
  -d '{
    "device_id": "34020000002000000004",
    "realm": "3402000000",
    "password": "password123",
    "sip_server": "182.92.251.233:6060",
    "local_addr": "0.0.0.0:5070",
    "transport": "UDP",
    "version": "2022"
  }'

TCP 模式示例

curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/servers \
  -H "Content-Type: application/json" \
  -d '{
    "device_id": "34020000002000000004",
    "realm": "3402000000",
    "password": "password123",
    "sip_server": "182.92.251.233:6060",
    "local_addr": "0.0.0.0:5070",
    "transport": "TCP",
    "version": "2022"
  }'

成功响应

{"code": 0, "msg": "server added"}

常见错误

HTTP响应体说明
400{"code":-1,"msg":"invalid tcp_source_addr"}tcp_source_addr 格式错误
500{"code":-1,"msg":"TCP source port must not equal listening port"}源端口与监听端口相同

19.3 删除级联服务器

DELETE/api/servers删除级联服务器
curl -H "Authorization: Bearer <token>" -X DELETE http://127.0.0.1:3002/api/servers \
  -H "Content-Type: application/json" \
  -d '{"id":"182.92.251.233:6060"}'
⚠️
删除时请同时手动清理服务器上对应的 iptables 规则(如果添加了)。

20. 系统备份与恢复

20.1 备份系统配置

POST/api/backup/system导出配置

导出所有代理配置、目录管理数据、通道绑定关系。

curl -H "Authorization: Bearer <token>" -X POST http://localhost:3002/api/backup/system -o backup.json

20.2 恢复系统配置

POST/api/restore/system恢复配置
参数类型说明
clear_beforeBoolean是否清空现有数据再恢复,默认 false
stream_proxiesArray拉流代理数组(可选)
stream_pusher_proxiesArray推流代理数组(可选)
admin_region_namesObject行政区域名称(可选)
biz_group_namesObject业务分组名称(可选)
channel_biz_groupObject通道业务分组绑定(可选)
channel_bindingsObject正向通道绑定(可选)
channel_bindings_revObject反向通道绑定(可选)
channel_namesObject通道自定义名称(可选)
curl -H "Authorization: Bearer <token>" -X POST http://localhost:3002/api/restore/system \
  -H "Content-Type: application/json" -d @backup.json

21. Webhook 回调(sip / zlm-node)

💡
录像完成 hook(on_record_mp4)自 v0.9.1 起改由 zlm-node 处理。
端点监听方用途
/hook/on_record_mp4zlm-node:3004录像完成,上传 S3 并通知 mgr
/hook/healthzlm-node:3004健康检查,返回 ok
/hook/on_stream_changedsip流状态变化
/hook/on_playsip播放鉴权
/hook/on_publishsip推流鉴权
/hook/on_stream_none_readersip无人观看自动关闭
/hook/on_stream_not_foundsip触发自动拉流
/hook/on_rtp_server_timeoutsipRTP 超时清理
/hook/on_server_startedsip恢复流代理

22. 定时任务管理

💡
认证:JWT Bearer Token。内部执行:X-Internal-Token,仅供 scheduler 调用。
调度器扫描间隔:30 秒。通配符:"*"("all" 已废弃)。

22.1 创建定时任务

POST/api/schedule/tasks新建任务
参数类型必填说明
action*String是snapshot / record / cleanup_sessions / sync_device_status / cleanup_media / cleanup_snapshot / cleanup_orphan_devices / cleanup_orphan_nodes / cleanup_transcribe_orphans
cron_expr*String是Cron 表达式(UTC)
device_idString条件"*" 表示全部设备
channel_idString条件"*" 表示该设备全部通道
duration_secsIntegerrecord 必填录制时长
concurrencyInteger否并发数,默认 5
retention_daysInteger否清理任务保留天数,默认 7

22.1.1 常见示例

示例 1:每天凌晨 3 点清理所有 7 天前的录像

curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/schedule/tasks \
  -H "Content-Type: application/json" \
  -d '{"action":"cleanup_media","cron_expr":"0 3 * * *","retention_days":7}'

示例 2:每天凌晨 4 点清理所有 7 天前的截图

curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/schedule/tasks \
  -H "Content-Type: application/json" \
  -d '{"action":"cleanup_snapshot","cron_expr":"0 4 * * *","retention_days":7}'

示例 3:只清理 live 应用下 camera1 流的 7 天前录像

curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/schedule/tasks \
  -H "Content-Type: application/json" \
  -d '{"action":"cleanup_media","cron_expr":"0 3 * * *","retention_days":7,"app":"live","stream":"camera1"}'

示例 4:每周日凌晨 5 点清理残留会话

curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/schedule/tasks \
  -H "Content-Type: application/json" \
  -d '{"action":"cleanup_sessions","cron_expr":"0 5 * * 0"}'

22.2 清理任务行为

动作清理范围建议 Cron
cleanup_media录像文件 + DB + Redis S3 缓存0 3 * * *
cleanup_snapshot截图文件0 4 * * *
cleanup_sessions残留级联会话按需
cleanup_orphan_devices孤儿设备0 0 3 * * 0
cleanup_orphan_nodes孤儿节点0 0 4 1 * *
cleanup_transcribe_orphans孤立转录0 0 5 * * 0

22.2.1 设备状态同步任务

定时扫描所有设备,仅状态变化时写入 device_status_log。支持 callback_url 推送状态变化事件。

  • 环境变量:SYNC_BATCH_SIZE(默认 2000)、SYNC_MAX_ITERATIONS(默认 10)、DEVICE_OFFLINE_TIMEOUT_SECS(默认 180)
  • 自动清理:扫描过程中会自动移除 all_devices 中的无效设备 ID

回调格式(当提供了 callback_url 时):

POST {callback_url}
Content-Type: application/json

{
  "event": "device_status_changed",
  "changes": [
    {
      "device_id": "34020000001320000001",
      "previous_status": "ON",
      "current_status": "OFF",
      "ts": 1722225000
    }
  ]
}

22.2.2 Cron 表达式与时区

⚠️
Cron 使用 UTC。北京时间 = UTC + 8。例如北京凌晨 3:00 = UTC 前一天 19:00,写为 0 19 * * *。

22.3 其它接口

GET/api/schedule/tasks?page=1&page_size=20列出全部任务
GET/api/schedule/tasks/{task_id}查询任务详情
PUT/api/schedule/tasks/{task_id}更新任务
DELETE/api/schedule/tasks/{task_id}删除任务
PATCH/api/schedule/tasks/{task_id}/enable启用/禁用
POST/api/internal/task/exec内部执行接口

23. 截图与辅助 API

POST/api/zlm-snapZLM 截图(详见 11.2)
GET/api/all-channels全部设备通道
POST/api/start-record-task主动录像及事件回调
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/start-record-task \
  -H "Content-Type: application/json" \
  -d '{"app":"live","stream":"test","path":"callback_test.mp4","back_ms":10000,"forward_ms":10000,"callback_url":"http://your-server.com/notify"}'
POST/api/batch-snap批量截图

24. ONVIF 设备发现与代理

所有接口挂 proxy:manage 权限。底层实现委托给 ZLM 节点。建议与待发现设备同网段的 ZLM 节点才能搜到 ONVIF 组播响应。

POST/api/onvif/search搜索 ONVIF 设备
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/onvif/search \
  -H "Content-Type: application/json" \
  -d '{"timeout_ms":5000,"subnet_prefix":"192.168.1.","zlm_node":"my-node-01"}'
POST/api/onvif/stream-url获取 RTSP 流地址
POST/api/onvif/add-proxy一键添加为拉流代理
⚠️
zlm_node 必须显式指定!源码强制校验,不允许为空。

25. 移动端多用户与通道分配

GBHub 支持为移动端 App 创建独立用户,每个用户可被分配 设备通道 或 拉流代理 的播放权限。移动端通过 JWT Bearer Token 认证,管理员通过 JWT 管理用户和权限。

💡
JWT 配置:需在 .env 中设置 JWT_SECRET,默认有效期为 7 天(可通过 JWT_EXPIRE_DAYS 调整)。
权限格式:设备通道使用 <device_id>:<channel_id>,拉流代理使用 proxy:<app>:<stream>。

25.0 可用权限列表

权限标识说明
devices:read查看设备列表、设备详情、通道列表
devices:write添加/删除设备、修改设备配置、通道绑定/解绑、通道名称管理、设备音频封装模式
records:read查询云端录像
records:delete删除云端录像记录
alarms:read查询告警记录
alarms:delete删除告警记录
proxy:manage管理拉流代理、推流代理、FFmpeg 代理、ONVIF 操作
zlm:manage管理 ZLM 节点(增删改查、轮询)
system:config系统配置:备份/恢复、定时任务、修改密码、平台信息
user:manage用户管理:创建/删除用户、修改用户权限、通道批量分配
snapshot请求截图、查询截图缓存
record:control手动控制录制(开始/停止/状态查询)
ptz:control云台控制、预置位
audio:control语音广播与对讲
💡
默认超级管理员 root 拥有以上全部权限。权限变更后即时生效,无需重启服务。

25.1 管理员接口

25.1.1 列出所有用户

GET/api/admin/users列出用户
curl -H "Authorization: Bearer <token>" http://127.0.0.1:3002/api/admin/users
{
  "code": 0,
  "data": ["alice", "bob", "charlie"]
}

25.1.2 创建用户

POST/api/admin/users创建用户
参数类型必填说明
username*String是用户名
password*String是密码(明文,服务端 Bcrypt 加密)
permissionsArray否权限列表,默认空数组
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/admin/users \
  -H "Content-Type: application/json" \
  -d '{"username":"alice","password":"secret123","permissions":["devices:read","records:read"]}'

25.1.3 删除用户

DELETE/api/admin/users/:username删除用户

25.1.4 管理员修改用户密码

PUT/api/admin/users/:username/password修改密码

25.1.5 获取用户权限

GET/api/admin/users/:username/permissions查询权限

25.1.6 更新用户权限(覆盖)

PUT/api/admin/users/:username/permissions设置权限
⚠️
此操作会完全覆盖用户原有权限,请谨慎操作。权限变更后立即生效。

25.1.7 获取用户通道列表

GET/api/admin/users/:username/channels用户已分配通道
{
  "code": 0,
  "data": [
    {
      "type": "device",
      "device_id": "34020000001320000001",
      "channel_id": "34020000001310000003",
      "device_name": "NVR-01",
      "channel_name": "摄像头01"
    },
    {
      "type": "proxy",
      "app": "live",
      "stream": "camera1",
      "name": "大门RTSP"
    }
  ]
}

25.1.8 分配通道权限(设备通道)

POST/api/admin/users/:username/channels分配单通道
参数类型必填说明
channel_id*String是格式 <device_id>:<channel_id>
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/admin/users/alice/channels \
  -H "Content-Type: application/json" \
  -d '{"channel_id":"34020000001320000001:34020000001310000003"}'

25.1.9 移除通道权限(设备通道)

DELETE/api/admin/users/:username/channels移除单通道

25.1.10 清理用户无效通道权限

POST/api/admin/users/:username/channels/clean清理无效通道

自动扫描用户所有权限,移除那些设备已不存在、通道已删除或代理已失效的权限。

25.1.11 分配代理权限

POST/api/admin/users/:username/proxy分配代理

25.1.12 移除代理权限

DELETE/api/admin/users/:username/proxy取消代理

25.1.13 批量分配通道权限

POST/api/admin/users/:username/channels/batchmode: add / remove / replace
⚠️
replace 谨慎使用:会清空用户原有全部通道权限。

25.1.14 列出代理通道 ID

GET/api/admin/proxies/ids代理通道 ID 列表

25.2 移动端接口

25.2.1 登录

POST/api/mobile/login移动端登录
参数类型必填说明
username*String是用户名
password*String是密码
curl -X POST http://127.0.0.1:3002/api/mobile/login \
  -H "Content-Type: application/json" \
  -d '{"username":"alice","password":"secret123"}'
{
  "code": 0,
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

25.2.2 获取当前用户的通道列表

GET/api/mobile/channels用户可见通道

返回当前登录用户被授权的所有通道(包含设备通道和代理),同时附带播放地址、截图 URL 及是否有缓存截图。

{
  "code": 0,
  "data": [
    {
      "type": "device",
      "device_id": "34020000001320000001",
      "channel_id": "34020000001310000003",
      "device_name": "NVR-01",
      "channel_name": "摄像头01",
      "play_url": "http://192.168.28.252:9080/rtp/34020000001320000001_34020000001310000003.live.mp4",
      "snapshot_url": "http://static.example.com/snapshots/...",
      "has_snapshot": true
    },
    {
      "type": "proxy",
      "app": "live",
      "stream": "camera1",
      "name": "大门RTSP",
      "play_url": "http://192.168.28.252:9080/live/camera1.live.mp4",
      "snapshot_url": "/api/mobile/snapshot?id=proxy:live:camera1",
      "has_snapshot": false
    }
  ]
}

25.2.3 获取通道播放地址(自动截图)

GET/api/mobile/play/:channel_id获取播放地址

返回指定通道的播放地址,并在后台异步触发截图(仅对国标设备有效,代理不会自动截图)。

路径参数类型说明
channel_id*String格式 <device_id>:<channel_id> 或 proxy:<app>:<stream>
💡
自动截图行为:仅对国标设备有效。服务端会在返回播放地址后,延迟 2 秒尝试请求设备截图,并将结果永久缓存(Redis key snapshot:latest:<device_id>:<channel_id>)。若已有缓存或正在截图,则不会重复执行。

25.2.4 移动端修改密码

PUT/api/mobile/change-pwd修改密码

25.2.5 移动端截图

GET/api/mobile/snapshot主动截图

主动请求通道截图,支持国标设备和拉流代理。对于代理,若流不在线则会尝试按需拉流,等待流上线后再截图。

查询参数类型必填说明
idString条件必填代理标识,格式 proxy:<app>:<stream>(与 device_id+channel_id 二选一)
device_idString条件必填国标设备 ID
channel_idString条件必填国标通道 ID
⚠️
权限校验:无论何种方式,均会校验当前用户是否拥有该通道/代理的权限,否则返回 403。

26. 录像转录(Transcribe)

将指定设备通道的历史录像片段异步录制为 MP4 文件,并提供播放地址。任务在后台执行,支持去重、并发控制、取消和状态查询。

💡
并发限制:由环境变量 TRANSCRIBE_MAX_CONCURRENT 控制,默认 3 个任务。
防重机制:同一 device_id + channel_id + start_time + end_time 的任务只会执行一次。
原速录制:任务以原速拉取录像流,不会倍速处理。

26.1 启动转录任务

POST/api/playback/transcribe启动转录
参数类型必填说明
device_id*String是国标设备 ID
channel_id*String是视频通道 ID
start_time*String是开始时间
end_time*String是结束时间
zlm_nodeString否指定 ZLM 节点
callback_urlString否转录完成回调地址
curl -H "Authorization: Bearer <token>" -X POST http://127.0.0.1:3002/api/playback/transcribe \
  -H "Content-Type: application/json" \
  -d '{
    "device_id": "34020000001320000001",
    "channel_id": "34020000001310000003",
    "start_time": "2026-08-07 16:00:00",
    "end_time": "2026-08-07 16:30:00"
  }'

成功响应

{
  "code": 0,
  "msg": "transcribe task started",
  "task_id": "550e8400-e29b-41d4-a716-446655440000"
}

常见错误

HTTPcodemsg
400-1缺少必填参数或时间格式错误
401-1未授权(缺少或无效 JWT)
409-1任务已在运行中(同一时间段)
429-1并发任务数已达上限
⚠️
若同一时间段已转录过,接口会直接返回 {"code":0, "msg":"already transcribed", "file_url":"..."},不再创建新任务。

26.2 停止转录任务

POST/api/playback/transcribe/stop停止转录
参数类型必填说明
task_id*String是任务 ID

26.3 查询转录结果

GET/api/playback/transcribe/query查询结果
参数类型必填说明
device_id*String是设备 ID
channel_id*String是通道 ID
start_time*String是开始时间
end_time*String是结束时间

响应(已完成)

{
  "code": 0,
  "status": "completed",
  "file_url": "http://192.168.28.252:9080/record/rtp/proxy_playback_.../xxx.mp4"
}

响应(运行中)

{
  "code": 0,
  "status": "running",
  "msg": "task is still in progress",
  "task_id": "550e8400-e29b-41d4-a716-446655440000"
}

响应(未找到)

{
  "code": 0,
  "status": "not_found",
  "msg": "no transcription found for this time range"
}

26.4 回调通知

POST {callback_url}
Content-Type: application/json

{
  "task_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "file_url": "http://192.168.28.252:9080/record/rtp/.../xxx.mp4"
}

26.5 常见问题

⚠️
通道 ID 错误:若填入设备不存在的通道 ID,设备将返回 404 Not Found,任务会在约 15 秒后超时失败,请先通过 /api/device-channels 确认正确的通道 ID。
💡
任务"丢失":服务重启后,正在运行的任务会消失,但 Redis 中的状态键仍保留为 running,导致该时间段无法重新发起转录。可手动删除 Redis 键 transcribe:status:{core} 和 transcribe:task_id:{core} 后重试。

27. 设备与通道统计

获取平台当前设备总数和通道总数,适合运维监控、仪表盘展示。采用 Redis Pipeline 优化,设备数 ≤ 1 万时响应迅速。

GET/api/stats/summary设备与通道统计
curl -H "Authorization: Bearer <token>" http://127.0.0.1:3002/api/stats/summary

成功响应

{
  "code": 0,
  "data": {
    "device_count": 128,
    "channel_count": 456
  }
}
字段类型说明
codeint0 表示成功,-1 表示失败
device_countint已注册设备总数(来自 Redis 集合 all_devices 的基数)
channel_countint所有设备通道数量累加

错误响应

HTTP响应体说明
401{"code":-1,"msg":"unauthorized"}未认证或 JWT 无效
403{"code":-1,"msg":"forbidden"}权限不足
500{"code":-1,"msg":"internal error"}Redis 异常或内部错误
💡
性能说明:设备数 ≤ 10000 时,接口响应时间通常在几十毫秒内。如果设备量超过一万,建议使用计数器缓存方案或进一步优化。

28. 多 SIP 节点管理

平台支持挂载多个 SIP 节点。共享 Redis 架构下,心跳(sip_node:hb:*)和设备上报由 SIP 直接写 Redis,不经 mgr。

28.1 注册 SIP 节点(内部)

POST/api/internal/sip-nodes/registerSIP 节点自注册

28.2 - 28.7 节点查询

GET/api/sip-nodes节点列表
GET/api/sip-nodes/{id}节点详情
GET/api/sip-nodes/{id}/stats节点统计
GET/api/sip-nodes/{id}/devices节点设备(分页/搜索/在线过滤)
GET/api/sip-nodes/{id}/channels节点通道
GET/api/sip-nodes/{id}/cascades节点级联

28.8 - 28.10 级联操作

POST/api/sip-nodes/{id}/cascades创建级联
DELETE/api/sip-nodes/{id}/cascades/{key}删除级联
POST/api/sip-nodes/{id}/reassign级联迁移
⚠️
迁移只改 Redis,目标 SIP 节点需要重启才能加载新级联。

28.11 - 28.12 注销与推送

DELETE/api/sip-nodes/{id}注销节点
POST/api/push-catalog推送目录

29. 内部接口与录像上传

以下接口仅供内部服务间调用,不对外暴露。除特别说明外,均需在请求头携带 X-Internal-Token: <INTERNAL_API_TOKEN>。

29.1 生成录像上传 Presigned URL

POST/api/internal/presign-record给 zlm-node 返回 S3 上传地址
{"stream":"34020000001320000001_34020000001310000001","app":"rtp","vhost":"__defaultVhost__","file_path":"/opt/media/xxx.mp4"}

29.2 录像完成事件通知

POST/api/internal/on-record-eventzlm-node 上传完成后回调
💡
路径变更:旧:POST /internal/on-record-event;新:POST /api/internal/on-record-event

29.3 录像链路整体流程

💡
ZLM 侧:录像完成 → 调用 zlm-node /hook/on_record_mp4
zlm-node 侧:调 mgr /api/internal/presign-record 拿 URL → PUT S3 → 删本地 → 调 /api/internal/on-record-event 通知入库
mgr 侧:写库 + 通知前端

30. 通话绑定管理

用于管理「会议房间 → ZLM 节点」的绑定关系,是会议通话(对讲)的核心配置。自动绑定由 meeting 侧在会议创建时写入(TTL 30 分钟),管理员可通过本接口写入永久绑定(无 TTL)。

💡
Redis 数据结构:meeting:room:{room}:zlm,值 = ZLM 节点 ID。
自动绑定:SET NX EX 1800,有 TTL。
手动绑定:SET 无 EX,无 TTL,永久。
列表返回 ttl_secs:-1 表示永久,>0 表示剩余秒数,-2 表示 key 不存在。

30.1 列出所有绑定

GET/api/meeting/bindings扫描全部房间绑定
curl -H "Authorization: Bearer <token>" \
  http://127.0.0.1:3002/api/meeting/bindings
{
  "code": 0,
  "data": [
    { "room_id": "abc", "node_id": "node-1", "ttl_secs": -1 },
    { "room_id": "xyz", "node_id": "node-2", "ttl_secs": 1500 }
  ]
}

30.2 查询单个房间的绑定

GET/api/meeting/bindings/{room_id}获取房间绑定详情
💡
room_id 校验规则:非空、≤ 64 字符、只允许 [a-zA-Z0-9_-]。

30.3 创建/更新绑定(永久)

POST/api/meeting/bindings/{room_id}绑定房间到指定节点(无 TTL)
参数类型必填说明
node_id*String是ZLM 节点 ID,需存在且在线
⚠️
校验规则:
1. node_id 非空且 ≤ 64 字符;
2. Redis 中 zlm_node:{node_id} 必须存在(否则返回 node not found);
3. node_id 必须在集合 zlm_nodes:online 中(否则返回 node not online)。

30.4 解除单个绑定

DELETE/api/meeting/bindings/{room_id}删除该房间的绑定

30.5 批量解除绑定

POST/api/meeting/bindings/batch-delete批量删除房间绑定
参数类型必填说明
room_ids*Array<String>是房间 ID 列表,最多 1000 个;非法 ID 会被自动过滤

30.6 错误码

HTTP / codemsg说明
200 / 0ok成功
200 / -1invalid room_idroom_id 非法
200 / -1invalid node_idnode_id 非法
200 / -1node not found节点不存在
200 / -1node not online节点离线
200 / -1room_ids required批量请求缺 room_ids
200 / -1too many (max 1000)批量超过 1000
200 / -1no valid room_ids全部 room_id 非法
200 / -1internal errorRedis 异常

31. 变更记录

v0.9.7 NEW

  • 语音广播/对讲补齐独占锁机制:新增 /api/audio-broadcast-heartbeat 接口;audio-broadcast、audio-talk、audio-broadcast-stop、audio-talk-stop 增加必填参数 owner;新增响应字段 stream_id/transport/status/answer_port/mode。
  • 截图管理新增 3 个接口:GET /api/snapshot-list、POST /api/snapshot-delete、GET /api/snapshot-query 补齐参数表。
  • device-config / channel-config 补字段表。
  • 语音广播/对讲错误码补全。
  • 前端实现要点:明确「先推流后 API」时序,避免死锁。

v0.9.6

  • 新增「通话绑定管理」章节:/api/meeting/bindings* 五个接口。

v0.9.5

  • 新增「设备音频封装模式」接口:GET/POST/DELETE /api/device/audio-ps。

v0.9.4

  • 对讲/广播 SIP 报文修复:SDP m=audio 端口从 0 改为设备返回的真实端口;Subject 头从 <id>:<ssrc>,<id>:0 改为 <id>:<ssrc>;Broadcast Notify 后增加等待。
  • 新增 TCP 入 INVITE 处理。
  • 双模式仲裁:BROADCAST_MODE = auto / client / server。

v0.9.3

  • ZLM 截图接口新增 async 参数,默认 true。
  • 截图调用链统一改造。
  • 修复 6 个 ZLM 接口 URL 参数未编码。

v0.9.2

  • ZLM 节点管理补充完整接口。
  • 新增 ZLM ↔ SIP 绑定。
  • 新增「多 SIP 节点管理」章节。

v0.9.1

  • 新增 mgr: POST /api/internal/presign-record。
  • 新增 zlm-node: POST /hook/on_record_mp4、GET /hook/health。
  • 路径变更:/internal/on-record-event → /api/internal/on-record-event。
  • schedule 新增 action:cleanup_orphan_devices、cleanup_orphan_nodes、cleanup_transcribe_orphans。

v0.9.0

  • 移动端多用户、通道批量分配、代理通道 ID 列表、录像转录、设备与通道统计、ONVIF、批量绑定、全局通道索引。
↑