This gist will show how to setup a generic SBC Debian / Ubuntu install as a headless Bluetooth A2DP audio sink. This will allow your phone, laptop or other Bluetooth device to play audio wirelessly through a Rasperry Pi.
This is forked from another gist specific to the Raspberry Pi on Stretch. A required package isn't in Ubuntu's repos, so in this gist we build it from scratch.
Tested to be working on Armbian/Ubuntu/Debian images of the Orange Pi Zero, ODROID XU4, ODROID N2, and Atomic Pi.
- A linux SBC running Debian or Ubuntu
- Bluetooth Dongle or integrated Bluetooth.
- Sound card (internal or external) that has been set up to work with Alsa.
curl https://gist.githubusercontent.com/qcasey/5bd4943b27320e65a033948fafb86d19/raw/2a3be1bc78e9ac30b744c2fdd332d035ac13d77d/bt-a2dp-autoinstall.sh | sudo bash
cURL-ing to bash can be dangerous, in the event of a hack. Please ensure what you're downloading first.
First make sure the system is up to date using the following commands.
sudo apt-get update
sudo apt-get upgrade
Then reboot the device to ensure the latest kernel is loaded.
Now install the required packages.
sudo apt-get install alsa git gcc make autoconf libtool blueman bluez bluetooth libbluetooth-dev libfdk-aac-dev libsbc-dev libasound2-dev libdbus-1-dev python-dbus glib-2.0-dev libperl-dev libgtk2.0-dev
Change over to your /tmp directory, and clone then build another requirement.
cd /tmp
git clone https://github.com/Arkq/bluez-alsa
cd bluez-alsa/
autoreconf --install
mkdir build && cd build
../configure --enable-aac --enable-ofono --enable-debug
make && sudo make install
Normally a Bluetooth device is only discoverable for a limited amount of time. Since this is a headless setup we want the device to always be discoverable.
- Set the DiscoverableTimeout in
/etc/bluetooth/main.conf
to 0
# How long to stay in discoverable mode before going back to non-discoverable
# The value is in seconds. Default is 180, i.e. 3 minutes.
# 0 = disable timer, i.e. stay discoverable forever
DiscoverableTimeout = 0
- Enable discovery on the Bluetooth controller
sudo bluetoothctl
power on
discoverable on
exit
A Bluetooth agent is a piece of software that handles pairing and authorization of Bluetooth devices. The following agent allows the Raspberry Pi to automatically pair and accept A2DP connections from Bluetooth devices. All other Bluetooth services are rejected.
Copy the included file a2dp-agent to /usr/local/bin
and make the file executable with
sudo chmod +x /usr/local/bin/a2dp-agent
A Python 3 version has been generously provided by @abelmatser in another gist
Before continuing, verify that the agent is functional. The Raspberry Pi should be discoverable, pairable and recognized as an audio device.
Note: At this point the device will not output any audio. This step is only to verify the Bluetooth is discoverable and bindable.
- Manually run the agent by executing
sudo /usr/local/bin/a2dp-agent
- Attempt to pair and connect with the Raspberry Pi using your phone or computer.
- The agent should output the accepted and rejected Bluetooth UUIDs
A2DP Agent Registered
AuthorizeService (/org/bluez/hci0/dev_94_01_C2_47_01_AA, 0000111E-0000-1000-8000-00805F9B34FB)
Rejecting non-A2DP Service
AuthorizeService (/org/bluez/hci0/dev_94_01_C2_47_01_AA, 0000110d-0000-1000-8000-00805f9b34fb)
Authorized A2DP Service
AuthorizeService (/org/bluez/hci0/dev_94_01_C2_47_01_AA, 0000111E-0000-1000-8000-00805F9B34FB)
Rejecting non-A2DP Service
To make the A2DP Bluetooth Agent run on boot copy the included file bt-agent-a2dp.service to /etc/systemd/system
.
Now run the following command to enable the A2DP Agent service
sudo systemctl enable bt-agent-a2dp.service
Thanks to @matthijskooijman for fixing up some issues in the Bluetooth Agent service.
Bluetooth devices should now be able to discover, pair and connect to the Raspberry Pi without any user intervention.
Now that Bluetooth devices can pair and connect with the Raspberry Pi we can test the audio playback.
The tool bluealsa-aplay
is used to forward audio from the Bluetooth device to the ALSA output device (sound card).
Execute the following command to accept A2DP audio from any connected Bluetooth device.
bluealsa-aplay -vv 00:00:00:00:00:00
Play a song on the Bluetooth device and the Raspberry Pi should output audio on either the headphone jack or the HDMI port. See this guide for configuring the audio output device of the Raspberry Pi.
To make the audio playback run on boot copy the included file a2dp-playback.service to /etc/systemd/system
.
Now run the following command to enable A2DP Playback service
sudo systemctl enable a2dp-playback.service
We also need to install bluealsa as a service, copy that to /etc/systemd/system
as well and enable it.
sudo systemctl enable bluealsa.service
Reboot and enjoy!
If you are experiencing low volume output, run alsamixer
and increase the volume of the Pi's soundcard.
Thanks a lot for this fork. It allowed me to start streaming music to my Orange Pi Zero (running Armbian 21 Buster with an external USB Bluetooth dongle), which I could not get the hang of with the original script. I used this to configure a Bluetooth sink option for Snapcast.
Configure Bluetooth
Follow the auto-install script on this page.
To test this I could attach my headphones to my OPZ and stream music from my phone to the device. I could hear this in my headphones - which are configured as the default sound output for me - so the script worked for me.
Sometimes my phone would not connect to the Bluetooth device anymore due to erronous changes made by me. To enter the bluetooth adapter use
bluetoothctl
for manual commands or remove and unpair your phone in one command withecho untrust ${MAC} | bluetoothctl && echo remove ${MAC} | bluetoothctl
Configure Alsa loopback & Snapcast
Create a temporary loop
sudo modprobe snd-aloop
Find out which device is the loopback device
aplay -l
For me the loopback card is card 1. The loop in is subdevice 0
hw:1,0,x
and the loop out is subdevice 1hw:1,1,x
. You can choose any value between 0 and 7 for x, I chose 0.In
/etc/snapserver.conf
addsource = alsa://?name=Bluetooth&device=hw:1,1,0&send_silence=true&idle_threshold=100
Restart the snapserver service:
sudo service snapserver restart
Open a playback window for snapcast at http://${IP}:1780/ and switch to the 'Bluetooth' channel
Play the speaker test to the loop in:
speaker-test -D hw:1,0,0 -c 2
this should now playback in your browser, showing the loopback works successfully. If it does not, maybe your devices are different from mine.Create a lasting loopback device by adding
snd-aloop
to/etc/modules
.Tie it all together
Finally, change the default sound output device. This redirects the output from the bluetooth sink to the loop in, since the bluetooth sink just uses the default audio device.
Create
/etc/asound.conf
with insideNow the loopback will transfer all sound coming into the default sound card (hw:1,0,0) to the loop out (hw:1,1,0), which in turn is read and played by Snapcast.
Reboot to get all elements to play nicely together. Now you can enjoy!