MQTT + UDP 混合通信プロトコル文書

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暗号化キー(16進文字列)
  • udp.nonce:AES暗号化ノンス(16進文字列)

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:IoT制御
  • 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転送で音声データのリアルタイム性を保証

このプロトコルはリアルタイム性要求の高い音声対話シーンに適用されますが、ネットワーク複雑度と転送パフォーマンス間でトレードオフを考慮する必要があります。

関連文書