Now you might think this is a straight forward operation. There must be many people who have this kind of setup and a simple script will run all the required actions for you.
Well this is almost true. It took me very many hours to get this working and its still not perfect. Mostly because there is a feature in how bluetooth and wifi work on the Raspberry Pi 3. For audio to sound perfect you need to either have an external bt-adapter or external wifi-adapter. If you have internal bluetooth and wifi enabled at the same time then at the time of this posting you will have a choppy audio experience. Also volume seems to be very low even at maximum but I will investigate this further (look in the comments for a solution to low volume). Now then lets get hacking.
Raspberry Pi 3 Initial state
For these steps to work I will put it here that the device I was using was a fresh install of Raspbian Lite. So your journey will be different depending on the state of your machine.
Configure the PI
Configure your password, set preferred boot options etc.
sudo apt-get update sudo apt-get upgrade sudo raspi-config
The one option that I would recommend you to set is
Advanced Options -> Audio -> Force 3.5mm
So the audio will definitely output to the analog output.
Install BT-Speaker daemon
A wonderful German software engineer who goes by the name lukasjapan in github has made a good bt-speaker daemon which we will be using. https://github.com/lukasjapan/bt-speaker
Quick Installation for Raspbian:
sudo -i bash <(curl -s https://raw.githubusercontent.com/lukasjapan/bt-speaker/master/install.sh)
The script we just ran installed bluez from raspbian repo which is not the most up to date version available. To get the newest bluez version we must download the source from bluez website and compile it for raspbian.
Check the most up to date version from their download page.
Bluez download page
cd ~ wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.47.tar.xz tar -xf bluez-5.47.tar.xz
sudo apt-get update sudo apt-get install -y libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev
Configure, make and install Bluez
cd bluez-5.47/ ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-library --disable-systemd make sudo make install sudo install -v -dm755 /etc/bluetooth sudo install -v -m644 src/main.conf /etc/bluetooth/main.conf
Rename your bluetooth to something descriptive
sudo nano /etc/bluetooth/main.conf
Testing the waters
The bt_speaker.service doesn’t work yet. There are some permissions that need to be set before it can send commands to the bluetooth but we can try that our system is working so far by manually running the bt_speaker.py
First lets stop bluetooth and the possibly running bt_speaker.
sudo systemctl stop bluetooth sudo systemctl stop bt_speaker
Now lets start bluetooth again and make it discoverable.
sudo systemctl start bluetooth sudo bluetoothctl power on discoverable on exit
Now you can try to connect to the Raspberry Pi with your phone and see if it is discoverable and able to connect. Audio will not work yet at this point. If you were successful in discovering and connecting to the Raspberry Pi via bluetooth then we can start the bt_speaker.py manually to test audio.
cd /opt/bt-speaker python bt_speaker.py
You will need to first unpair the pi from your phone and the connect again for the bt_speaker daemon to register the connection and offer the audio services.
If all went well you should now be able to play music from your phone through the Pi to the speakers.
But as you might notice the audio is quite choppy and in the terminal you can see “underrun!!! (at…” text at regular intervals.
To get the audio to be smooth we need to disable the internal wifi adapter
sudo ifconfig wlan0 down
After this restart the bt_speaker.py and notice a smooth audio experience.
If anyone knows a solution to this problem other that buying an external wifi-adapter it would be much appreciated.
Next we need to give some permission for the btspeaker user that the bt_speaker install script created and is using to start the bt_speaker.service.
Lets open the bluetooth.conf file and add some lines.
sudo nano /etc/dbus-1/system.d/bluetooth.conf
Add these lines to the file after root policies inside <busconfig>
<policy user="btspeaker"> <allow own="org.bluez"/> <allow send_destination="org.bluez"/> </policy>
Now if you start the bt_speaker service it should start without a hitch.
sudo systemctl start bt_speaker sudo systemctl status bt_speaker
Then all there is left to do is to set this up so that it starts nicely after the Raspberry boots up.
Some of these steps might be unnecessary but it’s all the things I had to do to get this working.
First lets modify the /etc/bluetooth/main.conf
sudo nano /etc/bluetooth/main.conf
Modify/Add the end of the file to
AutoEnable = true
Now for some reason that alone didn’t autostart the bluetooth for me. For some reason the bluetooth does not power on. So for that we will create our own service.
sudo mkdir /opt/bt_power sudo nano /opt/bt_power/bt_power.sh
Inside this file will look like this
#!/bin/bash echo -e "power on\nexit\n" | bluetoothctl echo -e "power on\nexit\n" | bluetoothctl systemd-notify --ready --status="Bluetooth power on"
Then create the bt_power.service file
sudo nano /etc/systemd/system/bt_power.service
And this is the contents
[Unit] Description="Turn bluetooth power on" After=bluetooth.service [Service] Type=notify WorkingDirectory=/opt/bt_power ExecStart=/opt/bt_power/bt_power.sh [Install] WantedBy=multi-user.target
Next we will modify the bt_speaker.service to wait for bt_power.service to finish and also to check that bluetooth service is running.
sudo nano /etc/systemd/system/bt_speaker.service
Modify to match this
[Unit] Description="Simple bluetooth speaker for the Raspberry Pi" After=bt_power.service Requires=bluetooth.service Wants=bluetooth.service [Service] TimeoutStartSec=30 WorkingDirectory=/opt/bt-speaker ExecStartPre=/bin/sleep 10 ExecStart=/opt/bt-speaker/bt_speaker.py StartLimitBurst=100 Restart=always User=btspeaker [Install] WantedBy=multi-user.target
Then lets enable our service
sudo systemctl enable bt_power.service
And finally reload systemctl daemon
sudo systemctl daemon-reload
Now all there is left to do is to reboot the Pi and enjoy the fruits of our labours.
If all went well after your Raspberry Pi reboots you should be able to connect via bluetooth and start blasting some beats.
Don’t forget to disable the internal wifi adapter. How to permanently disable wifi from autostarting at boot is left as an exercise for the reader 🙂