摄像头控制与历史播放
约 3352 字大约 11 分钟
2026-10-16
本页包含已接线核心流程及可选扩展;具体子能力必须按设备、平台与用户授权求交集。参见支持范围、场景索引和命令手册。图中S编号只用于本文定位,不放入实际JSON。
前置条件
摄像头控制复用产品物模型,具体 action/属性必须先注册;takePhoto 通道已存在,PTZ、预置位、隐私和录像标识为产品设计示例。
图中P代表经鉴权的平台业务控制器和媒体节点,不要求同一进程;A是用户应用,D是设备。控制图描述一种合法顺序,跨通道不承诺严格同序。
完整时序
报文索引
编号按图阅读;编号保留历史引用,不要求数值连续。字段定义以命令链接为准。
| 编号 | 发送→接收 | Topic/接口 | 方法及契约 | 应答/等待 | 状态或作用 |
|---|---|---|---|---|---|
| S08-M01 | A→P | APP↑ | device.action | HTTP受理;随后 interaction.result;10秒 | 应用控制物模型;服务端生成并记录 action token 映射,不直接信任调用者设备身份。 |
| S08-M02 | P→D | ACT↓ | action | actionReply;不等待 | 连续移动有最大持续时间;设备断网自行停机。 |
| S08-M03 | D→P | ACT↑ | actionReply | —;不等待 | 确认实际开始。 |
| S08-M04 | P→A | APP↓ | interaction.result | —;不等待 | 经 WS interaction.event 发给原操作者,原 token;设备通知不能充当应用请求应答。 |
| S08-M05 | P→D | ACT↓ | action | actionReply;不等待 | 释放按钮或安全超时触发。 |
| S08-M06 | D→P | ACT↑ | actionReply | —;不等待 | 确认已停。 |
| S08-M07 | P→D | ACT↓ | action | actionReply;不等待 | 预置位属于物模型,不进入SDP。 |
| S08-M08 | D→P | ACT↑ | actionReply | —;不等待 | 到位结果按产品定义。 |
| S08-M09 | P→D | ACT↓ | action | actionReply;不等待 | 拍照上传。 |
| S08-M10 | D→P | ACT↑ | actionReply | —;不等待 | 文件引用独立鉴权,不传base64。 |
| S08-M11 | A→P | APP↑ | device.propertyControl | HTTP受理;随后 interaction.result;10秒 | 配置属性与会话控制分离;具体取值见物模型章节。 |
| S08-M12 | P→D | PROP↓ | control | controlReply;不等待 | 写产品属性,平台保存请求与应用token映射。 |
| S08-M13 | D→P | PROP↑ | controlReply | —;不等待 | 控制回执不替代实际属性report。 |
| S08-M14 | D→P | PROP↑ | report | 产品属性上报应答;不等待 | 隐私report触发S07停流;录像策略不建立媒体。 |
| S08-M15 | P→A | APP↓ | interaction.result | —;不等待 | 经 WS interaction.event 发给原操作者,原 token;设备通知不能充当应用请求应答。 |
| S08-M16 | A→P | APP↑ | interaction.open | HTTP受理;随后 interaction.result;10秒 | 平台验证目标、策略和能力后邀请设备;接收 HTTP202 不是接通。 |
| S08-M17 | P→A | APP↓ | interaction.result | —;不等待 | 经 WS interaction.event 发给原操作者,原 token;设备通知不能充当应用请求应答。 |
| S08-M18 | P→D | SIG↓ | sessionInvite | sessionAccept 或 sessionReject;30秒/到期 | 平台邀请;humanCall 固定 accept;direct 也必须设备确认资源和隐私状态,不能跳过 sessionAccept。 |
| S08-M19 | D→P | SIG↑ | sessionAccept | requestAck;10秒 | 沿用邀请 msgToken。邀请答复本身是需确认的请求,等待平台 ACK 后协商媒体。 |
| S08-M20 | P→D | SIG↓ | requestAck | —;不等待 | 原邀请 token;确认接听有效,不携带 SDP、不宣告已接通。 |
| S08-M21 | D→P | SIG↑ | mediaOffer | mediaAnswer;15秒 | 设备为自身 Peer 的 offerer;初始与重协商同一方法,只允许一个在途 offer。 |
| S08-M22 | P→D | SIG↓ | mediaAnswer | —;不等待 | 完成 SDP 交换,仍需 ICE/DTLS 连通与 mediaState,不直接 established。 |
| S08-M23 | D→P | SIG↑ | mediaState | requestAck;10秒 | 报告设备实际传输状态。WebRTC 需 ICE/DTLS 成功;UDP 需有效会话媒体探测且平台也收到有效包。 |
| S08-M24 | P→D | SIG↓ | requestAck | —;不等待 | 仅确认状态上报;平台须独立验证自身连通状态。 |
| S08-M25 | A→P | APP↑ | interaction.mediaOffer | interaction.result;10秒 | 此参与者自己的Peer独立协商,不复用别人的连接。 |
| S08-M26 | P→A | APP↓ | interaction.result | —;不等待 | 仅完成SDP交换,尚未接通。 |
| S08-M27 | A→P | APP↑ | interaction.mediaState | interaction.result;10秒 | 应用实际连通上报,平台还要校验媒体节点状态。 |
| S08-M28 | P→A | APP↓ | interaction.result | —;不等待 | 确认状态已受理,不等于首帧显示。 |
| S08-M29 | P→D | SIG↓ | sessionEstablished | —;不等待 | 平台确认所需参与端媒体已连通后通知;不等于已收到首包或扬声器起播。 |
| S08-M30 | A→P | APP↑ | interaction.end | HTTP受理;随后 interaction.result;10秒 | 由参与者结束其有权结束的会话;观看者只退出自己的观看会话,不终止共享源。 |
| S08-M31 | P→A | APP↓ | interaction.result | —;不等待 | 经 WS interaction.event 发给原操作者,原 token;设备通知不能充当应用请求应答。 |
| S08-M32 | P→D | SIG↓ | sessionEnded | —;不等待 | 主动结束用原 token 和 code;其他结束用独立事件 token 与 eventSeq。ended 是唯一会话终态。 |
逐条JSON
S08-M01 · device.action
{
"msgToken": "s08-118",
"method": "device.action",
"params": {
"actionID": "ptzMove",
"input": {
"direction": "left",
"speed": 0.5,
"durationMs": 1000
}
},
"target": {
"productID": "p-demo",
"deviceName": "device-demo"
}
}S08-M02 · action
{
"msgToken": "ptz-1",
"method": "action",
"actionID": "ptzMove",
"params": {
"direction": "left",
"speed": 0.5,
"durationMs": 1000
}
}S08-M03 · actionReply
{
"msgToken": "ptz-1",
"method": "actionReply",
"actionID": "ptzMove",
"code": 200,
"msg": "success",
"data": {
"moving": true
}
}S08-M04 · interaction.result
{
"msgToken": "s08-118",
"method": "interaction.result",
"code": 200,
"data": {
"operation": "device.action",
"state": "applied"
}
}S08-M05 · action
{
"msgToken": "ptz-stop",
"method": "action",
"actionID": "ptzStop",
"params": {}
}S08-M06 · actionReply
{
"msgToken": "ptz-stop",
"method": "actionReply",
"actionID": "ptzStop",
"code": 200,
"msg": "success",
"data": {
"stopped": true
}
}S08-M07 · action
{
"msgToken": "preset-1",
"method": "action",
"actionID": "ptzPreset",
"params": {
"operation": "goto",
"presetId": "door"
}
}S08-M08 · actionReply
{
"msgToken": "preset-1",
"method": "actionReply",
"actionID": "ptzPreset",
"code": 200,
"msg": "success",
"data": {
"presetId": "door"
}
}S08-M09 · action
{
"msgToken": "photo-1",
"method": "action",
"actionID": "takePhoto",
"params": {}
}S08-M10 · actionReply
{
"msgToken": "photo-1",
"method": "actionReply",
"actionID": "takePhoto",
"code": 200,
"msg": "success",
"data": {
"fileUri": "<file-uri>"
}
}S08-M11 · device.propertyControl
{
"msgToken": "s08-119",
"method": "device.propertyControl",
"params": {
"properties": {
"privacyMode": true,
"nightVision": "auto",
"recordingPolicy": "motion"
}
},
"target": {
"productID": "p-demo",
"deviceName": "device-demo"
}
}S08-M12 · control
{
"msgToken": "prop-1",
"method": "control",
"params": {
"privacyMode": true,
"nightVision": "auto",
"recordingPolicy": "motion"
}
}S08-M13 · controlReply
{
"msgToken": "prop-1",
"method": "controlReply",
"code": 200,
"msg": "success",
"data": {
"privacyMode": true,
"nightVision": "auto",
"recordingPolicy": "motion"
}
}S08-M14 · report
{
"msgToken": "report-1",
"method": "report",
"params": {
"privacyMode": true,
"nightVision": "auto",
"recordingPolicy": "motion"
}
}S08-M15 · interaction.result
{
"msgToken": "s08-119",
"method": "interaction.result",
"code": 200,
"data": {
"operation": "device.propertyControl",
"state": "applied"
}
}S08-M16 · interaction.open
{
"msgToken": "s08-120",
"method": "interaction.open",
"params": {
"purpose": "recordPlayback",
"cameraId": "front",
"recordingId": "record-1"
},
"target": {
"productID": "p-demo",
"deviceName": "device-demo"
}
}S08-M17 · interaction.result
{
"msgToken": "s08-120",
"method": "interaction.result",
"sessionId": "s08-playback",
"code": 200,
"data": {
"operation": "interaction.open",
"state": "invited",
"sessionId": "s08-playback"
}
}S08-M18 · sessionInvite
{
"msgToken": "s08-121",
"method": "sessionInvite",
"sessionId": "s08-playback",
"eventSeq": 1,
"params": {
"purpose": "recordPlayback",
"admission": "direct",
"transport": "webrtc",
"tracks": [
{
"trackId": "video-1",
"kind": "video",
"sourceId": "front",
"direction": "sendonly",
"codec": "H264",
"state": "requested"
}
],
"expiresAt": 1900000000000,
"cameraId": "front",
"recordingId": "record-1"
}
}S08-M19 · sessionAccept
{
"msgToken": "s08-121",
"method": "sessionAccept",
"sessionId": "s08-playback",
"params": {
"acceptedTracks": [
"video-1"
]
}
}S08-M20 · requestAck
{
"msgToken": "s08-121",
"method": "requestAck",
"sessionId": "s08-playback",
"code": 200,
"data": {
"requestMethod": "sessionAccept",
"result": {
"state": "negotiating"
}
}
}S08-M21 · mediaOffer
{
"msgToken": "s08-122",
"method": "mediaOffer",
"sessionId": "s08-playback",
"params": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S08-M22 · mediaAnswer
{
"msgToken": "s08-122",
"method": "mediaAnswer",
"sessionId": "s08-playback",
"code": 200,
"data": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
}
}S08-M23 · mediaState
{
"msgToken": "s08-123",
"method": "mediaState",
"sessionId": "s08-playback",
"params": {
"mediaRevision": 1,
"state": "connected"
}
}S08-M24 · requestAck
{
"msgToken": "s08-123",
"method": "requestAck",
"sessionId": "s08-playback",
"code": 200,
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 1,
"state": "connected"
}
}
}S08-M25 · interaction.mediaOffer
{
"msgToken": "s08-playback-peer-5",
"method": "interaction.mediaOffer",
"sessionId": "s08-playback",
"params": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP playback offer>"
}
}
}S08-M26 · interaction.result
{
"msgToken": "s08-playback-peer-5",
"method": "interaction.result",
"sessionId": "s08-playback",
"code": 200,
"data": {
"operation": "interaction.mediaOffer",
"state": "negotiating",
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP playback answer>"
}
}
}S08-M27 · interaction.mediaState
{
"msgToken": "s08-playback-peer-6",
"method": "interaction.mediaState",
"sessionId": "s08-playback",
"params": {
"mediaRevision": 1,
"state": "connected"
}
}S08-M28 · interaction.result
{
"msgToken": "s08-playback-peer-6",
"method": "interaction.result",
"sessionId": "s08-playback",
"code": 200,
"data": {
"operation": "interaction.mediaState",
"state": "connected",
"mediaRevision": 1
}
}S08-M29 · sessionEstablished
{
"msgToken": "s08-124",
"method": "sessionEstablished",
"sessionId": "s08-playback",
"eventSeq": 2,
"data": {
"state": "established",
"mediaRevision": 1
}
}S08-M30 · interaction.end
{
"msgToken": "s08-125",
"method": "interaction.end",
"sessionId": "s08-playback",
"params": {
"reason": "userStopped"
}
}S08-M31 · interaction.result
{
"msgToken": "s08-125",
"method": "interaction.result",
"sessionId": "s08-playback",
"code": 200,
"data": {
"operation": "interaction.end",
"state": "ended"
}
}S08-M32 · sessionEnded
{
"msgToken": "s08-126",
"method": "sessionEnded",
"sessionId": "s08-playback",
"eventSeq": 3,
"data": {
"state": "ended",
"reason": "userStopped"
}
}媒体与本地动作
| 编号 | 路径 | 格式与约束 |
|---|---|---|
| S08-R01 | D→D | 本地看门狗动作:durationMs 到期强制 ptzStop;无 MQTT 依赖,不伪造云端回执。 |
| S08-R02 | D→P | WebRTC ICE + DTLS 握手;完整 SDP 不代表握手成功;只有网络连通后才报告 connected。 |
| S08-R03 | A→P | WebRTC ICE + DTLS 握手;本参与端独立完成连通验证。 |
| S08-R04 | D→A | 独立 WebRTC 历史视频轨,经媒体节点转发;观看者必须按S07完成自己的Peer;与实时预览不同sessionId,不允许共用预览权限绕过录像权限。 |
异常、状态与资源释放
以下JSON仅为报文正文;编号、方向、说明不发送。loop下一轮需分配新token/inputId;同一次请求重试必须沿用原token。字段以命令手册为准。
路由缩写均展开于公共约定。ACT/PROP超时以产品配置为准;内部工具以工具超时为准,不套用10秒设备统一信令超时。
录像检索和下载走已有业务接口,不定义为 MQTT 媒体命令。告警复用 event/report 与产品事件定义,不因告警自动分享画面给 AI。云台回执超时不得假报已停;设备看门狗是必要的独立安全保护。
能力不支持、无权限、设备拒绝、协商失败、断网、重复请求、过期会话及迟到媒体按S11共通失败流程和公共错误表处理。业务专属分支以本页为准,不因错误静默打开额外能力。
验证入口
更新日志
2026/10/16 16:04
查看所有更新日志
fe3a7-docs(AI与音视频): 按场景整理完整接入流程与命令契约于
