Raspberry Pi and realtime, low-latency audio

The Raspberry Pi can be set up to handle realtime, low-latency audio but it requires quite some tweaking. Hence this Wiki article in which some common bottlenecks as well as some possible optimizations will be described. Last but not least this article will explain how to get JACK aka jackd running on your RPi.

Powering the RPi

If you use the micro-USB power input to power the RPi you might encounter sudden reboots when plugging in or unplugging USB devices. If you want to be sure your RPi doesn't reboot in such cases you can try backfeed powering your RPi by connecting the power supply to one of the USB ports or use a powered USB hub that backfeeds. Also make sure your power supply can provide at least 700mA at 5V. If you plan on using an USB interface you might need more power so try to find a power supply that provides 2A or even more.

Overclocking

With the raspi-config tool or by editing /boot/config.txt directly it is possible to overclock various parts of the RPi (CPU, GPU, SDRAM). It is recommended to only use the overclock options offered by raspi-config. A common issue with overclocking is SD card corruption. You can prevent this from happening by never using a core_freq (GPU frequency) value higher than 250. If you really want to use a higher core_freq value you could either use a SD card that doesn't show this behavior or put your root filesystem on an USB drive. Overclocking provides more processing power and since it doesn't void your warranty and you don't need to add fans or a heatsink you could consider it a must for doing audio related things on your RPi.

More info on overclocking: http://elinux.org/RPiconfig#Overclocking

CPU frequency scaling

From the aforementioned link:

“The latest kernel has a cpufreq kernel driver with the “ondemand” governor enabled by default. It has no effect if you have no overclock settings. But when you do, the arm frequency will vary with processor load.”1)

So when overclocking your RPi for audio usage you should set the governor to performance as a scaling CPU can cause audible glitches. This can be done with the following command on the RPi1:

echo -n performance \
| sudo tee /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

RPi2:

for cpu in /sys/devices/system/cpu/cpu[0-9]*; do echo -n performance \
| sudo tee $cpu/cpufreq/scaling_governor; done

Another option is to disable CPU frequency scaling by disabling it in the kernel. You can do this when modifying the kernel config (with for example make menuconfig) by unticking CPU Power Management - CPU Frequency scaling - CPU Frequency scaling.

Disabling unneeded services

By default the RPi runs quite some services that are not really needed or even get in the way when setting up a real-time, low-latency environment. One way to disable such services from running and chewing up precious CPU cycles is to write a little script, an example can be found here: https://github.com/autostatic/scripts/blob/rpi/jackstart

Breaking down the script:

#!/bin/bash

## Stop the ntp service
sudo service ntp stop

## Stop the triggerhappy service
sudo service triggerhappy stop

## Stop the dbus service. Warning: this can cause unpredictable behaviour when running a desktop environment on the RPi
sudo service dbus stop

## Stop the console-kit-daemon service. Warning: this can cause unpredictable behaviour when running a desktop environment on the RPi
sudo killall console-kit-daemon

## Stop the polkitd service. Warning: this can cause unpredictable behaviour when running a desktop environment on the RPi
sudo killall polkitd

## Only needed when Jack2 is compiled with D-Bus support (Jack2 in the AutoStatic RPi audio repo is compiled without D-Bus support)
#export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket

## Remount /dev/shm to prevent memory allocation errors
sudo mount -o remount,size=128M /dev/shm

## Kill the usespace gnome virtual filesystem daemon. Warning: this can cause unpredictable behaviour when running a desktop environment on the RPi
killall gvfsd

## Kill the userspace D-Bus daemon. Warning: this can cause unpredictable behaviour when running a desktop environment on the RPi
killall dbus-daemon

## Kill the userspace dbus-launch daemon. Warning: this can cause unpredictable behaviour when running a desktop environment on the RPi
killall dbus-launch

## Uncomment if you'd like to disable the network adapter completely
#echo -n “1-1.1:1.0” | sudo tee /sys/bus/usb/drivers/smsc95xx/unbind
## In case the above line doesn't work try the following
#echo -n “1-1.1” | sudo tee /sys/bus/usb/drivers/usb/unbind

## Set the CPU scaling governor to performance
echo -n performance | sudo tee /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

## And finally start JACK
jackd -P70 -p16 -t2000 -d alsa -dhw:UA25 -p 128 -n 3 -r 44100 -s &

exit

Also, as long as you don't need networking, adding these also frees up some resources:

sudo service ifplugd stop
sudo killall ifplugd
sudo service networking stop

Running a headless RPi

You can get a significant performance gain by not using a desktop environment on the RPi. That's nice and all but how do I control the RPi then and what if the software I'd like to use has a GUI? Enter X-forwarding over SSH. X-forwarding over SSH allows you to run software from the RPi within the desktop environment of the machine you're SSH'ing from. That machine does need to have Xorg installed so using Linux is your best option. Open a terminal on the machine you want to connect to the RPi over SSH and simply type:

ssh -X pi@ip.address.of.rpi

This will give you shell access to the RPi. Now you can start GUI software by invoking them from the command line, like guitarix which will open the guitarix GUI on your connected Linux machine while the software itself runs on the RPi.

Using this method also works around the issue of non-working mice and keyboards when using the dwc_otg.speed=1 option in your /boot/cmdline.txt file because now you can control the software with the mouse and keyboard of the connected Linux machine.

On-board audio

The on-board chipset of the RPi has quite some limitations unfortunately. It only does playback and because of its PWM (Pulse Wide Modulation) based design it is not really suited for real-time, low-latency audio processing. It does work with JACK now that it has MMAP support but don't expect it to run without glitches at lower latencies.

Other drawbacks of the analog audio output:

  • it can produce clicks and pops due to the design of the RPi
  • apparently the on-board audio is 11 bits only

More info:
http://www.raspberrypi.org/phpBB3/viewtopic.php?f=38&t=30669
http://www.raspberrypi.org/phpBB3/viewtopic.php?p=297563

GPIO (On-board) audio

Various sound card hats and addons are available for high quality audio. These sound cards use the GPIO I2S (and I2C) pins on the GPIO header. Some sound cards have inputs as well as outputs. Sound cards range from 2 channels (in/out) to 8 channels out and 6 channels in.

A short list of GPIO sound cards can be found on eLinux :
http://elinux.org/index.php?title=RPi_Expansion_Boards#Sound

On-board MIDI

The on board PL011 based UART may be used as a MIDI interface. A kernel module (snd-serial-pl011) may be found here: https://github.com/kmtaylor/rpi_patches

Usage is similar to the snd-serial-u16550 module found in the mainline kernel, please refer to the documentation for that module. Also within the repository is a patch for jack2 for MIDI only usage with the ALSA driver.

USB audio

To work around having only audio out an external USB audio interface can be an option as a lot of USB audio interfaces have both audio inputs and outputs that can be used simultaneously. You can also use JACK directly with an USB audio interface. To get a working set-up you will first need to work around some of the limitations of the USB implementation of the RPi.

Supported USB devices

USB1.1

Any class compliant USB1.1 audio interface will work with the RPi. You can determine if a device is class compliant if the specifications of the interface state that no drivers are needed when using Mac or Windows. If unsure several listings of supported interfaces are available:

USB2

There are USB2.0 interfaces that are supported by the Linux audio driver stack (ALSA). Those interfaces should also work with the RPi. An example is the M-Audio Fast Track Ultra 8R, it has been reported that this interface works with the RPi. If your USB2 interface doesn't work properly keep an eye on this forum thread:
http://www.raspberrypi.org/phpBB3/viewtopic.php?f=28&t=39175
Hopefully the fiq_split patch will make it into the main kernels available for the RPi in due time.

Force USB1.1 mode

The RPi has a USB2.0 controller that apparently can cause issues with USB1.1 audio interfaces. The solution is to force the controller to use USB1.1 mode. You can do this by adding the following kernel parameter to your /boot/cmdline.txt file on your RPi:

dwc_otg.speed=1

Ethernet controller

While you're at it you might also want to disable the turbo mode for the ethernet controller of the RPi by adding:

smsc95xx.turbo_mode=N
“This feature enables the USB device to send multiple received ethernet packets in one USB transaction. This enables more efficient usage of the USB bus, and therefore higher throughput, but it causes multiple RAM allocation requests to happen at once as multiple incoming packets are processed. Turning it off means memory allocations happen in a less bursty fashion, so are less likely to fail when RAM is scarce.”2)

You could also disable the ethernet connection altogether to make sure you can use the full bandwidth of the USB controller:

echo -n "1-1.1:1.0" | sudo tee /sys/bus/usb/drivers/smsc95xx/unbind

USB1.1 and more than two inputs

If your USB1.1 interface has more than two inputs and fails to work properly with JACK try forcing using only two inputs with the -i 2 option of the ALSA backend driver.

Setting the default soundcard

The order in which soundcards are indexed is determinded by the content of /etc/modprobe.d/alsa-base.conf. By default USB soundcards (or actually the snd-usb-audio kernel module) gets index -2 so it will never end up as the default soundcard. If you want your USB audio interface to be the default soundcard look up the following line in /etc/modprobe.d/alsa-base.conf:

options snd-usb-audio index=-2

And either comment it:

#options snd-usb-audio index=-2

Or assign an index of 0:

options snd-usb-audio index=0

Another option is to comment or remove the kernel module for the onboard soundcard (snd-bcm2835) from /etc/modules. Keep in mind this will disable the onboard sound altogether. This might save you some precious CPU cycles too but don't expect too much of it.

Using JACK

JACK (JACK Audio Connection Kit), often referred to as jackd, is a

“system for handling real-time, low latency audio (and MIDI). It runs on GNU/Linux, Solaris, FreeBSD, OS X and Windows (and can be ported to other POSIX-conformant platforms). It can connect a number of different applications to an audio device, as well as allowing them to share audio between themselves. Its clients can run in their own processes (ie. as normal applications), or can they can run within the JACK server (ie. as a “plugin”). JACK also has support for distributing audio processing across a network, both fast & reliable LANs as well as slower, less reliable WANs.

JACK was designed from the ground up for professional audio work, and its design focuses on two key areas: synchronous execution of all clients, and low latency operation.”
3)

Patching JACK

You will need a patched JACK1 for the RPi otherwise you will encounter the infamous “Bus error” when starting JACK. This is because JACK uses packed structs and the RPi doesn't like those: http://comments.gmane.org/gmane.comp.audio.jackit/26713.

There's a patched JACK2 package in the default Raspbian repositories so JACK2 will work out of the box.

Patches for both JACK1 and JACK2 can be found here: https://github.com/AutoStatic/jack-armel The patches apply cleanly to Jack1 0.121.3 git commit 75e3e20b and Jack2 1.9.8 git commit 007cdc37 but since the patches are relatively simple they can be easily adapted for other JACK versions.

Packages

There are also packages available that contain patched versions of Jack1 and Jack2. You can find them in the aforementioned audio repository.

After having added the repository you can install either Jack1 or Jack2 with apt-get.

Jack1

sudo apt-get --no-install-recommends install jackd1

Jack2

sudo apt-get --no-install-recommends install jackd2

Running JACK

If you've set gpu_mem to a value higher than 64 you will want to increase the size of /dev/shm before starting JACK:

sudo mount -o remount,size=128M /dev/shm

So JACK will not complain that it cannot allocate memory. Also set the CPU governor to performance so the CPU frequency does not scale:

echo -n performance \
| sudo tee /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

When using Jack2 you might want to disable dbus dependent code in JACK components if you want to run Jack2 on a headless RPi (so without X). You can do this by building without the –dbus option. The JACK2 packages in the AutoStatic repositories have dbus disabled. Another option is to export the following environment variable before starting JACK2:

export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket

And then add the following lines to /etc/dbus-1/system.conf before the closing </busconfig> tag:

  <policy user="pi">
        <allow own="org.freedesktop.ReserveDevice1.Audio0"/>
        <allow own="org.freedesktop.ReserveDevice1.Audio1"/>
  </policy>
  

WARNING: In Raspbian Stretch I had to do the following instead of modifying system.conf:

Create a new file /etc/dbus-1/system-local.conf with the following contents:

  <?xml version="1.0"?> <!--*-nxml-*-->
  <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
          "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
  
  <busconfig>
  
          <policy context="default">
                  <allow own="org.freedesktop.ReserveDevice1.Audio0"/>
                  <allow own="org.freedesktop.ReserveDevice1.Audio1"/>
          </policy>
  
  </busconfig>

Using an external USB audio interface

Now you should be able to fire up jackd, the actual daemon of the JACK package. Capture or playback only should be no problem but full-duplex can be troublesome, ALSA will report a lot of xruns and when using Jack1 the watchdog thread will kick in after a while killing JACK. In this case, try adding the ALSA -s option (softmode) and see if that improves stability. An example JACK command would look like this:

jackd -P70 -p16 -t2000 -dalsa -dhw:UA25 -p128 -n3 -r44100 -s &

Which translates to: run JACK with a realtime priority of 70 (-P70), use a port maximum of 16 (-p16), use a client timeout of 2000s (-t2000, default is 500 and this can cause issues with some applications), use the ALSA driver stack (-dalsa), use the USB interface with cardname UA25 (-dhw:UA25, this is an Edirol UA-25 USB interface), use a frames/period setting of 128 (-p128), use a periods/buffer setting of 3 (-n3, this is the recommended setting for USB interfaces, the default is 2), use a sample rate of 44.1kHz (-r44100) and use the softmode setting of ALSA (-s) to ignore xruns reported by the ALSA driver. The ampersand (&) at the end puts the whole jackd process in the background.

Using the on-board audio

Work has been done on adding MMAP support to the ALSA driver of the Broadcom SoC so with a fully updated Raspbian installation you can now use JACK directly with the onboard audio codec. Don't expect wonders from using the onboard audio in a real-time context, the onboard audio uses an intermediate buffer so you probably can't use period settings below 256.

Real-time kernel

It is possible to use a real-time kernel on the RPi. You will need to compile it yourself after having patched the kernel sources with the RT patchset and a fix for the memory card reader driver of the RPi.

Building a kernel for the Raspberry Pi

Building a real-time kernel

Instructions for kernel compilation modernized for Pi 3

wiki/raspberrypi.txt · Last modified: 2020/03/15 17:50 by autostatic