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