```markdown # 状态机与 `device-bootstrap` 术语说明 ## 一、核心结论 **状态机**:用于管理一次视频会话或设备流程的状态变化,明确规定当前处于什么状态、下一步能进入什么状态、异常时如何处理。 **`device-bootstrap`**:设备启动或上线时访问的接入服务,用于完成设备认证,并下发 MQTT 临时凭证、topic 权限、连接配置和设备能力配置。 --- ## 二、状态机是什么意思 ### 1. 通俗理解 状态机可以理解成一张**流程规则表**。 比如一次智能锁视频通话,不应该只有: ```text 开始通话 结束通话 ``` 而应该有完整流程: ```text 待创建 -> 呼叫中 -> 已接听 -> 连接中 -> 已连接 -> 已结束 ``` 每个状态只能按照规则进入下一个状态。 例如: ```text pending -> ringing -> accepted -> connecting -> connected -> ended ``` 不能随意跳转,例如: ```text pending -> connected ``` 通常是不合理的,因为中间还没有经过设备接听、媒体连接等步骤。 --- ## 三、状态机在智能锁项目中的作用 旧方案里,可能通过 UDP 字段直接通知 APP 或锁: ```text 开始视频 结束视频 ``` 这种方式简单,但容易出现以下问题: - APP 以为开始了,设备没收到 - 设备接听了,APP 已经取消 - 网络抖动导致消息重复 - 云端不知道当前到底是“呼叫中”还是“已连接” - 通话失败后不好追踪原因 新方案中,由 `session-orchestrator` 统一管理状态机。 也就是云端统一记录: ```text 这个 sessionId 当前到底处于什么状态 ``` --- ## 四、视频会话状态机示例 ### 1. 推荐状态 | 状态 | 中文含义 | |---|---| | `pending` | 会话刚创建,等待发起呼叫 | | `ringing` | 正在呼叫设备 / 设备响铃 | | `accepted` | 设备已接听 | | `connecting` | APP 和设备正在建立媒体连接 | | `connected` | 音视频已连通 | | `degraded` | 通话质量下降 | | `switching_route` | 正在切换媒体线路 | | `recovered` | 切换后恢复正常 | | `ended` | 正常结束 | | `rejected` | 被拒接 | | `timeout` | 超时未响应 | | `failed` | 异常失败 | --- ### 2. 正常通话流程 ```text pending -> ringing -> accepted -> connecting -> connected -> ended ``` 对应中文流程: ```text 创建会话 -> 呼叫设备 -> 设备接听 -> 建立 WebRTC / ZLM 连接 -> 通话成功 -> 挂断结束 ``` --- ### 3. 异常流程示例 #### 设备不在线 ```text pending -> failed ``` 失败原因: ```text device_offline ``` #### 设备没有响应 ```text pending -> ringing -> timeout ``` 失败原因: ```text invite_timeout ``` #### 用户取消 ```text pending -> ringing -> ended ``` 结束原因: ```text caller_cancelled ``` #### 设备拒接 ```text pending -> ringing -> rejected ``` 失败原因: ```text device_rejected ``` #### WebRTC 连接失败后切换 ZLMediaKit ```text pending -> ringing -> accepted -> connecting -> degraded -> switching_route -> recovered -> connected ``` --- ## 五、为什么需要状态机 ### 1. 保证流程不乱 没有状态机时,可能出现: ```text 已经挂断了,又收到设备 accept ``` 有状态机后可以规定: ```text ended 状态下收到 accept,直接忽略或记录为迟到事件 ``` --- ### 2. 方便排查问题 有状态机后,可以按 `sessionId` 查完整流程: ```text sessionId = abc123 pending at 10:00:01 ringing at 10:00:02 accepted at 10:00:05 connecting at 10:00:06 timeout at 10:00:16 reason = ice_timeout ``` 这样可以明确知道失败原因是: ```text 设备接听了,但 WebRTC 没连上 ``` 而不是笼统地显示: ```text 通话失败 ``` --- ### 3. 方便做超时和重试 状态机可以支持: - 呼叫设备 15 秒没响应,自动超时 - WebRTC 10 秒没连上,切换 ZLMediaKit - 设备 ACK 没回来,重发 invite - 通话结束后清理 token 和流媒体资源 --- ## 六、`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 ``` ```