Low-latency audio settings for Linux

threadirqs

When threadirqs is enabled in the kernel command-line, Linux only acknowledges the triggered interrupt with preemption disabled, and right after that assigns a thread for the interrupt handler, thus reducing the overall latency.

rtirq-init package contains rtirq initialization script, which assigns a real-time priority to all interrupt handlers according to the rules in the /etc/default/rtirq configuration file. The default configuration is geared towards audio, giving the highest priority for the sound card and the USB host controller:

$ ps -T -o comm,policy,rtprio -p $(pgrep -w -d ',' irq) | egrep '(snd|hci)'
irq/126-xhci_hc FF 85 irq/143-snd_hda FF 90

CPU frequency scaling

One of the first things to tune, when aiming towards a stable audio latency, is the CPU frequency scaling. More precisely, it should preferably be constant.

Downscaling
occurs when the operating frequency of a CPU is decreased. By default kernel uses the powersave governor, which proactively downscales the operating frequency when the overall utilization is lower, in order to save power.

It can be substituted with the performance governor, which keeps the operating frequency at maximum, as follows:

echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

Upscaling occurs when the operating frequency is temporarily increased above the maximum. Intel x86 CPU's have a feature called Turbo Boost, which causes the CPU to automatically upscale when the demand for processing is high enough.

Turbo Boost can be disabled as follows:

echo 1 | sudo tee /sys/devices/system/cpu/intel_pstate/no_turbo

Resource limits

Popular audio software, such as JACK and Reaper, can often take the advantage of real-time scheduling and memory locking, if such resources are available for the application process.

In order to protect a system from misbehaving or malicious software, it is better to create a new group only for users, who require these capabilities, e.g.:

sudo groupadd realtime
sudo gpasswd -a $USER realtime

Then, just create /etc/security/limits.d/realtime.conf:

@realtime - memlock 8388608 # 8 GB
@realtime - rtprio 49

It's not advisable to set memory locking unlimited, but rather set an appropriate fixed limit to fit to your requirement, because a privileged user could also be running software that is misbehaving.

rtprio should be always capped below the IRQ priorities, because failing to serve the external hardware in time could potentially damage the system.

JACK Audio Connection Kit (JACK)

JACK Audio Connection Kit (JACK) is a low-latency audio server for sharing the available audio devices for multiple application processes. It is centered around a command-line tool called jack_control, which is a command-line interface for the jackdbus daemon process.

jackdbus takes care of:

  • managing the jackd daemon process, which is the actual audio server and connection end point for the JACK clients.
  • providing JACK sink and source for PulseAudio.

Here's a simple configuration script for configuring JACK:

#!/bin/bash

SOUND_CARD=$1
SAMPLE_RATE=$2
FRAMES_PER_INT=$3
FRAME_SIZE=$4

# Use the ALSA backend.

jack_control ds alsa

# Enable rtprios.

jack_control eps realtime true

# Configure the sound card.

jack_control dps device $SOUND_CARD
jack_control dps capture $SOUND_CARD
jack_control dps playback $SOUND_CARD
jack_control dps rate $SAMPLE_RATE
jack_control dps nperiods $FRAMES_PER_INT
jack_control dps period $FRAME_SIZE

The configuration is written into ~/.config/jack/conf.xml. JACK can be started with jack_control start and stopped with jack_control stop. The runtime log of jackdbus is stored into ~/.log/jack/jackdbus.log.

Sampling a web browser to Reaper using JACK

JACK gives quite convenient tools to sample audio from a web browser, or any other desktop application, which is sometimes so much convenient than trying to save it as a file. It's just a trivial matter of re-routing PulseAudio interconnections:

$ jack_connect "PulseAudio JACK Sink:front-left" REAPER:in1
$ jack_connect "PulseAudio JACK Sink:front-right" REAPER:in2
$ jack_disconnect "PulseAudio JACK Sink:front-left" system:playback_1
$ jack_disconnect "PulseAudio JACK Sink:front-right" system:playback_2

Now desktop audio can be only heard when monitored from Reaper and can be trivially record to any track.