My ultimate guide to the Raspberry pi audio server I wanted — Bluetooth
Part 1 — Bluetooth
Given my prior experience, I wanted to start by the bluetooth sink. It’s my first priority to connect my amplifier and I felt it would be easier to configure the rest of my requirements according to bluetooth constraints. I found an excellent guide for the bluetooth setup, which really covered all my bluetooth needs:
- configuration of bluetooth as audio sink with Pulseaudio
- start Pulseaudio on boot
- authentication though Pin code
- post mentions some additionnal configuration with AVRCP to control volume, but it seemed to work out of the box for me, so I’ll leave it out here
First thing we have to install Pulseaudio and its bluetooth module
$ sudo apt-get install pulseaudio pulseaudio-module-bluetooth
We will be running pulse audio as a normal user as recommended, so we need to add our user to the bluetooth group
$ sudo usermod -a -G bluetooth pi
$ systemctl --user enable pulseaudio
Created symlink /home/pi/.config/systemd/user/default.target.wants/pulseaudio.service → /usr/lib/systemd/user/pulseaudio.service.
Created symlink /home/pi/.config/systemd/user/sockets.target.wants/pulseaudio.socket → /usr/lib/systemd/user/pulseaudio.socket.
Lets modify our bluetooth configuration to declare it as audio sink
/etc/bluetooth/main.conf
[General]
Name = Ampli-BT
Class = 0x200428
DiscoverableTimeout = 0 #Always discoverable
[Policy]
AutoEnable=true
We use raspi-config to do the autologin part
$ sudo raspi-config
activate autologin for user “pi” by selecting
- 3 Boot Options
- B1 Desktop/CLI
- B2 Console Autologin.
Close raspi-config and then reboot
Now let’s login again. Pulseaudio and bluetooth should be started:
$ systemctl status --user pulseaudio
● pulseaudio.service — Sound Service
Loaded: loaded (/usr/lib/systemd/user/pulseaudio.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2020–04–18 01:26:23 CEST; 15h ago
Main PID: 426 (pulseaudio)
CGroup: /user.slice/user-1000.slice/user@1000.service/pulseaudio.service
└─426 /usr/bin/pulseaudio --daemonize=no
Apr 18 01:25:56 Ampli-BT systemd[413]: Starting Sound Service…
Apr 18 01:26:23 Ampli-BT systemd[413]: Started Sound Service.
$ sudo systemctl status bluetooth
● bluetooth.service — Bluetooth service
Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2020–04–18 01:25:32 CEST; 15h ago
Docs: man:bluetoothd(8)
Main PID: 281 (bluetoothd)
Status: “Running”
Memory: 4.1M
CGroup: /system.slice/bluetooth.service
└─281 /usr/lib/bluetooth/bluetoothd
Apr 18 01:25:30 Ampli-BT systemd[1]: Starting Bluetooth service…
Apr 18 01:25:32 Ampli-BT bluetoothd[281]: Bluetooth daemon 5.50
Apr 18 01:25:32 Ampli-BT systemd[1]: Started Bluetooth service.
Apr 18 01:25:32 Ampli-BT bluetoothd[281]: Starting SDP server
Apr 18 01:25:32 Ampli-BT bluetoothd[281]: Bluetooth management interface 1.14 initialized
Apr 18 01:25:32 Ampli-BT bluetoothd[281]: Sap driver initialization failed.
Apr 18 01:25:32 Ampli-BT bluetoothd[281]: sap-server: Operation not permitted (1)
Apr 18 01:26:23 Ampli-BT bluetoothd[281]: Endpoint registered: sender=:1.15 path=/MediaEndpoint/A2DPSource
Apr 18 01:26:23 Ampli-BT bluetoothd[281]: Endpoint registered: sender=:1.15 path=/MediaEndpoint/A2DPSink
Now using bluetoothctl we’ll be able to pair our phone with the pi audio sink.
$ bluetoothctl
[NEW] Controller XX:XX:XX:XX:XX:XX Ampli-BT [default]
[bluetooth]# power on
Changing power on succeeded
[bluetooth]# discoverable on
Changing discoverable on succeeded
[CHG] Controller XX:XX:XX:XX:XX:XX Discoverable: yes
[bluetooth]# pairable on
Changing pairable on succeeded
[bluetooth]# agent on
Agent registered
[bluetooth]# default-agent
Default agent request successful
We should now be able to pair with our phone, but we’ll need to trust the device from the pi before being able to play music
[NEW] Device YY:YY:YY:YY:YY:YY <your smartphone>
[bluetooth]# trust YY:YY:YY:YY:YY:YY
Changing YY:YY:YY:YY:YY:YY trust succeeded
[bluetooth]# quit
[DEL] Controller XX:XX:XX:XX:XX:XX Ampli-BT [default]
From your phone you should now be able to play music and hear it from the speakers connected to your pi
Pretty nice, but nobody wants to start a computer when playing music from a new device. So we’ll add PIN authentication to make pairing and trusting headless. We’ll need a new package including bt-agent to help with that
$ sudo apt-get install bluez-tools
Create /etc/bluetooth/pin.conf WITH a trailing line
* 1234
And set permissions as needed.
$ sudo chown root:root /etc/bluetooth/pin.conf
$ sudo chmod 600 /etc/bluetooth/pin.conf
* represents all phone, we could give a different PIN for different bluetooth MAC address, but that’s not interesting here.
We need a new systemd unit to automate bt-agent /etc/systemd/system/bt-agent.service
[Unit]
Description=Bluetooth Auth Agent
After=bluetooth.service
PartOf=bluetooth.service
[Service]
Type=simple
ExecStart=/usr/bin/bt-agent -c NoInputNoOutput -p /etc/bluetooth/pin.conf
ExecStartPost=/bin/sleep 1
ExecStartPost=/bin/hciconfig hci0 sspmode 0
[Install]
WantedBy=bluetooth.target
and automates this at boot
$ sudo systemctl daemon-reload
$ sudo systemctl enable bt-agent
$ sudo systemctl restart bt-agent
$ sudo systemctl status bt-agent.service
● bt-agent.service — Bluetooth Auth Agent
Loaded: loaded (/etc/systemd/system/bt-agent.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2020–04–18 01:25:33 CEST; 16h ago
Main PID: 303 (bt-agent)
Memory: 2.5M
CGroup: /system.slice/bt-agent.service
└─303 /usr/bin/bt-agent -c NoInputNoOutput -p /etc/bluetooth/pin.conf
Apr 18 01:25:32 Ampli-BT systemd[1]: Starting Bluetooth Auth Agent…
Apr 18 01:25:33 Ampli-BT bt-agent[303]: Agent registered
Apr 18 01:25:33 Ampli-BT bt-agent[303]: Default agent requested
Apr 18 01:25:33 Ampli-BT systemd[1]: Started Bluetooth Auth Agent.
Our headless bluetooth speaker is now working as expected.
Playing sound when bluetooth connects
I also wanted to play a sound when a device connects to bluetooth to get audio feedback on the connection. I used udev for this. Udev helps you executes script based on filtered kernel events. Here we’ll look for an add event in the bluetooth subsystem.
# Edit: I found a better udev rule. An input device is also added later in the bluetooth connection process, so sound is now only played after PIN code authentication has happened, which makes more sense.
/etc/udev/rules.d/99-local.conf
# I kept 1st version as as reminder
#ACTION==”add”, SUBSYSTEM==”bluetooth”, RUN+=”/usr/local/bin/bt-connection.sh”# This stopped working after a kernel upgrade
#ACTION==”add”, KERNEL==”input[0–9]*”, SUBSYSTEM==”input”, ATTR{name}==”*:*:*:*:*:*”, RUN+=”/usr/local/bin/bt-connection.sh”# This stopped working after a kernel upgrade
ACTION==”add”, KERNEL==”input[0–9]*”, SUBSYSTEM==”input”, ENV{PHYS}==”\”*:*:*:*:*:*\””, ENV{ID_BUS}=”bluetooth”, RUN+=”/usr/local/bin/bt-connection.sh”ACTION==”add”, SUBSYSTEM==”bluetooth”, RUN+=”/usr/local/bin/bt-connection.sh”
/usr/local/bin/bt-connection.sh
#!/bin/sh
if [[ $(whoami) == “root” ]]; then
/bin/su - pi -c 'pactl play-sample success'
else
pactl play-sample success
fi
echo “$(date): ${NAME} successfully connected”
We now need to restart udev to apply this new rule
$ sudo udevadm control --reload-rules
A sound is now indeed played when a device bluetooth connects. But there ̶a̶r̶e̶ was a few anoying things about it:
- if you’re careful you’ll notice sound is played before connexion has been actually established, before authentication is done as a matter of fact. #fixed by udev rule
- It will also be triggered at boot because a bluetooth dongle is plugged. #fixed by udev rule
- It needs a new mpg123 program to play sound
#fixed by using pulseaudio directly. I used following commands:
$ mpg123 -w /usr/local/share/sounds/success.wav /usr/local/share/sounds/success.mp3
$ pactl upload-sample /usr/local/share/sounds/success.wav
$ sudo apt remove mpg123
So I’ll look for a more precise udev rule, and a way of playing sound from mpc, MPD default command line interface some day.
# Edit: More precise udev rule found.
# Edit: mpg123 removed
# Edit: fixed udev rule after kernel upgrade