Linuxオーディオ:ALSAとPulseAudioの関係
音関係に詳しくないので、Linuxで音声を扱っていると、なんだかよく分からないけどまあ音が出たからいいかとやり過ごしてしまう場面が多々あります。
その原因の1つはALSAとPulseAudioの関係をきちんと理解していないためだと思われるので、自分なりに少し整理してみました。
ALSA
ALSA(Advanced Linux Sound Architecture)はサウンドデバイスへアクセスするためのAPIを提供するものです。
例えば、ラズパイ5にIQaudioのPiDAC+を取り付けた場合は、下記のようにHDMIのカード2つと、DACのサウンドカード1つがALSAから利用できる感じになります。
どのようなサウンドカードが利用できるかは、aplayに-lオプションを付けて実行すればリストが表示されます。
$ aplay -l
**** ハードウェアデバイス PLAYBACK のリスト ****
カード 0: vc4hdmi0 [vc4-hdmi-0], デバイス 0: MAI PCM i2s-hifi-0 [MAI PCM i2s-hifi-0]
サブデバイス: 1/1
サブデバイス #0: subdevice #0
カード 1: vc4hdmi1 [vc4-hdmi-1], デバイス 0: MAI PCM i2s-hifi-0 [MAI PCM i2s-hifi-0]
サブデバイス: 1/1
サブデバイス #0: subdevice #0
カード 2: DAC [RPi DAC+], デバイス 0: Raspberry Pi DAC+ HiFi pcm512x-hifi-0 [Raspberry Pi DAC+ HiFi pcm512x-hifi-0]
サブデバイス: 1/1
サブデバイス #0: subdevice #0
例えば、音楽CDからリッピングしたwavファイル(16bit/44.1kHz/2ch)をPiDAC+で再生させたいなら、デバイス指定(-D)にhw:2,0を付けて実行すれば再生されます。"hw:2,0"は”hw:CARD=DAC,DEV=0”という書き方でも良いです。
$ aplay -D hw:2,0 test.wav
再生中 WAVE 'test.wav' : Signed 16 bit Little Endian, レート 44100 Hz, ステレオ
しかし、例えばJVCハイレゾリューションサイトに置いてある24bit/192kHzのハイレゾ音源のwavファイルを指定した場合には、下記のようにフォーマットが違うということでエラーになってしまい、再生できません。
$ aplay -D hw:2,0 Keep_your_side_24bit192kHz_short.wav
再生中 WAVE '/home/kaneko/Music/Keep_your_side_24bit192kHz_short.wav' : Signed 24 bit Little Endian in 3bytes, レート 192000 Hz, ステレオ
aplay: set_params:1352: サンプルフォーマットが使用不可能
Available formats:
- S16_LE
- S24_LE
- S32_LE
この場合、デバイスの指定を"hw:2,0"の代わりに"plughw:2,0"とすると再生できます。hwの場合は、入力のデータフォーマットをそのまま出力先デバイスに送りますが、plughwを指定した場合には、出力先デバイスに合わせて変換が行われるようです。どのような変換が行われたかは、aplayで-vオプションを付けて実行すると表示されます。
今回の場合だと下記に示すように、format:S24_3LE, mbits:24が、format:S24_LE, mbits:32に変換されてPiDAC+に送られています。3バイトに24bitデータが格納されている元のデータが、4バイトに24bitデータが格納されているデータへ変換されているようです。
$ aplay -v -D plughw:2,0 Keep_your_side_24bit192kHz_short.wav
再生中 WAVE '/home/kaneko/Music/Keep_your_side_24bit192kHz_short.wav' : Signed 24 bit Little Endian in 3bytes, レート 192000 Hz, ステレオ
Plug PCM: Linear conversion PCM (S24_LE)
Its setup is:
stream : PLAYBACK
access : RW_INTERLEAVED
format : S24_3LE
subformat : STD
channels : 2
rate : 192000
exact rate : 192000 (192000/1)
msbits : 24
buffer_size : 65536
period_size : 512
period_time : 2666
tstamp_mode : NONE
tstamp_type : MONOTONIC
period_step : 1
avail_min : 512
period_event : 0
start_threshold : 65536
stop_threshold : 65536
silence_threshold: 0
silence_size : 0
boundary : 4611686018427387904
Slave: Hardware PCM card 2 'RPi DAC+' device 0 subdevice 0
Its setup is:
stream : PLAYBACK
access : MMAP_INTERLEAVED
format : S24_LE
subformat : STD
channels : 2
rate : 192000
exact rate : 192000 (192000/1)
msbits : 32
buffer_size : 65536
period_size : 512
period_time : 2666
tstamp_mode : NONE
tstamp_type : MONOTONIC
period_step : 1
avail_min : 512
period_event : 0
start_threshold : 65536
stop_threshold : 65536
silence_threshold: 0
silence_size : 0
boundary : 4611686018427387904
appl_ptr : 0
hw_ptr : 0
では、plughwにすれば何でも変換してくれるかというとそうでも無いようで、HDMIデバイスに対しては、hwでもplughwでも再生できません。
$ aplay -D hw:0,0 test.wav
再生中 WAVE 'test.wav' : Signed 16 bit Little Endian, レート 44100 Hz, ステレオ
aplay: set_params:1352: サンプルフォーマットが使用不可能
Available formats:
- IEC958_SUBFRAME_LE
$ aplay -D plughw:0,0 test.wav
再生中 WAVE 'test.wav' : Signed 16 bit Little Endian, レート 44100 Hz, ステレオ
aplay: set_params:1352: サンプルフォーマットが使用不可能
Available formats:
- IEC958_SUBFRAME_LE
デバイス名に指定できるのはhwやplughwだけでなく色々なものがあるようです。それらは、aplayで-Lオプションを付けて実行すると一覧が表示されます。
$ aplay -L
null
Discard all samples (playback) or generate zero samples (capture)
default
Playback/recording through the PulseAudio sound server
sysdefault
Default Audio Device
lavrate
Rate Converter Plugin Using Libav/FFmpeg Library
samplerate
Rate Converter Plugin Using Samplerate Library
speexrate
Rate Converter Plugin Using Speex Resampler
jack
JACK Audio Connection Kit
oss
Open Sound System
pulse
PulseAudio Sound Server
speex
Plugin using Speex DSP (resample, agc, denoise, echo, dereverb)
upmix
Plugin for channel upmix (4,6,8)
vdownmix
Plugin for channel downmix (stereo) with a simple spacialization
hw:CARD=vc4hdmi0,DEV=0
vc4-hdmi-0, MAI PCM i2s-hifi-0
Direct hardware device without any conversions
plughw:CARD=vc4hdmi0,DEV=0
vc4-hdmi-0, MAI PCM i2s-hifi-0
Hardware device with all software conversions
sysdefault:CARD=vc4hdmi0
vc4-hdmi-0, MAI PCM i2s-hifi-0
Default Audio Device
hdmi:CARD=vc4hdmi0,DEV=0
vc4-hdmi-0, MAI PCM i2s-hifi-0
HDMI Audio Output
dmix:CARD=vc4hdmi0,DEV=0
vc4-hdmi-0, MAI PCM i2s-hifi-0
Direct sample mixing device
usbstream:CARD=vc4hdmi0
vc4-hdmi-0
USB Stream Output
hw:CARD=vc4hdmi1,DEV=0
vc4-hdmi-1, MAI PCM i2s-hifi-0
Direct hardware device without any conversions
plughw:CARD=vc4hdmi1,DEV=0
vc4-hdmi-1, MAI PCM i2s-hifi-0
Hardware device with all software conversions
sysdefault:CARD=vc4hdmi1
vc4-hdmi-1, MAI PCM i2s-hifi-0
Default Audio Device
hdmi:CARD=vc4hdmi1,DEV=0
vc4-hdmi-1, MAI PCM i2s-hifi-0
HDMI Audio Output
dmix:CARD=vc4hdmi1,DEV=0
vc4-hdmi-1, MAI PCM i2s-hifi-0
Direct sample mixing device
usbstream:CARD=vc4hdmi1
vc4-hdmi-1
USB Stream Output
hw:CARD=DAC,DEV=0
RPi DAC+, Raspberry Pi DAC+ HiFi pcm512x-hifi-0
Direct hardware device without any conversions
plughw:CARD=DAC,DEV=0
RPi DAC+, Raspberry Pi DAC+ HiFi pcm512x-hifi-0
Hardware device with all software conversions
sysdefault:CARD=DAC
RPi DAC+, Raspberry Pi DAC+ HiFi pcm512x-hifi-0
Default Audio Device
dmix:CARD=DAC,DEV=0
RPi DAC+, Raspberry Pi DAC+ HiFi pcm512x-hifi-0
Direct sample mixing device
usbstream:CARD=DAC
RPi DAC+
USB Stream Output
ここでは、"hw:0,0"という略した表記でなく、"hw:CARD=vc4hdmi0,DEV=0"というCARD名とDEV番号での表記になっています。
先ほどのHDMIへの出力の場合では、"sysdefault:CARD=vc4hdmi0"という指定をすれば再生してくれます。"sysdefault:0"という表記でもOKです。先ほどのハイレゾのwavファイルでも同じ指定で再生してくれます。
$ aplay -v -D sysdefault:0 Keep_your_side_24bit192kHz_short.wav
再生中 WAVE 'Keep_your_side_24bit192kHz_short.wav' : Signed 24 bit Little Endian in 3bytes, レート 192000 Hz, ステレオ
Plug PCM: Rate conversion PCM (48000, sformat=S24_3LE)
Converter: libspeex (external)
Protocol version: 10003
Its setup is:
stream : PLAYBACK
access : RW_INTERLEAVED
format : S24_3LE
subformat : STD
channels : 2
rate : 192000
exact rate : 192000 (192000/1)
msbits : 24
buffer_size : 96000
period_size : 24000
period_time : 125000
tstamp_mode : NONE
tstamp_type : MONOTONIC
period_step : 1
avail_min : 24000
period_event : 0
start_threshold : 96000
stop_threshold : 96000
silence_threshold: 0
silence_size : 0
boundary : 6755399441055744000
Slave: Soft volume PCM
Control: PCM Playback Volume
min_dB: -51
max_dB: 0
resolution: 256
Its setup is:
stream : PLAYBACK
access : MMAP_INTERLEAVED
format : S24_3LE
subformat : STD
channels : 2
rate : 48000
exact rate : 48000 (48000/1)
msbits : 24
buffer_size : 24000
period_size : 6000
period_time : 125000
tstamp_mode : NONE
tstamp_type : MONOTONIC
period_step : 1
avail_min : 6000
period_event : 0
start_threshold : 24000
stop_threshold : 24000
silence_threshold: 0
silence_size : 0
boundary : 6755399441055744000
Slave: IEC958 subframe conversion PCM (IEC958_SUBFRAME_LE)
Its setup is:
stream : PLAYBACK
access : MMAP_INTERLEAVED
format : S24_3LE
subformat : STD
channels : 2
rate : 48000
exact rate : 48000 (48000/1)
msbits : 24
buffer_size : 24000
period_size : 6000
period_time : 125000
tstamp_mode : NONE
tstamp_type : MONOTONIC
period_step : 1
avail_min : 6000
period_event : 0
start_threshold : 24000
stop_threshold : 24000
silence_threshold: 0
silence_size : 0
boundary : 6755399441055744000
Slave: Hooks PCM
Its setup is:
stream : PLAYBACK
access : MMAP_INTERLEAVED
format : IEC958_SUBFRAME_LE
subformat : STD
channels : 2
rate : 48000
exact rate : 48000 (48000/1)
msbits : 24
buffer_size : 24000
period_size : 6000
period_time : 125000
tstamp_mode : NONE
tstamp_type : MONOTONIC
period_step : 1
avail_min : 6000
period_event : 0
start_threshold : 24000
stop_threshold : 24000
silence_threshold: 0
silence_size : 0
boundary : 6755399441055744000
Slave: Hardware PCM card 0 'vc4-hdmi-0' device 0 subdevice 0
Its setup is:
stream : PLAYBACK
access : MMAP_INTERLEAVED
format : IEC958_SUBFRAME_LE
subformat : STD
channels : 2
rate : 48000
exact rate : 48000 (48000/1)
msbits : 24
buffer_size : 24000
period_size : 6000
period_time : 125000
tstamp_mode : NONE
tstamp_type : MONOTONIC
period_step : 1
avail_min : 6000
period_event : 0
start_threshold : 24000
stop_threshold : 24000
silence_threshold: 0
silence_size : 0
boundary : 6755399441055744000
appl_ptr : 0
hw_ptr : 0
各オーディオカードの設定は、alsamixerを実行すると行うことができます。
F6キーでサウンドカードを選択でき、PiDAC+の場合は下記の画面になります。上下左右のカーソルキーを使って設定を変更できます。PiDAC+ではDSPのフィルタの変更などもできるようです(私の耳では音の違いが分からないので、本当に変わっているのかどうかは不明です)。
ちなみに、alsamixerを起動したときに最初に出てくるマスターの音量調整は、次に説明するPulseAudioの音量調整となっているので、直接hwなどで出力先デバイスを指定して再生している場合には、このボリュームを変更しても音量は変わりません。
PulseAudio
PulseAudioはサウンドサーバーと呼ばれる物で、アプリケーションとサウンドカード(ALSAのレイヤ)との間に入って動作するものです。
現在では、ラズパイOSも含め多くのLinuxでは、インストールしたときに最初から動作しているように思います。
イメージとしては、下記の図のような信号の流れになる感じです。
先ほどまでのALSAの説明で、aplayで出力先デバイスを明示的に指定する方法を説明しました。それは、この図の青線やオレンジ線に相当します。一方、デバイスの指定をしない場合は、デフォルトとしてPluseAudioに入力されるようになっているようで、これは緑線に相当します。
したがって、aplayで出力先デバイスの指定なしで音声ファイルを再生すると、色々なフォーマットの音声ファイルであっても、そのデータはPluseAudioが受け取ってくれるので、エラーも無く再生が実行されます。出力先のデバイスやそれに合わせたフォーマット変換、音量調整などはすべてPulseAudioが行っているようです。
pavucontrolを起動すると下図のようなウインドウが開き、出力先のデバイスの指定や、音量調整などのPulseAudioの設定が行えます。
PulseAudioが間に入るメリットの1つに、複数のアプリケーションが同一のサウンドデバイスに対して同時に再生が行える点があります。
例えば、aplayが直接サウンドカードを使って再生しているときに、別のaplayを使って同一デバイスに再生をすると、デバイスが利用できないとエラーになってしまいます。
一方、PulseAudioを介した場合、いくつでも再生を実行することができます。PulseAudioがミックスして、同一のデバイスに出力してくれます。
また、それぞれの出力先を異なるものにすることもできます。
再生アプリケーションごとの音量調整や出力先の設定はpavucontrolでできます。下記はaplayで3つ同時に音声ファイルを再生した場合の画面です。
この例では、2つはミックスしてHDMI出力へ、1つはPiDAC+へ出力設定しています。