后台休眠弱网与状态同步
约 2616 字大约 9 分钟
2026-10-16
本页包含已接线核心流程及可选扩展;具体子能力必须按设备、平台与用户授权求交集。参见支持范围、场景索引和命令手册。图中S编号只用于本文定位,不放入实际JSON。
前置条件
可移植C++ IPC预览新增原控制连接内的媒体恢复:实际ICE失联上报原代次mediaState(disconnected),原ACK后才生成下一代SDP,实际连通确认后恢复Active,不等待第二条sessionEstablished。原Peer、轨和采集意图保持;不重新调用采集启动,不恢复用户已暂停/停止的来源。首次失联起15秒截止覆盖全部阶段,旧answer/connected/轨控制不得越代次。短暂媒体失联不等于MQTT重新鉴权;本增量不替换ConnectionEpoch,也不假定会议对讲支持同一种恢复。真实验收状态见支持范围。
MQTT/WS重连先重新鉴权;业务保持策略和端身份仍有效时才查询会话快照。断网、后台和显式暂停是不同原因,不能无限复用旧会话。
当前正在实施的 IPC 子集仅是已建立、同原连接的完整名册查询:设备明确声明 participantRosterSync,平台在原邀请中提供公开 endpointEpoch 与 capabilityRevision,才可使用 sessionSync/sessionSnapshot。快照必须包含完整控制状态、全量 participants 和原短期 expiresAt;合法空名册只清成员展示,不停止主媒体。它不等于本图的15秒重连、连接替换、旧socket围栏或媒体代次恢复;这些仍待后继端云验收。
同一 sessionId 的共享事件水位不能在重协商后归零。同步等待期间先消费更高水位的增量或控制事件时,迟到的较低水位快照不得回滚展示;原token重放仍返回原字节和原期限,过期或水位落后的快照只标记同步未知,下一次独立查询必须使用新token。
纯控制连接断开而媒体仍活跃时停止新控制写操作;15秒恢复窗口内可以同步。后台未获麦克风权限时立即停采集,不靠keepalive绕过系统权限。弱网先请求降低编码质量,必要时退回音频;不能静默变更业务purpose或Provider。未声明对应能力的端epoch和旧代次媒体全部拒绝。
当前IPC已接质量调整子集:mediaUpdate → pending → 实际驱动 → trackState → requestAck → applied/failed。以下图同时保留待完整验收的恢复流程;质量路径不能等待 applied 才回报,否则端云互等。质量不改SDP时沿用当前Peer及mediaRevision;本例恢复后为2,不能照抄为初始会话的1。驱动10秒截止、平台15秒截止,失败不终止主通话。真实媒体补验状态以task.md为准,不以图完成代替验收。
D/D2是不同设备参与端,A是应用端,P是平台和媒体节点。各端分别使用鉴权Topic/登录态,不能冒用另一端身份。基础会话与媒体协商见S01/S06,复用时保留本场景sessionId并独立分配密钥和token。
完整时序
报文索引
编号按图阅读;编号保留历史引用,不要求数值连续。字段定义以命令链接为准。
| 编号 | 发送→接收 | Topic/接口 | 方法及契约 | 应答/等待 | 状态或作用 |
|---|---|---|---|---|---|
| S19-M01 | D→P | SIG↑ | sessionSync | sessionSnapshot;10秒受理,媒体协商15秒 | |
| S19-M02 | P→D | SIG↓ | sessionSnapshot | 应答/状态事件;不等待ACK | |
| S19-M03 | D→P | SIG↑ | mediaOffer | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S19-M04 | P→D | SIG↓ | mediaAnswer | 应答/状态事件;不等待ACK | |
| S19-M05 | D→P | SIG↑ | mediaState | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S19-M06 | P→D | SIG↓ | requestAck | 应答/状态事件;不等待ACK | |
| S19-M07 | P→D | SIG↓ | sessionEstablished | 应答/状态事件;不等待ACK | |
| S19-M08 | D→P | SIG↑ | mediaUpdate | mediaUpdated;10秒受理,媒体协商15秒 | |
| S19-M12 | P→D | SIG↓ | mediaUpdated | 原token受理应答 | 启动原轨实际驱动,不是已生效 |
| S19-M11 | D→P | SIG↑ | trackState | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S19-M13 | P→D | SIG↓ | requestAck | 原事实token应答 | 逐轨事实持久收录 |
| S19-M09 | P→D | SIG↓ | mediaUpdated | 应答/状态事件;不等待ACK | |
| S19-M15 | P→D | SIG↓ | mediaUpdated | 独立失败事件;不等待ACK | 原计划收敛,不恢复撤权轨 |
| S19-M14 | P→D | SIG↓ | mediaUpdated | 原请求409应答 | 拒绝本次切换,主通话保持 |
| S19-M10 | P→D | SIG↓ | sessionSnapshot | 应答/状态事件;不等待ACK |
逐条JSON
S19-M01 · sessionSync
{
"msgToken": "s19-72",
"method": "sessionSync",
"sessionId": "s19-session",
"params": {
"lastEventSeq": 12,
"lastMessageSeq": 8,
"endpointEpoch": 1,
"mediaRevision": 1
}
}S19-M02 · sessionSnapshot
{
"msgToken": "s19-72",
"method": "sessionSnapshot",
"sessionId": "s19-session",
"data": {
"state": "established",
"revision": 5,
"eventWatermark": 18,
"messageWatermark": 10,
"endpointEpoch": 1,
"mediaRevision": 1,
"tracks": [
{
"trackId": "mic",
"kind": "audio",
"sourceId": "mic",
"sourceType": "microphone",
"direction": "sendonly",
"codec": "opus",
"state": "requested"
}
],
"controls": {
"call": {
"state": "active",
"revision": 1
},
"focus": {
"state": "suspended",
"revision": 2,
"focusId": "focus-before-sleep",
"resources": [
"microphone",
"speaker"
]
},
"floor": null,
"recordings": [],
"playbacks": [],
"processors": [],
"mediaPlan": {
"revision": 0,
"tracks": [
{
"trackId": "mic",
"kind": "audio",
"sourceId": "mic",
"sourceType": "microphone",
"direction": "sendonly",
"codec": "opus",
"state": "requested"
}
]
},
"broadcasts": [],
"handoffs": [],
"ai": null
},
"resumeAllowed": true,
"capabilityRevision": 1
},
"code": 200
}S19-M03 · mediaOffer
{
"msgToken": "s19-73",
"method": "mediaOffer",
"sessionId": "s19-session",
"params": {
"mediaRevision": 2,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S19-M04 · mediaAnswer
{
"msgToken": "s19-73",
"method": "mediaAnswer",
"sessionId": "s19-session",
"data": {
"mediaRevision": 2,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
},
"code": 200
}S19-M05 · mediaState
{
"msgToken": "s19-74",
"method": "mediaState",
"sessionId": "s19-session",
"params": {
"mediaRevision": 2,
"state": "connected"
}
}S19-M06 · requestAck
{
"msgToken": "s19-74",
"method": "requestAck",
"sessionId": "s19-session",
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 2,
"state": "connected"
}
},
"code": 200
}S19-M07 · sessionEstablished
{
"msgToken": "s19-75",
"method": "sessionEstablished",
"sessionId": "s19-session",
"data": {
"state": "established",
"mediaRevision": 2
},
"eventSeq": 19
}S19-M08 · mediaUpdate
{
"msgToken": "s19-76",
"method": "mediaUpdate",
"sessionId": "s19-session",
"params": {
"operation": "setQuality",
"expectedRevision": 0,
"trackIds": [
"mic"
],
"profile": "low"
}
}S19-M12 · mediaUpdated
{"msgToken":"s19-76","method":"mediaUpdated","sessionId":"s19-session","code":200,"data":{"state":"pending","revision":1,"mediaRevision":2,"tracks":[{"trackId":"mic","kind":"audio","sourceId":"mic","direction":"sendonly","codec":"opus","state":"active"}]}}S19-M11 · trackState
{
"msgToken": "s19-quality-observed",
"method": "trackState",
"sessionId": "s19-session",
"data": {
"trackId": "mic",
"state": "active",
"mediaRevision": 2,
"requestToken": "s19-76",
"revision": 1
}
}S19-M13 · requestAck
{"msgToken":"s19-quality-observed","method":"requestAck","sessionId":"s19-session","code":200,"data":{"requestMethod":"trackState","result":{"trackId":"mic","state":"active","mediaRevision":2}}}S19-M09 · mediaUpdated
{
"msgToken": "s19-quality-applied",
"method": "mediaUpdated",
"sessionId": "s19-session",
"eventSeq": 20,
"data": {
"state": "applied",
"revision": 1,
"mediaRevision": 2,
"tracks": [
{
"trackId": "mic",
"kind": "audio",
"sourceId": "mic",
"sourceType": "microphone",
"direction": "sendonly",
"codec": "opus",
"state": "active"
}
],
"requestToken": "s19-76"
}
}S19-M15 · mediaUpdated
{"msgToken":"s19-quality-failed","method":"mediaUpdated","sessionId":"s19-session","eventSeq":20,"data":{"state":"failed","revision":1,"requestToken":"s19-76","reason":"qualityTimeout"}}S19-M14 · mediaUpdated
{"msgToken":"s19-76","method":"mediaUpdated","sessionId":"s19-session","code":409,"data":{"reason":"updatePending","currentRevision":1}}S19-M10 · sessionSnapshot
{
"msgToken": "s19-72",
"method": "sessionSnapshot",
"sessionId": "s19-session",
"data": {
"state": "ended",
"revision": 6,
"eventWatermark": 19,
"messageWatermark": 10,
"endpointEpoch": 1,
"mediaRevision": 1,
"tracks": [],
"controls": {
"call": null,
"focus": null,
"floor": null,
"recordings": [],
"playbacks": [],
"processors": [],
"mediaPlan": {
"revision": 0,
"tracks": []
},
"broadcasts": [],
"handoffs": [],
"ai": null
},
"resumeAllowed": false,
"reason": "sessionExpired",
"capabilityRevision": 1
},
"code": 200
}媒体与本地动作
| 编号 | 路径 | 格式与约束 |
|---|---|---|
| S19-R01 | D→P | ICE与DTLS握手,非MQTT;失败走S11 |
| S19-R02 | D→P | 新Peer的WebRTC媒体;先安装快照水位再处理新事件 |
| S19-R03 | D→D | 清旧播放队列、Peer与本地输入,不恢复费用连接 |
异常、状态与资源释放
路由与信封见公共约定;阶段性状态不代表最终完成。操作终态时限见命令手册;编号、超时等元信息不发送。
能力不足422、无权限403、资源/修订号冲突409、超时504按S11处理,不静默开启设备能力。同token只重放原结果;事件按eventSeq去重,旧会话/端代次不可恢复。验证本页正常路径、alt分支及支持范围断言。文档通过不代表代码或硬件已实现。
验证入口
更新日志
2026/10/16 16:04
查看所有更新日志
fe3a7-docs(AI与音视频): 按场景整理完整接入流程与命令契约于
