PulseAudioをコマンドラインで操作したときのメモ

#はじめに
pulseaudioのコマンドラインでの使い方についてのメモ


#pulseaudioとは？
主にlinuxにて使われているオーディオ信号の経路制御や音量制御、ミキシング等を行うための裏方ツール。音声をネットワークで配信する環境も提供する。

#実験に使用した環境
* RaspberryPi(4BとZero。OSはどちらもbuster)
* USBマイクx2
* HDMI接続TV(音がで出ることが必要)
* ステレオヘッドフォン
* pulseaudioがユーザ権限で動いている

## pulseaudio起動時にこんなエラーが発生することがある場合(自分の場合)

```
$ pulseaudio --start
N: [pulseaudio] main.c: ユーザーが設定したサーバー unix:/tmp/pulseaudio.socket は start/autospawn を拒否しています。
```

色々調べて見たところ、/etc/pulse/client.confに以下の設定が含まれていると、ユーザ権限で起動できないらしい。私の場合はこれに該当した。いついじったのか記憶がないのだが…

```
/etc/pulse/client.conf:
autospawn = no
default-server = unix:/tmp/pulseaudio.socket
```

ということで設定を変更する。次に以下を実行して起動時設定ファイルをローカルにコピー。

```
$ cp /etc/pulse/client.conf .config/pulse/client.conf
```

コピーしたファイルの当該箇所をテキストエディタでコメントにして設定を無効化。

```
$HOME/.config/pulse/client.conf:
# autospawn = no
# default-server = unix:/tmp/pulseaudio.socket
```

これでユーザ権限で起動できるようになった

```
$ pulseaudio --start
$
```


#試したPulseAudioの機能

※以下、pacmdというコマンドでpulseaudioの設定を行っている

## USBマイクの音声をアプリを動かすことなくそのままHDMI-OUTに出力したい

### まずUSBマイクのデバイス名を取得

```
$pacmd list-sources|grep name:
```

audioのsourceデバイスリストを取得するコマンド。sourceとは入力デバイスのこと。
以下のような返事が返ってくる。

```
name: <alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-mono>
name: <alsa_output.platform-bcm2835_audio.digital-stereo.monitor>
name: <alsa_output.platform-bcm2835_audio.analog-stereo.monitor>
name: <alsa_output.platform-soc_sound.stereo-fallback.monitor>
```

最初に表示されたものが今回使うUSBマイクのデバイス名である


### 次にHDMI-OUTのデバイス名を取得

```
$pacmd list-sinks|grep name:
```

audioのsinkデバイスリストを取得する。sinkとは出力デバイスのこと。
以下のような返事が返ってくる。

```
name: <alsa_output.platform-bcm2835_audio.digital-stereo>
name: <alsa_output.platform-bcm2835_audio.analog-stereo>
name: <alsa_output.platform-soc_sound.stereo-fallback>
```

最初に表示されたものがHDMI-OUTのデバイス名
2行目のデバイスはヘッドフォン端子のデバイス名


### USBマイク(source)をHDMI-OUT(sink)に接続
loopbackモジュールを使ってデバイスの接続を行う

```
$pacmd load-module module-loopback source=alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-mono sink=alsa_output.platform-bcm2835_audio.digital-stereo
```

設定が成功すると、USBマイクの出力がHDMIで接続されたモニタのスピーカから出力されるはず(ハウリングに注意)。
module-loopbackでは、ch数、サンプリング周波数等を設定することも可能。詳細は下の参考リンクにて確認が可能

## HDMI-OUTに出力した音声をアナログ出力(ヘッドフォン端子)にも出力したい
これもloopbackモジュールを使って接続を行う

```
$pacmd load-module module-loopback source=alsa_output.platform-bcm2835_audio.digital-stereo.monitor sink=alsa_output.platform-bcm2835_audio.analog-stereo
```

設定が成功すると、USBマイクの出力がヘッドフォン端子からも出力される。
pulseaudio環境では、sinkデバイス名に".monitor"をつけたデバイスがsourceとして存在する。
このデバイスをloopbackモジュールによりヘッドフォン端子に接続することで、
最初に設定したHDMI-OUTとともにヘッドフォン端子への出力設定も有効になる。


### USBマイク(source)の入力レベルを変えたい
最大値が0x10000とのことだが、これより大きい値も設定可能ではある(その場合、大きな音が入った時は歪んでしまう)

```
$pacmd set-source-volume alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-mono 0x10000
```

sink側でもvolume設定は可能。以下のコマンドで変更可能な項目と現在の値を表示できる。


```
$pacmd dump|grep "\-volume"
set-sink-volume alsa_output.platform-bcm2835_audio.digital-stereo 0x10000
set-sink-volume alsa_output.platform-bcm2835_audio.analog-stereo 0x10000
set-sink-volume alsa_output.platform-soc_sound.stereo-fallback 0x10000
set-source-volume alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-mono 0x10000
set-source-volume alsa_output.platform-bcm2835_audio.digital-stereo.monitor 0x10000
set-source-volume alsa_output.platform-bcm2835_audio.analog-stereo.monitor 0x10000
set-source-volume alsa_output.platform-soc_sound.stereo-fallback.monitor 0x10000
```


## 2つのUSBマイク音声をミキシングしてヘッドフォン端子に出力したい
### まず2つのマイクのデバイス名を取得

```
$pacmd list-sources|grep name:
```

```
name: <alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-mono>
name: <alsa_output.platform-bcm2835_audio.digital-stereo.monitor>
name: <alsa_output.platform-bcm2835_audio.analog-stereo.monitor>
name: <alsa_output.platform-soc_sound.stereo-fallback.monitor>
name: <alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-mono.2>
```

最初の行と最後の行がそれぞれUSBマイクのデバイス名。

### module-null-sinkを使ってミキシングを行う

```
$pacmd load-module module-null-sink sink_name=null_mix
$pacmd load-module module-loopback sink=null_mix source=alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-mono
$pacmd load-module module-loopback sink=null_mix source=alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-mono.2
$pacmd load-module module-loopback source=null_mix.monitor sink=alsa_output.platform-bcm2835_audio.analog-stereo
```

* module-null-sinkを使ってnull_mixという名前の仮想sinkデバイスを生成。
* 各USBマイクをsource、null_mixをsinkとして、各マイク毎にmodule-loopbackを使ってnull_mixに接続。
* 最後にnull_mix.monitorをsource、ヘッドフォン端子をsinkとして、module-loopbackにて接続することで、ミキシング音声がヘッドフォン端子に出力される。


## RTPにて音声をネットワークで伝送したい

### 送信側設定(送信側IPアドレス: 192.168.1.20)
USBマイクの音声をユニキャスト(相手先指定)で直接RTP送信する場合。
destination_ipにマルチキャストアドレスを指定することもできる。

```
$pacmd load-module module-rtp-send source=alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-mono source_ip=192.168.1.20 destination_ip=192.168.1.10
```

```
$pacmd dump|grep rtp
load-module module-rtp-send source=alsa_input.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-mono source_ip=192.168.1.20 destination_ip=192.168.1.10
```

2行目のコマンドで設定内容が帰ってくれば正常に設定されている。
何も帰ってこない場合は、設定内容に誤りがある。


### 受信側設定(受信側IPアドレス: 192.168.1.10)
RTP受信したストリームをヘッドフォン端子に出力する場合。
sap_addressには0.0.0.0を設定しないと受信できない。
複数の送信端末がある場合、同時に受信できるっぽい(受信時にミキシングされる印象)。

```
$pacmd load-module module-rtp-recv sap_address=0.0.0.0 sink=alsa_output.platform-bcm2835_audio.analog-stereo
$pacmd dump|grep rtp
load-module module-rtp-recv sap_address=0.0.0.0 sink=alsa_output.platform-bcm2835_audio.analog-stereo
```

2行目のコマンドで設定内容が帰ってくれば正常に設定されている。
何も帰ってこない場合は、設定内容に誤りがある。


### 補足事項
* 上記設定では、通信が確立すると受信側のヘッドフォンから送信側の音が垂れ流しになる。
* RTP転送では若干の伝送遅延が発生することに注意(数10-数100msec)。


# 最後に
今回の実験により、これまであまり知らなかったpulseaudioの機能について少し理解が深まった気がする。また、コマンドでいじれるとスクリプトでの自動設定や遠隔操作の際に都合がよい。

参考リンク
[PulseAudio-module](https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Modules/ "Pulseudio-module")