ALSA Configuration - andy3471/GBD GitHub Wiki
ALSA Background
The Advanced Linux Sound Architecture was conceived around 20 years ago (1998)
but still remains quite an advanced and powerful sound system. ALSA is highly configurable and
modular. However, its flexibility comes at a (slight) price that
requires some patience for the uninitiated. This section will walk the
unfamiliar through the steps required to configure ALSA for real world
audio applications (i.e. other than aplay(1)
) working in a GBD setup.
ALSA PCM Plugins
The ALSA library supports a mechanism for PCM plugins. Basically a PCM plugin is a software module
that plugs into the ALSA PCM "pipleline" (i.e. the audio stream route between the audio player and the hardware).
PCM Plugins can be internal (i.e. ALSA native) or external (supplied by a 3rd party). Standard ALSA internal PCM
plugins (such as hw
, plugin
, and dmix
) perform the most basic and common operations expected of any decent OS sound system, e.g. software conversions for sample formats, resampling, channel duplication and mixing, etc.
In other words, these software conversions are applied to the PCM parameters of an
audio signal being routed through ALSA. As discussed in section GBD Quick Start, the most
important PCM parameters with respect to the GBD framework are the ALSA period size,
sample rate, and sample format.
On the other hand, external PCM plugins -- and more precisely external PCM filter plugins -- are meant for miscellaneous DSP related operations on audio signals. The supplied GBD client is an external PCM filter plugin.
To control the order of PCM plugins in the ALSA "pipeline", a user defines an ALSA virtual
PCM device. Virtual PCM devices allow the user to specify the chain of software
conversions and DSP operations to be applied to the signals of an audio stream before they eventually
get routed to the hardware. Virtual PCM devices are defined in an ALSA configuration file. Ordinarily,
the user will edit the ~/.asoundrc
config file when defining a custom virtual PCM device.
ALSA PCM Plugins vs. Sound Servers
On systems that don't support hardware audio stream mixing, using native ALSA PCM plugins is generally not compatible with PulseAudio -- or other sound server -- services. In other words, audio applications must either exclusively use one audio framework or the other.
The GBD client PCM plugin should always be configured for ALSA PCM plugins
such as hw
, plug
, and dmix
. This is because ALSA PCM plugins
allow deterministic control of an audio stream's PCM parameters, notably
the ALSA period size. The beat detection algorithm by the GBD library is
particularly sensitive to this parameter. Sound servers implement their
own buffering mechanisms to control sound flows between their clients. This
leads to unpredictable latencies and jitter (i.e. the statistical distribution,
or simply variance, in latencies).
On systems with a sound server installed, first test whether the sound server (or any other resource) has claimed the playback device, e.g.
$ aplay -D plughw foo.wav
aplay: main:722: audio open error: Device or resource busy
On hardware that does not support PCM stream mixing, likely causes of this error include active instances of sound server clients or some other application using, say, hw
. The obvious solution in this scenario would be to stop or terminate all other programs
currently performing playback. Nevertheless, some applications either run in the background or make use of the
sound system in unexpected ways, making it quite difficult to identify and stop them. The following examples present
a few tricks that can be employed when troubleshooting these matters:
-
Example 1:
Consider,
$ sudo lsof -w /dev/snd/pcmC0D0p COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME audacity 5808 user mem CHR 116,3 513 /dev/snd/pcmC0D0p audacity 5808 user 164u CHR 116,3 0t0 513 /dev/snd/pcmC0D0p audacity 5808 user 166u CHR 116,3 0t0 513 /dev/snd/pcmC0D0p ...
where:
/dev/snd/pcmC0D0p
is the PCM (pcm
) device file for the audio interface's card0 (C0
) device0 (D0
) playback (p
) unit. On this machine, this interface happened to be a 3.5mm line-out. Check/proc/asound/devices
to view the mappings between the audio interface's cards and devices.
In this particular instance,
audacity(1)
's playback settings weredefault
, which is a special ALSA PCM Plugin typically configured for the distro's default sound server --pulseaudio(1)
in this case. Executing,$ kill -15 `pidof audacity` $ sync $ sudo lsof -w /dev/snd/pcmC0D0p ## empty output
allowed the
aplay(1)
command above to succeed. -
Example 2:
Web browser instances running some brand of JavaScript Audio code (e.g. Web Audio API) are quite a notorious breed. It is not uncommon that merely loading a page with the associated JavaScript causes the web browser to attempt to claim the playback sound device even if no audio is immediately being streamed. In these scenarios, and on systems with a sound server installed as the default audio subsystem,
lsof(1)
is quite likely to report:$ sudo lsof -w +c 11 /dev/snd/pcmC0D0p COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME pulseaudio 15366 user mem CHR 116,3 561 /dev/snd/pcmC0D0p pulseaudio 15366 user 22u CHR 116,3 0t0 561 /dev/snd/pcmC0D0p
Try this by visiting any video/music streaming site. Notice that
COMMAND
now readspulseaudio
and not the name of the audio application (i.e. the browser).Now try closing the respective browser window/tab, and then execute
sync(1)
thenlsof(1)
to check whether the audio device has been released.
Once you are good to go with the native ALSA PCM plugins, then you are implicitly cleared for tests with the GBD ALSA PCM plugin.
ALSA Virtual PCM Devices for GBD
To obtain the PCM parameter settings expected by the GBD framework:
- an ALSA period size of 1024 ALSA frames (i.e. 1024 samples per channel; only stereo supported)
- Samples in the ALSA
FLOAT
format - Sample rate of 44100Hz
an audio player is pointed to an ALSA virtual PCM device configured for GBD.
Basic
The simplest possible virtual PCM device definition was already presented in chapter Quick Start: Test Procedure. Here is the definition once again:
pcm.gbd {
type plug
slave {
pcm plugGbd
rate 44100
}
}
pcm.plugGbd {
type gbdclient
slave.pcm "plughw"
ipaddr "192.168.0.19"
port "7777"
}
With respect to the PCM parameters for audio signals meant for the GBD framework, notice that this device definition
accounts for sample format conversions (e.g. from S16
to FLOAT
and vice versa) as well as resampling
to 44100Hz (if necessary) via the plug
PCM plugin. However, notice that there is no explicit configuration for the required
ALSA period size, i.e. 1024. Hence the aplay(1)
commandline in the example in Quick Start:Test Procedure included the --period-size 1024
parameter.
Unfortunately, many "real world" audio applications (e.g. mpv(1)
, mplayer(1)
) do not directly export interfaces
which allow the user to explicitly specify the ALSA period size. Therefore, to use these audio
applications in the GBD framework, some additional ALSA configuration is required.
Controlling ALSA Period Size via DMIX ALSA PCM Plugin
RPi DMIX Issues, Note
Recall that for standalone RPi setups, a low-latency PiHat soundcard addon is required.
Now, dmix
with the RPi's on-board audio device has had a history of issues. For instance, when using the on-board RPi (line-out or HDMI) audio interfaces (on Stretch):
pi@raspberrypi:~ $ aplay -D plug:hw foo.wav ## sound is audible e.g. line-out or HDMI
pi@raspberrypi:~ $ aplay -D plug:dmix foo.wav ## no sound!
But this dmix
problem might not apply when using a GPIO soundcard solution.
System-wide Configuration
This is the simplest way of forcing (most) applications using dmix
to pass 1024 ALSA period sizes
to the ALSA PCM pipeline. The downside is that it will require editing certain distro (i.e. system-wide)
settings for the dmix
PCM plugin; this means that henceforth, the new dmix
configuration will apply to
any other audio application that uses dmix
.
For instance on Ubuntu 16.04 LTS, to configure dmix
to use a base sample rate of 44100Hz and 1024 ALSA period sizes:
-
Modify
/usr/share/alsa/alsa.conf
to reflect:$ cat /usr/share/alsa/alsa.conf | grep 44100 defaults.pcm.dmix.rate 44100
-
Then edit
/usr/share/alsa/pcm/dmix.conf
for 1024 period sizes, i.e.:$ cat /usr/share/alsa/pcm/dmix.conf pcm.!dmix { @args [ CARD DEV SUBDEV FORMAT RATE ] ... slave { ... period_size { @func refer name { ... } default 1024 } ...
Now, edit ~/.asoundrc
to include:
pcm.gbd {
type plug
slave {
pcm plugGbd
rate 44100
}
}
pcm.plugGbd {
type gbdclient
slave.pcm "plug:dmix"
ipaddr "192.168.0.19"
port "7777"
}
Test this configuration with the following aplay(1)
command line
$ aplay -D gbd foo.wav -v
Notice the omission of the --period-size 1024
parameter. Inspect the output.
At least at the Slave: gbdclient
level, make sure that you have obtained the
exact settings displayed in this snippet.
...
Slave: gbdclient
Its setup is:
stream : PLAYBACK
access : MMAP_INTERLEAVED
format : FLOAT_LE
subformat : STD
channels : 2
rate : 44100
...
period_size : 1024
...
Slave: Plug PCM: Linear Integer <-> Linear Float conversion PCM (S32_LE)
Its setup is:
...
Slave: Direct Stream Mixing PCM
Its setup is:
stream : PLAYBACK
access : MMAP_INTERLEAVED
format : S32_LE
subformat : STD
channels : 2
rate : 44100
...
period_size : 1024
...
Hardware PCM card 0 'HDA Intel PCH' device 0 subdevice 0
Its setup is:
stream : PLAYBACK
access : MMAP_INTERLEAVED
format : S32_LE
subformat : STD
channels : 2
rate : 44100
...
period_size : 1024
...
Device-specific Configuration
An alternative, should modifying system-wide ALSA settings not be an option, is the following virtual PCM device definition:
pcm.gbd {
type plug
slave {
pcm plugGbd
rate 44100
}
}
pcm.plugGbd {
type gbdclient
slave.pcm "plugGbdDmix"
ipaddr "192.168.0.19"
port "7777"
}
pcm.plugGbdDmix {
type plug
slave.pcm "gbdDmix"
}
pcm.gbdDmix {
type dmix
ipc_key 555888 # any unique value
ipc_key_add_uid true
slave {
pcm "hw"
format S32_LE
rate 44100
period_size 1024
}
}
where the sample format specified against the format
keyword in the slave
PCM plugin for the gbdDmix
device
should be a format directly supported by the hardware (i.e. since the slave or "output" PCM plugin is hw
)