diff --git a/状态机.md b/状态机.md index 75f0da2..4ab368c 100644 --- a/状态机.md +++ b/状态机.md @@ -1,183 +1,211 @@ -状态机就是“把一次视频会话/设备流程拆成明确状态,并规定状态之间怎么流转”的机制。 -device-bootstrap 就是“设备启动或上线时,先来云端报到、认证,并领取连接 MQTT/实时系统所需临时配置和凭证”的接入服务。 +```markdown +# 状态机与 `device-bootstrap` 术语说明 -1. 状态机是什么意思 -1.1 通俗解释 -状态机可以理解成一张流程规则表。 +## 一、核心结论 -比如一次智能锁视频通话,不应该只是简单地说: +**状态机**:用于管理一次视频会话或设备流程的状态变化,明确规定当前处于什么状态、下一步能进入什么状态、异常时如何处理。 +**`device-bootstrap`**:设备启动或上线时访问的接入服务,用于完成设备认证,并下发 MQTT 临时凭证、topic 权限、连接配置和设备能力配置。 + +--- + +## 二、状态机是什么意思 + +### 1. 通俗理解 + +状态机可以理解成一张**流程规则表**。 + +比如一次智能锁视频通话,不应该只有: + +```text 开始通话 结束通话 -而是应该有一系列明确状态: +``` + +而应该有完整流程: + +```text +待创建 -> 呼叫中 -> 已接听 -> 连接中 -> 已连接 -> 已结束 +``` -待创建 -> 呼叫中 -> 已接听 -> 连接中 -> 已连接 -> 通话中 -> 已结束 每个状态只能按照规则进入下一个状态。 例如: +```text pending -> ringing -> accepted -> connecting -> connected -> ended -不能乱跳,比如: +``` +不能随意跳转,例如: + +```text pending -> connected -通常就不合理,因为中间还没经过设备接听和媒体连接。 +``` -1.2 在你这个智能锁项目里的含义 -你们旧方案里可能是通过 UDP 字段告诉 APP 或锁: +通常是不合理的,因为中间还没有经过设备接听、媒体连接等步骤。 +--- + +## 三、状态机在智能锁项目中的作用 + +旧方案里,可能通过 UDP 字段直接通知 APP 或锁: + +```text 开始视频 结束视频 -这种方式简单,但问题是: +``` -APP 以为开始了,设备没收到 +这种方式简单,但容易出现以下问题: -设备接听了,APP 已经取消 +- APP 以为开始了,设备没收到 +- 设备接听了,APP 已经取消 +- 网络抖动导致消息重复 +- 云端不知道当前到底是“呼叫中”还是“已连接” +- 通话失败后不好追踪原因 -网络抖动导致消息重复 - -云端不知道现在到底是“呼叫中”还是“已连接” - -通话失败后不好追踪原因 - -所以新方案里要用 session-orchestrator 管理状态机。 +新方案中,由 `session-orchestrator` 统一管理状态机。 也就是云端统一记录: +```text 这个 sessionId 当前到底处于什么状态 -2. 视频会话状态机例子 -2.1 推荐状态 -pending -ringing -accepted -connecting -connected -degraded -switching_route -recovered -ended -rejected -timeout -failed -可以翻译成: +``` -状态 +--- -中文含义 +## 四、视频会话状态机示例 -pending +### 1. 推荐状态 -会话刚创建,等待发起呼叫 +| 状态 | 中文含义 | +|---|---| +| `pending` | 会话刚创建,等待发起呼叫 | +| `ringing` | 正在呼叫设备 / 设备响铃 | +| `accepted` | 设备已接听 | +| `connecting` | APP 和设备正在建立媒体连接 | +| `connected` | 音视频已连通 | +| `degraded` | 通话质量下降 | +| `switching_route` | 正在切换媒体线路 | +| `recovered` | 切换后恢复正常 | +| `ended` | 正常结束 | +| `rejected` | 被拒接 | +| `timeout` | 超时未响应 | +| `failed` | 异常失败 | -ringing +--- -正在呼叫设备 / 设备响铃 - -accepted - -设备已接听 - -connecting - -APP 和设备正在建立媒体连接 - -connected - -音视频已连通 - -degraded - -通话质量下降 - -switching_route - -正在切换媒体线路 - -recovered - -切换后恢复正常 - -ended - -正常结束 - -rejected - -被拒接 - -timeout - -超时未响应 - -failed - -异常失败 - -2.2 状态流转例子 -一次正常视频通话: +### 2. 正常通话流程 +```text pending -> ringing -> accepted -> connecting -> connected -> ended -中文就是: +``` +对应中文流程: + +```text 创建会话 -> 呼叫设备 -> 设备接听 -> 建立 WebRTC / ZLM 连接 -> 通话成功 -> 挂断结束 -2.3 异常情况例子 -设备不在线 +``` + +--- + +### 3. 异常流程示例 + +#### 设备不在线 + +```text pending -> failed -原因: +``` +失败原因: + +```text device_offline -设备没有响应 +``` + +#### 设备没有响应 + +```text pending -> ringing -> timeout -原因: +``` +失败原因: + +```text invite_timeout -用户取消 +``` + +#### 用户取消 + +```text pending -> ringing -> ended -原因: +``` +结束原因: + +```text caller_cancelled -设备拒接 -pending -> ringing -> rejected -原因: +``` +#### 设备拒接 + +```text +pending -> ringing -> rejected +``` + +失败原因: + +```text device_rejected -WebRTC 连接失败,切 ZLMediaKit +``` + +#### WebRTC 连接失败后切换 ZLMediaKit + +```text pending -> ringing -> accepted -> connecting - -> failed_p2p - -> switching_route - -> connected -或者更规范一点: - -connecting -> degraded -> switching_route -> recovered -> connected -3. 为什么一定要状态机 -3.1 保证流程不乱 +``` + +--- + +## 五、为什么需要状态机 + +### 1. 保证流程不乱 + 没有状态机时,可能出现: +```text 已经挂断了,又收到设备 accept -那系统不知道该怎么办。 +``` 有状态机后可以规定: +```text ended 状态下收到 accept,直接忽略或记录为迟到事件 -3.2 方便排查问题 -有状态机后,每个会话都能查: +``` +--- + +### 2. 方便排查问题 + +有状态机后,可以按 `sessionId` 查完整流程: + +```text sessionId = abc123 pending at 10:00:01 ringing at 10:00:02 @@ -185,21 +213,344 @@ accepted at 10:00:05 connecting at 10:00:06 timeout at 10:00:16 reason = ice_timeout -这样就能知道失败原因是: +``` -设备接了,但 WebRTC 没连上 -而不是一句模糊的: +这样可以明确知道失败原因是: +```text +设备接听了,但 WebRTC 没连上 +``` + +而不是笼统地显示: + +```text 通话失败 -3.3 方便做超时和重试 -比如: +``` -呼叫设备 15 秒没响应,自动超时 +--- -WebRTC 10 秒没连上,切 ZLM +### 3. 方便做超时和重试 -设备 ACK 没回来,重发 invite +状态机可以支持: -通话结束后清理 token 和流资源 +- 呼叫设备 15 秒没响应,自动超时 +- WebRTC 10 秒没连上,切换 ZLMediaKit +- 设备 ACK 没回来,重发 invite +- 通话结束后清理 token 和流媒体资源 -这些都依赖状态机。 \ No newline at end of file +--- + +## 六、`device-bootstrap` 是什么意思 + +### 1. 通俗理解 + +`device-bootstrap` 可以理解为: + +> 设备上线入口 / 设备启动接入服务 / 设备报到服务 + +设备开机后,不应该直接随便连接 MQTT,也不应该把固定账号密码写死在固件里。 + +更安全的做法是: + +```text +设备开机 + -> 调用 device-bootstrap + -> 云端验证设备身份 + -> 云端返回 MQTT 地址、临时账号、topic 权限、配置 + -> 设备再连接 BifroMQ +``` + +--- + +## 七、`device-bootstrap` 在项目中的作用 + +### 1. 设备启动时的流程 + +设备,也就是 WiFi 网关锁,启动后先请求: + +```http +POST /device/bootstrap +``` + +请求中通常携带: + +```json +{ + "deviceId": "device_001", + "firmwareVersion": "1.0.0", + "timestamp": 1710000000, + "signature": "xxxxx", + "capabilities": { + "webrtc": true, + "zlm": true, + "ai": true + } +} +``` + +云端验证通过后返回: + +```json +{ + "mqtt": { + "host": "mqtt.example.com", + "port": 8883, + "clientId": "lock_xxx", + "username": "tmp_user", + "password": "tmp_password", + "expiresIn": 3600 + }, + "topics": { + "subscribe": [ + "tenant/t1/device/d1/control", + "tenant/t1/session/+/signal/device" + ], + "publish": [ + "tenant/t1/device/d1/status", + "tenant/t1/device/d1/event", + "tenant/t1/session/+/signal/app" + ] + }, + "config": { + "heartbeatInterval": 30, + "webrtcEnabled": true, + "zlmEnabled": true, + "aiEnabled": true + } +} +``` + +含义是: + +- 设备认证通过 +- 返回 MQTT 连接地址 +- 返回临时账号密码 +- 返回允许订阅的 topic +- 返回允许发布的 topic +- 返回心跳周期 +- 返回设备功能开关配置 + +--- + +## 八、`device-bootstrap` 解决的问题 + +### 1. 避免设备写死 MQTT 密码 + +不推荐: + +```text +所有设备固件里写同一个 MQTT 用户名和密码 +``` + +风险是:一旦泄露,所有设备都会受影响。 + +推荐: + +```text +每台设备启动时领取自己的临时凭证 +``` + +--- + +### 2. 控制设备权限 + +例如设备 `device_001` 只能访问: + +```text +tenant/t1/device/device_001/... +``` + +不能访问: + +```text +tenant/t1/device/device_002/... +``` + +--- + +### 3. 支持设备配置下发 + +例如某个设备支持 WebRTC: + +```json +{ + "webrtcEnabled": true +} +``` + +另一个旧设备不支持: + +```json +{ + "webrtcEnabled": false +} +``` + +系统就可以按设备能力下发不同策略。 + +--- + +### 4. 支持灰度升级 + +例如只让 10% 的设备启用 ZLMediaKit: + +```json +{ + "zlmEnabled": true +} +``` + +其它设备暂时不开启。 + +--- + +## 九、`device-bootstrap` 和 `session-orchestrator` 的区别 + +| 模块 | 作用 | 类比 | +|---|---|---| +| `device-bootstrap` | 设备上线认证、领取 MQTT 凭证、获取配置 | 门卫 / 报到处 | +| `session-orchestrator` | 管理一次视频会话的创建、呼叫、接听、连接、切路、挂断 | 调度员 / 指挥中心 | +| BifroMQ | 负责消息通道 | 对讲机频道 / 消息总线 | +| ZLMediaKit / WebRTC | 负责音视频传输 | 真正的视频通话线路 | + +简单理解: + +```text +device-bootstrap 管设备怎么接入系统 +session-orchestrator 管一次通话怎么开始、进行、结束 +``` + +--- + +## 十、完整流程���例 + +### 1. 设备上线流程 + +```text +WiFi锁开机 + -> 调用 device-bootstrap + -> bootstrap 验证设备身份 + -> 返回 MQTT 临时凭证 + -> WiFi锁连接 BifroMQ + -> WiFi锁上报 online +``` + +这部分由 `device-bootstrap` 负责。 + +--- + +### 2. 用户发起视频通话流程 + +```text +APP 点击视频通话 + -> 调用 starlock + -> starlock 校验用户是否有权限访问这把锁 + -> starlock 调用 session-orchestrator 创建 session + -> session-orchestrator 通过 BifroMQ 给设备发 invite + -> 设备响铃并返回 accept + -> APP 和设备交换 WebRTC signaling + -> 建立 P2P / TURN / ZLM 媒体链路 +``` + +这部分由 `session-orchestrator` 负责。 + +--- + +### 3. 通话中弱网切换流程 + +```text +APP 上报丢包高 +设备上报 RTT 高 +session-orchestrator 判断质量差 + -> 下发 switch-route + -> APP 和设备切到 ZLMediaKit +``` + +这仍然属于状态机控制。 + +--- + +## 十一、���团队的简短解释 + +### 状态机一句话 + +> 状态机就是云端统一管理“这次通话现在进行到哪一步、下一步允许做什么、超时或异常怎么处理”的规则系统。 + +### `device-bootstrap` 一句话 + +> `device-bootstrap` 就是设备开机后的接入报到服务,负责认证设备,并给设备下发 MQTT 临时凭证、topic 权限和能力配置。 + +--- + +## 十二、项目落地建议 + +### 1. 状态机第一版建议 + +第一版状态不要太复杂,建议先支持: + +```text +created +ringing +accepted +connecting +connected +ended +rejected +timeout +failed +``` + +后续稳定后再增加: + +```text +degraded +switching_route +recovered +``` + +--- + +### 2. `device-bootstrap` 第一版必须返回 + +```text +mqttHost +mqttPort +clientId +username +password +expiresIn +subscribeTopics +publishTopics +heartbeatInterval +capabilities +``` + +不要让设备直接写死 MQTT 账号密码。 + +--- + +## 十三、最简对照表 + +| 模块 | 负责内容 | +|---|---| +| 状态机 | 管“通话流程” | +| `device-bootstrap` | 管“设备上线接入” | +| BifroMQ | 管“消息通道” | +| WebRTC / ZLM | 管“视频声音怎么传” | +| `starlock` | 管“用户有没有权限” | +| `starcloud` | 管“共享业务能力” | + +--- + +## 十四、总结 + +在智能锁实时系统中: + +```text +用户有没有权限开视频:starlock / starcloud 判断 +设备怎么连上云:device-bootstrap +控制消息怎么传:BifroMQ +这次通话现在到哪一步:session-orchestrator 状态机 +视频音频怎么传:WebRTC / TURN / ZLMediaKit +``` +``` \ No newline at end of file