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 were default, 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 reads pulseaudio 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) then lsof(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)