Bluetooth Audio with Rasbian Stretch on the Raspberry Pi 3
May 13, 2018
Baby Bluetooth Steps on Raspberry Pi 3 - Raspbian (Stretch)
Music on Console, ALSA, and Bluetooth on Raspbian Stretch)

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 around 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 enable device.

Table of Contents

  1. Installing Raspian Stretch
  2. Updating BlueZ
  3. Connecting Bluetooth Audio Devices
  4. Sending Sound to Bluetooth Audio Devices
  5. Controlling the Playback Volume of a Bluetooth Speaker
  6. Receiving Sound from Bluetooth Audio Devices
  7. There's more?

  1. Installing Raspian Stretch
  2. 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). belongs to root so the super user prefix must be used

    pi@raspberrypi:~ $ sudo raspi-config
    1. Change password for the current user mandatory
    2. Configure network settings - did nothing
    3. Boot Options - did nothing
    4. Localisation Options
      • I2 Change Timezone - to America/Moncton
    5. Interfacing Options
      • P2 SSH - enabled mandatory
      • P4 SPI - enabled
      • P5 I2C - enabled
    6. Overclock - did noth ing
    7. 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 have not enabled the WiFi interface in raspi-config and I have not setup a static IP address for it in the dhcpcd configuration file. Using a WiFi network connectino and streaming Bluetooth audio on the Raspberry Pi is not really possible. This is because doing both simultaneously overwhelms the single IC responsible for both links.

    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 ...

  3. Updating BlueZ
  4. 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:~ $ 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 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-alas. 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

  5. Connecting Bluetooth Audio Devices
  6. Connecting Bluetooth speakers to the Raspberry Pi is a relatively simple matter especially if 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 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.

  7. Sending Sound to Bluetooth Audio Devices
  8. 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

  9. Controlling the Playback Volume of a Bluetooth Speaker
  10. 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%.

  11. Receiving Sound from Bluetooth Audio Devices
  12. 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.

    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.

    1. 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.
    2. 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]#
    3. 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.
    4. 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.
    5. 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.
    6. 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.
    7. 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
    8. 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.

  13. There's more?
  14. 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/.
Baby Bluetooth Steps on Raspberry Pi 3 - Raspbian (Stretch)
Music on Console, ALSA, and Bluetooth on Raspbian Stretch)