After a few people asking me how to use the A2DP Sink with BlueZ, I’ve decided to write this mini-tutorial with a step-by-step on how to establish a A2DP stream from any device to a BlueZ-enabled host.
Before we start the hands-on, let’s see a little bit of nomenclature. In our use-case we have an stream being transmitted between two devices through a pipeline. Our pipeline is constructed of the remote host, BlueZ and PulseAudio. Each element of this pipeline has a Source (SRC) and a Sink (SNK) interface. The stream is handled between different elements by being sent from one element’s source to another element’s sink. So, the big picture of our pipeline is something like this (with the stream being represented by an arrow):
Remote-SRC ----> SNK-BlueZ-SRC ----> SNK-PulseAudioBT-SRC
With the PulseAudio bluetooth source being available for applications to connect to it and serve themselves with fresh, just-decoded PCM frames of pure stereo audio. In our example, we gonna add another element to the pipeline tho. In order to able to hear the audio we’re receiving, we gonna connect the PulseAudio bluetooth source to a PulseAudio ALSA sink which pushes the audio out through our soundcard speakers.
PulseAudioBT-SRC ----> SNK-PulseAudioALSA ----> SoundCard
So after these lines on theory, let’s get out hands dirty. First of all, you need a recent version of BlueZ and PulseAudio. BlueZ 4.46 and PulseAudio 0.9.16 should be enough, but I strongly recommend getting the newest releases available by the time you read this. Right now the most recent releases are BlueZ 4.58 and PulseAudio 0.9.21.
- PulseAudio must be running with module-bluetooth-discover loaded;
- This module is automatically loaded on startup with the default configuration;
- If it’s not loaded you can use pactl to load it manually or configure PulseAudio to load it on startup in /etc/pulse/default.pa;
- Enable the Source interface on BlueZ:
- edit /etc/bluetooth/audio.conf and add the following line: Enable=Source ;
- restart bluetoothd;
- Pair both devices;
- On the object path representing the remote host, on org.bluez D-Bus service, call the org.bluez.AudioSource.Connect() method;
- For the connection to succeed you’ll probably have to grant access on the remote host;
- When the connection is established, a new card should show up on PulseAudio with one source available;
- Connect PulseAudio bluetooth source to PulseAudio ALSA sink;
- load-module module-loopback source=<name> sink=<name>
- You can use the line above to load the module-loopback, using pactl (on the command line) or inside pacmd shell;
- To find out the name of the source and the sink, you can use the commands list-sources and list-sinks inside pacmd shell;
- This step is only needed if you want to send the audio coming through A2DP to your speakers.
It’s important to remember that the current implementation is working but could see some improvements, so expect to hear some glitches if you go through signal variation. Happy bluetooth audio streaming!