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接続情報を使用して音声チャネルを確立:
- UDPサーバーアドレスとポートを解析
- 暗号化キーとノンスを解析
- AES-CTR暗号化コンテキストを初期化
- UDP接続を確立
4.2 音声データ形式
4.2.1 暗号化音声パケット構造
|type 1byte|flags 1byte|payload_len 2bytes|ssrc 4bytes|timestamp 4bytes|sequence 4bytes|
|payload payload_len bytes|
フィールド説明:
type
:データパケットタイプ、固定で0x01flags
:フラグビット、現在未使用payload_len
:ペイロード長(ネットワークバイトオーダー)ssrc
:同期ソース識別子timestamp
:タイムスタンプ(ネットワークバイトオーダー)sequence
:シーケンス番号(ネットワークバイトオーダー)payload
:暗号化されたOpus音声データ
4.2.2 暗号化アルゴリズム
AES-CTRモードを使用して暗号化:
- キー:128ビット、サーバーが提供
- ノンス:128ビット、サーバーが提供
- カウンタ:タイムスタンプとシーケンス番号情報を含む
4.3 シーケンス番号管理
- 送信側:
local_sequence_
単調増加 - 受信側:
remote_sequence_
連続性検証 - リプレイ防止:期待値より小さいシーケンス番号のデータパケットを拒否
- エラー耐性処理:軽微なシーケンス番号スキップを許可、警告を記録
4.4 エラー処理
- 復号失敗:エラーログ記録、データパケット破棄
- シーケンス番号異常:警告ログ記録、但しデータパケットは処理
- データパケット形式エラー:エラーログ記録、データパケット破棄
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 + UDP | WebSocket |
---|---|---|
制御チャネル | MQTT | WebSocket |
音声チャネル | UDP (暗号化) | WebSocket (バイナリ) |
リアルタイム性 | 高 (UDP) | 中等 |
信頼性 | 中等 | 高 |
複雑度 | 高 | 低 |
暗号化 | AES-CTR | TLS |
ファイアウォール親和性 | 低 | 高 |
11. デプロイ推奨
11.1 ネットワーク環境
- UDPポートが到達可能であることを確保
- ファイアウォールルールを設定
- NAT穿透を考慮
11.2 サーバー設定
- MQTT Broker設定
- UDPサーバーデプロイ
- キー管理システム
11.3 監視指標
- 接続成功率
- 音声転送遅延
- データパケット損失率
- 復号失敗率
12. まとめ
MQTT + UDP混合プロトコルは以下の設計で効率的な音声通信を実現:
- 分離アーキテクチャ:制御とデータチャネル分離、それぞれの役割を果たす
- 暗号化保護:AES-CTRで音声データの安全転送を確保
- シーケンス管理:リプレイ攻撃とデータアウトオブオーダーを防止
- 自動回復:接続切断後の自動再接続をサポート
- パフォーマンス最適化:UDP転送で音声データのリアルタイム性を保証
このプロトコルはリアルタイム性要求の高い音声対話シーンに適用されますが、ネットワーク複雑度と転送パフォーマンス間でトレードオフを考慮する必要があります。
関連文書
- WebSocket通信プロトコル - WebSocket通信プロトコル詳細説明
- MCPプロトコル文書 - MCPプロトコル相互作用フロー
- MCP使用ガイド - MCPプロトコル使用方法