メモ: Linuxのサウンド周り(特にエコーキャンセリング)
ゆえあってエコーキャンセリングについて調査中。まあそれだけに限らずLinuxのサウンドや音響関連の記事を少し収集。
結構するのな
PulseAudioにはモジュールがある
結構使用されている
当初は、Raspberry Pi の OS に採用されている PulseAudio の echo cancellation モジュールを利用してエコーキャンセルを試みましたが、十分な効果が得られなかったため、今回はエコーキャンセル機能を使わない運用としました。その代わり、エージェントが発話中はユーザーが新たに話しかけることを制限し、エージェントの発話が完了するまで待機する方式を採用しました。これにより、ユーザーはエージェントの発話終了後であれば質問を行えるようになりました。
これは実際に試してみて判断したい
GitHubやHuggingFaceを見ると色々ありそうな気もする。
まずは、PulseAudioでエコーキャンセリングモジュールを有効にする。ちなみに環境はRPi4。
~/.config/pulse/default.pa
に以下を追加する
.include /etc/pulse/default.pa
load-module module-echo-cancel
PulseAudioを再起動
systemctl --user restart pulseaudio.service
sourceとsinkに仮想デバイスが生える。"echo cancel"という文字が見えているのがわかる。
pactl list sources short
0 alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-monomodule-alsa-card.c s16le 1ch 48000Hz SUSPENDED
1 alsa_output.platform-bcm2835_audio.stereo-fallback.monitor module-alsa-card.c s16le 2ch 44100Hz SUSPENDED
2 alsa_output.platform-bcm2835_audio.stereo-fallback.2.monitor module-alsa-card.c s16le 2ch 48000Hz SUSPENDED
3 alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-mono.echo-cancel module-echo-cancel.c float32le 1ch 32000Hz SUSPENDED
4 alsa_output.platform-bcm2835_audio.stereo-fallback.2.echo-cancel.monitor module-echo-cancel.c float32le 1ch 32000Hz SUSPENDED
pactl list sinks short
0 alsa_output.platform-bcm2835_audio.stereo-fallback module-alsa-card.c s16le 2ch 44100Hz SUSPENDED
1 alsa_output.platform-bcm2835_audio.stereo-fallback.2 module-alsa-card.c s16le 2ch 48000Hz SUSPENDED
2 alsa_output.platform-bcm2835_audio.stereo-fallback.2.echo-cancel module-echo-cancel.c float32le 1ch 32000Hz SUSPENDED
このあたりの理屈がいまいちわからなくて、例として、
- 何らかの音声を入力で受ける
- それを元に何らかの処理を行う
- 結果を音声で出力する
みたいなアプリケーションの場合に、エコーキャンセリングモジュールがどのように機能するか?をChatGPTと壁打ちした。
まず、エコーキャンセリングモジュールがない、普通の場合。
エコーキャンセリングモジュールがある場合。
で、OSのオーディオ設定で、これらの仮想デバイスを参照するようにすればいいらしいのだが、デバイスのオーディオルーティングをきちんと理解しようとすると非常にわかりにくい。そのあたりをまとめようと思ったけど、面倒なので設定で書いた。
.include /etc/pulse/default.pa
load-module module-echo-cancel source_name=ec_source sink_name=ec_sink aec_method=webrtc
update-source-proplist ec_source device.description="Microphone (EC)"
update-sink-proplist ec_sink device.description="Speaker (EC)"
set-default-source ec_source
set-default-sink ec_sink
とりあえずこれで検証する。
自分が試してみた限りは結構しっかり効いてた。むしろちょっと効きすぎぐらいの感じ。パラメータでもう少しいじれないものかを確認してみたい。
参考