Skip to content

Commit 1ae649f

Browse files
voluntasclaude
andcommitted
Linux で PipeWire による録音ストリームを実装する
PipeWire ネイティブ API を使用した録音機能を実装。 主な変更: - InitRecording() で PipeWire 録音ストリームを作成 - StartRecording()/StopRecording() でストリームの開始/停止 - OnRecStreamProcess() コールバックで音声データを AudioDeviceBuffer に転送 - サンプルレート 48kHz、2ch ステレオで動作 - audio_transport_ を追加して RegisterAudioCallback() と AttachAudioBuffer() の順序問題を解決 - Terminate() でストリームを適切に破棄 - EnumerateDevices() の pw_thread_loop_wait() をタイムアウト付きの sleep に変更 audio グループ権限の問題: - ユーザーが audio グループに所属していないと /dev/snd/controlC* にアクセスできず、 PipeWire の ALSA モニターがデバイスを認識しない問題を発見 - sudo usermod -a -G audio $USER でユーザーを audio グループに追加することで解決 - ログアウト/ログインまたはシステム再起動が必要 動作確認: - wpctl status で USB デバイス (Yamaha YVC-200, Insta360 Link, HyperX QuadCast S) が認識されることを確認 - --list-devices でデバイス一覧が正常に表示されることを確認 - Sora モードでの動作を開始 (音声送信テストは未完了) ドキュメント: - doc/LINUX_PIPEWIRE.md を追加 - audio グループへの追加手順を記載 - 動作確認方法とコマンド例を記載 - timeout の使用を推奨 (PipeWire 初期化に時間がかかるため) 今後の課題: - 実際の音声送信が動作するか確認 - 再生 (playout) ストリームの実装 - エラーハンドリングの改善 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 708cd13 commit 1ae649f

File tree

7 files changed

+433
-12
lines changed

7 files changed

+433
-12
lines changed

doc/LINUX_PIPEWIRE.md

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# Linux PipeWire オーディオデバイス実装
2+
3+
## 概要
4+
5+
Ubuntu 24.04 以降で採用されている PipeWire をネイティブサポートするためのオーディオデバイス実装。
6+
7+
## 重要: audio グループへの追加が必要
8+
9+
PipeWire で USB オーディオデバイスにアクセスするには、ユーザーを `audio` グループに追加する必要があります。
10+
11+
```bash
12+
# ユーザーを audio グループに追加
13+
sudo usermod -a -G audio $USER
14+
15+
# ログアウト/ログインまたはシステム再起動
16+
17+
# グループメンバーシップを確認
18+
groups
19+
# 出力に "audio" が含まれていることを確認
20+
```
21+
22+
`audio` グループに所属していない場合、`/dev/snd/controlC*` デバイスファイルにアクセスできず、PipeWire の ALSA モニターがデバイスを認識できません。
23+
24+
## 実装状況
25+
26+
### 完了した機能
27+
28+
- [x] PipeWire 初期化処理
29+
- [x] デバイス列挙機能 (`--list-devices`)
30+
- [x] オーディオ入力デバイス一覧の取得
31+
- [x] オーディオ出力デバイス一覧の取得
32+
- [x] コマンドラインオプション追加 (`--audio-input-device`, `--audio-output-device`)
33+
- [x] デバイス選択機能 (インデックスまたは名前による指定)
34+
- [x] CMake ビルド設定 (`USE_LINUX_PIPEWIRE_AUDIO`)
35+
- [x] 録音 (recording) の実装
36+
- [x] PipeWire 録音ストリームの作成
37+
- [x] オーディオデータの取得と AudioDeviceBuffer への転送
38+
- [x] サンプルレート (48kHz)、チャンネル数 (2ch ステレオ) の設定
39+
- [x] audio グループ権限の問題を解決
40+
41+
### 未実装の機能
42+
43+
- [ ] 再生 (playout) の実装
44+
- [ ] PipeWire 再生ストリームの作成
45+
- [ ] AudioDeviceBuffer からのオーディオデータ取得
46+
- [ ] PipeWire へのデータ転送
47+
- [ ] エラーハンドリング
48+
- [ ] PipeWire 接続エラー時の処理
49+
- [ ] ストリーム作成失敗時の処理
50+
- [ ] デバイス切断時の処理
51+
- [ ] 遅延 (latency) の計測と報告
52+
- [ ] 音量制御機能 (現在は未実装として -1 を返している)
53+
- [ ] ミュート制御機能 (現在は未実装として -1 を返している)
54+
55+
## アーキテクチャ
56+
57+
### ファイル構成
58+
59+
```
60+
src/rtc/
61+
├── audio_device_pipewire_linux.h # PipeWire デバイス実装のヘッダー
62+
├── audio_device_pipewire_linux.cpp # PipeWire デバイス実装
63+
├── audio_device_module_pipewire.h # AudioDeviceModule wrapper ヘッダー
64+
└── audio_device_module_pipewire.cpp # AudioDeviceModule wrapper 実装
65+
```
66+
67+
### クラス構成
68+
69+
```
70+
AudioDeviceModule (interface)
71+
└── AudioDeviceModulePipeWire (wrapper)
72+
└── AudioDeviceLinuxPipeWire (implementation)
73+
└── AudioDeviceGeneric (base class)
74+
```
75+
76+
- `AudioDeviceModulePipeWire`: WebRTC の AudioDeviceModule インターフェースを実装する wrapper クラス
77+
- `AudioDeviceLinuxPipeWire`: PipeWire を使った実際のデバイス制御を行うクラス
78+
79+
### PipeWire オブジェクト
80+
81+
```
82+
pw_thread_loop (メインループ)
83+
└── pw_context (コンテキスト)
84+
├── pw_core (コア接続)
85+
│ └── pw_registry (デバイスレジストリ)
86+
├── pw_stream (録音ストリーム) ← 未実装
87+
└── pw_stream (再生ストリーム) ← 未実装
88+
```
89+
90+
## 実装の詳細
91+
92+
### デバイス列挙
93+
94+
PipeWire registry を使ってデバイス情報を取得:
95+
96+
1. `pw_registry_add_listener()` でレジストリイベントをリスン
97+
2. `OnRegistryGlobal()` コールバックで新しいデバイスを検出
98+
3. `PW_TYPE_INTERFACE_Node` かつ `media.class``Audio/Source` または `Audio/Sink` のデバイスを収集
99+
4. デバイス情報 (ID, 名前, 説明) を保存
100+
101+
### デバイス選択
102+
103+
- インデックスまたは名前でデバイスを指定可能
104+
- `SetPlayoutDevice()` / `SetRecordingDevice()` で選択したデバイスのインデックスを保存
105+
- 実際のストリーム作成時に選択したデバイスを使用 (未実装)
106+
107+
## 今後の実装課題
108+
109+
### 優先度: 高
110+
111+
1. **録音ストリームの実装**
112+
- `InitRecording()` で PipeWire ストリームを作成
113+
- `pw_stream_new()` でストリームを作成
114+
- `pw_stream_add_listener()` でイベントリスナーを追加
115+
- `pw_stream_connect()` で録音デバイスに接続
116+
- データコールバックで AudioDeviceBuffer にデータを転送
117+
118+
2. **再生ストリームの実装**
119+
- `InitPlayout()` で PipeWire ストリームを作成
120+
- AudioDeviceBuffer からデータを取得
121+
- PipeWire ストリームにデータを書き込み
122+
123+
3. **オーディオフォーマットの設定**
124+
- サンプルレート (48000 Hz が一般的)
125+
- チャンネル数 (1: モノラル, 2: ステレオ)
126+
- バッファサイズの設定
127+
128+
### 優先度: 中
129+
130+
4. **エラーハンドリング**
131+
- PipeWire 接続エラーの検出と再接続
132+
- ストリーム作成失敗時のフォールバック
133+
- デバイス切断時の通知
134+
135+
5. **遅延の計測**
136+
- `PlayoutDelay()` の実装
137+
- PipeWire の遅延情報を取得
138+
139+
### 優先度: 低
140+
141+
6. **音量・ミュート制御**
142+
- PipeWire の音量制御 API を使用
143+
- スピーカー/マイクの音量とミュート状態の取得・設定
144+
145+
## 参考実装
146+
147+
- WebRTC の ALSA 実装: `modules/audio_device/linux/audio_device_alsa_linux.cc`
148+
- WebRTC の PulseAudio 実装: `modules/audio_device/linux/audio_device_pulse_linux.cc`
149+
- macOS の実装: `src/rtc/rtc_manager.cpp` (デバイス選択部分)
150+
151+
## ビルド方法
152+
153+
```bash
154+
# PipeWire を有効にしてビルド (デフォルトで ON)
155+
python3 run.py build ubuntu-24.04_x86_64
156+
157+
# PipeWire を無効にしてビルド (ALSA を使用)
158+
cmake -DUSE_LINUX_PIPEWIRE_AUDIO=OFF ...
159+
```
160+
161+
## 動作確認
162+
163+
```bash
164+
# 1. audio グループに所属していることを確認
165+
groups
166+
# 出力に "audio" が含まれていること
167+
168+
# 2. PipeWire でデバイスが認識されているか確認
169+
wpctl status
170+
# Audio Devices に USB デバイスが表示されること
171+
172+
# 3. momo でデバイス一覧を表示 (動作確認済み)
173+
timeout 3 ./momo --no-video-device --list-devices
174+
175+
# 例: 出力
176+
# === Available audio input devices ===
177+
# [0] HyperX QuadCast S Analog Stereo (alsa_input.usb-HP__Inc_HyperX_QuadCast_S-00.analog-stereo)
178+
# [1] Yamaha YVC-200 Mono (alsa_input.usb-Yamaha_Corporation_Yamaha_YVC-200-00.mono-fallback)
179+
# [2] Insta360 Link Mono (alsa_input.usb-Insta360_Insta360_Link-02.mono-fallback)
180+
#
181+
# === Available audio output devices ===
182+
# [0] HyperX QuadCast S Analog Stereo (alsa_output.usb-HP__Inc_HyperX_QuadCast_S-00.analog-stereo)
183+
# [1] Yamaha YVC-200 Mono (alsa_output.usb-Yamaha_Corporation_Yamaha_YVC-200-00.mono-fallback)
184+
185+
# 4. デバイスを指定して Sora モードで実行 (録音機能実装済み)
186+
timeout 30 ./momo --no-video-device --audio-input-device 1 sora \
187+
--signaling-urls wss://example.com/signaling \
188+
--role sendonly --channel-id test --video false --audio true
189+
```
190+
191+
**注意**:
192+
- `--list-devices` は PipeWire 初期化に時間がかかるため、`timeout` を使用して 3 秒程度で終了させることを推奨
193+
- Sora モードでのテストも `timeout` を使用して適切なタイミングで終了させること
194+
195+
## 既知の問題
196+
197+
### 解決済み: audio グループ権限の問題
198+
199+
**問題**: ユーザーが `audio` グループに所属していないと、USB オーディオデバイスが PipeWire で認識されない
200+
201+
**原因**: `/dev/snd/controlC*` デバイスファイルは `root:audio` 権限 (0660) で作成され、audio グループに所属していないユーザーはアクセスできない
202+
203+
**解決方法**: ユーザーを audio グループに追加し、ログアウト/ログインまたはシステム再起動を行う
204+
205+
```bash
206+
sudo usermod -a -G audio $USER
207+
# ログアウト/ログインまたはシステム再起動
208+
```
209+
210+
### その他の問題
211+
212+
1. PipeWire 設定ファイルの警告
213+
- `can't load config client.conf: No such file or directory`
214+
- 動作には影響なし (警告レベル)
215+
216+
2. AudioDeviceBuffer not attached エラー (解決済み)
217+
- `RegisterAudioCallback()``AttachAudioBuffer()` より先に呼ばれる
218+
- `audio_transport_` を保存して後で登録する方式に変更済み
219+
220+
## 実装見積もり
221+
222+
### 完了済み
223+
- 録音ストリーム実装: 約 250 行 (完了)
224+
- デバイス列挙と選択: 約 200 行 (完了)
225+
226+
### 残作業
227+
- 再生ストリーム実装: 300-500 行 (録音ストリームと同様の実装パターン)
228+
- エラーハンドリング: 100-200 行
229+
- 残り合計: 400-700 行程度
230+
231+
実装期間: 残り 1-2 週間程度

src/main.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@
5959

6060
#if defined(__linux__)
6161
#include "sora/v4l2/v4l2_device.h"
62+
#if defined(USE_LINUX_PIPEWIRE_AUDIO)
63+
#include "rtc/audio_device_module_pipewire.h"
64+
#endif
6265
#endif
6366

6467
#ifdef _WIN32
@@ -75,9 +78,13 @@ const size_t kDefaultMaxLogFileSize = 10 * 1024 * 1024;
7578

7679
static void ListDevices() {
7780
// オーディオデバイス一覧
81+
#if defined(USE_LINUX_PIPEWIRE_AUDIO)
82+
auto adm = webrtc::CreatePipeWireAudioDeviceModule();
83+
#else
7884
auto adm = webrtc::CreateAudioDeviceModule(
7985
webrtc::CreateEnvironment(),
8086
webrtc::AudioDeviceModule::kPlatformDefaultAudio);
87+
#endif
8188
if (!adm) {
8289
std::cerr << "Warning: Failed to create AudioDeviceModule" << std::endl;
8390
} else {
@@ -354,7 +361,7 @@ int main(int argc, char* argv[]) {
354361

355362
rtcm_config.no_video_device = args.no_video_device;
356363
rtcm_config.no_audio_device = args.no_audio_device;
357-
#if defined(__APPLE__)
364+
#if defined(__APPLE__) || defined(__linux__)
358365
rtcm_config.audio_input_device = args.audio_input_device;
359366
rtcm_config.audio_output_device = args.audio_output_device;
360367
#endif

src/rtc/audio_device_module_pipewire.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <optional>
66

7+
#include <rtc_base/logging.h>
78
#include <rtc_base/ref_count.h>
89
#include <rtc_base/ref_counted_object.h>
910

@@ -40,7 +41,10 @@ class AudioDeviceModulePipeWire : public AudioDeviceModule {
4041
}
4142

4243
int32_t Init() override {
44+
RTC_LOG(LS_INFO) << "AudioDeviceModulePipeWire::Init() called";
4345
AudioDeviceGeneric::InitStatus status = impl_->Init();
46+
RTC_LOG(LS_INFO) << "AudioDeviceLinuxPipeWire::Init() returned status: "
47+
<< static_cast<int>(status);
4448
return status == AudioDeviceGeneric::InitStatus::OK ? 0 : -1;
4549
}
4650

@@ -248,8 +252,10 @@ class AudioDeviceModulePipeWire : public AudioDeviceModule {
248252
};
249253

250254
webrtc::scoped_refptr<AudioDeviceModule> CreatePipeWireAudioDeviceModule() {
251-
return webrtc::scoped_refptr<AudioDeviceModule>(
252-
new AudioDeviceModulePipeWire());
255+
RTC_LOG(LS_INFO) << "CreatePipeWireAudioDeviceModule() called";
256+
auto* module = new AudioDeviceModulePipeWire();
257+
RTC_LOG(LS_INFO) << "AudioDeviceModulePipeWire created: " << module;
258+
return webrtc::scoped_refptr<AudioDeviceModule>(module);
253259
}
254260

255261
} // namespace webrtc

0 commit comments

Comments
 (0)