In support of the proposition that there is "more ways than one to skin a
cat," this is a second take on connecting a Bluetooth speaker to the
Raspberry Pi 3 running under Raspbian Stretch (based
on Debian 9). In the first attempt, I showed some
work arounds for the bugs in the Bluetooth stack found by clever people. In this
version, I follow a somewhat more radical route by updating BlueZ (the Official Linux Bluetooth protocol stack) to the
current version which, in my mind at least, provides a better solution even
if it is somewhat more complicated. This post goes a bit further by showing
how the Raspberry Pi 3 can be a "Bluetooth sink" which is gobbledygook for
using the Raspberry Pi 3 as a Bluetooth speaker playing sound emanating from
another Bluetooth enabled device.
- Installing Raspian Stretch
This first section is about setting up Raspbian (Stretch) on a Raspberry
Pi 3 B (RPi3 for short) for headless operation. It can probably be
skipped by most users of the RPi3. It is a bit terse and assumes you
know how to locate a newly connected computer on the local area network.
While installing Stretch should work on any Raspberry Pi, a Bluetooth dongle
will be needed with older Raspberry Pi; on board WiFi and Bluetooth
connectivity was added on the Raspberry Pi 3 and Raspberry Pi Zero W.
At the time of writing this post, the most recent Rasbpian
image available from the Raspberry Foundation is
Raspbian Stretch Lite
Minimal image based on Debian Stretch
Version: April 2018
Release date: 2018-04-19
Kernel version: 4.14.
The RASPBIAN download page at the Raspberry Pi Foundation
always contains the newest image and under most circumstances that is what
should be installed. Older versions of Rasbian Lite going back to November
2015 are available here if there is a need to install an older
version.
I downloaded the latest image and burned it to a 8GB SD card using Etcher as
per the instructions at raspberrypi.org
. I suggest
that before doing this you uncheck the Auto-unmount on success
option in the programs Settings
. If this is not done, it will be
necessary to remove and reinsert the SD card in the desktop SD card reader to
perform the next step.
In order to configure the RPi3 without monitor and keyboard, I created
an empty file called ssh
in the card's boot partition.
michel@hp:~$ sudo touch /media/michel/boot/ssh
michel@hp:~$ ls /media/michel/boot/ssh
/media/michel/boot/ssh
Then I unmounted the two partitions on the SD card, inserted the latter
in the RPi3 SD card reader, connected an Ethernet cable to the board and
powered it up. If all goes well, the red and green LED will flash on and off.
I think the RPi3 is expanding its file system so give it some time to perform
that one-time task. Wait until the green LED no longer flashes and the red
LED is mostly on. It is time to open an SSH session. Use the usual means to
find the IP address of the RPi3. In my case, it was simple, because I had
recently connected the RPi3 to the network, so its IP address lease was still
in effect. However this meant that the security key had to be changed. Its no
big deal, just follow the instructions if that happens.
michel@hp:~$ ssh pi@192.168.1.134
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:ZI+DfebhaxZeK+yy1cHkCmKoup0eNPALps0q60VF/Lw.
Please contact your system administrator.
Add correct host key in /home/michel/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/michel/.ssh/known_hosts:36
remove with:
ssh-keygen -f "/home/michel/.ssh/known_hosts" -R "192.168.0.138"
ECDSA host key for 192.168.0.138 has changed and you have requested strict checking.
Host key verification failed.
michel@hp:~$ ssh-keygen -f "/home/michel/.ssh/known_hosts" -R "192.168.0.138"
# Host 192.168.0.138 found: line 36
/home/michel/.ssh/known_hosts updated.
Original contents retained as /home/michel/.ssh/known_hosts.old
michel@hp:~$ ssh pi@192.168.1.134
The authenticity of host '192.168.1.134 (192.168.1.134)' can't be established.
ECDSA key fingerprint is SHA256:ZI+DfebhaxZeK+yy1cHkCmKoup0eNPALps0q60VF/Lw.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.134' (ECDSA) to the list of known hosts.
pi@192.168.0.138's password: raspberry not echoed to screen
Linux raspberrypi 4.14.34-v7+ #1110 SMP Mon Apr 16 15:18:51 BST 2018 armv7l
...
SSH is enabled and the default password for the 'pi' user has not been changed.
This is a security risk - please login as the 'pi' user and type 'passwd' to set a new password.
Instead of using passwd
, I used raspi-config
to
change the password and the rest of the configuration to suit my situation.
The configuration program requires superuser
privileges, (
authorization, permission or whatever other term meaning the same thing) that
belongs to root
, so the super user sudo
prefix must be used
pi@raspberrypi:~ $ sudo raspi-config
- Change password for the current user mandatory
- Configure network settings - did nothing
- Boot Options - did nothing
- Localisation Options
- I2 Change Timezone - to America/Moncton
- Interfacing Options
- P2 SSH - enabled mandatory
- P4 SPI - enabled
- P5 I2C - enabled
- Overclock - did noth ing
- Advanced Options
- A1 Expand Filesystem
- A3 Memory Split - minimum 16 MB for the GPU
On leaving raspi-config
, I did not choose to reboot.
Instead, I followed the instructions for the dhcpcd method of
setting up static addresses on the Raspberry Pi StackExchange, I first backed up the
dchcpc
configuration file and then edited it.
pi@rpi3:~ $ sudo cp /etc/dhcpcd.conf /etc/dhcpcd.conf.bak
pi@rpi3:~ $ sudo nano /etc/dhcpcd.conf
...
# Example static IP configuration:
#interface eth0
#static ip_address=192.168.0.10/24
#static ip6_address=fd51:42f8:caae:d92e::ff/64
#static routers=192.168.0.1
#static domain_name_servers=192.168.0.1 8.8.8.8 fd51:42f8:caae:d92e::1
interface eth0
static ip_address=192.168.1.34/24
static routers=192.168.1.1
static domain_name_servers=192.168.1.1
...
In this instance, I did not enabled the WiFi interface in
raspi-config
and I did not setup a static IP address for it in
the dhcpcd
configuration file. Using a WiFi network connection
while streaming Bluetooth audio on the Raspberry Pi is not really possible.
Apperently doing both simultaneously overwhelms the single IC responsible for
both wireless links. Judging from posts on the Web, it is possible to do both
if one of the wireless connection is passed on to usb wifi adapter or a usb
Bleutooth adapter. I have yet to test this.
The basic setup is now completed, so I rebooted, and then after a short
while logged back onto the RPi3.
pi@raspberrypi:~ $ sudo reboot
Connection to 192.168.1.134 closed by remote host.
Connection to 192.168.1.134 closed.
michel@hp:~$ ssh pi@192.168.1.34
pi@192.168.1.34's password: the new one of course!
Linux raspberrypi 4.14.34-v7+ #1110 SMP Mon Apr 16 15:18:51 BST 2018 armv7l
...
- Updating BlueZ
The first thing to do before adding or changing parts of the system is
to update and upgrade it.
pi@rpi3:~ $ sudo apt-get update && sudo apt-get upgrade
...
The following packages will be upgraded:
bluez-firmware wget
2 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 892 kB of archives.
After this operation, 7,168 B of additional disk space will be used.
Do you want to continue? [Y/n] y
...
There are a couple of ways to ascertain the version of the current BlueZ
package after the upgrade. We can query the bluetoothctl
utility
or we can get the status of the Bluetooth service which provides much more
information than just the version number.
pi@raspberrypi:~ $ sudo bluetoothctl -v
5.43
pi@raspberrypi:~ $ sudo systemctl status blue*
● bluetooth.target - Bluetooth
Loaded: loaded (/lib/systemd/system/bluetooth.target; static; vendor preset:
Active: active since Sun 2018-05-13 13:17:51 ADT; 1h 17min ago
Docs: man:systemd.special(7)
May 13 13:17:51 raspberrypi systemd[1]: Reached target Bluetooth.
● bluetooth.service - Bluetooth service
Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset
Active: active (running) since Sun 2018-05-13 13:17:51 ADT; 1h 17min ago
Docs: man:bluetoothd(8)
Main PID: 446 (bluetoothd)
Status: "Running"
CGroup: /system.slice/bluetooth.service
└─446 /usr/lib/bluetooth/bluetoothd
May 13 13:17:51 raspberrypi systemd[1]: Starting Bluetooth service...
May 13 13:17:51 raspberrypi bluetoothd[446]: Bluetooth daemon 5.43
May 13 13:17:51 raspberrypi systemd[1]: Started Bluetooth service.
May 13 13:17:51 raspberrypi bluetoothd[446]: Starting SDP server
May 13 13:17:51 raspberrypi bluetoothd[446]: Bluetooth management interface 1.14 initialized
May 13 13:17:51 raspberrypi bluetoothd[446]: Failed to obtain handles for "Service Changed" characteristic
May 13 13:17:51 raspberrypi bluetoothd[446]: Sap driver initialization failed.
May 13 13:17:51 raspberrypi bluetoothd[446]: sap-server: Operation not permitted (1)
Version 5.43 is installed, and the problems with the service as discussed
on my first post on the subject (Baby Bluetooth Steps on Raspberry Pi 3 - Raspbian
(Stretch) are still present. The latest version of BlueZ is available from its home and download pages. The latest release is version 5.49 dating
back to the 11th of march 2018. Upgrading to this newer version removes all
the errors reported above.
The first step is to obtain needed packages.
pi@raspberrypi:~ $ sudo apt install libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev
...
The following NEW packages will be installed:
icu-devtools libdbus-1-dev libglib2.0-bin libglib2.0-dev libical-dev libical2 libicu-dev libpcre16-3 libpcre3-dev libpcre32-3
libpcrecpp0v5 libreadline-dev libtinfo-dev libudev-dev
0 upgraded, 14 newly installed, 0 to remove and 0 not upgraded.
Need to get 22.3 MB of archives.
After this operation, 88.1 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
While we asked for 5 new packages, 14 packages were in fact installed.
The next steps consist in downloading the archive and extracting its
content.
pi@raspberrypi:~ $ wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.49.tar.xz
...
2018-05-13 15:00:58 (272 KB/s) - ‘bluez-5.49.tar.xz’ saved [1744860/1744860]
pi@raspberrypi:~ $ tar -xf bluez-5.49.tar.xz
pi@raspberrypi:~ $ cd bluez-5.49/
Time to compile and install the stack. This takes a bit of time on a
Raspberry Pi 3, especially the make
part.
pi@raspberrypi:~/bluez-5.49 $ ./configure --prefix=/usr --mandir=/usr/share/man --sysconfdir=/etc --localstatedir=/var --enable-experimental
...
pi@raspberrypi:~/bluez-5.49 $ make -j4
...
pi@raspberrypi:~/bluez-5.49 $ sudo make install
To ensure that the user (pi
) has permission to invoke
bluetoothctl
, the user needs to be added to the
bluetooth
group and the Dbus Bluetooth configuration file which
was overriden in the BlueZ installation needs to
be restored. In essence that means adding a policy for the
bluetooth
group.
pi@raspberrypi:~/bluez-5.49 $ sudo adduser pi bluetooth
pi@raspberrypi:~ $ sudo cp /etc/dbus-1/system.d/bluetooth.conf /etc/dbus-1/system.d/bluetooth.conf.bak
pi@raspberrypi:~ $ sudo nano /etc/dbus-1/system.d/bluetooth.conf
...
<policy user="root">
<allow own="org.bluez"/>
<allow send_destination="org.bluez"/>
<allow send_interface="org.bluez.Agent1"/>
<allow send_interface="org.bluez.MediaEndpoint1"/>
<allow send_interface="org.bluez.MediaPlayer1"/>
<allow send_interface="org.bluez.Profile1"/>
<allow send_interface="org.bluez.AlertAgent1"/>
<allow send_interface="org.bluez.ThermometerWatcher1"/>
<allow send_interface="org.bluez.HeartRateWatcher1"/>
<allow send_interface="org.bluez.CyclingSpeedWatcher1"/>
<allow send_interface="org.bluez.GattCharacteristic1"/>
<allow send_interface="org.bluez.GattDescriptor1"/>
<allow send_interface="org.bluez.LEAdvertisement1"/>
<allow send_interface="org.freedesktop.DBus.ObjectManager"/>
<allow send_interface="org.freedesktop.DBus.Properties"/>
</policy>
<!-- allow users of bluetooth group to communicate -->
<policy group="bluetooth">
<allow send_destination="org.bluez"/>
</policy>
<policy at_console="true">
<allow send_destination="org.bluez"/>
</policy>
The parts in bold red colour were the elements of the original file that
need to be included in the configuration. It is necessary to reboot to update
everything. Then log back on and check that the newest version of Bluetooth
stack has been installed and look at the status of the Bluetooth service.
pi@raspberrypi:~ $ sudo reboot
Connection to 192.168.1.34 closed by remote host.
Connection to 192.168.1.34 closed.
wait a while and then
michel@hp:~$ ssh pi@192.168.1.34
pi@192.168.1.34's password: new_password
Linux raspberrypi 4.14.34-v7+ #1110 SMP Mon Apr 16 15:18:51 BST 2018 armv7l
...
pi@raspberrypi:~ $ bluetoothctl -v
bluetoothctl: 5.49
pi@raspberrypi:~ $ sudo systemctl status blueto*
● bluetooth.target - Bluetooth
Loaded: loaded (/lib/systemd/system/bluetooth.target; static; vendor preset: enabled)
Active: active since Sun 2018-05-13 21:49:01 ADT; 49s ago
Docs: man:systemd.special(7)
May 13 21:49:01 raspberrypi systemd[1]: Reached target Bluetooth.
● bluetooth.service - Bluetooth service
Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2018-05-13 21:49:01 ADT; 49s ago
Docs: man:bluetoothd(8)
Main PID: 432 (bluetoothd)
Status: "Running"
CGroup: /system.slice/bluetooth.service
└─432 /usr/libexec/bluetooth/bluetoothd
May 13 21:49:01 raspberrypi systemd[1]: Starting Bluetooth service...
May 13 21:49:01 raspberrypi bluetoothd[432]: Bluetooth daemon 5.49
May 13 21:49:01 raspberrypi systemd[1]: Started Bluetooth service.
May 13 21:49:01 raspberrypi bluetoothd[432]: Starting SDP server
May 13 21:49:01 raspberrypi bluetoothd[432]: Bluetooth management interface 1.14 initialized
Great! Everything seems to be correct, no more failure messages. There is
still a missing piece, the Bluetooth Audio ALSA Backend bluez-alsa. Luckily this is easily added.
pi@raspberrypi:~ $ sudo apt install bluealsa
...
The following NEW packages will be installed:
bluealsa libbluetooth3 libsbc1
0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded.
Need to get 170 kB of archives.
After this operation, 504 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
This will load the service immediately, it should now be possible to
connect a Bluetooth speaker without the need to restart anything.
Two references gave me basically all the information I needed to
update the BlueZ protocol stack correctly.
- Updating BlueZ on Raspberry Pi (5.43 to 5.48)
- by max at SCRIBLES, February 14, 2018.
- How to connect to Bluetooth LE devices without being root
- by Douglas6 on the Raspberry Pi forum, March 16, 2013
- Connecting Bluetooth Audio Devices
Connecting Bluetooth speakers to the Raspberry Pi is a relatively
simple matter especially if the Bluetooth chip is already turned on.
pi@raspberrypi:~ $ bluetoothctl
Agent registered
[bluetooth]# scan on
Discovery started
[CHG] Controller B8:27:EB:B2:91:B5 Discovering: yes
...
[NEW] Device 30:21:3E:31:C6:2B AUDIOPOD2b
[bluetooth]# pair 30:21:3E:31:C6:2B
Attempting to pair with 30:21:3E:31:C6:2B
[CHG] Device 30:21:3E:31:C6:2B Connected: yes
[CHG] Device 30:21:3E:31:C6:2B UUIDs: 00001108-0000-1000-8000-00805f9b34fb
[CHG] Device 30:21:3E:31:C6:2B UUIDs: 0000110b-0000-1000-8000-00805f9b34fb
[CHG] Device 30:21:3E:31:C6:2B UUIDs: 0000110c-0000-1000-8000-00805f9b34fb
[CHG] Device 30:21:3E:31:C6:2B UUIDs: 0000110e-0000-1000-8000-00805f9b34fb
[CHG] Device 30:21:3E:31:C6:2B UUIDs: 0000111e-0000-1000-8000-00805f9b34fb
[CHG] Device 30:21:3E:31:C6:2B ServicesResolved: yes
[CHG] Device 30:21:3E:31:C6:2B Paired: yes
Pairing successful
[CHG] Device 30:21:3E:31:C6:2B ServicesResolved: no
[CHG] Device 30:21:3E:31:C6:2B Connected: no
[bluetooth]# connect 30:21:3E:31:C6:2B
[CHG] Device 30:21:3E:31:C6:2B Connected: yes
Connection successful
[CHG] Device 30:21:3E:31:C6:2B ServicesResolved: yes
"ding dong" from the speaker signalling it was connected:
If the Bluetooth device is off, turning discovery on will not work. It is
necessary to power up the chip before scanning and continuing as shown above.
pi@raspberrypi:~ $ bluetoothctl
Agent registered
[bluetooth]# scan on
Failed to start discovery: org.bluez.Error.NotReady
[bluetooth]# power on
[CHG] Controller B8:27:EB:B2:91:B5 Class: 0x006c0000
Changing power on succeeded
[CHG] Controller B8:27:EB:B2:91:B5 Powered: yes
[bluetooth]# scan on
Discovery started
[CHG] Controller B8:27:EB:B2:91:B5 Discovering: yes
...
Thankfully, it is not necessary to go through the interactive procedure
described above to connect a Bluetooth device, once it has been paired. If a
paired device is "trusted" by a controller, such as the Raspberry Pi 3, then
connection will be done automatically whenever the device is near that
controller. Trusting a paired device is a simple procedure.
[AUDIOPOD2]# trust 30:21:3E:31:C6:2B
[CHG] Device 30:21:3E:31:C6:2B Trusted: yes
Changing 30:21:3E:31:C6:2B trust succeeded
[AUDIOPOD2]# info 30:21:3E:31:C6:2B
Device 30:21:3E:31:C6:2B (public)
Name: AUDIOPOD2
Alias: AUDIOPOD2
Class: 0x00240408
Icon: audio-card
Paired: yes
Trusted: yes
Blocked: no
Connected: yes
LegacyPairing: no
UUID: Headset (00001108-0000-1000-8000-00805f9b34fb)
UUID: Audio Sink (0000110b-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb)
UUID: Handsfree (0000111e-0000-1000-8000-00805f9b34fb)
RSSI: -55
[AUDIOPOD2]# quit or exit
pi@raspberrypi:~ $
Once the or all Bluetooth devices have been paired, it is probably a
good idea to stop discovery. Apparently, scanning can interfere with some
operations with some bluetooth hardware. Again this is not difficult.
pi@raspberrypi:~ $ bluetoothctl
Agent registered
[bluetooth]# scan off
Discovery stopped
If instead of Discovery stopped
the utility printed
something like Failed to stop discovery: org.bluez.Error.Failed
there is no need to worry; scanning was already off. Scanning
is not needed for automatic connection of trusted Bluetooth devices; it
is only used to discover the MAC address of new Bluetooth devices in order
to pair them which means adding them to the controler's database of known
devices.
I used the D-Bus introspection tool busctl
to monitor the status
of the Bluetooth speaker.
pi@raspberrypi:~ $ busctl tree org.bluez
└─/org
└─/org/bluez
└─/org/bluez/hci0
├─/org/bluez/hci0/dev_30_21_3E_31_C6_2B
│ └─/org/bluez/hci0/dev_30_21_3E_31_C6_2B/fd0
├─/org/bluez/hci0/dev_5C_21_CB_1C_D3_56
└─/org/bluez/hci0/dev_B8_78_2E_44_D5_DE
The connected device, the Bluetooth device is easily identified; it
is the only one that has what seems to be a descriptor fd0
. The
other two listed devices, that are not connected, are probably my desktop
computer and another Raspberry Pi 3 that were both in the vicinity.
Looking at the status of the Bluetooth
service there were
apparently two problems.
pi@raspberrypi:~ $ sudo systemctl status bluetooth.service
● bluetooth.service - Bluetooth service
Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2018-05-13 21:49:01 ADT; 42min ago
Docs: man:bluetoothd(8)
Main PID: 432 (bluetoothd)
Status: "Running"
CGroup: /system.slice/bluetooth.service
└─432 /usr/libexec/bluetooth/bluetoothd
May 13 21:49:01 raspberrypi systemd[1]: Starting Bluetooth service...
May 13 21:49:01 raspberrypi bluetoothd[432]: Bluetooth daemon 5.49
May 13 21:49:01 raspberrypi systemd[1]: Started Bluetooth service.
May 13 21:49:01 raspberrypi bluetoothd[432]: Starting SDP server
May 13 21:49:01 raspberrypi bluetoothd[432]: Bluetooth management interface 1.14 initialized
May 13 21:54:18 raspberrypi bluetoothd[432]: a2dp-sink profile connect failed for 30:21:3E:31:C6:2B: Protocol not available
May 13 21:59:07 raspberrypi bluetoothd[432]: Endpoint registered: sender=:1.11 path=/A2DP/SBC/Source/1
May 13 21:59:07 raspberrypi bluetoothd[432]: Endpoint registered: sender=:1.11 path=/A2DP/SBC/Sink/1
May 13 22:13:25 raspberrypi bluetoothd[432]: Endpoint registered: sender=:1.11 path=/A2DP/SBC/Source/2
May 13 22:13:26 raspberrypi bluetoothd[432]: Unable to get io data for Headset Voice gateway: getpeername: Transport endpoint is not connected (107)
I have not investigated those error message for the time being, but they
do not seem to be significant.
As far as I know, a device such as a speaker can be connected to only one
controller at a time. That was something to remember as I had connected
and trusted the Bluetooth speaker to my desktop computer at one point. I had
to make sure that I disconnected and untrusted the Bluetooth speaker from
the desktop Bluetooth controller to connect them to the RPi3. This is
easily done. Below is how I did that on the RPi3, but it is exactly the
same thing on my Ubuntu desktop.
pi@raspberrypi:~ $ bluetoothctl
[AUDIOPOD2]# untrust 30:21:3E:31:C6:2B
[CHG] Device 30:21:3E:31:C6:2B Trusted: no
Changing 30:21:3E:31:C6:2B untrust succeeded
[AUDIOPOD2]# disconnect 30:21:3E:31:C6:2B
Attempting to disconnect from 30:21:3E:31:C6:2B
[CHG] Device 30:21:3E:31:C6:2B ServicesResolved: no
Successful disconnected
[CHG] Device 30:21:3E:31:C6:2B Connected: no
"trrong trring" from the speaker signalling it was disconnected:
[bluetooth]# quit
pi@raspberrypi:~ $
The speaker remained paired, and it is possible to connect or disconnect
to it with a single command piped to the control program. This could be
useful in bash scripts.
pi@raspberrypi:~ $ echo -e "connect 30:21:3E:31:C6:2B" | bluetoothctl
Agent registered
[bluetooth]# connect 30:21:3E:31:C6:2B
Attempting to connect to 30:21:3E:31:C6:2B
pi@raspberrypi:~ $ echo -e "disconnect 30:21:3E:31:C6:2B" | bluetoothctl
Agent registered
[AUDIOPOD2]# disconnect 30:21:3E:31:C6:2B
Attempting to disconnect from 30:21:3E:31:C6:2B
The speaker made its connected or disconnected sound confirming the
success of the operation. The output from the control utility is cleaner than
in the previous version, but it can be entirely suppressed by sending it to
the null
device as in the following command.
pi@raspberrypi:~ $ echo -e "connect 30:21:3E:31:C6:2B" | bluetoothctl > /dev/null 2>&1
Finally, to "unpair" a device which means removing its MAC address from the
controller database of known devices use the bluetoothctl
command remove <device_mac>
(of course
<device_mac> must be replaced with the device MAC address such as
30:21:3E:31:C6:2B
). Should the device need to be connected in
the future, it will have to be paired again.
- Sending Sound to Bluetooth Audio Devices
Now its time to try to make a sound come out of the speaker. To do that a
WAV
(signed 16 or 32 bit PCM encoded) file is needed on the
RPi3. I used Audacity to export an MP3
piece of music to both 16 and 32 bit formats and saved them to a directory
named sound
. Just to make sure that the file was correct, I
played it using the powered speakers connected to the 3.5 mm jack on the
Raspberry Pi.
pi@raspberrypi:~ $ cd sound
pi@raspberrypi:~/sound $ aplay test16.wav
Playing WAVE 'test16.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
If you get this output on the terminal as if everything works, but no
sound is heard, look at the next section on controlling the sound level.
Recall that this is a done on a fresh install of Raspbian. Hence there is
no ALSA configuration file .asoundrc
in place.
Connect a Bluetooth speaker as explained above. Following the
Configuration & Usage instructions on the bluez-alsa
site, the following command will send the audio stream to the
Bluetooth speaker.
pi@raspberrypi:~/sound $ aplay -D bluealsa:HCI=hci0,DEV=30:21:3E:31:C6:2B,PROFILE=a2dp test16.wav
Playing WAVE 'test16.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
Of course, the Bluetooth MAC address of the speaker 30:21:3E:31:C6:2B
will need to be replaced with the correct value.
There is only one Bluetooth device on the Raspberry Pi 3 as can be seen
from the hciconfig
command.
pi@raspberrypi:~ $ hciconfig -a
hci0: Type: Primary Bus: UART
BD Address: B8:27:EB:B2:91:B5 ACL MTU: 1021:8 SCO MTU: 64:1
UP RUNNING PSCAN
RX bytes:23037554 acl:53965 sco:0 events:1104 errors:0
TX bytes:15376 acl:217 sco:0 commands:527 errors:0
Features: 0xbf 0xfe 0xcf 0xfe 0xdb 0xff 0x7b 0x87
Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
Link policy: RSWITCH SNIFF
Link mode: SLAVE ACCEPT
Name: 'raspberrypi'
Class: 0x6c0000
Service Classes: Rendering, Capturing, Audio, Telephony
Device Class: Miscellaneous,
HCI Version: 4.1 (0x7) Revision: 0x168
LMP Version: 4.1 (0x7) Subversion: 0x2209
Manufacturer: Broadcom Corporation (15)
So we can simplify the command a little bit by not indicating which
Bluetooth device to use. Similarly, the a2dp
profile seems
to be the default and does not need to be specified.
pi@rpi3:~ $ aplay -D bluealsa:DEV=30:21:3E:31:C6:2B test16.wav
Playing WAVE 'test16.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
Instead of identifying the playback device in detail in the
aplay
command, a default configuration file, can be created.
pi@raspberrypi:~/sound $ nano ~/.asoundrc
defaults.bluealsa.interface "hci0"
defaults.bluealsa.device "30:21:3E:31:C6:2B"
defaults.bluealsa.profile "a2dp"
defaults.bluealsa.delay 10000
This is not quite the same as what I showed in my previous post on
this subject, but it is what is recommended on the
bluez-alsa page and as I explained in a later post
this minimalist approach makes life much simpler when the Music On Console (MOC) audio media player is to be used
with either the Raspberry Pi built-in sound card or with a Bluetooth speaker.
Now all that is needed to play the file is the following command.
pi@raspberrypi:~/sound $ aplay -D bluealsa test16.wav
Playing WAVE 'test16.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
- Controlling the Playback Volume of a Bluetooth Speaker
Controlling the playback volume when using ALSA service is often quite
important. Indeed one could assume that something is horribly wrong with the
installation because nothing is heard when the only problem is that the sound
output has been turned off completely or the output volume is much too low.
There are two ALSA utilities that can be used to control the volume,
amixer
which is a traditional command line utility and
alsamixer
which has a more convivial text based graphical user
interface. With the latter, the volume is set by using the left and
right cursor keys to choose the control and then the up and down cursor
keys to set the sound level. Either utility can be used in a
second terminal as the sound is being played with aplay
in
the first terminal. I recommend using alsamixer
initially;
amixer
is better for use in scripts.
Launch the alsamixer
specifying the bluealsa
device. You can start the utility without the -D
parameter but
then when the F6 key is pressed to select a sound
card, bluealsa
will not be listed. However, you could use the
enter device name...
option and then manually enter
bluealsa
but it is easier to do it on the command line. The
image below is recycled from a previous post, in the present context it would
say pi@raspberrypi: ~
on the window caption bar.
pi@raspeberrypi:~/sound $ alsamixer -D bluealsa
Press on F3 to view the Playback
devices. Use the left and right cursor keys to select the
AUDIOPOD2 - A2DP
device. Then use the up and down
cursor keys to adjust the volume of the output. As I said, this is best done while playing a sound file in another
terminal so as to hear the sound level. As shown on the screen, close the
application by pressing the Esc key.
Alternatively, the volume can be set with the command line utility.
pi@raspeberrypi:~/sound $ amixer -D bluealsa sset "AUDIOPOD2 - A2DP" 50%
Simple mixer control 'AUDIOPOD2 - A2DP',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 64 [50%] [on]
Front Right: Playback 64 [50%] [on]
Append a "+" or "-" to move the volume up or down. For example, to set
the volume to 30% of full volume when it is already at 50%, request a
diminution of 20% as follows.
pi@raspeberrypi:~/sound $ amixer -D bluealsa sset "AUDIOPOD2 - A2DP" 20%-
Simple mixer control 'AUDIOPOD2 - A2DP',0
Capabilities: pvolume pswitch
Playback channels: Front Left - Front Right
Limits: Playback 0 - 127
Mono:
Front Left: Playback 38 [30%] [on]
Front Right: Playback 38 [30%] [on]
Thus 20%- is not a reduction of 20% of the current
volume because that would have brought the volume to 40% of the maximum
(20% of 50% is 10% and 50% - 10% give 40%.
- Receiving Sound from Bluetooth Audio Devices
The situation can be turned on its head and the Raspberry Pi can be used
as a Bluetooth speaker (if a powered speaker is connected to it of course).
There are comments out "there" about the foolishness of this given the low
price of dedicated Bluetooth speakers. Granted, but I do have a use for this.
I will be using my Raspberry Pi to update a rather good and relatively
expensive bookshelf sound system in my living room so that it can stream
Internet radio stations. It would be useful to be able to use a tablet to
find new stations on the Web and pass them on to the sound system until such
time as I decide to update the database of Internet radio stations on the
RPi3 itself.
When I first tried this, I used A simple Bluetooth
Speaker Daemon for the Raspberry Pi 3 by lukasjapan (Lukas
"[the] german Full Stack Software Engineer currently working and living in
Tokyo"). I followed the instruction posted in December 2017 by Markus
Järvisalo Making the Raspberry Pi 3 a bluetooth audio receiver but
without updating the version 5.43 BleuZ stack that
came with Rasbian Stretch. I was a bit disappointed with the delay in the
sound output and that is what prompted me to update the bluealsa
package. If you decide to go that route, I recommend not following Markus'
instructions on updating. The usual ./configure, make, make install
as describe in section 2 above works just fine.
As it happens, BleuZ contains everything needed
to "sink" Bluetooth audio. In other words, it has its own playback utility:
bluealsa-aplay
which is deceptively easy to use. Again, thanks
to a max post at SCRIBBLES for alerting me on to this
possibility. Here are the broad strokes.
- Connect the source. Mine was Nexus 7 tablet running Android 6.0.1.
Its Bluetooth MAC address is
D8:50:E6:72:E1:EA
.
- In the Bluetooth settings on the Nexus, make sure that
Media audio
is
enabled.
- On the Raspberry Pi, run the playback utility:
bluealsa-aplay D8:50:E6:72:E1:EA
The hardest part of this was establishing the Bluetooth connection
between the tablet and the Raspberrry Pi. As that was a first attempt, it was
a bit confusing and I cannot quite recollect how it went. I did it again in a
more controlled fashion with an Acer Iconia (Android 7.0), taking a
few screenshots while going along. I will show the steps below, but expect
the details to be different from one device to another and with different
versions of Android. Of course this could be done with an IOS tablet
but again the details will be different.
- Go to Settings on the Android tablet and then go to
Bluetooth
and if it is Off
set it to
On
by sliding the control to the right.
As can be seen, no Bluetooth devices were found.
- Start the
bluetoothctl
utility on the Rpi3
and make the Raspberry Pi discoverable.
pi@raspberrypi:~ $ bluetoothctl
Agent registered
[bluetooth]# discoverable on
Changing discoverable on succeeded
[CHG] Controller B8:27:EB:B2:91:B5 Discoverable: yes
[bluetooth]#
- Wait for
raspberrypi
to show up as an available device
on the tablet.
Impatient? Toggle Bluetooth
off and then back on,
the RPi3 will be found immediately.
- Press on the
raspberrypi
headset icon or
on the label itself. Just below, Pairing...
will be displayed
in grey, and then a dialog window will pop up asking if the device is to
be paired.
Click on the PAIR button. On the RPi3, bluetoothctl
will
show that the tablet's Bluetooth has been seen but it is not connected.
bluetoothctl
[CHG] Device 68:B3:5E:48:E2:5F Connected: yes
[CHG] Device 68:B3:5E:48:E2:5F Connected: no
When pairing is done, the raspberrypi
will now appear as
a paired device.
- From the Raspberry Pi, connect to the tablet.
[bluetooth]# connect 68:B3:5E:48:E2:5F
Attempting to connect to 68:B3:5E:48:E2:5F
[CHG] Device 68:B3:5E:48:E2:5F Connected: yes
Connection successful
[CHG] Device 68:B3:5E:48:E2:5F ServicesResolved: yes
The RPi3 then shows up as a connected device on the tablet.
- Click on the cog icon beside
raspberrypi
and make sure that the device can be used for
Media audio
.
From now on all sound from the Android tablet is diverted from the
speaker and instead streamed on the Bluetooth connection.
- The
bluetoothctl
utility can be closed
or a new terminal session can be opened, and the BlueZ
ALSA player must be launched.
[B3-A40]# quit
pi@raspberrypi:~ $ bluealsa-aplay 00:00:00:00:00:00
-
To test, play some audio content on the tablet such as a YouTube video
or an internet radio station or a recording. Anything actually. Use
the tablet volume control to adjust the sound level. If it seems too
low, use
alsamixer
Raspeberry Pi to set the mixer volume to 100
(do not use the -D
option, this is PCM mixer for the 3.5mm jack
that is being set).
Why the 00:00:00:00:00:00
MAC address in this last invocation of
bluealsa-aplay
while the actual address of the Bluetooth device
in the Nexus was used before? Because I am lazy.
pi@raspberrypi:~ $ bluealsa-aplay --help
Usage:
bluealsa-aplay [OPTION]... ...
Options:
-h, --help print this help and exit
-V, --version print version and exit
-v, --verbose make output more verbose
-i, --hci=hciX HCI device to use
-d, --pcm=NAME PCM device to use
--pcm-buffer-time=INT PCM buffer time
--pcm-period-time=INT PCM period time
--profile-a2dp use A2DP profile
--profile-sco use SCO profile
--single-audio single audio mode
Note:
If one wants to receive audio from more than one Bluetooth device, it is
possible to specify more than one MAC address. By specifying any/empty MAC
address (00:00:00:00:00:00), one will allow connections from any Bluetooth
device.
If the sound is choppy, if there is too much stuttering, make sure that
the WiFi interface is down. As stated in the first section, a single and
sometimes overwhelmed chip is responsible for both WiFi and Bluetooth on the
Raspberry Pi 3 and Raspberry Pi Zero W. Also turn Bluetooth scanning off.
pi@raspberrypi:~ $ sudo ip link set wlan0 down
pi@raspberrypi:~ $ echo -e "scan off" | bluetoothctl
Agent registered
[B3-A40]# scan off
When streaming the audio from a video playing on my tablet, there is an
annoying delay. The sound is out of synchronisation and looking at the video
is much like looking at an old overdubbed film where heard words do not match
the movement of the actor's lips. It is a subject of discussion on the Web, but I
do not know of a solution for this.
- There's more?
Of course there is more. There is always more; we just settle for good
enough at some point. In this case, doing without WiFi connectivity if
the Raspberry Pi 3 is to be used as a Bluetooth sink is not tenable. I need
to place my RPi3 near the living room sound system where there is no Ethernet
jack.
It seems to me that there are two ways of getting around that problem:
add a WiFi-USB dongle or add a Bluetooth-USB dongle. The only dongle
I have is a WiFi-USB dongle used on my Raspberry Pi 2 hosting my home
automation system. I will not be disrupting that system. Besides, I am
curious to try a Bluetooth dongle. Beside the obvious reason, it may be that
the inability to use the SCO profile of the Bluetooth speakers is caused by
a bug or defect of the BCM43438 WiFi/Bluetooth chip.
The pairing, connection of the Bluetooth devices and launching of the
playback utility should be simplified and automated as much as possible. I
have not looked at this yet, but I do have a good reference which I hope
will prove helpful later on. And while at it, here is the reference for
the use of bluealsa-aplay
. Only after reading that post could
I make sense of the instructions on the BlueZ
site.
- Headless A2DP Audio Streaming on Raspbian Stretch by Tucker Kern
- https://gist.github.com/mill1000/74c7473ee3b4a5b13f6325e9994ff84c.
- Streaming Bluetooth Audio from Phone to Raspberry Pi using ALSA by max at SCRIBBLES.
- https://scribles.net/streaming-bluetooth-audio-from-phone-to-raspberry-pi-using-alsa/.