ソースからビルド
目次
必要なもの
- Rust(stable、1.90 以降)。rustup で入れます
- Visual Studio 2022 以降(Build Tools でも可)と「C++ によるデスクトップ開発」ワークロード。C のライブラリ(BTstack、コーデック)を MSVC でコンパイルします
- UI 用に Node.js 22 と pnpm(
corepack enableで pnpm が使えます) - Git(サブモジュールの取得)
build.ps1/build.bat用に PowerShell 7(pwsh。winget install Microsoft.PowerShell)- ARM64 版をビルドするとき: Visual Studio のコンポーネント「MSVC v143 - VS 2022 C++ ARM64 ビルド ツール」と、x64 の PC では「Windows 用 C++ Clang コンパイラ」(rustls の
ringが ARM64 のアセンブリを clang で組むため。installer/build-release.ps1は Visual Studio の clang を自分で探す)、それにrustup target add aarch64-pc-windows-msvc
クイックビルド
git clone --recursive https://github.com/SeiyaFunaokaJP/A2DP-Windows-Bridge.git
cd A2DP-Windows-Bridge
pwsh ./build.ps1
エクスプローラーで build.bat をダブルクリックしても同じです(build.ps1 を実行し、最後にキー入力を待ちます。build.bat -Test のようにスイッチも渡せます)。build.ps1 は最初に Rust、Node.js、pnpm、サブモジュールがそろっているかを確かめ、node_modules がなければ pnpm install を実行し、ウィンドウのページを組んでから 3 つのプログラムを target/release/ に作ります。a2dpwb-core.exe(常駐するコア。Bluetooth、音声、タスクトレイ)、a2dpwb.exe(ウィンドウ)、a2dpwb-driver.exe(WinUSB ドライバの割り当てと解除をする、管理者権限のヘルパー)です。3 つは同じフォルダに置いてください。a2dpwb-core.exe --cli ならウィンドウなしで配信できます。
スイッチ: -Debug(開発プロファイル、target/debug/)、-Test(続けて「テスト」のチェック)、-Decoder(デコーダツールも)、-Emu(実機なしでのテストも)、-Release -Arch x64|arm64(リリーススクリプトのみ。「リリースパッケージ」参照)。
手順を分けて行う場合(build.ps1 がしていること。a2dpwb.exe はウィンドウのページを埋め込むので、ページを先に組みます):
cargo build --release -p a2dpwb-core-exe -p a2dpwb-driver
cd app/src/ui
pnpm install --frozen-lockfile
pnpm build
cd ../../..
cargo build --release -p a2dpwb-ui
--recursive なしでクローン済みの場合
git submodule update --init --recursive
プロジェクト構成
A2DP-Windows-Bridge/
├── app/
│ ├── src/
│ │ ├── core/ a2dpwb-core.exe: 常駐コア、タスクトレイ、IPC サーバー、--cli
│ │ ├── ui/ a2dpwb.exe: Tauri 2 + SolidJS(pnpm dev でモックのコアとブラウザで動く)
│ │ ├── driver/ a2dpwb-driver.exe: WinUSB の割り当て / 解除(管理者権限)
│ │ └── crates/ ライブラリ: btstack-sys、hci-transport、bt-host、codec、コーデックの -sys クレート、
│ │ pipeline、audio-capture、win-sys、core(a2dpwb-core)、ipc、le-audio、lc3-sys
│ ├── lang/ 翻訳(en.json が原本。他の言語は tools/check_lang.py で確認)
│ └── resources/ アイコンとマニフェスト
├── Cargo.toml Cargo workspace
├── installer/ リリース用スクリプト、NSIS のフック、更新の手順(installer/README.md)
├── compat/ AOSP コード用の MSVC 互換ヘッダー
├── docs/ ドキュメント(このサイト)と設計書(v2-design.md)
├── extern/ サードパーティの C ライブラリ(git サブモジュール)
│ ├── btstack/ BTstack Bluetooth スタック
│ ├── libldac/ AOSP LDAC エンコーダ
│ ├── libopenaptx/ aptX / aptX HD / aptX LL エンコーダ
│ ├── fdk-aac/ Fraunhofer AAC エンコーダ
│ ├── lhdcv5-enc/ LHDC V5 エンコーダ
│ └── opus/ libopus(Opus エンコーダ)
└── tools/
├── a2dp_decode/ a2dpwb_decode: HCI キャプチャ(.pklg)内のメディアストリームを検査 / デコード
├── emu/ 仮想 Bluetooth シンクを相手にしたエンドツーエンドテスト(Python)
└── linux_sink/ a2dpwb_sink: Linux で動く計測用 A2DP 受信機(Python、Bumble)
テスト
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cd app/src/ui && pnpm exec tsc --noEmit && pnpm exec vitest run
python tools/check_lang.py
リリースパッケージ
pwsh installer/build-release.ps1 -Arch x64
target/dist にインストーラ(A2DPWB-<バージョン>-win64-setup.exe)、ポータブル版の zip、更新用のマニフェストを書き出します。アプリ内更新の署名などは installer/README.md を見てください。
実機なしでのテスト(tools/emu)
tools/emu は、同じ PC 上の仮想 Bluetooth シンクへ全コーデックを配信して確かめます。アダプタもヘッドホンも要りません。Windows 専用で、Python 3.11 以降と、デコーダツール用の CMake(Visual Studio に同梱)が必要です。
python tools/emu/setup_env.py # 初回のみ: tools/emu/.venv を作る(パッケージは固定版)
cmake -S tools/a2dp_decode -B build/a2dp_decode # 初回のみ: デコーダツール
cmake --build build/a2dp_decode --config Release
cargo build --release -p a2dpwb-core-exe
python tools/emu/run_test.py # 全コーデックで約 35 秒
仕組み:
emu_sink.pyは、プロセス内のリンクでつないだ 2 つの Bumble 仮想コントローラを動かします。1 つは A2DPWB 向けに H4 over TCP(127.0.0.1)で公開し、もう 1 つは SBC、AAC、aptX、aptX HD、aptX LL、LDAC を受けられる Bumble の A2DP シンクが使い、その HCI 通信を記録します。run_test.pyはコーデックごとにa2dpwb-core.exe --cliを開発用のオプション付きで動かします。--hci-tcp(WinUSB の代わりに仮想コントローラ)、--test-tone(システムの音の代わりに左 1 kHz / 右 1.5 kHz)、--duration、--hci-capture。環境変数A2DPWB_CONFIG_DIRで別の設定フォルダを使うので、仮想シンクとのペアリングが本物のリンクキーに触れることはありません。- 最後に両方の HCI キャプチャを
a2dpwb_decodeで調べます(シンク側は--received)。
次のすべてを満たしたコーデックが合格です。
- 指定したコーデックで接続した
- 送信側と受信側のどちらでも
a2dpwb_decodeが問題を見つけない - A2DPWB が送ったメディアパケットとフレームをシンクがすべて受け取り、指定した長さの 90% 以上を送った
- LDAC 以外(オープンソースのデコーダがないため): デコードした音が両側で一致し、テストトーンである
| オプション | 説明 |
|---|---|
--codecs sbc aac ... | このコーデックだけを試す(sbc aac aptx aptxhd aptxll ldac、既定は全部) |
--duration <秒> | コーデックごとの配信時間(既定 5) |
--max-packet <バイト> | A2DPWB に渡す(最大メディアパケットサイズ。使い方を参照) |
--a2dpwb <exe> | 試すコア(既定 target/release/a2dpwb-core.exe) |
--decoder <exe> | デコーダツール(既定 build/a2dp_decode/Release/a2dpwb_decode.exe) |
--out <フォルダ> | 出力先(既定 tools/emu/out) |
tools/emu/out/<コーデック>/ には、キャプチャ(a2dpwb.pklg、sink.pklg)、ログ、a2dpwb_decode の結果、デコードした WAV が残ります。全コーデックが合格すると終了コードは 0 です。
仮想リンクには電波がありません。エンコード、パケット化、AVDTP / L2CAP のやり取り、独立した Bluetooth スタック(Bumble)との相互接続は確かめられますが、電波の状態、実機でのタイミング、実際のヘッドホンでの鳴り方は確かめられません。Bumble のパッケージはテスト用の道具で、A2DPWB には含まれません(THIRD_PARTY_LICENSES.md を参照)。
emu_vhci.py は同じことを Linux の Bluetooth スタックに向けて行います。Linux 上で /dev/vhci から BlueZ に仮想アダプタを付け、計測用受信機 tools/linux_sink がそれを本物のアダプタと同じように使うので、実機なしで試せます(メディアパケットの欠落や遅延も --drop、--stall で再現できます)。tools/linux_sink/README.md を見てください。
依存関係
C のライブラリは git サブモジュールです。Rust のクレートと UI の npm パッケージは Cargo と pnpm が取得します(バージョンは Cargo.lock と app/src/ui/pnpm-lock.yaml で固定。ライセンスは cargo deny check で確認)。
| ライブラリ | 取得方法 | 固定バージョン | ライセンス |
|---|---|---|---|
| BTstack | git サブモジュール | v1.8.1-6-g5bc5cbdbe | BTstack License(非商用条項付きの BSD-3-Clause 類似ライセンス) |
| Bluedroid SBC コーデック | エンコーダは Rust に移植。デコーダ(テストとツール)は BTstack 同梱のもの | BTstack に準拠 | Apache-2.0 |
| rijndael | BTstack に同梱(3rd-party/rijndael) | BTstack に準拠 | パブリックドメイン |
| liblc3 (lc3-google) | BTstack に同梱(3rd-party/lc3-google) | BTstack に準拠 | Apache-2.0 |
| micro-ecc | BTstack に同梱(3rd-party/micro-ecc) | BTstack に準拠 | BSD-2-Clause |
| libldac (AOSP) | git サブモジュール | android-15.0.0_r36-4-geeee1a3 | Apache-2.0 |
| libopenaptx | git サブモジュール | 0.2.0(更新しないこと) | LGPL-2.1+ |
| fdk-aac | git サブモジュール | v2.0.3-158-gd8e6b1a | FDK AAC License |
| LHDC V5 エンコーダ | git サブモジュール | 固定したコミット | Apache-2.0 |
| libopus | git サブモジュール | v1.5.2 | BSD-3-Clause |
| Tauri、SolidJS、Rust のクレート | Cargo / pnpm | Cargo.lock、pnpm-lock.yaml | MIT / Apache-2.0 など(リリースの licenses/rust-crates.txt) |
BTstack をリンクしているため、A2DPWB のソースコード自体は Apache-2.0 / MIT のデュアルライセンスであっても、ビルドした A2DPWB は個人的かつ非商用の目的でのみ使用・再配布できます。
ライセンスの全文は THIRD_PARTY_LICENSES.md を参照してください。