能力与会话
约 4114 字大约 14 分钟
2026-10-16
本页包含已接线核心流程及可选扩展;具体子能力必须按设备、平台与用户授权求交集。参见支持范围、场景索引和命令手册。图中S编号只用于本文定位,不放入实际JSON。
前置条件
设备先完成 MQTT 认证;平台使用已鉴权 Topic 身份。设备发起和平台邀请是两条独立路径,后续各场景均复用本页媒体协商与关闭规则。
图中P代表经鉴权的平台业务控制器和媒体节点,不要求同一进程;A是用户应用,D是设备。控制图描述一种合法顺序,跨通道不承诺严格同序。
完整时序
报文索引
编号按图阅读;编号保留历史引用,不要求数值连续。字段定义以命令链接为准。
| 编号 | 发送→接收 | Topic/接口 | 方法及契约 | 应答/等待 | 状态或作用 |
|---|---|---|---|---|---|
| S01-M01 | D→P | SIG↑ | capabilityReport | requestAck;10秒 | 全量替换本设备当前能力;断线重连重新上报,不授予权限。 |
| S01-M02 | P→D | SIG↓ | requestAck | —;不等待 | 同 revision 同内容返回原结果;同 revision 不同内容返回 409。 |
| S01-M03 | D→P | SIG↑ | sessionCreate | sessionCreated;10秒 | 设备发起会话;平台验证设备能力、业务配置、资源与授权交集,不指定供应商。 |
| S01-M04 | P→D | SIG↓ | sessionCreated | —;不等待 | 仅代表创建并分配媒体资源成功,不代表媒体连通;成功必须带顶层 sessionId。 |
| S01-M05 | D→P | SIG↑ | mediaOffer | mediaAnswer;15秒 | 设备为自身 Peer 的 offerer;初始与重协商同一方法,只允许一个在途 offer。 |
| S01-M06 | P→D | SIG↓ | mediaAnswer | —;不等待 | 完成 SDP 交换,仍需 ICE/DTLS 连通与 mediaState,不直接 established。 |
| S01-M07 | D→P | SIG↑ | mediaState | requestAck;10秒 | 报告设备实际传输状态。WebRTC 需 ICE/DTLS 成功;UDP 需有效会话媒体探测且平台也收到有效包。 |
| S01-M08 | P→D | SIG↓ | requestAck | —;不等待 | 仅确认状态上报;平台须独立验证自身连通状态。 |
| S01-M09 | P→D | SIG↓ | sessionEstablished | —;不等待 | 平台确认所需参与端媒体已连通后通知;不等于已收到首包或扬声器起播。 |
| S01-M10 | D→P | SIG↑ | sessionEnd | sessionEnded;10秒 | 设备主动结束整个会话,立即本地停采集/播放;平台撤销轨、处理器、密钥/令牌及资源占用。 |
| S01-M11 | P→D | SIG↓ | sessionEnded | —;不等待 | 主动结束用原 token 和 code;其他结束用独立事件 token 与 eventSeq。ended 是唯一会话终态。 |
| S01-M12 | P→D | SIG↓ | sessionCreated | —;不等待 | 仅代表创建并分配媒体资源成功,不代表媒体连通;成功必须带顶层 sessionId。 |
| S01-M13 | A→P | APP↑ | interaction.open | HTTP受理;随后 interaction.result;10秒 | 平台验证目标、策略和能力后邀请设备;接收 HTTP202 不是接通。 |
| S01-M14 | P→A | APP↓ | interaction.result | —;不等待 | 经 WS interaction.event 发给原操作者,原 token;设备通知不能充当应用请求应答。 |
| S01-M15 | P→D | SIG↓ | sessionInvite | sessionAccept 或 sessionReject;30秒/到期 | 平台邀请;humanCall 固定 accept;direct 也必须设备确认资源和隐私状态,不能跳过 sessionAccept。 |
| S01-M16 | D→P | SIG↑ | sessionAccept | requestAck;10秒 | 沿用邀请 msgToken。邀请答复本身是需确认的请求,等待平台 ACK 后协商媒体。 |
| S01-M17 | P→D | SIG↓ | requestAck | —;不等待 | 原邀请 token;确认接听有效,不携带 SDP、不宣告已接通。 |
| S01-M18 | D→P | SIG↑ | mediaOffer | mediaAnswer;15秒 | 设备为自身 Peer 的 offerer;初始与重协商同一方法,只允许一个在途 offer。 |
| S01-M19 | P→D | SIG↓ | mediaAnswer | —;不等待 | 完成 SDP 交换,仍需 ICE/DTLS 连通与 mediaState,不直接 established。 |
| S01-M20 | D→P | SIG↑ | mediaState | requestAck;10秒 | 报告设备实际传输状态。WebRTC 需 ICE/DTLS 成功;UDP 需有效会话媒体探测且平台也收到有效包。 |
| S01-M21 | P→D | SIG↓ | requestAck | —;不等待 | 仅确认状态上报;平台须独立验证自身连通状态。 |
| S01-M22 | A→P | APP↑ | interaction.mediaOffer | interaction.result;10秒 | 此参与者自己的Peer独立协商,不复用别人的连接。 |
| S01-M23 | P→A | APP↓ | interaction.result | —;不等待 | 仅完成SDP交换,尚未接通。 |
| S01-M24 | A→P | APP↑ | interaction.mediaState | interaction.result;10秒 | 应用实际连通上报,平台还要校验媒体节点状态。 |
| S01-M25 | P→A | APP↓ | interaction.result | —;不等待 | 确认状态已受理,不等于首帧显示。 |
| S01-M26 | P→D | SIG↓ | sessionEstablished | —;不等待 | 平台确认所需参与端媒体已连通后通知;不等于已收到首包或扬声器起播。 |
| S01-M27 | P→A | APP↓ | interaction.state | —;不等待 | 原操作者/参与者会话事件;与 interaction.result 独立;有 eventSeq。 |
| S01-M28 | D→P | SIG↑ | mediaOffer | mediaAnswer;15秒 | 设备为自身 Peer 的 offerer;初始与重协商同一方法,只允许一个在途 offer。 |
| S01-M29 | P→D | SIG↓ | mediaAnswer | —;不等待 | 完成 SDP 交换,仍需 ICE/DTLS 连通与 mediaState,不直接 established。 |
| S01-M30 | D→P | SIG↑ | mediaState | requestAck;10秒 | 报告设备实际传输状态。WebRTC 需 ICE/DTLS 成功;UDP 需有效会话媒体探测且平台也收到有效包。 |
| S01-M31 | P→D | SIG↓ | requestAck | —;不等待 | 仅确认状态上报;平台须独立验证自身连通状态。 |
| S01-M32 | D→P | SIG↑ | sessionEnd | sessionEnded;10秒 | 设备主动结束整个会话,立即本地停采集/播放;平台撤销轨、处理器、密钥/令牌及资源占用。 |
| S01-M33 | P→D | SIG↓ | sessionEnded | —;不等待 | 主动结束用原 token 和 code;其他结束用独立事件 token 与 eventSeq。ended 是唯一会话终态。 |
| S01-M34 | D→P | SIG↑ | sessionReject | requestAck;10秒 | 沿用邀请 token;不创建媒体连接,不抢占现有前台会话。 |
| S01-M35 | P→D | SIG↓ | requestAck | —;不等待 | 成功拒绝请求的 code=200,与业务拒绝原因区分;后发独立 sessionEnded 终态通知。 |
| S01-M36 | P→D | SIG↓ | sessionEnded | —;不等待 | 主动结束用原 token 和 code;其他结束用独立事件 token 与 eventSeq。ended 是唯一会话终态。 |
| S01-M37 | P→A | APP↓ | interaction.state | —;不等待 | 原操作者/参与者会话事件;与 interaction.result 独立;有 eventSeq。 |
| S01-M38 | P→D | SIG↓ | sessionEnded | —;不等待 | 主动结束用原 token 和 code;其他结束用独立事件 token 与 eventSeq。ended 是唯一会话终态。 |
| S01-M39 | P→A | APP↓ | interaction.state | —;不等待 | 原操作者/参与者会话事件;与 interaction.result 独立;有 eventSeq。 |
逐条JSON
S01-M01 · capabilityReport
{
"msgToken": "cap-s01",
"method": "capabilityReport",
"params": {
"revision": 1,
"purposes": [
"aiConversation"
],
"transports": [
"udp",
"webrtc"
],
"supportedInteractionModes": [
"halfDuplex",
"fullDuplex"
],
"aecMode": "device",
"audio": {
"format": "opus",
"sampleRate": 16000,
"channels": 1,
"frameDuration": 20
},
"features": [
"audio"
]
}
}S01-M02 · requestAck
{
"msgToken": "cap-s01",
"method": "requestAck",
"code": 200,
"data": {
"requestMethod": "capabilityReport",
"result": {
"acceptedRevision": 1
}
}
}S01-M03 · sessionCreate
{
"msgToken": "s01-1",
"method": "sessionCreate",
"params": {
"purpose": "aiConversation",
"transport": "webrtc",
"supportedInteractionModes": [
"halfDuplex"
],
"audioParams": {
"format": "opus",
"sampleRate": 16000,
"channels": 1,
"frameDuration": 20
},
"tracks": [
{
"trackId": "mic-1",
"kind": "audio",
"sourceId": "mic",
"direction": "sendonly",
"codec": "opus",
"state": "requested"
},
{
"trackId": "speaker-1",
"kind": "audio",
"sourceId": "speaker",
"direction": "recvonly",
"codec": "opus",
"state": "requested"
}
]
}
}S01-M04 · sessionCreated
{
"msgToken": "s01-1",
"method": "sessionCreated",
"sessionId": "s01-session",
"code": 200,
"data": {
"state": "negotiating",
"selected": {
"transport": "webrtc",
"interactionMode": "halfDuplex",
"audioParams": {
"format": "opus",
"sampleRate": 16000,
"channels": 1,
"frameDuration": 20
}
},
"tracks": [
{
"trackId": "mic-1",
"kind": "audio",
"sourceId": "mic",
"direction": "sendonly",
"codec": "opus",
"state": "requested"
},
{
"trackId": "speaker-1",
"kind": "audio",
"sourceId": "speaker",
"direction": "recvonly",
"codec": "opus",
"state": "requested"
}
]
}
}S01-M05 · mediaOffer
{
"msgToken": "s01-2",
"method": "mediaOffer",
"sessionId": "s01-session",
"params": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S01-M06 · mediaAnswer
{
"msgToken": "s01-2",
"method": "mediaAnswer",
"sessionId": "s01-session",
"code": 200,
"data": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
}
}S01-M07 · mediaState
{
"msgToken": "s01-3",
"method": "mediaState",
"sessionId": "s01-session",
"params": {
"mediaRevision": 1,
"state": "connected"
}
}S01-M08 · requestAck
{
"msgToken": "s01-3",
"method": "requestAck",
"sessionId": "s01-session",
"code": 200,
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 1,
"state": "connected"
}
}
}S01-M09 · sessionEstablished
{
"msgToken": "s01-4",
"method": "sessionEstablished",
"sessionId": "s01-session",
"eventSeq": 1,
"data": {
"state": "established",
"mediaRevision": 1
}
}S01-M10 · sessionEnd
{
"msgToken": "s01-5",
"method": "sessionEnd",
"sessionId": "s01-session",
"params": {
"reason": "userHangup"
}
}S01-M11 · sessionEnded
{
"msgToken": "s01-5",
"method": "sessionEnded",
"sessionId": "s01-session",
"code": 200,
"data": {
"state": "ended",
"reason": "userHangup"
}
}S01-M12 · sessionCreated
{
"msgToken": "s01-1",
"method": "sessionCreated",
"code": 422,
"data": {
"reason": "unsupportedCapability"
}
}S01-M13 · interaction.open
{
"msgToken": "s01-6",
"method": "interaction.open",
"params": {
"purpose": "ipcLiveView",
"cameraId": "front"
},
"target": {
"productID": "p-demo",
"deviceName": "device-demo"
}
}S01-M14 · interaction.result
{
"msgToken": "s01-6",
"method": "interaction.result",
"sessionId": "s01-invited",
"code": 200,
"data": {
"operation": "interaction.open",
"state": "invited",
"sessionId": "s01-invited"
}
}S01-M15 · sessionInvite
{
"msgToken": "s01-7",
"method": "sessionInvite",
"sessionId": "s01-invited",
"eventSeq": 1,
"params": {
"purpose": "ipcLiveView",
"admission": "accept",
"transport": "webrtc",
"cameraId": "front",
"tracks": [
{
"trackId": "video-1",
"kind": "video",
"sourceId": "front",
"direction": "sendonly",
"codec": "H264",
"state": "requested"
}
],
"expiresAt": 1900000000000
}
}S01-M16 · sessionAccept
{
"msgToken": "s01-7",
"method": "sessionAccept",
"sessionId": "s01-invited",
"params": {
"acceptedTracks": [
"video-1"
]
}
}S01-M17 · requestAck
{
"msgToken": "s01-7",
"method": "requestAck",
"sessionId": "s01-invited",
"code": 200,
"data": {
"requestMethod": "sessionAccept",
"result": {
"state": "negotiating"
}
}
}S01-M18 · mediaOffer
{
"msgToken": "s01-8",
"method": "mediaOffer",
"sessionId": "s01-invited",
"params": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S01-M19 · mediaAnswer
{
"msgToken": "s01-8",
"method": "mediaAnswer",
"sessionId": "s01-invited",
"code": 200,
"data": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
}
}S01-M20 · mediaState
{
"msgToken": "s01-9",
"method": "mediaState",
"sessionId": "s01-invited",
"params": {
"mediaRevision": 1,
"state": "connected"
}
}S01-M21 · requestAck
{
"msgToken": "s01-9",
"method": "requestAck",
"sessionId": "s01-invited",
"code": 200,
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 1,
"state": "connected"
}
}
}S01-M22 · interaction.mediaOffer
{
"msgToken": "s01-invited-peer-1",
"method": "interaction.mediaOffer",
"sessionId": "s01-invited",
"params": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP viewer offer>"
}
}
}S01-M23 · interaction.result
{
"msgToken": "s01-invited-peer-1",
"method": "interaction.result",
"sessionId": "s01-invited",
"code": 200,
"data": {
"operation": "interaction.mediaOffer",
"state": "negotiating",
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP viewer answer>"
}
}
}S01-M24 · interaction.mediaState
{
"msgToken": "s01-i2",
"method": "interaction.mediaState",
"sessionId": "s01-invited",
"params": {
"mediaRevision": 1,
"state": "connected"
}
}S01-M25 · interaction.result
{
"msgToken": "s01-i2",
"method": "interaction.result",
"sessionId": "s01-invited",
"code": 200,
"data": {
"operation": "interaction.mediaState",
"state": "connected",
"mediaRevision": 1
}
}S01-M26 · sessionEstablished
{
"msgToken": "s01-10",
"method": "sessionEstablished",
"sessionId": "s01-invited",
"eventSeq": 2,
"data": {
"state": "established",
"mediaRevision": 1
}
}S01-M27 · interaction.state
{
"msgToken": "s01-11",
"method": "interaction.state",
"sessionId": "s01-invited",
"eventSeq": 3,
"data": {
"state": "established"
}
}S01-M28 · mediaOffer
{
"msgToken": "s01-12",
"method": "mediaOffer",
"sessionId": "s01-invited",
"params": {
"mediaRevision": 2,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S01-M29 · mediaAnswer
{
"msgToken": "s01-12",
"method": "mediaAnswer",
"sessionId": "s01-invited",
"code": 200,
"data": {
"mediaRevision": 2,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
}
}S01-M30 · mediaState
{
"msgToken": "s01-13",
"method": "mediaState",
"sessionId": "s01-invited",
"params": {
"mediaRevision": 2,
"state": "connected"
}
}S01-M31 · requestAck
{
"msgToken": "s01-13",
"method": "requestAck",
"sessionId": "s01-invited",
"code": 200,
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 2,
"state": "connected"
}
}
}S01-M32 · sessionEnd
{
"msgToken": "s01-14",
"method": "sessionEnd",
"sessionId": "s01-invited",
"params": {
"reason": "userHangup"
}
}S01-M33 · sessionEnded
{
"msgToken": "s01-14",
"method": "sessionEnded",
"sessionId": "s01-invited",
"code": 200,
"data": {
"state": "ended",
"reason": "userHangup"
}
}S01-M34 · sessionReject
{
"msgToken": "s01-7",
"method": "sessionReject",
"sessionId": "s01-invited",
"params": {
"reason": "privacyEnabled"
}
}S01-M35 · requestAck
{
"msgToken": "s01-7",
"method": "requestAck",
"sessionId": "s01-invited",
"code": 200,
"data": {
"requestMethod": "sessionReject",
"result": {
"state": "ended",
"reason": "privacyEnabled"
}
}
}S01-M36 · sessionEnded
{
"msgToken": "s01-15",
"method": "sessionEnded",
"sessionId": "s01-invited",
"eventSeq": 4,
"data": {
"state": "ended",
"reason": "userRejected"
}
}S01-M37 · interaction.state
{
"msgToken": "s01-16",
"method": "interaction.state",
"sessionId": "s01-invited",
"eventSeq": 5,
"data": {
"state": "ended",
"reason": "userRejected"
}
}S01-M38 · sessionEnded
{
"msgToken": "s01-17",
"method": "sessionEnded",
"sessionId": "s01-invited",
"eventSeq": 6,
"data": {
"state": "ended",
"reason": "inviteTimeout"
}
}S01-M39 · interaction.state
{
"msgToken": "s01-18",
"method": "interaction.state",
"sessionId": "s01-invited",
"eventSeq": 7,
"data": {
"state": "ended",
"reason": "inviteTimeout"
}
}媒体与本地动作
| 编号 | 路径 | 格式与约束 |
|---|---|---|
| S01-R01 | D→P | WebRTC ICE + DTLS 握手;完整 SDP 不代表握手成功;只有网络连通后才报告 connected。 |
| S01-R02 | D→P | WebRTC ICE + DTLS 握手;完整 SDP 不代表握手成功;只有网络连通后才报告 connected。 |
| S01-R03 | A→P | WebRTC ICE + DTLS 握手;本参与端独立完成连通验证。 |
| S01-R04 | D→P | WebRTC ICE + DTLS 握手;完整 SDP 不代表握手成功;只有网络连通后才报告 connected。 |
异常、状态与资源释放
以下JSON仅为报文正文;编号、方向、说明不发送。loop下一轮需分配新token/inputId;同一次请求重试必须沿用原token。字段以命令手册为准。
路由缩写均展开于公共约定。ACT/PROP超时以产品配置为准;内部工具以工具超时为准,不套用10秒设备统一信令超时。
重复请求复用原 token,不能重复分配会话。WebRTC 重连只对当前未结束会话增加 mediaRevision;断网恢复窗口 15 秒,超时结束。无权限在创建前返回 403,不下发邀请或媒体凭据。
能力不支持、无权限、设备拒绝、协商失败、断网、重复请求、过期会话及迟到媒体按S11共通失败流程和公共错误表处理。业务专属分支以本页为准,不因错误静默打开额外能力。
验证入口
更新日志
2026/10/16 16:04
查看所有更新日志
fe3a7-docs(AI与音视频): 按场景整理完整接入流程与命令契约于
