人与人音视频
约 7033 字大约 23 分钟
2026-10-16
本页包含已接线核心流程及可选扩展;具体子能力必须按设备、平台与用户授权求交集。参见支持范围、场景索引和命令手册。图中S编号只用于本文定位,不放入实际JSON。
前置条件
多人业务复用支持范围的conversationId、callId、成员和生命周期;以下新接口是适配设计,不再建独立会议群。加入本次通话与加入IM群是两回事;人数/忙线/最后成员离开规则沿IM约束。
多人身份与当前实施边界
conversationId标识原IM群,callId标识该群本次通话;sessionId始终标识某个参与端的独立媒体腿,不能把群或整场通话当作一条设备会话。成员身份来自已鉴权登录上下文,participantId仅为平台派生名册标识,不能由正文授权自己加入或替他人离开。
S06-M33的interaction.join与s-group仍为待完成的适配设计,不是当前可调用契约。当前会议加入复用原group_invite/group_join,再用interaction.open(purpose=ipcTalk,target,cameraId,callId)取得本端独立媒体腿;不能把群或整场通话ID传成sessionId。S06-M42的interaction.leave已按应用命令契约接入正式会议音频腿,完整现行流程见主持移出与自退。旧调用方仍可先interaction.end结束自己的媒体,再原group_leave退出IM通话;旧接口意义不变。
显式成员增量和完整名册查询已有后端/C++组件实现;正常活腿只读查询为snapshotOnly/resumeAllowed=false。主持解禁但用户本地静音、主持移出后当前成员集合的权威重取另有显式四端验收矩阵,见支持范围,现场结果仍待执行。权威重取不是断网或媒体恢复;弱网恢复形态见S19。不能把四端Opus混音通过视为群视频、成员独立音轨订阅或重连恢复已完成。
主叫为已鉴权应用,被叫设备具备本地接听能力;音频 Opus、视频 H264 需双方能力求交集。humanCall 不携带 AI 的 interactionMode。
图中P代表经鉴权的平台业务控制器和媒体节点,不要求同一进程;A是用户应用,D是设备。控制图描述一种合法顺序,跨通道不承诺严格同序。
完整时序
报文索引
编号按图阅读;编号保留历史引用,不要求数值连续。字段定义以命令链接为准。
| 编号 | 发送→接收 | Topic/接口 | 方法及契约 | 应答/等待 | 状态或作用 |
|---|---|---|---|---|---|
| S06-M01 | A→P | APP↑ | interaction.open | HTTP受理;随后 interaction.result;10秒 | 平台验证目标、策略和能力后邀请设备;接收 HTTP202 不是接通。 |
| S06-M02 | P→A | APP↓ | interaction.result | —;不等待 | 经 WS interaction.event 发给原操作者,原 token;设备通知不能充当应用请求应答。 |
| S06-M03 | P→D | SIG↓ | sessionInvite | sessionAccept 或 sessionReject;30秒/到期 | 平台邀请;humanCall 固定 accept;direct 也必须设备确认资源和隐私状态,不能跳过 sessionAccept。 |
| S06-M04 | D→P | SIG↑ | sessionAccept | requestAck;10秒 | 沿用邀请 msgToken。邀请答复本身是需确认的请求,等待平台 ACK 后协商媒体。 |
| S06-M05 | P→D | SIG↓ | requestAck | —;不等待 | 原邀请 token;确认接听有效,不携带 SDP、不宣告已接通。 |
| S06-M06 | D→P | SIG↑ | mediaOffer | mediaAnswer;15秒 | 设备为自身 Peer 的 offerer;初始与重协商同一方法,只允许一个在途 offer。 |
| S06-M07 | P→D | SIG↓ | mediaAnswer | —;不等待 | 完成 SDP 交换,仍需 ICE/DTLS 连通与 mediaState,不直接 established。 |
| S06-M08 | D→P | SIG↑ | mediaState | requestAck;10秒 | 报告设备实际传输状态。WebRTC 需 ICE/DTLS 成功;UDP 需有效会话媒体探测且平台也收到有效包。 |
| S06-M09 | P→D | SIG↓ | requestAck | —;不等待 | 仅确认状态上报;平台须独立验证自身连通状态。 |
| S06-M10 | A→P | APP↑ | interaction.mediaOffer | HTTP受理;随后 interaction.result;10秒 | 应用 Peer 自己协商;设备完成 SDP 不代替应用 Peer。 |
| S06-M11 | P→A | APP↓ | interaction.result | —;不等待 | 经 WS interaction.event 发给原操作者,原 token;设备通知不能充当应用请求应答。 |
| S06-M12 | A→P | APP↑ | interaction.mediaState | HTTP受理;随后 interaction.result;10秒 | 应用报告 ICE/DTLS 状态;平台需独立校验。 |
| S06-M13 | P→A | APP↓ | interaction.result | —;不等待 | 经 WS interaction.event 发给原操作者,原 token;设备通知不能充当应用请求应答。 |
| S06-M14 | P→D | SIG↓ | sessionEstablished | —;不等待 | 平台确认所需参与端媒体已连通后通知;不等于已收到首包或扬声器起播。 |
| S06-M15 | P→A | APP↓ | interaction.state | —;不等待 | 原操作者/参与者会话事件;与 interaction.result 独立;有 eventSeq。 |
| S06-M16 | D→P | SIG↑ | trackControl | 反方向 trackState;10秒 | publish/stop 控制源轨;subscribe/unsubscribe 仅本参与端订阅;pause/resume 只作用本端发布或订阅,不关闭其他观看者。请求不等于实际生效。 |
| S06-M17 | P→D | SIG↓ | trackState | —;不等待 | 双向实际状态;应答同 token 和 code,主动报告独立 token。设备失联只能标 unknown,不能假报 stopped。 |
| S06-M18 | D→P | SIG↑ | trackControl | 反方向 trackState;10秒 | publish/stop 控制源轨;subscribe/unsubscribe 仅本参与端订阅;pause/resume 只作用本端发布或订阅,不关闭其他观看者。请求不等于实际生效。 |
| S06-M19 | P→D | SIG↓ | trackState | —;不等待 | 双向实际状态;应答同 token 和 code,主动报告独立 token。设备失联只能标 unknown,不能假报 stopped。 |
| S06-M20 | D→P | SIG↑ | trackControl | 反方向 trackState;10秒 | publish/stop 控制源轨;subscribe/unsubscribe 仅本参与端订阅;pause/resume 只作用本端发布或订阅,不关闭其他观看者。请求不等于实际生效。 |
| S06-M21 | P→D | SIG↓ | trackState | —;不等待 | 双向实际状态;应答同 token 和 code,主动报告独立 token。设备失联只能标 unknown,不能假报 stopped。 |
| S06-M22 | D→P | SIG↑ | trackControl | 反方向 trackState;10秒 | publish/stop 控制源轨;subscribe/unsubscribe 仅本参与端订阅;pause/resume 只作用本端发布或订阅,不关闭其他观看者。请求不等于实际生效。 |
| S06-M23 | P→D | SIG↓ | trackState | —;不等待 | 双向实际状态;应答同 token 和 code,主动报告独立 token。设备失联只能标 unknown,不能假报 stopped。 |
| S06-M24 | A→P | APP↑ | interaction.trackControl | interaction.result;10秒 | 主叫静音仅暂停自己的上行音轨;不暂停被叫麦克风。 |
| S06-M25 | P→A | APP↓ | interaction.result | —;不等待 | 平台媒体节点已暂停该参与端轨。 |
| S06-M26 | D→P | SIG↑ | sessionEnd | sessionEnded;10秒 | 设备主动结束整个会话,立即本地停采集/播放;平台撤销轨、处理器、密钥/令牌及资源占用。 |
| S06-M27 | P→D | SIG↓ | sessionEnded | —;不等待 | 主动结束用原 token 和 code;其他结束用独立事件 token 与 eventSeq。ended 是唯一会话终态。 |
| S06-M28 | P→A | APP↓ | interaction.state | —;不等待 | 原操作者/参与者会话事件;与 interaction.result 独立;有 eventSeq。 |
| S06-M29 | D→P | SIG↑ | sessionReject | requestAck;10秒 | 沿用邀请 token;不创建媒体连接,不抢占现有前台会话。 |
| S06-M30 | P→D | SIG↓ | requestAck | —;不等待 | 成功拒绝请求的 code=200,与业务拒绝原因区分;后发独立 sessionEnded 终态通知。 |
| S06-M31 | P→D | SIG↓ | sessionEnded | —;不等待 | 主动结束用原 token 和 code;其他结束用独立事件 token 与 eventSeq。ended 是唯一会话终态。 |
| S06-M32 | P→A | APP↓ | interaction.state | —;不等待 | 原操作者/参与者会话事件;与 interaction.result 独立;有 eventSeq。 |
| S06-M33 | A→P | APP↑ | interaction.join | HTTP受理;随后 interaction.result;10秒 | 成员登录态必须有加入权限,不能冒用参数身份。 |
| S06-M34 | P→A | APP↓ | interaction.result | —;不等待 | 经 WS interaction.event 发给原操作者,原 token;设备通知不能充当应用请求应答。 |
| S06-M35 | A→P | APP↑ | interaction.mediaOffer | interaction.result;10秒 | 此参与者自己的Peer独立协商,不复用别人的连接。 |
| S06-M36 | P→A | APP↓ | interaction.result | —;不等待 | 仅完成SDP交换,尚未接通。 |
| S06-M37 | A→P | APP↑ | interaction.mediaState | interaction.result;10秒 | 应用实际连通上报,平台还要校验媒体节点状态。 |
| S06-M38 | P→A | APP↓ | interaction.result | —;不等待 | 确认状态已受理,不等于首帧显示。 |
| S06-M39 | P→D | SIG↓ | participantChanged | —;不等待 | 成员变化独立于 sessionEstablished;离开撤销该成员源轨和订阅,不结束其他成员会话。 |
| S06-M40 | D→P | SIG↑ | trackControl | 反方向 trackState;10秒 | publish/stop 控制源轨;subscribe/unsubscribe 仅本参与端订阅;pause/resume 只作用本端发布或订阅,不关闭其他观看者。请求不等于实际生效。 |
| S06-M41 | P→D | SIG↓ | trackState | —;不等待 | 双向实际状态;应答同 token 和 code,主动报告独立 token。设备失联只能标 unknown,不能假报 stopped。 |
| S06-M42 | A→P | APP↑ | interaction.leave | HTTP受理;随后 interaction.result;10秒 | 退出自己,主持人移除他人需要额外权限;其他成员继续。 |
| S06-M43 | P→A | APP↓ | interaction.result | —;不等待 | 经 WS interaction.event 发给原操作者,原 token;设备通知不能充当应用请求应答。 |
| S06-M44 | P→D | SIG↓ | participantChanged | —;不等待 | 成员变化独立于 sessionEstablished;离开撤销该成员源轨和订阅,不结束其他成员会话。 |
| S06-M45 | P→D | SIG↓ | trackState | —;不等待 | 双向实际状态;应答同 token 和 code,主动报告独立 token。设备失联只能标 unknown,不能假报 stopped。 |
逐条JSON
S06-M01 · interaction.open
{
"msgToken": "s06-76",
"method": "interaction.open",
"params": {
"purpose": "humanCall",
"callType": "video"
},
"target": {
"productID": "p-demo",
"deviceName": "device-demo"
}
}S06-M02 · interaction.result
{
"msgToken": "s06-76",
"method": "interaction.result",
"sessionId": "s06-session",
"code": 200,
"data": {
"operation": "interaction.open",
"state": "invited",
"sessionId": "s06-session"
}
}S06-M03 · sessionInvite
{
"msgToken": "s06-77",
"method": "sessionInvite",
"sessionId": "s06-session",
"eventSeq": 1,
"params": {
"purpose": "humanCall",
"callType": "video",
"admission": "accept",
"transport": "webrtc",
"expiresAt": 1900000000000,
"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"
},
{
"trackId": "video-1",
"kind": "video",
"sourceId": "front",
"direction": "sendonly",
"codec": "H264",
"state": "requested"
}
],
"callGroupId": "call-group-s06-session"
}
}S06-M04 · sessionAccept
{
"msgToken": "s06-77",
"method": "sessionAccept",
"sessionId": "s06-session",
"params": {
"acceptedTracks": [
"mic-1",
"speaker-1",
"video-1"
]
}
}S06-M05 · requestAck
{
"msgToken": "s06-77",
"method": "requestAck",
"sessionId": "s06-session",
"code": 200,
"data": {
"requestMethod": "sessionAccept",
"result": {
"state": "negotiating"
}
}
}S06-M06 · mediaOffer
{
"msgToken": "s06-78",
"method": "mediaOffer",
"sessionId": "s06-session",
"params": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S06-M07 · mediaAnswer
{
"msgToken": "s06-78",
"method": "mediaAnswer",
"sessionId": "s06-session",
"code": 200,
"data": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
}
}S06-M08 · mediaState
{
"msgToken": "s06-79",
"method": "mediaState",
"sessionId": "s06-session",
"params": {
"mediaRevision": 1,
"state": "connected"
}
}S06-M09 · requestAck
{
"msgToken": "s06-79",
"method": "requestAck",
"sessionId": "s06-session",
"code": 200,
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 1,
"state": "connected"
}
}
}S06-M10 · interaction.mediaOffer
{
"msgToken": "s06-80",
"method": "interaction.mediaOffer",
"sessionId": "s06-session",
"params": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP caller offer>"
}
}
}S06-M11 · interaction.result
{
"msgToken": "s06-80",
"method": "interaction.result",
"sessionId": "s06-session",
"code": 200,
"data": {
"operation": "interaction.mediaOffer",
"state": "negotiating",
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP caller answer>"
}
}
}S06-M12 · interaction.mediaState
{
"msgToken": "s06-81",
"method": "interaction.mediaState",
"sessionId": "s06-session",
"params": {
"mediaRevision": 1,
"state": "connected"
}
}S06-M13 · interaction.result
{
"msgToken": "s06-81",
"method": "interaction.result",
"sessionId": "s06-session",
"code": 200,
"data": {
"operation": "interaction.mediaState",
"state": "connected",
"mediaRevision": 1
}
}S06-M14 · sessionEstablished
{
"msgToken": "s06-82",
"method": "sessionEstablished",
"sessionId": "s06-session",
"eventSeq": 2,
"data": {
"state": "established",
"mediaRevision": 1
}
}S06-M15 · interaction.state
{
"msgToken": "s06-83",
"method": "interaction.state",
"sessionId": "s06-session",
"eventSeq": 3,
"data": {
"state": "established"
}
}S06-M16 · trackControl
{
"msgToken": "s06-84",
"method": "trackControl",
"sessionId": "s06-session",
"params": {
"trackId": "mic-1",
"operation": "pause",
"mediaRevision": 1
}
}S06-M17 · trackState
{
"msgToken": "s06-84",
"method": "trackState",
"sessionId": "s06-session",
"code": 200,
"data": {
"trackId": "mic-1",
"state": "paused",
"mediaRevision": 1
}
}S06-M18 · trackControl
{
"msgToken": "s06-85",
"method": "trackControl",
"sessionId": "s06-session",
"params": {
"trackId": "video-1",
"operation": "pause",
"mediaRevision": 1
}
}S06-M19 · trackState
{
"msgToken": "s06-85",
"method": "trackState",
"sessionId": "s06-session",
"code": 200,
"data": {
"trackId": "video-1",
"state": "paused",
"mediaRevision": 1
}
}S06-M20 · trackControl
{
"msgToken": "s06-86",
"method": "trackControl",
"sessionId": "s06-session",
"params": {
"trackId": "mic-1",
"operation": "resume",
"mediaRevision": 1
}
}S06-M21 · trackState
{
"msgToken": "s06-86",
"method": "trackState",
"sessionId": "s06-session",
"code": 200,
"data": {
"trackId": "mic-1",
"state": "active",
"mediaRevision": 1
}
}S06-M22 · trackControl
{
"msgToken": "s06-87",
"method": "trackControl",
"sessionId": "s06-session",
"params": {
"trackId": "video-1",
"operation": "resume",
"mediaRevision": 1
}
}S06-M23 · trackState
{
"msgToken": "s06-87",
"method": "trackState",
"sessionId": "s06-session",
"code": 200,
"data": {
"trackId": "video-1",
"state": "active",
"mediaRevision": 1
}
}S06-M24 · interaction.trackControl
{
"msgToken": "s06-app-mute",
"method": "interaction.trackControl",
"sessionId": "s06-session",
"params": {
"trackId": "caller-mic",
"operation": "pause",
"mediaRevision": 1
}
}S06-M25 · interaction.result
{
"msgToken": "s06-app-mute",
"method": "interaction.result",
"sessionId": "s06-session",
"code": 200,
"data": {
"operation": "interaction.trackControl",
"state": "paused",
"mediaRevision": 1
}
}S06-M26 · sessionEnd
{
"msgToken": "s06-88",
"method": "sessionEnd",
"sessionId": "s06-session",
"params": {
"reason": "userHangup"
}
}S06-M27 · sessionEnded
{
"msgToken": "s06-88",
"method": "sessionEnded",
"sessionId": "s06-session",
"code": 200,
"data": {
"state": "ended",
"reason": "userHangup"
}
}S06-M28 · interaction.state
{
"msgToken": "s06-89",
"method": "interaction.state",
"sessionId": "s06-session",
"eventSeq": 4,
"data": {
"state": "ended",
"reason": "userHangup"
}
}S06-M29 · sessionReject
{
"msgToken": "s06-77",
"method": "sessionReject",
"sessionId": "s06-session",
"params": {
"reason": "resourceBusy"
}
}S06-M30 · requestAck
{
"msgToken": "s06-77",
"method": "requestAck",
"sessionId": "s06-session",
"code": 200,
"data": {
"requestMethod": "sessionReject",
"result": {
"state": "ended",
"reason": "resourceBusy"
}
}
}S06-M31 · sessionEnded
{
"msgToken": "s06-90",
"method": "sessionEnded",
"sessionId": "s06-session",
"eventSeq": 5,
"data": {
"state": "ended",
"reason": "userRejected"
}
}S06-M32 · interaction.state
{
"msgToken": "s06-91",
"method": "interaction.state",
"sessionId": "s06-session",
"eventSeq": 6,
"data": {
"state": "ended",
"reason": "resourceBusy"
}
}S06-M33 · interaction.join
{
"msgToken": "s06-92",
"method": "interaction.join",
"sessionId": "s-group-device-leg",
"params": {
"participantId": "user-b"
}
}S06-M34 · interaction.result
{
"msgToken": "s06-92",
"method": "interaction.result",
"sessionId": "s-group-device-leg",
"code": 200,
"data": {
"operation": "interaction.join",
"state": "joined"
}
}S06-M35 · interaction.mediaOffer
{
"msgToken": "s-group-peer-9",
"method": "interaction.mediaOffer",
"sessionId": "s-group-device-leg",
"params": {
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP member offer>"
}
}
}S06-M36 · interaction.result
{
"msgToken": "s-group-peer-9",
"method": "interaction.result",
"sessionId": "s-group-device-leg",
"code": 200,
"data": {
"operation": "interaction.mediaOffer",
"state": "negotiating",
"mediaRevision": 1,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP member answer>"
}
}
}S06-M37 · interaction.mediaState
{
"msgToken": "s-group-peer-10",
"method": "interaction.mediaState",
"sessionId": "s-group-device-leg",
"params": {
"mediaRevision": 1,
"state": "connected"
}
}S06-M38 · interaction.result
{
"msgToken": "s-group-peer-10",
"method": "interaction.result",
"sessionId": "s-group-device-leg",
"code": 200,
"data": {
"operation": "interaction.mediaState",
"state": "connected",
"mediaRevision": 1
}
}S06-M39 · participantChanged
{
"msgToken": "s06-93",
"method": "participantChanged",
"sessionId": "s-group-device-leg",
"eventSeq": 1,
"data": {
"participantId": "user-b",
"change": "joined",
"tracks": [
{
"trackId": "user-b-audio",
"kind": "audio",
"sourceId": "user-b",
"direction": "recvonly",
"codec": "opus",
"state": "requested"
}
]
}
}该事件绑定接收设备自己的会话腿 s-group-device-leg,不把 IM 组标识放进 sessionId;仅已显式声明 participantRoster 的端接收。名册及轨描述不等于媒体发布/订阅或 IM 话权授权。成员加入的应用入口和平台事件生成仍待接线,不能由本事件的接收测试代替。
S06-M40 · trackControl
{
"msgToken": "s06-94",
"method": "trackControl",
"sessionId": "s-group-device-leg",
"params": {
"trackId": "user-b-audio",
"operation": "subscribe",
"mediaRevision": 1
}
}S06-M41 · trackState
{
"msgToken": "s06-94",
"method": "trackState",
"sessionId": "s-group-device-leg",
"code": 200,
"data": {
"trackId": "user-b-audio",
"state": "active",
"mediaRevision": 1
}
}S06-M42 · interaction.leave
{
"msgToken": "s06-95",
"method": "interaction.leave",
"sessionId": "s-original-app-leg",
"params": {
"callId": "gcall-example",
"participantId": "103",
"expectedMemberEpoch": 1
}
}S06-M43 · interaction.result
{
"msgToken": "s06-95",
"method": "interaction.result",
"sessionId": "s-original-app-leg",
"code": 200,
"data": {
"operation": "interaction.leave",
"callId": "gcall-example",
"participantId": "103",
"memberEpoch": 1,
"remaining": ["101", "102"],
"ended": false
}
}S06-M44 · participantChanged
{
"msgToken": "s06-96",
"method": "participantChanged",
"sessionId": "s-group-device-leg",
"eventSeq": 2,
"data": {
"participantId": "user-b",
"change": "left",
"tracks": [
{
"trackId": "user-b-audio",
"kind": "audio",
"sourceId": "user-b",
"direction": "recvonly",
"codec": "opus",
"state": "stopped"
}
]
}
}S06-M45 · trackState
{
"msgToken": "s06-97",
"method": "trackState",
"sessionId": "s-group-device-leg",
"eventSeq": 3,
"data": {
"trackId": "user-b-audio",
"state": "stopped",
"mediaRevision": 1,
"participantId": "user-b",
"reason": "participantLeft"
}
}当前会议音频:主持移出与自退
适用于已建立的当前 ipcTalk 会议音频腿,不承诺上述未来成员独立音视频轨设计已经实现。U1是原活通话发起人,U3是待移出成员,D是仍在场的C++设备腿。sessionId=s-u1 为U1自己的媒体腿;禁止传整场群通话ID或U3腿ID冒充操作者。
| 编号 | 方向 | 路由 | 接口/命令 | 应答/状态/截止 |
|---|---|---|---|---|
| S06-M46 | U1→P | HTTP | POST /api/v1/im/interaction/talk/audio-access | 原活成员只读,不续租;响应M47,失败不控制。 |
| S06-M47 | P→U1 | HTTP | 原音权read响应 | 目标memberEpoch,不是媒体状态。 |
| S06-M48 | U1→P | HTTP | POST /api/v1/im/interaction/commands,内层interaction.leave | 10秒;原token最多重试2次,不换token。 |
| S06-M49 | P→U1 | HTTP | 原命令共享失败响应 | msg受语言设置影响;非200不证明未执行。 |
| S06-M50 | P→U1 | HTTP | 原命令accepted响应 | 只证明受理,不是采集停止。 |
| S06-M55 | P→U1 | APP↓ | interaction.result,原端点events | 原IM事实;按deliveryId ACK。 |
| S06-M51 | P→U3 | APP↓ | interaction.state | 原Owner持久终态;APP独立HAL真停止。 |
| S06-M52 | P→D | SIG↓ | participantChanged | 保留原媒体,不重邀设备;tracks为空。 |
| S06-M56 | P→I | 内部事件 | 既有FastEvent im.call.signal,不是MQTT设备信令 | 2秒投递预算;失败持久重试原通知,原有效期10分钟。目标重入丢弃旧left,不改变新媒体。 |
| S06-M57 | P→I | 内部事件 | 既有FastEvent im.call.signal | 发送前读当前原IM群通话及群成员交集,读取失败不广播假结束。 |
| S06-M58 | P→I | 内部事件 | 既有FastEvent im.message.new | 仅原结束卡片首次落库;原群行锁使未声明对应能力的端清理也不重复写卡片。 |
| S06-M53 | U1→P | HTTP | 原M48同字节/同token重试 | pending无回执未知,不重做。 |
| S06-M54 | P→U1 | APP↓ | interaction.result | 原M55同字节历史结果,不能恢复媒体。 |
| 媒体编号 | 格式与状态 |
|---|---|
| S06-R10 | 原已协商Opus WebRTC轨;实际解码持续,不以包计数冒充有声样本。 |
S06-M46 · 原IM音权只读请求
{"operation":"read","callId":"gcall-example","targetUserID":"103"}S06-M47 · 原IM音权只读响应
{"code":200,"msg":"success","data":{"callId":"gcall-example","targetUserID":"103","publishAllowed":true,"audioRevision":3,"memberEpoch":1,"expiresAt":1900000002000}}S06-M48 · interaction.leave
{"endpointId":"original-u1-endpoint","command":{"msgToken":"host-remove-1","method":"interaction.leave","sessionId":"s-u1","params":{"callId":"gcall-example","participantId":"103","expectedMemberEpoch":1}}}S06-M49 · HTTP失败结果
{"code":100017,"msg":"error.sys.serverError"}S06-M50 · HTTP受理
{"code":200,"msg":"success","data":{"accepted":true,"msgToken":"host-remove-1","replay":false}}S06-M55 · interaction.result
{"msgToken":"host-remove-1","method":"interaction.result","sessionId":"s-u1","code":200,"data":{"operation":"interaction.leave","callId":"gcall-example","participantId":"103","memberEpoch":1,"remaining":["101","102"],"ended":false}}S06-M51 · interaction.state
{"msgToken":"u3-ended-fact","method":"interaction.state","sessionId":"s-u3","eventSeq":4,"data":{"state":"ended","reason":"permissionRevoked"}}S06-M52 · participantChanged
{"msgToken":"member-left-fact","method":"participantChanged","sessionId":"s-device-leg","eventSeq":6,"data":{"participantId":"103","change":"left","tracks":[]}}S06-M56 · 既有peer.left内部事件
{"event":"peer.left","callId":"gcall-example","scope":"group","conversationId":9001,"fromUserId":103,"targetUserId":"103","notifyUserIds":[101,102],"timestamp":1900000000}S06-M57 · 既有group.state内部事件
{"event":"group.state","callId":"gcall-example","callType":"voice","scope":"group","conversationId":9001,"members":["101","102"],"notifyUserIds":[101,102,103],"timestamp":1900000000}S06-M58 · 既有结束卡片新消息内部事件
{"msgId":501,"conversationId":9001,"recipientUserIds":[101,102,103]}M58仅在操作结束整场时出现,与示例M55的ended=false互斥;JSON中的卡片ID是占位,真实卡片必须同事务落入原IM消息表,不是设备自报。I复用原应用IM推送通道,不引入另一套设备会议信令;这里展示平台内部事件,不伪装为MQTT消息。
S06-M53 · 原请求重试
{"endpointId":"original-u1-endpoint","command":{"msgToken":"host-remove-1","method":"interaction.leave","sessionId":"s-u1","params":{"callId":"gcall-example","participantId":"103","expectedMemberEpoch":1}}}S06-M54 · interaction.result
{"msgToken":"host-remove-1","method":"interaction.result","sessionId":"s-u1","code":200,"data":{"operation":"interaction.leave","callId":"gcall-example","participantId":"103","memberEpoch":1,"remaining":["101","102"],"ended":false}}示例端点、会话和水位均为占位,不是可直接连接的真实身份。本人自退时 participantId 改为自己的规范用户ID,仍要求原应用腿与目标加入实例;不替他人发旧 group_leave,也不调用群聊 remove-member。目标重入必须产生更大 memberEpoch;原移出结果重放和迟到旧腿音频不能影响新实例。剩余IM成员不足两人时原通话结束,各原Owner释放资源;不会向设备伪造 trackState(reason=participantLeft) 回执。
真实四端、单元/集成/race及剩余验收见支持范围,不把本节协议实现等同于群视频、重连恢复或实体硬件验收。
媒体与本地动作
| 编号 | 路径 | 格式与约束 |
|---|---|---|
| S06-R01 | D→P | WebRTC ICE + DTLS 握手;完整 SDP 不代表握手成功;只有网络连通后才报告 connected。 |
| S06-R02 | A→P | WebRTC ICE + DTLS 握手;主叫 Peer 独立于设备 Peer。 |
| S06-R03 | A→P | WebRTC DTLS-SRTP Opus + H264;主叫上行;媒体节点按授权转发。 |
| S06-R04 | P→D | WebRTC DTLS-SRTP Opus + H264;被叫下行。 |
| S06-R05 | D→P | WebRTC DTLS-SRTP Opus + H264;被叫上行。 |
| S06-R06 | P→A | WebRTC DTLS-SRTP Opus + H264;主叫下行。 |
| S06-R07 | A→P | WebRTC ICE + DTLS 握手;本参与端独立完成连通验证。 |
异常、状态与资源释放
以下JSON仅为报文正文;编号、方向、说明不发送。loop下一轮需分配新token/inputId;同一次请求重试必须沿用原token。字段以命令手册为准。
路由缩写均展开于公共约定。ACT/PROP超时以产品配置为准;内部工具以工具超时为准,不套用10秒设备统一信令超时。
多人新成员先按本页应用 Peer 协商,再发布/订阅轨;加入事件不代表首音到达。邀请超时用 S01 分支;协商失败和重连用共通失败流程。来电邀请不抢占 AI,只有用户接听后才原子切换音频焦点并清旧播放。
能力不支持、无权限、设备拒绝、协商失败、断网、重复请求、过期会话及迟到媒体按S11共通失败流程和公共错误表处理。业务专属分支以本页为准,不因错误静默打开额外能力。
验证入口
更新日志
2026/10/16 16:04
查看所有更新日志
fe3a7-docs(AI与音视频): 按场景整理完整接入流程与命令契约于
