MQTT + UDP 混合通訊協議文件

基於程式碼實作整理的 MQTT + UDP 混合通訊協議文件,概述裝置端與伺服器之間如何透過 MQTT 進行控制訊息傳輸,透過 UDP 進行音訊資料傳輸的互動方式。

1. 協議概覽

本協議採用混合傳輸方式:

  • MQTT:用於控制訊息、狀態同步、JSON 資料交換
  • UDP:用於即時音訊資料傳輸,支援加密

1.1 協議特點

  • 雙通道設計:控制與資料分離,確保即時性
  • 加密傳輸:UDP 音訊資料使用 AES-CTR 加密
  • 序列號保護:防止資料包重放和亂序
  • 自動重連:MQTT 連線斷開時自動重連

2. 總體流程概覽

  sequenceDiagram
    participant Device as ESP32 裝置
    participant MQTT as MQTT 伺服器
    participant UDP as UDP 伺服器

    Note over Device, UDP: 1. 建立 MQTT 連線
    Device->>MQTT: MQTT Connect
    MQTT->>Device: Connected

    Note over Device, UDP: 2. 請求音訊通道
    Device->>MQTT: Hello Message (type: "hello", transport: "udp")
    MQTT->>Device: Hello Response (UDP 連線資訊 + 加密金鑰)

    Note over Device, UDP: 3. 建立 UDP 連線
    Device->>UDP: UDP Connect
    UDP->>Device: Connected

    Note over Device, UDP: 4. 音訊資料傳輸
    loop 音訊串流傳輸
        Device->>UDP: 加密音訊資料 (Opus)
        UDP->>Device: 加密音訊資料 (Opus)
    end

    Note over Device, UDP: 5. 控制訊息交換
    par 控制訊息
        Device->>MQTT: Listen/TTS/MCP 訊息
        MQTT->>Device: STT/TTS/MCP 回應
    end

    Note over Device, UDP: 6. 關閉連線
    Device->>MQTT: Goodbye Message
    Device->>UDP: Disconnect

3. MQTT 控制通道

3.1 連線建立

裝置透過 MQTT 連接到伺服器,連線參數包括:

  • Endpoint:MQTT 伺服器地址和埠號
  • Client ID:裝置唯一識別符
  • Username/Password:認證憑證
  • Keep Alive:心跳間隔(預設240秒)

3.2 Hello 訊息交換

3.2.1 裝置端傳送 Hello

{
  "type": "hello",
  "version": 3,
  "transport": "udp",
  "features": {
    "mcp": true
  },
  "audio_params": {
    "format": "opus",
    "sample_rate": 16000,
    "channels": 1,
    "frame_duration": 60
  }
}

3.2.2 伺服器回應 Hello

{
  "type": "hello",
  "transport": "udp",
  "session_id": "xxx",
  "audio_params": {
    "format": "opus",
    "sample_rate": 24000,
    "channels": 1,
    "frame_duration": 60
  },
  "udp": {
    "server": "192.168.1.100",
    "port": 8888,
    "key": "0123456789ABCDEF0123456789ABCDEF",
    "nonce": "0123456789ABCDEF0123456789ABCDEF"
  }
}

欄位說明:

  • udp.server:UDP 伺服器地址
  • udp.port:UDP 伺服器埠號
  • udp.key:AES 加密金鑰(十六進位字串)
  • udp.nonce:AES 加密隨機數(十六進位字串)

3.3 JSON 訊息類型

3.3.1 裝置端→伺服器

Listen 訊息

{
  "session_id": "xxx",
  "type": "listen",
  "state": "start",
  "mode": "manual"
}

Abort 訊息

{
  "session_id": "xxx",
  "type": "abort",
  "reason": "wake_word_detected"
}

MCP 訊息

{
  "session_id": "xxx",
  "type": "mcp",
  "payload": {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {...}
  }
}

Goodbye 訊息

{
  "session_id": "xxx",
  "type": "goodbye"
}

3.3.2 伺服器→裝置端

支援的訊息類型與 WebSocket 協議一致,包括:

  • STT:語音辨識結果
  • TTS:語音合成控制
  • LLM:情感表達控制
  • MCP:物聯網控制
  • System:系統控制
  • Custom:自訂訊息(可選)

4. UDP 音訊通道

4.1 連線建立

裝置收到 MQTT Hello 回應後,使用其中的 UDP 連線資訊建立音訊通道:

  1. 解析 UDP 伺服器地址和埠號
  2. 解析加密金鑰和隨機數
  3. 初始化 AES-CTR 加密上下文
  4. 建立 UDP 連線

4.2 音訊資料格式

4.2.1 加密音訊包結構

|type 1byte|flags 1byte|payload_len 2bytes|ssrc 4bytes|timestamp 4bytes|sequence 4bytes|
|payload payload_len bytes|

欄位說明:

  • type:資料包類型,固定為 0x01
  • flags:標誌位,目前未使用
  • payload_len:負載長度(網路位元組序)
  • ssrc:同步來源識別符
  • timestamp:時間戳記(網路位元組序)
  • sequence:序列號(網路位元組序)
  • payload:加密的 Opus 音訊資料

4.2.2 加密演算法

使用 AES-CTR 模式加密:

  • 金鑰:128位元,由伺服器提供
  • 隨機數:128位元,由伺服器提供
  • 計數器:包含時間戳記和序列號資訊

4.3 序列號管理

  • 傳送端local_sequence_ 單調遞增
  • 接收端remote_sequence_ 驗證連續性
  • 防重放:拒絕序列號小於期望值的資料包
  • 容錯處理:允許輕微的序列號跳躍,記錄警告

4.4 錯誤處理

  1. 解密失敗:記錄錯誤,丟棄資料包
  2. 序列號異常:記錄警告,但仍處理資料包
  3. 資料包格式錯誤:記錄錯誤,丟棄資料包

5. 狀態管理

5.1 連線狀態

  stateDiagram
    direction TB
    [*] --> Disconnected
    Disconnected --> MqttConnecting: StartMqttClient()
    MqttConnecting --> MqttConnected: MQTT Connected
    MqttConnecting --> Disconnected: Connect Failed
    MqttConnected --> RequestingChannel: OpenAudioChannel()
    RequestingChannel --> ChannelOpened: Hello Exchange Success
    RequestingChannel --> MqttConnected: Hello Timeout/Failed
    ChannelOpened --> UdpConnected: UDP Connect Success
    UdpConnected --> AudioStreaming: Start Audio Transfer
    AudioStreaming --> UdpConnected: Stop Audio Transfer
    UdpConnected --> ChannelOpened: UDP Disconnect
    ChannelOpened --> MqttConnected: CloseAudioChannel()
    MqttConnected --> Disconnected: MQTT Disconnect

5.2 狀態檢查

裝置透過以下條件判斷音訊通道是否可用:

bool IsAudioChannelOpened() const {
    return udp_ != nullptr && !error_occurred_ && !IsTimeout();
}

6. 設定參數

6.1 MQTT 設定

從設定中讀取的設定項目:

  • endpoint:MQTT 伺服器地址
  • client_id:客戶端識別符
  • username:使用者名稱
  • password:密碼
  • keepalive:心跳間隔(預設240秒)
  • publish_topic:發布主題

6.2 音訊參數

  • 格式:Opus
  • 取樣率:16000 Hz(裝置端)/ 24000 Hz(伺服器端)
  • 聲道數:1(單聲道)
  • 幀時長:60ms

7. 錯誤處理與重連

7.1 MQTT 重連機制

  • 連線失敗時自動重試
  • 支援錯誤上報控制
  • 斷線時觸發清理流程

7.2 UDP 連線管理

  • 連線失敗時不自動重試
  • 依賴 MQTT 通道重新協商
  • 支援連線狀態查詢

7.3 逾時處理

基底類別 Protocol 提供逾時檢測:

  • 預設逾時時間:120 秒
  • 基於最後接收時間計算
  • 逾時時自動標記為不可用

8. 安全考量

8.1 傳輸加密

  • MQTT:支援 TLS/SSL 加密(埠號8883)
  • UDP:使用 AES-CTR 加密音訊資料

8.2 認證機制

  • MQTT:使用者名稱/密碼認證
  • UDP:透過 MQTT 通道分發金鑰

8.3 防重放攻擊

  • 序列號單調遞增
  • 拒絕過期資料包
  • 時間戳記驗證

9. 效能最佳化

9.1 並行控制

使用互斥鎖保護 UDP 連線:

std::lock_guard<std::mutex> lock(channel_mutex_);

9.2 記憶體管理

  • 動態建立/銷毀網路物件
  • 智慧指標管理音訊資料包
  • 及時釋放加密上下文

9.3 網路最佳化

  • UDP 連線重用
  • 資料包大小最佳化
  • 序列號連續性檢查

10. 與 WebSocket 協議的比較

特性MQTT + UDPWebSocket
控制通道MQTTWebSocket
音訊通道UDP (加密)WebSocket (二進位)
即時性高 (UDP)中等
可靠性中等
複雜度
加密AES-CTRTLS
防火牆友好度

11. 部署建議

11.1 網路環境

  • 確保 UDP 埠號可達
  • 設定防火牆規則
  • 考慮 NAT 穿透

11.2 伺服器設定

  • MQTT Broker 設定
  • UDP 伺服器部署
  • 金鑰管理系統

11.3 監控指標

  • 連線成功率
  • 音訊傳輸延遲
  • 資料包遺失率
  • 解密失敗率

12. 總結

MQTT + UDP 混合協議透過以下設計實作高效的音視訊通訊:

  • 分離式架構:控制與資料通道分離,各司其職
  • 加密保護:AES-CTR 確保音訊資料安全傳輸
  • 序列化管理:防止重放攻擊和資料亂序
  • 自動恢復:支援連線斷開後的自動重連
  • 效能最佳化:UDP 傳輸保證音訊資料的即時性

該協議適用於對即時性要求較高的語音互動場景,但需要在網路複雜度和傳輸效能之間做出權衡。

相關文件