视频升级摄像头切换与屏幕共享
约 4220 字大约 14 分钟
2026-10-16
本页包含扩展设计,不能作为当前整场景已实现的承诺。参见支持范围、场景索引和命令手册。图中S编号只用于本文定位,不放入实际JSON。
前置条件
已有语音/视频通话或AI视频会话。设备能力中列出camera/screen/systemAudio源;屏幕与系统音频需要分别授权。
屏幕共享是sourceType=screen的视频轨;共享摄像头与屏幕可并存,受maxVideoTracks约束。屏幕音频是systemAudio独立音轨,不能误当麦克风;宿主停止共享或撤权立即stop轨并通知平台。setQuality改变编码约束时重协商,否则沿当前代次;退回audioOnly仅停止视频,不静默停止主语音。
D/D2是不同设备参与端,A是应用端,P是平台和媒体节点。各端分别使用鉴权Topic/登录态,不能冒用另一端身份。基础会话与媒体协商见S01/S06,复用时保留本场景sessionId并独立分配密钥和token。
完整时序
报文索引
编号按图阅读;编号保留历史引用,不要求数值连续。字段定义以命令链接为准。
| 编号 | 发送→接收 | Topic/接口 | 方法及契约 | 应答/等待 | 状态或作用 |
|---|---|---|---|---|---|
| S14-M01 | D→P | SIG↑ | mediaUpdate | mediaUpdated;10秒受理,媒体协商15秒 | |
| S14-M02 | P→D | SIG↓ | mediaUpdated | 应答/状态事件;不等待ACK | |
| S14-M03 | D→P | SIG↑ | mediaOffer | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S14-M04 | P→D | SIG↓ | mediaAnswer | 应答/状态事件;不等待ACK | |
| S14-M05 | D→P | SIG↑ | mediaState | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S14-M06 | P→D | SIG↓ | requestAck | 应答/状态事件;不等待ACK | |
| S14-M34 | D→P | SIG↑ | trackState | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S14-M07 | P→D | SIG↓ | mediaUpdated | 应答/状态事件;不等待ACK | |
| S14-M08 | P→D | SIG↓ | mediaUpdated | 应答/状态事件;不等待ACK | |
| S14-M09 | D→P | SIG↑ | mediaUpdate | mediaUpdated;10秒受理,媒体协商15秒 | |
| S14-M10 | P→D | SIG↓ | mediaUpdated | 应答/状态事件;不等待ACK | |
| S14-M11 | D→P | SIG↑ | mediaOffer | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S14-M12 | P→D | SIG↓ | mediaAnswer | 应答/状态事件;不等待ACK | |
| S14-M13 | D→P | SIG↑ | mediaState | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S14-M14 | P→D | SIG↓ | requestAck | 应答/状态事件;不等待ACK | |
| S14-M35 | D→P | SIG↑ | trackState | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S14-M31 | P→D | SIG↓ | mediaUpdated | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S14-M15 | D→P | SIG↑ | mediaUpdate | mediaUpdated;10秒受理,媒体协商15秒 | |
| S14-M16 | P→D | SIG↓ | mediaUpdated | 应答/状态事件;不等待ACK | |
| S14-M17 | D→P | SIG↑ | mediaOffer | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S14-M18 | P→D | SIG↓ | mediaAnswer | 应答/状态事件;不等待ACK | |
| S14-M19 | D→P | SIG↑ | mediaState | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S14-M20 | P→D | SIG↓ | requestAck | 应答/状态事件;不等待ACK | |
| S14-M36 | D→P | SIG↑ | trackState | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S14-M32 | P→D | SIG↓ | mediaUpdated | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S14-M21 | D→P | SIG↑ | mediaUpdate | mediaUpdated;10秒受理,媒体协商15秒 | |
| S14-M22 | P→D | SIG↓ | mediaUpdated | 应答/状态事件;不等待ACK | |
| S14-M23 | D→P | SIG↑ | mediaOffer | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S14-M24 | P→D | SIG↓ | mediaAnswer | 应答/状态事件;不等待ACK | |
| S14-M25 | D→P | SIG↑ | mediaState | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S14-M26 | P→D | SIG↓ | requestAck | 应答/状态事件;不等待ACK | |
| S14-M37 | D→P | SIG↑ | trackState | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S14-M44 | D→P | SIG↑ | trackState | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S14-M33 | P→D | SIG↓ | mediaUpdated | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S14-M27 | D→P | SIG↑ | sessionEnd | 对应应答见命令;10秒受理,媒体协商15秒 | |
| S14-M28 | P→D | SIG↓ | sessionEnded | 应答/状态事件;不等待ACK | |
| S14-M29 | D→P | SIG↑ | mediaUpdate | mediaUpdated;10秒 | |
| S14-M30 | P→D | SIG↓ | mediaUpdated | 实际状态应答;不等待ACK | |
| S14-M38 | D→P | SIG↑ | mediaOffer | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S14-M39 | P→D | SIG↓ | mediaAnswer | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S14-M40 | D→P | SIG↑ | mediaState | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S14-M41 | P→D | SIG↓ | requestAck | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
| S14-M42 | D→P | SIG↑ | trackState | 按契约等待10秒 | 核对补齐,不以受理替代完成 |
| S14-M43 | P→D | SIG↓ | mediaUpdated | 应答或事件,无ACK | 核对补齐,不以受理替代完成 |
逐条JSON
S14-M01 · mediaUpdate
{
"msgToken": "s14-20",
"method": "mediaUpdate",
"sessionId": "s14-session",
"params": {
"operation": "add",
"expectedRevision": 0,
"tracks": [
{
"trackId": "video-new",
"kind": "video",
"sourceId": "front",
"sourceType": "camera",
"direction": "sendonly",
"codec": "H264",
"state": "requested"
}
],
"consentIds": [
"camera-consent",
"peer-video-consent"
]
}
}S14-M02 · mediaUpdated
{
"msgToken": "s14-20",
"method": "mediaUpdated",
"sessionId": "s14-session",
"data": {
"state": "pending",
"revision": 1,
"mediaRevision": 2,
"tracks": [
{
"trackId": "video-new",
"kind": "video",
"sourceId": "front",
"sourceType": "camera",
"direction": "sendonly",
"codec": "H264",
"state": "requested"
}
],
"requestToken": "s14-20"
},
"code": 200
}S14-M03 · mediaOffer
{
"msgToken": "s14-21",
"method": "mediaOffer",
"sessionId": "s14-session",
"params": {
"mediaRevision": 2,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S14-M04 · mediaAnswer
{
"msgToken": "s14-21",
"method": "mediaAnswer",
"sessionId": "s14-session",
"data": {
"mediaRevision": 2,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
},
"code": 200
}S14-M05 · mediaState
{
"msgToken": "s14-22",
"method": "mediaState",
"sessionId": "s14-session",
"params": {
"mediaRevision": 2,
"state": "connected"
}
}S14-M06 · requestAck
{
"msgToken": "s14-22",
"method": "requestAck",
"sessionId": "s14-session",
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 2,
"state": "connected"
}
},
"code": 200
}S14-M34 · trackState
{
"msgToken": "s14-observed-video-new-2",
"method": "trackState",
"sessionId": "s14-session",
"data": {
"trackId": "video-new",
"state": "active",
"mediaRevision": 2
}
}S14-M07 · mediaUpdated
{
"msgToken": "s14-23",
"method": "mediaUpdated",
"sessionId": "s14-session",
"data": {
"state": "applied",
"revision": 1,
"mediaRevision": 2,
"tracks": [
{
"trackId": "video-new",
"kind": "video",
"sourceId": "front",
"sourceType": "camera",
"direction": "sendonly",
"codec": "H264",
"state": "active"
}
],
"requestToken": "s14-20"
},
"eventSeq": 1
}S14-M08 · mediaUpdated
{
"msgToken": "s14-24",
"method": "mediaUpdated",
"sessionId": "s14-session",
"data": {
"state": "failed",
"revision": 1,
"reason": "videoConsentDenied",
"requestToken": "s14-20"
},
"eventSeq": 2
}S14-M09 · mediaUpdate
{
"msgToken": "s14-25",
"method": "mediaUpdate",
"sessionId": "s14-session",
"params": {
"operation": "replace",
"expectedRevision": 1,
"trackIds": [
"video-new"
],
"tracks": [
{
"trackId": "video-rear",
"kind": "video",
"sourceId": "rear",
"sourceType": "camera",
"direction": "sendonly",
"codec": "H264",
"state": "requested"
}
],
"consentIds": [
"rear-consent"
]
}
}S14-M10 · mediaUpdated
{
"msgToken": "s14-25",
"method": "mediaUpdated",
"sessionId": "s14-session",
"data": {
"state": "pending",
"revision": 2,
"mediaRevision": 3,
"tracks": [
{
"trackId": "video-rear",
"kind": "video",
"sourceId": "rear",
"sourceType": "camera",
"direction": "sendonly",
"codec": "H264",
"state": "requested"
}
],
"requestToken": "s14-25"
},
"code": 200
}S14-M11 · mediaOffer
{
"msgToken": "s14-26",
"method": "mediaOffer",
"sessionId": "s14-session",
"params": {
"mediaRevision": 3,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S14-M12 · mediaAnswer
{
"msgToken": "s14-26",
"method": "mediaAnswer",
"sessionId": "s14-session",
"data": {
"mediaRevision": 3,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
},
"code": 200
}S14-M13 · mediaState
{
"msgToken": "s14-27",
"method": "mediaState",
"sessionId": "s14-session",
"params": {
"mediaRevision": 3,
"state": "connected"
}
}S14-M14 · requestAck
{
"msgToken": "s14-27",
"method": "requestAck",
"sessionId": "s14-session",
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 3,
"state": "connected"
}
},
"code": 200
}S14-M35 · trackState
{
"msgToken": "s14-observed-video-rear-3",
"method": "trackState",
"sessionId": "s14-session",
"data": {
"trackId": "video-rear",
"state": "active",
"mediaRevision": 3
}
}S14-M31 · mediaUpdated
{
"method": "mediaUpdated",
"msgToken": "s14-audit-9",
"sessionId": "s14-session",
"eventSeq": 3,
"data": {
"state": "applied",
"revision": 2,
"mediaRevision": 3,
"tracks": [
{
"trackId": "video-rear",
"kind": "video",
"sourceId": "rear",
"sourceType": "camera",
"direction": "sendonly",
"codec": "H264",
"state": "active"
}
],
"requestToken": "s14-25"
}
}S14-M15 · mediaUpdate
{
"msgToken": "s14-28",
"method": "mediaUpdate",
"sessionId": "s14-session",
"params": {
"operation": "add",
"expectedRevision": 2,
"tracks": [
{
"trackId": "screen-1",
"kind": "video",
"sourceId": "display-1",
"sourceType": "screen",
"direction": "sendonly",
"codec": "H264",
"state": "requested"
}
],
"consentIds": [
"screen-consent"
]
}
}S14-M16 · mediaUpdated
{
"msgToken": "s14-28",
"method": "mediaUpdated",
"sessionId": "s14-session",
"data": {
"state": "pending",
"revision": 3,
"mediaRevision": 4,
"tracks": [
{
"trackId": "screen-1",
"kind": "video",
"sourceId": "display-1",
"sourceType": "screen",
"direction": "sendonly",
"codec": "H264",
"state": "requested"
}
],
"requestToken": "s14-28"
},
"code": 200
}S14-M17 · mediaOffer
{
"msgToken": "s14-29",
"method": "mediaOffer",
"sessionId": "s14-session",
"params": {
"mediaRevision": 4,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S14-M18 · mediaAnswer
{
"msgToken": "s14-29",
"method": "mediaAnswer",
"sessionId": "s14-session",
"data": {
"mediaRevision": 4,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
},
"code": 200
}S14-M19 · mediaState
{
"msgToken": "s14-30",
"method": "mediaState",
"sessionId": "s14-session",
"params": {
"mediaRevision": 4,
"state": "connected"
}
}S14-M20 · requestAck
{
"msgToken": "s14-30",
"method": "requestAck",
"sessionId": "s14-session",
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 4,
"state": "connected"
}
},
"code": 200
}S14-M36 · trackState
{
"msgToken": "s14-observed-screen-1-4",
"method": "trackState",
"sessionId": "s14-session",
"data": {
"trackId": "screen-1",
"state": "active",
"mediaRevision": 4
}
}S14-M32 · mediaUpdated
{
"method": "mediaUpdated",
"msgToken": "s14-audit-10",
"sessionId": "s14-session",
"eventSeq": 4,
"data": {
"state": "applied",
"revision": 3,
"mediaRevision": 4,
"tracks": [
{
"trackId": "screen-1",
"kind": "video",
"sourceId": "display-1",
"sourceType": "screen",
"direction": "sendonly",
"codec": "H264",
"state": "active"
}
],
"requestToken": "s14-28"
}
}S14-M21 · mediaUpdate
{
"msgToken": "s14-31",
"method": "mediaUpdate",
"sessionId": "s14-session",
"params": {
"operation": "setQuality",
"expectedRevision": 3,
"trackIds": [
"video-rear",
"screen-1"
],
"profile": "audioOnly"
}
}S14-M22 · mediaUpdated
{
"msgToken": "s14-31",
"method": "mediaUpdated",
"sessionId": "s14-session",
"data": {
"state": "pending",
"revision": 4,
"mediaRevision": 5,
"tracks": [],
"requestToken": "s14-31"
},
"code": 200
}S14-M23 · mediaOffer
{
"msgToken": "s14-32",
"method": "mediaOffer",
"sessionId": "s14-session",
"params": {
"mediaRevision": 5,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S14-M24 · mediaAnswer
{
"msgToken": "s14-32",
"method": "mediaAnswer",
"sessionId": "s14-session",
"data": {
"mediaRevision": 5,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
},
"code": 200
}S14-M25 · mediaState
{
"msgToken": "s14-33",
"method": "mediaState",
"sessionId": "s14-session",
"params": {
"mediaRevision": 5,
"state": "connected"
}
}S14-M26 · requestAck
{
"msgToken": "s14-33",
"method": "requestAck",
"sessionId": "s14-session",
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 5,
"state": "connected"
}
},
"code": 200
}S14-M37 · trackState
{
"msgToken": "s14-observed-screen-1-5",
"method": "trackState",
"sessionId": "s14-session",
"data": {
"trackId": "screen-1",
"state": "stopped",
"mediaRevision": 5
}
}S14-M44 · trackState
{
"msgToken": "s14-rear-stopped",
"method": "trackState",
"sessionId": "s14-session",
"data": {
"trackId": "video-rear",
"state": "stopped",
"mediaRevision": 5
}
}S14-M33 · mediaUpdated
{
"method": "mediaUpdated",
"msgToken": "s14-audit-11",
"sessionId": "s14-session",
"eventSeq": 5,
"data": {
"state": "applied",
"revision": 4,
"mediaRevision": 5,
"tracks": [],
"requestToken": "s14-31"
}
}S14-M27 · sessionEnd
{
"msgToken": "s14-34",
"method": "sessionEnd",
"sessionId": "s14-session",
"params": {
"reason": "userHangup"
}
}S14-M28 · sessionEnded
{
"msgToken": "s14-34",
"method": "sessionEnded",
"sessionId": "s14-session",
"data": {
"state": "ended",
"reason": "userHangup"
},
"code": 200
}S14-M29 · mediaUpdate
{
"msgToken": "s14-extra-28",
"method": "mediaUpdate",
"sessionId": "s14-another",
"params": {
"operation": "remove",
"expectedRevision": 0,
"trackIds": [
"screen-1"
]
}
}S14-M30 · mediaUpdated
{
"msgToken": "s14-extra-28",
"method": "mediaUpdated",
"sessionId": "s14-another",
"code": 200,
"data": {
"state": "pending",
"revision": 1,
"mediaRevision": 2,
"tracks": [],
"requestToken": "s14-extra-28"
}
}S14-M38 · mediaOffer
{
"msgToken": "s14-remove-offer",
"method": "mediaOffer",
"sessionId": "s14-another",
"params": {
"mediaRevision": 2,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP offer>"
}
}
}S14-M39 · mediaAnswer
{
"msgToken": "s14-remove-offer",
"method": "mediaAnswer",
"sessionId": "s14-another",
"code": 200,
"data": {
"mediaRevision": 2,
"webrtc": {
"iceMode": "complete",
"sdp": "<SDP answer>"
}
}
}S14-M40 · mediaState
{
"msgToken": "s14-remove-connected",
"method": "mediaState",
"sessionId": "s14-another",
"params": {
"mediaRevision": 2,
"state": "connected"
}
}S14-M41 · requestAck
{
"msgToken": "s14-remove-connected",
"method": "requestAck",
"sessionId": "s14-another",
"code": 200,
"data": {
"requestMethod": "mediaState",
"result": {
"mediaRevision": 2,
"state": "connected"
}
}
}S14-M42 · trackState
{
"msgToken": "s14-screen-stopped",
"method": "trackState",
"sessionId": "s14-another",
"data": {
"trackId": "screen-1",
"state": "stopped",
"mediaRevision": 2
}
}S14-M43 · mediaUpdated
{
"msgToken": "s14-r1",
"method": "mediaUpdated",
"sessionId": "s14-another",
"eventSeq": 1,
"data": {
"state": "applied",
"revision": 1,
"mediaRevision": 2,
"tracks": [],
"requestToken": "s14-extra-28"
}
}媒体与本地动作
| 编号 | 路径 | 格式与约束 |
|---|---|---|
| S14-R01 | D→P | ICE与DTLS握手,非MQTT;失败走S11 |
| S14-R02 | D→P | WebRTC H264视频轨;音轨保持 |
| S14-R03 | D→P | ICE与DTLS握手,非MQTT;失败走S11 |
| S14-R04 | D→P | ICE与DTLS握手,非MQTT;失败走S11 |
| S14-R05 | D→P | WebRTC独立screen-1视频轨;平台按mid映射,不经MQTT |
| S14-R06 | D→P | ICE与DTLS握手,非MQTT;失败走S11 |
| S14-R07 | D→P | WebRTC ICE/DTLS;移除屏幕后确认新代次;15秒失败释放候选资源 |
异常、状态与资源释放
路由与信封见公共约定;阶段性状态不代表最终完成。操作终态时限见命令手册;编号、超时等元信息不发送。
能力不足422、无权限403、资源/修订号冲突409、超时504按S11处理,不静默开启设备能力。同token只重放原结果;事件按eventSeq去重,旧会话/端代次不可恢复。验证本页正常路径、alt分支及支持范围断言。文档通过不代表代码或硬件已实现。
质量切换audioOnly同时停止video-rear和screen-1,M37/M44分别报告两个被停止轨;媒体节点也须确认不再转发,不能只收到一个轨报告就将整个计划applied。先本地停止已撤权画面,再协商收敛,不等待网络才停止采集。
验证入口
更新日志
2026/10/16 16:04
查看所有更新日志
fe3a7-docs(AI与音视频): 按场景整理完整接入流程与命令契约于
