Linux の Audio 機能をコマンドラインで設定

Linux の音声入出力の設定方法について調べた。目標: 組み込み Linux で自由に入出力先を設定出来る事。

## ALSA と PluseAudio の関係

歴史的な理由からか、Linux の音声入出力は PulseAudio と ALSA の二階建てになっている。ALSA は個々のサウンドカードを担当するのだが、一つのサウンドカードには一つのアプリしかアクセス出来ない。複数のアプリの音声入出力を調停するのは PulseAudio が担当している。具体的には、次のようになっている。

* ALSA は色んなサウンドカードを統一的に操作出来るようにする仕組み。
    * アプリは直接 ALSA を操作しなくても良い。
    * あるアプリが ASLA 経由でサウンドカードを操作している間、他のアプリからそのサウンドカードを使えない。
    * とはいえ、直接 ALSA を使って音声入出力を行うアプリが存在する。
* PluseAudio は複数のアプリが同時に同時にサウンドカードを使う仕組み。
    * お行儀の良いアプリは ALSA ではなく、PulseAudio 経由で音声入出力を行う。
    * とはいえ、直接 ASLA を使ってしまうアプリのために仮想サウンドカードの仕組みがある。

お行儀の良いアプリは PulseAudio 経由で音声入出力を行う事を期待しているが、ALSA を直接使ってしまうアプリのために PulseAudio は仮想サウンドカードとしても動作する。

* ASLA から見ると、PulseAudio は default サウンドカードとして動作する。
* アプリが default サウンドカードを通して再生を行うと、実際には PulseAudio がミキシングしてデフォルトのサウンドカードに音をだす。


## ALSA の [aplay](http://manpages.ubuntu.com/manpages/trusty/man1/aplay.1.html) で再生を確認

ALSA とは、Linux で音声入出力を行うための標準的な仕組み。開発者は ALSA を使う事によってサウンドカードの違いに煩わせず互換性のある音声入出力プログラムを書くことが出来る。ALSA による音声再生をテストするには `aplay` コマンドを使う。

サンプルデータのダウンロード

    $ wget http://freewavesamples.com/files/Kurzweil-K2000-Dual-Bass-C1.wav

`aplay -l` で再生デバイスのリストを表示して、Card 1, device 0 として接続されている Usb Headphone からサンプルデータを鳴らしてみる。

    $ aplay -l
    **** List of PLAYBACK Hardware Devices ****
    card 0: PCH [HDA Intel PCH], device 0: ALC233 Analog [ALC233 Analog]
      Subdevices: 1/1
      Subdevice #0: subdevice #0
    card 1: Set [C-Media USB Headphone Set], device 0: USB Audio [USB Audio]
      Subdevices: 1/1
      Subdevice #0: subdevice #0
	...
    $ aplay --device=hw:1,0 Kurzweil-K2000-Dual-Bass-C1.wav

`--device` オプションには `hw:card,device` のようにして Card 番号 と device 番号を渡す。これらは変化する可能性があるので、`aplay -L` の出力を使うと良いらしい。

`Device or resource busy` のエラーが出る時は起動中の他のアプリを止めてみる。alsa は生のデバイスを扱うため、一つのアプリからしか音を出せない。`--device=defaul` でPulseAudio の仮想サウンドカード経由で音をだす事も出来る。

    $ aplay -L
    sysdefault:CARD=PCH
        HDA Intel PCH, ALC233 Analog
        Default Audio Device
    sysdefault:CARD=Set
        C-Media USB Headphone Set, USB Audio
        Default Audio Device
	...
	$ aplay --device=sysdefault:CARD=Set Kurzweil-K2000-Dual-Bass-C1.wav

## ALSA の [amixer](http://manpages.ubuntu.com/manpages/trusty/man1/amixer.1.html) で再生を確認

これで音が出ない場合、音量の設定がおかしいかも知れない。音量の設定には `amixer` コマンドを使う。例えば Card 1 の現在の設定を見るにはオプション `-c` に 1 を渡して `amixer -c1` のようにする。

```
$ amixer -c1
Simple mixer control 'Headphone',0
  Capabilities: pvolume pswitch pswitch-joined
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 151
  Mono:
  Front Left: Playback 137 [91%] [-2.69dB] [on]
  Front Right: Playback 137 [91%] [-2.69dB] [on]
Simple mixer control 'Mic',0
  Capabilities: pvolume pvolume-joined cvolume cvolume-joined pswitch pswitch-joined cswitch cswitch-joined
  Playback channels: Mono
  Capture channels: Mono
  Limits: Playback 0 - 32 Capture 0 - 16
  Mono: Playback 0 [0%] [0.00dB] [off] Capture 13 [81%] [19.34dB] [on]
Simple mixer control 'Auto Gain Control',0
  Capabilities: pswitch pswitch-joined
  Playback channels: Mono
  Mono: Playback [on]
```

`amixer` を使ってサウンドカードの設定を変更するには二通りの方法がある。

* Simple mixer control
    * 簡単な方法
    * amixer の `set` または `sset` コマンドで設定
* Control
    * 細かく制御出来る方法
    * amixer の `cset` コマンドで設定
    
上の結果ではこのサウンドカードに "Headphone", "Mic", "Audio Gain Conotrol" の3つの Simple mixer control があって、それぞれの値が表示されている。`sset` コマンドで使える値には次のような物がある。また、左右ボリュームやミュート状態など複数の値を同時に設定出来る。

* 100% などのパーセント記法
* -20dB などのデシベル記法
* 単位をつけないとハードウェアで使っている数値
* mute | unmute 再生の無効有効
* nocap | cap 録音の無効有効
* front | rear | center | woofer チャンネル
* playback | capture 再生の設定か録音の設定か切り替え。(なぜかマイクにも再生音量が設定できるのでこのオプションがある)

たとえば "Headphone" の音量を左 100% 右 50% にして有効にするには次のようにする。

```
amixer -c1 sset Headphone 100%,50% unmute
Simple mixer control 'Headphone',0
  Capabilities: pvolume pswitch pswitch-joined
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 151
  Mono:
  Front Left: Playback 151 [100%] [-0.06dB] [on]
  Front Right: Playback 76 [50%] [-14.13dB] [on]
```

また、"Mic" の録音音量を 70% にして録音を有効にするには次のようにする。

```
amixer -c1 sset Mic capture 70% rec
Simple mixer control 'Mic',0
  Capabilities: pvolume pvolume-joined cvolume cvolume-joined pswitch pswitch-joined cswitch cswitch-joined
  Playback channels: Mono
  Capture channels: Mono
  Limits: Playback 0 - 32 Capture 0 - 16
  Mono: Playback 0 [0%] [0.00dB] [off] Capture 12 [75%] [17.85dB] [on]
```

もっと細かく制御したい場合は Simple mixer control ではなく control と `cset` コマンドを使う。どんな Control が存在するかを知るには、`contents` コマンドを使う。例えば Card 1 の Control を知るには `amixer -c1 contents` とする。

```
$ amixer -c1 contents
numid=5,iface=MIXER,name='Headphone Playback Switch'
  ; type=BOOLEAN,access=rw------,values=1
  : values=on
numid=6,iface=MIXER,name='Headphone Playback Volume'
  ; type=INTEGER,access=rw---R--,values=2,min=0,max=151,step=0
  : values=151,76
  | dBminmax-min=-28.37dB,max=-0.06dB
...
```

ここで Headphone Playback Volume を更新したい場合は `cset` を使って次のようにする。Control 名として ifname iface name などが使える。

```
amixer -c 1 cset name='Headphone Playback Volume' 20%
numid=6,iface=MIXER,name='Headphone Playback Volume'
  ; type=INTEGER,access=rw---R--,values=2,min=0,max=151,step=0
  : values=31,31
  | dBminmax-min=-28.37dB,max=-0.06dB
```

## PulseAudio でデフォルトの入出力先を切り替える

`/usr/share/alsa/alsa.conf` に ALSA の設定ファイルがある。ここで、default が PulseAudio の仮想サウンドカードになっている事を確認出来る。PulseAudio は ASLA とは別に複数の音声入出力を切り替える事が出来るので、こちらも調べる。

コマンドラインで出力先を切り替えたい場合、まず準備としておまじないが必要な場合がある。

    $ sudo vi /etc/pulse/default.pa
    load-module module-stream-restore restore_device=false
	(restore_device=false を追加)
    $ pulseaudio -k
    (設定を読み込むために pluseaudio を -k で終了する。ここで設定によっては pulseaudio が自動起動する)

現在再生可能なデバイスを `pacmd list-sinks` で表示する。

```
$ pacmd list-sinks  | grep name:
	name: <alsa_output.pci-0000_03_00.1.hdmi-stereo>
	name: <alsa_output.pci-0000_00_1b.0.analog-stereo>
	name: <alsa_output.usb-0d8c_C-Media_USB_Headphone_Set-00.analog-stereo>
```

デフォルト再生デバイスとして、USB Headphone を選択する。

    pacmd set-default-sink alsa_output.usb-0d8c_C-Media_USB_Headphone_Set-00.analog-stereo

## PulseAudio で音量を調整する

`amixer` で音量を調節していると、マシンによって control の名前が違いすぎてスクリプトで扱いづらい事が分かった。PulseAudio でデフォルトデバイスの音量調整をした方が確実だ。

ミュート解除

    pacmd set-sink-mute @DEFAULT_SINK@ 0
    
音量を 70 % 程度に設定 (0x10000 が最大値)

    pacmd set-sink-volume @DEFAULT_SINK@ 0xb400

## その他のツール

コマンドラインで音声ファイルを扱うには sox というツールが便利

     $ sudo apt install sox

録音

```
$ rec test.wav

Input File     : 'default' (alsa)
Channels       : 2
Sample Rate    : 48000
Precision      : 16-bit
Sample Encoding: 16-bit Signed Integer PCM

In:0.00% 00:00:15.02 [00:00:00.00] Out:717k  [      |=-    ]        Clip:0    ^C
Aborted.
```

再生

```
$ play test.wav

test.wav:

 File Size: 2.87M     Bit Rate: 1.54M
  Encoding: Signed PCM
  Channels: 2 @ 16-bit
Samplerate: 48000Hz
Replaygain: off
  Duration: 00:00:14.93

In:100%  00:00:14.93 [00:00:00.00] Out:717k  [      |      ]        Clip:0    
Done.
```

`alsamixer` を使うとターミナルから音量の調節が出来る。調整した音量は設定画面と同期しているような同期していないような不思議な動きなので調査中。ミュートの表示がわかりにくい。ボリュームの下の箱の表示の意味は次の通り。

* 00: 有効
* MM: ミュート中

## 参考

* [ALSA Architecture](https://en.wikipedia.org/wiki/Advanced_Linux_Sound_Architecture#Concepts)
    * card, device, interface, などの言葉の意味が書いてある。
* [man amixer](https://linux.die.net/man/1/amixer)
* [man pulse-cli-syntax](http://manpages.ubuntu.com/manpages/xenial/en/man5/pulse-cli-syntax.5.html)
    * pacmd で使うコマンドのマニュアル
* [/etc/pulse/default.pa の編集が必要な理由](https://askubuntu.com/questions/71863/how-to-change-pulseaudio-sink-with-pacmd-set-default-sink-during-playback/72076#72076)
* The Unofficial ALSA Wiki [Alsa Opensrc Org](https://alsa.opensrc.org/)