Skip to main content

architecture.md

jamjamの技術構成を定義する。本ドキュメントは実装の正とする。


1. システム概要

1.1 目的

ミュージシャンがインターネット越しにリアルタイムで演奏セッションを行うための、P2P音声通信を実現する。アプリケーション起因の片道遅延を限りなく0msに近づけることを目標とする(理論最小値: ~1.5ms、セクション11参照)。

1.2 設計原則

  • アプリケーション起因の遅延を限りなく0msに近づける(遅延 ≒ ネットワークRTTのみ)
  • 音声信号に余計な処理を加えない(ピュアな音声伝送)
  • プリセット選択のみで動作開始可能、上級者は詳細パラメータを設定可能

2. 対応プラットフォーム

プラットフォーム対応状況GUI フレームワーク
WindowsPhase 1Tauri 2.0
macOSPhase 1Tauri 2.0
LinuxPhase 1Tauri 2.0
iOSPhase 5Flutter
AndroidPhase 5Flutter

3. 技術スタック

3.1 言語

用途言語
コアエンジンRust (stable)
デスクトップGUITypeScript (Tauri 2.0)
モバイルGUIDart (Flutter)
シグナリングサーバーRust

3.2 主要ライブラリ

機能ライブラリ状態
音声I/Ocpal実装済
リングバッファ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

プラットフォームバックエンド
macOSCoreAudio
WindowsWASAPI(標準)、ASIO(対応インターフェース使用時)
LinuxPipeWire(優先)、ALSA(フォールバック)

4.2 音声フォーマット

パラメータ選択肢デフォルト
サンプルレート44100 / 48000 / 96000 Hz48000 Hz
ビット深度16 / 24 / 32 (float) bit24 bit
チャンネル数1(モノラル)/ 2(ステレオ)/ N(マルチ)1
フレームサイズ32 / 64 / 128 / 256 / 512 / 1024 samples128 samples

4.3 コーデック

コーデック用途ビットレート遅延特性
非圧縮PCMLAN内、コーデック起因遅延 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

コーデック別遅延比較:

コーデックコーデック起因遅延
非圧縮PCM0ms
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バイト):

フィールドサイズ説明
version1 byteプロトコルバージョン
type1 byteパケットタイプ
sequence4 bytesシーケンス番号
timestamp4 bytesタイムスタンプ(サンプル単位)
flags2 bytesフラグ(FEC、暗号化等)

パケットタイプ:

タイプ説明
0x01AUDIO音声データ
0x02FECFEC冗長データ
0x03CONTROL制御メッセージ
0x04KEEPALIVE接続維持

5.3 NAT越え

方式用途
STUNパブリックIP/ポートの取得
TURNSTUNで接続不可の場合のリレー
ICENAT越え手順の自動化

公開STUNサーバーを利用可能とする。TURNサーバーは自前で運用する。

IPv4/IPv6 デュアルスタック対応:

日本国内ISPではIPv6普及が進み、MAP-E/DS-Lite方式(共有IPv4 over IPv6)が増加している。 CGNATによるP2P接続の困難さに対応するため、以下の設計を採用:

機能説明
マルチ候補収集ローカルアドレス(IPv4/IPv6両方)とSTUN経由アドレスを収集
Happy Eyeballs接続複数候補に並列プローブ、最初に応答した経路を使用
プロトコル透過ユーザーがIPv4/IPv6を意識せずに接続可能
優先度ベース選択RFC 5245準拠の優先度計算でローカル接続を優先

候補優先度(高→低):

  1. ホスト候補(ローカルネットワーク内で最速)
  2. サーバーリフレクシブ候補(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)

コーデックビット深度チャンネル帯域
非圧縮PCM16bitモノラル768 kbps
非圧縮PCM24bitモノラル1.15 Mbps
非圧縮PCM32bit(float)モノラル1.54 Mbps
非圧縮PCM24bitステレオ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-30ms5-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
インターネット越し(日本国内)光回線 + 有線LANOpus推奨、非圧縮PCMも可
インターネット越し(海外)光回線 + 有線LANOpus必須

注意: 音楽セッション用途では有線LAN接続を強く推奨。WiFiはジッター(遅延のばらつき)が大きく、演奏に支障をきたす可能性がある。


6. シグナリング

6.1 概要

P2P接続確立のためのシグナリングサーバーを提供する。

6.2 プロトコル

項目仕様
トランスポートWebSocket over TLS
フォーマットJSON
認証なし(初期)、OAuth2(将来)

6.3 ホスティング

項目仕様
初期VPS(自前運用)
将来Cloudflare Workers検討

7. セッション管理

7.1 ルーム

項目仕様
ルームIDUUID 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秒

推奨設定のロジック:

ジッター推奨プリセット表示メッセージ
< 1mszero-latency「非常に安定。zero-latencyモード推奨」
1-3msultra-low-latency「安定。低遅延設定が可能」
3-10msbalanced「やや不安定。バッファ推奨」
> 10mshigh-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-latency0フレーム(パススルー)非圧縮PCM 32bit float32 samples国内光回線セッション
ultra-low-latency1フレーム非圧縮PCM64 samplesLAN内ジャム
balanced4フレームOpus 128kbps128 samples一般的なネット環境
high-quality8フレームOpus 256kbps256 samples録音・高速回線

ユーザーはプリセットをベースにカスタマイズし、名前を付けて保存できる。


9. 追加機能(Phase 4以降)

9.1 仮想オーディオデバイス

ミックスされた音声出力を仮想オーディオデバイスとして提供し、DAWや配信ソフトで利用可能とする。

プラットフォーム実装方式
macOSCore Audio HAL plugin
WindowsVirtual Audio Cable互換ドライバ
LinuxPipeWire/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.5ms10ms~12ms
国内光回線(RTT 20ms)balanced~10ms10ms~20ms
LAN内(RTT 1ms)ultra-low-latency~5ms0.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/CDGitHub Actions

14.2 配布形式

プラットフォーム形式
WindowsMSIインストーラー、ポータブルZIP
macOSDMG、Homebrew Cask
LinuxAppImage、deb、rpm

15. 国際化(i18n)

15.1 対応言語

言語コードステータス
日本語ja初期対応
英語en初期対応

15.2 実装

プラットフォームライブラリ翻訳ファイル形式
デスクトップ(Tauri)i18nextJSON
モバイル(Flutter)flutter_localizations + intlARB

15.3 翻訳ファイル配置

プラットフォームパス
デスクトップui/locales/{lang}.json
モバイルlib/l10n/app_{lang}.arb

15.4 言語検出

優先順位方法
1config.toml の language 設定
2システムロケール(OS設定)
3英語(フォールバック)

15.5 フォールバック動作

翻訳キーが見つからない場合:

  1. 英語の翻訳を使用
  2. 英語も存在しない場合はキー自体を表示
  3. コンソールに警告を出力

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