Skip to content

Using BlueALSA with the JACK Audio Connection Kit

Arkadiusz Bokowy edited this page Nov 11, 2024 · 7 revisions

Introduction

A BlueALSA PCM can be used with JACK in the same way as any other ALSA PCM, so long as the constraints imposed by Bluetooth Audio are taken into consideration:

  1. Bluetooth Audio is high-latency. There is nothing that BlueALSA or JACK can do to change that. So you need to resist the instinct of JACK users and general JACK advice to use very small period sizes and buffers. You will not succeed. At best you will waste CPU cycles and at worst experience constant underruns/overruns. Similarly, there is generally no need to run the jackd service with real-time priority unless that is also required by the jack client (for example zita-j2a and zita-a2j require real-time priority), it will not reduce latency.

  2. BlueALSA PCMs are transient. They can connect and disconnect at random intervals. JACK clients and servers always assume that PCMs are permanent; there is no provision in the JACK model for removal of a sound device while in use. jackd, alsa_out and other clients will fail if playing to a BlueALSA PCM that disconnects.

  3. A2DP transports may become "idle". The source may keep the transport open but not send any audio frames. Jack source clients such as zita-a2j and alsa_in will generate errors and possibly fail completely when this happens, so it is important to ensure the audio stream is running before starting the Jack source client, and that the stream continues to run as long as the Jack source is running. This issue applies only to BlueALSA capture devices.

There have been a number of bluez-alsa issues raised in respect of using BlueALSA with JACK. Athough those issues, and the recommendations and workarounds mentioned in them, were valid when written, there have been many improvements to both BlueALSA and JACK recently. So much so that by using the latest bluez-alsa release and recent JACK releases it now quite straightforward to use them together, within the constraints described above.

BlueALSA can be used without any need to create ~/.asoundrc entries, using either zita-j2a or alsa_out, and can even be used as the backend device of a jackd service.

zita-j2a

Possibly the simplest example is to create a jack sink using the bluealsa default PCM:

zita-j2a -j bluealsa -d bluealsa -p 1024 -n 3 -c 2 -L

The command line arguments are as follows:

-j bluealsa
    Use the name "bluealsa" for the sink. This is the name that jack
    clients use to send audio to the sink.

-d bluealsa
    Use the alsa device "bluealsa". This device name is predefined by
    the bluez-alsa installation, and used in this way will select the most
    recently connected A2DP playback device.

-p 1024
    Use an ALSA period size of 1024 frames.

-n 3
    Use an ALSA buffer of 3 periods. A smaller buffer will almost certainly
    result in constant underruns.

-c 2
    Use 2 channels. `zita-j2a` will create 2 jack ports, called
    `bluealsa:playback_1` and `bluealsa:playback_2`.

-L
    Use S16_LE samples. Without this option `zita-j2a` may convert to
    32-bit samples only for the ALSA `plug` plugin to convert them back
    to 16-bit.

To use a specific bluetooth device rather than the default, specify its MAC address in the device name, and give it a unique jack name:

zita-a2j -j bt_headphones -d bluealsa:XX:XX:XX:XX:XX:XX -p 4096 -n 3 -c 2 -L

We can now play to the headphones from any jack client. For example:

mpg123 -o jack -a bt_headphones:playback_1,bt_headphones:playback_2 MyFavouriteMusic.mp3

or

JACK_PLAY_CONNECT_TO=bt_headphones:playback_%d jack-play test_sounds.wav

alsa_out

The command line arguments for alsa_out are the same as for zita-j2a except that -L is not supported. For example:

alsa_out -j bt_headphones -d bluealsa:XX:XX:XX:XX:XX:XX -c 2 -p 4096 -n 3

There is still a bug in alsa_out that causes a buffer overflow if the device name is too long. It appears the longest device name allowed is 29 characters. Fortunately the form used here is only 26 characters.

jackd

BlueALSA can also be used as a backend for a jackd service

jackd -r -d alsa -P bluealsa -n 3 -S -o 2
-r
    Do not request real-time scheduling (optional - will also work without
    this)

-d alsa
    Use the ALSA backend

-P bluealsa
    Use the most recently connected BlueALSA playback device. You can also
    choose a specific device with `-P bluealsa:XX:XX:XX:XX:XX:XX`

-n 3
    Use an ALSA buffer of 3 periods. A smaller buffer is sure to produce
    underruns.

-o 2
    Create 2 output channels
-S
    Use S16_LE sample format

Clients can then send to the BlueALSA device with

JACK_PLAY_CONNECT_TO=system:playback_%d jack-play test_sounds.wav

.asoundrc

It is possible to remove the ALSA plug plugin from the audio processing chain, and instead rely on JACK's own audio processing features. To do this we have to define our PCMs in our ~/.asoundrc file. For example:

pcm.bt-headphones {
	type bluealsa
	device XX:XX:XX:XX:XX:XX
	profile a2dp
}
ctl.bt-headphones {
	type bluealsa
}

Remember here the limit of 29 characters for the PCM name when using alsa_out

With ALSA plug removed, we no longer need to force a sample format, so the -L or -S argument is no longer needed.

Then we can use this with JACK as:

zita-j2a -j bt-headphones -d bt-headphones -p 4096 -n 3 -c 2

or

jackd -r -d alsa -P bt-headphones -n 3 -o 2