architecture.md
jamjamの技術構成を定義する。本ドキュメントは実装の正とする。
1. システム概要
1.1 目的
ミュージシャンがインターネット越しにリアルタイムで演奏セッションを行うための、P2P音声通信を実現する。アプリケーション起因の片道遅延を限りなく0msに近づけることを目標とする(理論最小値: ~1.5ms、セクション11参照)。
1.2 設計原則
- アプリケーション起因の遅延を限りなく0msに近づける(遅延 ≒ ネットワークRTTのみ)
- 音声信号に余計な処理を加えない(ピュアな音声伝送)
- プリセット選択のみで動作開始可能、上級者は詳細パラメータを設定可能
2. 対応プラットフォーム
| プラットフォーム | 対応状況 | GUI フレームワーク |
|---|---|---|
| Windows | Phase 1 | Tauri 2.0 |
| macOS | Phase 1 | Tauri 2.0 |
| Linux | Phase 1 | Tauri 2.0 |
| iOS | Phase 5 | Flutter |
| Android | Phase 5 | Flutter |
3. 技術スタック
3.1 言語
| 用途 | 言語 |
|---|---|
| コアエンジン | Rust (stable) |
| デスクトップGUI | TypeScript (Tauri 2.0) |
| モバイルGUI | Dart (Flutter) |
| シグナリングサーバー | Rust |
3.2 主要ライブラリ
| 機能 | ライブラリ | 状態 |
|---|---|---|
| 音声I/O | cpal | 実装済 |
| リングバッファ | ringbuf | 実装済 |
| 非同期ランタイム | tokio | 実装済 |
| シリアライズ | bincode | 実装済 |
| ロギング | tracing | 実装済 |
| エラー処理 | thiserror | 実装済 |
| GUI(デスクトップ) | Tauri 2.0 | 実装済 |
| 音声コーデック(Opus) | opus-rs | 予定 |
| 音声コーデック(FLAC) | claxon | 予定 |
| GUI(モバイル) | Flutter + flutter_rust_bridge | 予定 |
3.3 実装済みモジュール構成
src/
├── audio/
│ ├── codec.rs # コーデック(PCM, Opus)
│ ├── device.rs # デバイス列挙
│ ├── engine.rs # オーディオエンジン
│ ├── error.rs # エラー型
│ └── plc.rs # Packet Loss Concealment
├── network/
│ ├── connection.rs # P2P接続管理
│ ├── encryption.rs # 暗号化レイヤー(AES-GCM, X25519)
│ ├── error.rs # ネットワークエラー
│ ├── fec.rs # 前方誤り訂正
│ ├── jitter_buffer.rs # Jitterバッファ
│ ├── sequence_tracker.rs # シーケンス追跡
│ ├── session.rs # セッション管理
│ ├── signaling.rs # シグナリング
│ ├── stun.rs # STUN クライアント
│ └── transport.rs # UDPトランスポート
├── protocol/
│ ├── mod.rs # プロトコル定義
│ └── packet.rs # パケット構造
├── bin/
│ └── signaling_server.rs # スタンドアロンシグナリングサーバー
├── lib.rs
└── main.rs
src-tauri/ # Tauri デスクトップアプリ
ui/
├── src/ # TypeScript ソース
│ ├── main.ts # エントリポイント
│ └── i18n/ # 国際化
└── locales/ # 翻訳ファイル(en.json, ja.json)
4. 音声サブシステム
4.1 オーディオI/O
| プラットフォーム | バックエンド |
|---|---|
| macOS | CoreAudio |
| Windows | WASAPI(標準)、ASIO(対応インターフェース使用時) |
| Linux | PipeWire(優先)、ALSA(フォールバック) |
4.2 音声フォーマット
| パラメータ | 選択肢 | デフォルト |
|---|---|---|
| サンプルレート | 44100 / 48000 / 96000 Hz | 48000 Hz |
| ビット深度 | 16 / 24 / 32 (float) bit | 24 bit |
| チャンネル数 | 1(モノラル)/ 2(ステレオ)/ N(マルチ) | 1 |
| フレームサイズ | 32 / 64 / 128 / 256 / 512 / 1024 samples | 128 samples |
4.3 コーデック
| コーデック | 用途 | ビットレート | 遅延特性 |
|---|---|---|---|
| 非圧縮PCM | LAN内、コーデック起因遅延 0ms | 約1.5 Mbps/ch (48kHz/16bit) | 最小 |
| Opus | インターネット越し | 64-256 kbps | 低(2.5ms フレーム対応) |
| FLAC | 録音用、ロスレス品質 | 可変(約800 kbps/ch) | 中 |
4.3.1 Opusレイテンシ詳細
Opusのレイテンシは以下の要素で構成される:
| 種類 | 説明 | 値 |
|---|---|---|
| フレームサイズ | 1フレーム分の音声を貯める時間 | 2.5ms / 5ms / 10ms / 20ms(選択可能) |
| アルゴリズム遅延 | コーデック内部のルックアヘッド | 約2.5-5ms(モードによる) |
| 処理時間 | CPU上でのエンコード/デコード | < 0.5ms |
最小構成(2.5msフレーム + RESTRICTED_LOWDELAY)での遅延:
| 処理 | 遅延 |
|---|---|
| エンコード(フレーム蓄積 + 処理) | 約 2.5-3ms |
| デコード(処理 + アルゴリズム遅延) | 約 2.5-3ms |
| Opus起因合計 | 約 5-6ms |
コーデック別遅延比較:
| コーデック | コーデック起因遅延 |
|---|---|
| 非圧縮PCM | 0ms |
| Opus(2.5ms frame) | 約 5-6ms |
| Opus(10ms frame) | 約 12-15ms |
LAN内は非圧縮PCM、インターネット越しはOpusという使い分けを推奨。どちらを使用するかはユーザーが選択可能とする。
4.4 音声処理
原則として音声処理は行わない。
| 処理 | 実装 | 理由 |
|---|---|---|
| エコーキャンセル(AEC) | なし | ヘッドホン使用を前提 |
| ノイズ抑制 | なし | ピュアな音声伝送を優先 |
| 自動ゲイン制御(AGC) | なし | 同上 |
5. ネットワークサブシステム
5.1 プロトコル構成
+------------------+
| Application |
+------------------+
| Audio Codec |
+------------------+
| jamjam Protocol | <- カスタムUDPプロトコル
+------------------+
| DTLS (optional)| <- 暗号化レイヤー
+------------------+
| UDP |
+------------------+
| IP |
+------------------+
5.2 jamjam Protocol
カスタムUDPプロトコルを使用する。
パケットヘッダ(12バイト):
| フィールド | サイズ | 説明 |
|---|---|---|
| version | 1 byte | プロトコルバージョン |
| type | 1 byte | パケットタイプ |
| sequence | 4 bytes | シーケンス番号 |
| timestamp | 4 bytes | タイムスタンプ(サンプル単位) |
| flags | 2 bytes | フラグ(FEC、暗号化等) |
パケットタイプ:
| 値 | タイプ | 説明 |
|---|---|---|
| 0x01 | AUDIO | 音声データ |
| 0x02 | FEC | FEC冗長データ |
| 0x03 | CONTROL | 制御メッセージ |
| 0x04 | KEEPALIVE | 接続維持 |
5.3 NAT越え
| 方式 | 用途 |
|---|---|
| STUN | パブリックIP/ポートの取得 |
| TURN | STUNで接続不可の場合のリレー |
| ICE | NAT越え手順の自動化 |
公開STUNサーバーを利用可能とする。TURNサーバーは自前で運用する。
IPv4/IPv6 デュアルスタック対応:
日本国内ISPではIPv6普及が進み、MAP-E/DS-Lite方式(共有IPv4 over IPv6)が増加している。 CGNATによるP2P接続の困難さに対応するため、以下の設計を採用:
| 機能 | 説明 |
|---|---|
| マルチ候補収集 | ローカルアドレス(IPv4/IPv6両方)とSTUN経由アドレスを収集 |
| Happy Eyeballs接続 | 複数候補に並列プローブ、最初に応答した経路を使用 |
| プロトコル透過 | ユーザーがIPv4/IPv6を意識せずに接続可能 |
| 優先度ベース選択 | RFC 5245準拠の優先度計算でローカル接続を優先 |
候補優先度(高→低):
- ホスト候補(ローカルネットワーク内で最速)
- サーバーリフレクシブ候補(STUN経由、NAT越え)
制約:
- IPv4とIPv6間での直接通信は不可能(プロトコル非互換)
- 両ピアが少なくとも1つの共通プロトコルを持つ必要がある
- TURNリレーは遅延増加のため使用しない(低遅延優先の設計方針)
5.4 暗号化
| 項目 | 仕様 |
|---|---|
| 方式 | DTLS 1.3 |
| デフォルト | ON |
| ユーザー設定 | OFF可能(アドバンスオプション) |
暗号化によるレイテンシ増加は無視できるレベル(数マイクロ秒)である。
5.5 パケットロス対策
FEC(前方誤り訂正):
| 項目 | 仕様 |
|---|---|
| 方式 | Reed-Solomon または XOR ベース |
| 冗長度 | 設定可能(デフォルト: 10%) |
| 遅延影響 | 1フレーム分 |
再送は行わない(リアルタイム性を優先)。
PLC(Packet Loss Concealment):
パケットロス時の音声補間処理。コーデックにより対応方式が異なる。
| コーデック | PLC方式 | 品質 | 備考 |
|---|---|---|---|
| Opus | 組み込みPLC | 高 | ピッチ・エネルギー情報を活用 |
| 非圧縮PCM | 前フレーム繰り返し + フェードアウト | 中 | 自前実装 |
非圧縮PCM用PLC手法:
| 手法 | 説明 | 品質 | 追加遅延 |
|---|---|---|---|
| ゼロ補間 | 欠損を無音に | 低(プチプチ音) | なし |
| 最終サンプル保持 | 直前の値を維持 | 低〜中 | なし |
| 前フレーム繰り返し | 直前フレームを再生 | 中 | なし |
| クロスフェード | 前後フレームをフェード | 中〜高 | 1フレーム |
本アプリケーションでは、非圧縮PCM使用時は「前フレーム繰り返し + フェードアウト」を採用する。遅延を追加せず、プチプチ音を軽減できる。
5.6 Jitterバッファ
| 項目 | 仕様 |
|---|---|
| 方式 | 適応的 |
| 最小サイズ | 0フレーム(パススルー)〜 ユーザー設定可能(デフォルト: 1フレーム) |
| 最大サイズ | 設定可能(デフォルト: 10フレーム) |
| 適応速度 | ネットワーク状況に応じて自動調整 |
| パススルーモード | ジッタバッファを完全にバイパス(zero-latencyプリセット用) |
5.7 帯域適応
| 項目 | 仕様 |
|---|---|
| 帯域推定 | パケットロス率、RTTに基づく |
| 適応動作 | コーデックビットレートの動的変更 |
| ユーザー制御 | 自動/手動切替可能 |
5.8 ネットワーク要件
5.8.1 必要帯域(1ストリームあたり、48kHz)
| コーデック | ビット深度 | チャンネル | 帯域 |
|---|---|---|---|
| 非圧縮PCM | 16bit | モノラル | 768 kbps |
| 非圧縮PCM | 24bit | モノラル | 1.15 Mbps |
| 非圧縮PCM | 32bit(float) | モノラル | 1.54 Mbps |
| 非圧縮PCM | 24bit | ステレオ | 2.3 Mbps |
| Opus | - | モノラル | 64-256 kbps |
※パケットヘッダ(12バイト/パケット)のオーバーヘッドは微小
2人セッション(送受信各1ストリーム)の場合、非圧縮PCM(24bit/モノラル)で上下各 1-2 Mbps 程度。
5.8.2 環境別ネットワーク特性
| 環境 | RTT | 片道遅延 | パケットロス |
|---|---|---|---|
| ギガビットLAN(有線) | < 1ms | < 0.5ms | ほぼ 0% |
| 光回線同士(日本国内) | 10-30ms | 5-15ms | < 0.1%(通常) |
| 光回線同士(海外) | 50-200ms+ | 25-100ms+ | 経路次第で 1%+ |
| WiFi(良好、5GHz近距離) | +1-5ms | +0.5-2.5ms | 低 |
| WiFi(混雑、距離あり) | +5-20ms | +2.5-10ms | 中 |
| WiFi(干渉、壁多い) | +20-50ms+ | +10-25ms+ | 高 |
5.8.3 パケットロスの影響
| コーデック | パケットロス 0.5% | パケットロス 2% |
|---|---|---|
| 非圧縮PCM | プチプチ音が発生 | かなり聞き取りづらい |
| Opus(PLC付き) | 補間されほぼ気にならない | 多少劣化するが会話可能 |
FEC(10%冗長)により軽度のパケットロスは軽減されるが、Opusの方がパケットロス耐性が高い。
5.8.4 推奨環境
| 用途 | 推奨環境 | コーデック |
|---|---|---|
| LAN内ジャムセッション | 有線LAN | 非圧縮PCM |
| インターネット越し(日本国内) | 光回線 + 有線LAN | Opus推奨、非圧縮PCMも可 |
| インターネット越し(海外) | 光回線 + 有線LAN | Opus必須 |
注意: 音楽セッション用途では有線LAN接続を強く推奨。WiFiはジッター(遅延のばらつき)が大きく、演奏に支障をきたす可能性がある。
6. シグナリング
6.1 概要
P2P接続確立のためのシグナリングサーバーを提供する。
6.2 プロトコル
| 項目 | 仕様 |
|---|---|
| トランスポート | WebSocket over TLS |
| フォーマット | JSON |
| 認証 | なし(初期)、OAuth2(将来) |
6.3 ホスティング
| 項目 | 仕様 |
|---|---|
| 初期 | VPS(自前運用) |
| 将来 | Cloudflare Workers検討 |
7. セッション管理
7.1 ルーム
| 項目 | 仕様 |
|---|---|
| ルームID | UUID v4 |
| 招待方式 | URL、招待コード(6文字英数字) |
| パスワード | オプション(SHA-256ハッシュ保存) |
| 最大参加者 | 10人以上(P2Pメッシュの限界まで) |
7.2 接続トポロジ
| 参加者数 | トポロジ |
|---|---|
| 2人 | 直接P2P |
| 3人以上 | フルメッシュP2P |
10人のフルメッシュでは各クライアントが9本の接続を維持する。
7.3 直接接続(アドバンスオプション)
シグナリングサーバーを介さず、IPアドレスとポートを直接指定して接続する機能を提供する。
8. ユーザーインターフェース
8.1 GUI
Tauri 2.0を使用したデスクトップGUIを提供する。
マルチウィンドウ構成:
| ウィンドウ | 表示タイミング | 機能 |
|---|---|---|
| 接続画面 | 未接続時 | セッション参加/作成 |
| ミキシングコンソール | 接続後(メイン) | 音量・パン調整、退室、接続情報 |
| チャット | 接続後(メイン) | テキストコミュニケーション、絵文字リアクション |
| 設定 | 必要時に開く | オーディオデバイス、プリセット、詳細設定 |
詳細: docs-spec/ui/multi-window-architecture.md
ウィンドウ別仕様:
| ウィンドウ | デフォルトサイズ | リサイズ | 備考 |
|---|---|---|---|
| 接続画面 | 400 x 300 px | 不可 | 閉じるとアプリ終了 |
| ミキシングコンソール | 800 x 600 px | 可 | 閉じると退室確認 |
| チャット | 400 x 500 px | 可 | 閉じると非表示(再表示可) |
| 設定 | 600 x 500 px | 可 | 非モーダル |
接続品質モニタリング
各参加者との接続品質をリアルタイムで表示し、最適な設定を推奨する。
表示項目(参加者ごと):
| 項目 | 説明 | 更新頻度 |
|---|---|---|
| RTT | 往復遅延(ms) | 1秒 |
| Jitter | 到着時刻の揺らぎ(ms) | 1秒 |
| Packet Loss | パケットロス率(%) | 1秒 |
| 推奨設定 | ジッター値に基づく推奨プリセット | 5秒 |
推奨設定のロジック:
| ジッター | 推奨プリセット | 表示メッセージ |
|---|---|---|
| < 1ms | zero-latency | 「非常に安定。zero-latencyモード推奨」 |
| 1-3ms | ultra-low-latency | 「安定。低遅延設定が可能」 |
| 3-10ms | balanced | 「やや不安定。バッファ推奨」 |
| > 10ms | high-quality | 「不安定。バッファを増やしてください」 |
UI表示例:
┌─────────────────────────────────────────────┐
│ 参加者: Alice │
│ RTT: 15ms Jitter: 0.8ms Loss: 0% │
│ ────────────────────────────────────────── │
│ ✓ 非常に安定。zero-latencyモード推奨 │
│ [zero-latencyに切り替え] │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ 参加者: Bob │
│ RTT: 25ms Jitter: 12ms Loss: 0.5% │
│ ────────────────────────────────────────── │
│ ⚠ 不安定。バッファを増やしてください │
│ 現在: zero-latency → 推奨: balanced │
│ [balancedに切り替え] │
└─────────────────────────────────────────────┘
自動切り替えオプション:
ジッター増加時に自動でバッファを増やすオプションを提供する(デフォルト: OFF)。 音楽セッションでは遅延の予測可能性が重要なため、手動切り替えを基本とする。
8.2 CLI
全機能をCLIから利用可能とする。E2Eテストの自動化に対応する。
主要コマンド:
jamjam host [--port PORT] [--password PASS]
jamjam join <ROOM_URL|IP:PORT>
jamjam devices list
jamjam devices set --input <ID> --output <ID>
jamjam preset list
jamjam preset use <NAME>
jamjam preset save <NAME>
8.3 プリセット
| プリセット名 | Jitterバッファ | コーデック | フレームサイズ | 用途 |
|---|---|---|---|---|
| zero-latency | 0フレーム(パススルー) | 非圧縮PCM 32bit float | 32 samples | 国内光回線セッション |
| ultra-low-latency | 1フレーム | 非圧縮PCM | 64 samples | LAN内ジャム |
| balanced | 4フレーム | Opus 128kbps | 128 samples | 一般的なネット環境 |
| high-quality | 8フレーム | Opus 256kbps | 256 samples | 録音・高速回線 |
ユーザーはプリセットをベースにカスタマイズし、名前を付けて保存できる。
9. 追加機能(Phase 4以降)
9.1 仮想オーディオデバイス
ミックスされた音声出力を仮想オーディオデバイスとして提供し、DAWや配信ソフトで利用可能とする。
| プラットフォーム | 実装方式 |
|---|---|
| macOS | Core Audio HAL plugin |
| Windows | Virtual Audio Cable互換ドライバ |
| Linux | PipeWire/JACK仮想デバイス |
10. スレッドモデル
10.1 スレッド構成
| スレッド | 優先度 | 役割 |
|---|---|---|
| Audio Capture | リアルタイム | 音声入力の取得 |
| Audio Playback | リアルタイム | 音声出力の再生 |
| Network Send | 高 | パケット送信 |
| Network Receive | 高 | パケット受信 |
| Jitter Buffer | 高 | バッファ管理 |
| GUI | 通常 | ユーザーインターフェース |
| Signaling | 通常 | シグナリング通信 |
10.2 リアルタイム制約
Audio Capture/Playbackスレッドでは以下を禁止する:
- メモリアロケーション
- ブロッキングI/O
- ミューテックスの長時間保持
- システムコール(可能な限り)
11. 遅延バジェット
11.1 設計目標
アプリケーション起因の遅延を限りなく0msに近づける。遅延 ≒ ネットワークRTT となることを目指す。
音楽セッション用途では30ms以上の遅延で演奏の心地よさを失う。日本国内光回線(RTT 10-25ms)での使用を主な対象とし、総遅延を可能な限り小さくする。
11.2 zero-latencyモード時の遅延バジェット(48kHz、32samples時)
| 処理 | 目標遅延 |
|---|---|
| 音声キャプチャバッファ | 0.67 ms (32 samples) |
| エンコード | 0 ms (PCM) |
| パケット化 | < 0.1 ms |
| 送信バッファ | < 0.1 ms |
| --- ネットワーク伝送 --- | (RTT/2) |
| 受信バッファ | < 0.1 ms |
| Jitterバッファ | 0 ms (パススルー) |
| デコード | 0 ms (PCM) |
| 再生バッファ | 0.67 ms (32 samples) |
| 合計(片道、アプリ起因) | < 2 ms |
11.3 balancedモード時の遅延バジェット(48kHz、128samples時)
| 処理 | 目標遅延 |
|---|---|
| 音声キャプチャバッファ | 2.67 ms (128 samples) |
| エンコード | < 0.5 ms |
| パケット化 | < 0.1 ms |
| 送信バッファ | < 0.5 ms |
| --- ネットワーク伝送 --- | (RTT/2) |
| 受信バッファ | < 0.5 ms |
| Jitterバッファ | 2.67 ms (最小、1フレーム) |
| デコード | < 0.5 ms |
| 再生バッファ | 2.67 ms (128 samples) |
| 合計(片道、アプリ起因) | < 10 ms |
11.4 環境別の想定総遅延
| 環境 | プリセット | アプリ起因 | ネットワーク片道 | 総片道遅延 |
|---|---|---|---|---|
| 国内光回線(RTT 20ms) | zero-latency | ~1.5ms | 10ms | ~12ms |
| 国内光回線(RTT 20ms) | balanced | ~10ms | 10ms | ~20ms |
| LAN内(RTT 1ms) | ultra-low-latency | ~5ms | 0.5ms | ~6ms |
ネットワーク遅延はRTT/2として加算される。
12. エラーハンドリング
12.1 接続断
| 状況 | 動作 |
|---|---|
| 一時的な切断(< 5秒) | 自動再接続試行 |
| 長時間切断(≥ 5秒) | ユーザーに通知、手動再接続 |
| シグナリングサーバー断 | P2P接続は維持、新規参加不可 |
12.2 音声デバイスエラー
| 状況 | 動作 |
|---|---|
| デバイス切断 | デフォルトデバイスにフォールバック |
| デバイス再接続 | ユーザーに通知、手動切替 |
13. 設定ファイル
13.1 保存場所
| プラットフォーム | パス |
|---|---|
| Windows | %APPDATA%\jamjam\config.toml |
| macOS | ~/Library/Application Support/jamjam/config.toml |
| Linux | ~/.config/jamjam/config.toml |
13.2 フォーマット
TOML形式を使用する。
14. ビルド・配布
14.1 ビルドシステム
| 項目 | ツール |
|---|---|
| Rustビルド | Cargo |
| GUIビルド | Tauri CLI |
| CI/CD | GitHub Actions |
14.2 配布形式
| プラットフォーム | 形式 |
|---|---|
| Windows | MSIインストーラー、ポータブルZIP |
| macOS | DMG、Homebrew Cask |
| Linux | AppImage、deb、rpm |
15. 国際化(i18n)
15.1 対応言語
| 言語 | コード | ステータス |
|---|---|---|
| 日本語 | ja | 初期対応 |
| 英語 | en | 初期対応 |
15.2 実装
| プラットフォーム | ライブラリ | 翻訳ファイル形式 |
|---|---|---|
| デスクトップ(Tauri) | i18next | JSON |
| モバイル(Flutter) | flutter_localizations + intl | ARB |
15.3 翻訳ファイル配置
| プラットフォーム | パス |
|---|---|
| デスクトップ | ui/locales/{lang}.json |
| モバイル | lib/l10n/app_{lang}.arb |
15.4 言語検出
| 優先順位 | 方法 |
|---|---|
| 1 | config.toml の language 設定 |
| 2 | システムロケール(OS設定) |
| 3 | 英語(フォールバック) |
15.5 フォールバック動作
翻訳キーが見つからない場合:
- 英語の翻訳を使用
- 英語も存在しない場合はキー自体を表示
- コンソールに警告を出力
15.6 翻訳キー命名規則
形式: {namespace}.{section}.{element}
| 名前空間 | 対象 | 例 |
|---|---|---|
| session | セッション管理 | session.create, session.leave |
| audio | 音声設定 | audio.device.input, audio.start |
| mixer | ミキサー | mixer.you, mixer.mute |
| settings | 設定画面 | settings.language, settings.preset |
| status | 接続状態 | status.connected, status.disconnected |
| error | エラー | error.connection.timeout |