# 第三方 API:直播播放 直播对接分成三件事:找到通道、让流真正上线、向当前播放器签发短时地址。API 返回“已受理”时不要马上拼 URL。 ```mermaid sequenceDiagram participant Backend as 第三方后端 participant API as AKStream.Next participant Device as 摄像机或国标设备 participant Media as MediaServer Backend->>API: 查询安全通道视图 opt 流未上线且有控制权限 Backend->>API: 启动通道或 GB28181 INVITE API->>Device: 拉流或发起点播 Device->>Media: 发送媒体 end Backend->>API: 查询流状态 API-->>Backend: Online Backend->>API: 申请短时播放地址 API-->>Backend: HLS/FLV/fMP4 URLs ``` ## 查询和启动通道 查询单个通道: ```http GET /api/v2/third-party/channels/{channelId} Authorization: Bearer ak_pat_ ``` 普通 RTSP/ONVIF 通道使用: ```http POST /api/v2/third-party/channels/{channelId}/start Authorization: Bearer ak_pat_ ``` GB28181 实时点播需要 SIP INVITE、RTP 端口和 SSRC 状态机,使用原生入口: ```http POST /api/v2/gb28181/live/invite Authorization: Bearer ak_pat_ Content-Type: application/json { "deviceId": "34020000001320000001", "channelId": "34020000001320000002", "mediaServerId": "zlm-prod-01", "rtpWithTcp": false, "timeoutSeconds": 30 } ``` 普通通道启动要求 `channels.manage`;GB28181 点播要求 `devices.control`。两者都只是受理动作,随后查询: ```http GET /api/v2/third-party/streams?mediaServerId=zlm-prod-01&streamId=camera-001&state=Online Authorization: Bearer ak_pat_ ``` ## GB28181 设备历史录像 `GET /api/v2/gb28181/records/query/{taskId}` 返回的是设备侧 RecordInfo 清单。设备原始 `file:///`、FilePath 和 Address 只是设备内部定位值,不是浏览器播放地址;安全响应不会再返回这些原值,而会为每条录像提供 `playback` 动作: 1. 按 `playback.method/endpoint/request` 调用 `POST /api/v2/gb28181/playback/invite`。 2. 保存响应中的 `session.id`,等待该 Session 的 app/stream 变为 Online。 3. 调用 `POST /api/v2/third-party/gb28181/playback-sessions/{sessionId}/playback-lease`。 4. 使用返回 `sources` 中的 HTTP-FLV、HTTP-fMP4 或 HLS 地址播放,并按 `renewAfter` 续租。 查询设备录像需要 `devices.view`,创建 Playback INVITE 需要 `devices.control`,签发 Web 播放租约需要 `streams.play`。 ## 申请播放地址 流为 `Online` 后,推荐创建 URL 不变的播放租约: ```http POST /api/v2/third-party/channels/{channelId}/playback-lease Authorization: Bearer ak_pat_ Content-Type: application/json { "protocols": ["http-flv", "http-fmp4", "hls"], "leaseSeconds": 120, "absoluteLifetimeSeconds": 43200 } ``` 响应示例: ```json { "leaseId": "01234567-89ab-cdef-0123-456789abcdef", "resourceKind": "live", "resourceId": "camera-001", "state": "Active", "createdAt": "2026-08-24T10:00:00Z", "expiresAt": "2026-08-24T10:02:00Z", "renewAfter": "2026-08-24T10:01:24Z", "absoluteExpiresAt": "2026-08-24T22:00:00Z", "sources": [ { "protocol": "http-flv", "url": "https://media.example.com/live/camera-001-main.live.flv?ak_ticket=<短时票据>", "contentType": "video/x-flv", "browserNative": false, "hint": "网页使用 flv.js;H.265 通常不兼容。" } ] } ``` | 协议 | 适合场景 | 客户端注意 | |---|---|---| | HLS | 兼容性优先、跨网络播放 | 延迟通常更高;多画面每个播放器使用独立 `ak_viewer` | | HTTP-FLV | PC 浏览器低延迟预览 | 使用 flv.js/MSE;H.265 通常不能播放 | | HTTP-fMP4 | 网页低延迟、部分 H.265 环境 | `.live.mp4` 是直播长连接,不是普通 MP4 文件 | ## 续签、停流和错误 滑动租期允许 60—600 秒,默认 120 秒;绝对寿命最长 12 小时,并且不会超过原 API Token 到期时间。服务端通常在本轮租期约 70% 处给出 `renewAfter`,客户端应直接使用该值,不要自己推算。到点后由后端调用: ```http POST /api/v2/third-party/playback-leases/{leaseId}/renew Authorization: Bearer ak_pat_ Content-Type: application/json {"leaseSeconds":120} ``` 续租不返回新 URL,也不会改变原 `ak_ticket`。HTTP-FLV 和 HTTP-fMP4 已建立的是单条长连接,无法注入新 URL,也不需要注入;HLS 继续使用同一 URL 和 MediaServer Cookie。连接断开时仍用原 URL 重连,只要租约已经续期即可。租约过期后不能复活,应创建新租约。 主动撤销使用 `DELETE /api/v2/third-party/playback-leases/{leaseId}`。撤销会拒绝新连接;默认不会强制踢断已经建立的播放连接。原 `/playback` 一次性地址继续兼容无需续租的短场景。 停止普通通道: ```http POST /api/v2/third-party/channels/{channelId}/stop Authorization: Bearer ak_pat_ ``` GB28181 停流使用 `/api/v2/gb28181/live/stop`。如果通道配置了自动拉流,先按业务要求暂停自动恢复,避免设备收到 BYE 后又被重新 INVITE。 | 状态/错误 | 表示什么 | 怎么处理 | |---|---|---| | `401 api_token_required` | 不是有效 API Token | 检查 Token、有效期、IP 白名单和吊销状态 | | `403 permission_denied` | 缺少当前动作权限 | 由管理员按最小权限调整,客户端不要自动扩大权限 | | `409 stream_not_ready` | 通道、流或媒体节点尚不可播放 | 查询通道、流命令和流会话,不要循环申请票据 | | `409 playback_lease_conflict` | 租约已过期、撤销、达到绝对寿命或并发冲突 | 过期/撤销时创建新租约;并发冲突可立即回读状态后重试 | | 播放请求 401/403 | 票据过期、错流、原 Token 已失效或权限收回 | 后端重新授权;不要重放旧地址 | | API 成功但播放器 404 | 流已掉线或媒体域名、端口、vhost/app/stream 不匹配 | 先重新查询 Online 状态和媒体节点候选地址 | 生产环境还要验证 HTTPS 混合内容、CORS、反向代理缓冲和长连接超时。API 域名不一定是媒体域名。