1

I'm running a 'bullseye Lite' system (i.e. no GUI), and trying to get it to play audio through a connected Bluetooth speaker. I'm not having much luck. I tried following an earlier approach (worked on 'buster Lite'), but it seems things have changed. I suspect that one of the changes is due to systemd; another perhaps to pacmd.

I've installed pulseaudio-module-bluetooth using apt; there was a long list of dependencies that were also installed.

Using bluetoothctl, I can connect from my RPi to the speaker ('JBL Flip 5'):

$ bluetoothctl
Agent registered
[CHG] Controller B8:27:EB:F3:8A:58 Pairable: yes
[bluetooth]# devices
Device B8:F6:53:9B:1A:97 JBL Flip 5
[bluetooth]# connect B8:F6:53:9B:1A:97
Attempting to connect to B8:F6:53:9B:1A:97
[CHG] Device B8:F6:53:9B:1A:97 Connected: yes
Connection successful
[JBL Flip 5]# info B8:F6:53:9B:1A:97
Device B8:F6:53:9B:1A:97 (public)
    Name: JBL Flip 5
    Alias: JBL Flip 5
    Class: 0x00240414
    Icon: audio-card
    Paired: yes
    Trusted: yes
    Blocked: no
    Connected: yes
    LegacyPairing: no
    UUID: Serial Port               (00001101-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)

It appears things are OK as far as the BT connection itself goes. I go to pacmd afterwards - things are much murkier here:

$ pacmd
No PulseAudio daemon running, or not running as session daemon.

$ pulseaudio --start

$ pacmd
Welcome to PulseAudio 14.2! Use "help" for usage information.
>>> list-sink-inputs
0 sink input(s) available.
>>> 

This seems to be a problem. I can start pulseaudio manually, but it apparently quits shortly after I do, and then pacmd becomes unresponsive. I checked status:

$ systemctl status --user pulseaudio
● pulseaudio.service - Sound Service
     Loaded: loaded (/usr/lib/systemd/user/pulseaudio.service; enabled; vendor preset: enabled)
     Active: inactive (dead)
TriggeredBy: ● pulseaudio.socket

I don't know what pulseaudio.socket is??? I tried starting the service manually:

$ systemctl --user --now 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.

$ systemctl status --user pulseaudio
● pulseaudio.service - Sound Service
     Loaded: loaded (/usr/lib/systemd/user/pulseaudio.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2024-04-07 05:55:19 UTC; 20s ago
TriggeredBy: ● pulseaudio.socket
   Main PID: 11323 (pulseaudio)
      Tasks: 2 (limit: 407)
        CPU: 229ms
     CGroup: /user.slice/user-1000.slice/[email protected]/app.slice/pulseaudio.service
             └─11323 /usr/bin/pulseaudio --daemonize=no --log-target=journal

Apr 07 05:55:19 rpi3a systemd[3188]: Starting Sound Service...
Apr 07 05:55:19 rpi3a pulseaudio[11323]: Failed to find a working profile.
Apr 07 05:55:19 rpi3a pulseaudio[11323]: Failed to load module "module-alsa-card" (argument: "device_id="1" name="platform-3f902000.hdmi" card_na>
Apr 07 05:55:19 rpi3a systemd[3188]: Started Sound Service.

This is no good; I seem to be in a 'catch-22' situation. How do I proceed from here to get BT sound working?

2
  • I am not a great fan (or user) of Bluetooth but I occasionally use for audio. I hate setting it up. Once I have succeeded (on a desktop install) I copy sudo su && tar cf bluePi3B+Buster.tar /var/lib/bluetooth and use this to setup other images. This is a kludge but it works.
    – Milliways
    Commented Apr 7 at 6:45
  • Maybe I'll try that once I get mine set up :)
    – Seamus
    Commented Apr 7 at 7:06

2 Answers 2

1

The bluez-alsa solution:

This is a "build from source" application (despite what the Debian wiki says). It also uses the "command line interface" exclusively, so maybe not well-suited to everyone. I generally don't like "build from source" packages, but decided to give this one a try. It's called bluez-alsa. My first impression was good (or I wouldn't be writing this); the principal reason for that is the technical support and documentation that's provided.

The instructions/documentation for building, installing and configuring bluez-alsa are available through their GitHub site. Much of the documentation is housed in a collection of wikis. Installation is summarized on the INSTALL.md page, and many more details are covered in the "Installation from source" wiki.

I installed & built bluez-alsa on an RPi Zero 2W under 64-bit 'bookworm' using the following commands:

$ cd && git clone https://github.com/arkq/bluez-alsa.git
$ sudo apt install git automake build-essential libtool pkg-config python3-docutils libasound2-dev libbluetooth-dev libdbus-1-dev libglib2.0-dev libsbc-dev mpg123
$ cd bluez-alsa && autoreconf --install --force 
$ mkdir build && cd build
$ ../configure --enable-systemd
$ make 
$ sudo make install
$ sudo systemctl enable bluealsa.service
$ sudo reboot

After booting, I had to run bluetoothctl to find, pair, trust & connect to my el cheapo BT speaker:

$ bluetoothctl
...
[bluetooth]# power on
[bluetooth]# scan on
... eventually finding Device B8:F6:53:9B:1A:97 Oontz Angle
[bluetooth]# pair B8:F6:53:9B:1A:97
[bluetooth]# trust B8:F6:53:9B:1A:97 
[bluetooth]# connect B8:F6:53:9B:1A:97
[bluetooth]# quit

At this point, all should be "ready", so start making noise!

$ nohup mpg123 -o alsa -a bluealsa --loop -1 rainstorm.mp3 &
[1] 698
$ nohup: ignoring input and appending output to 'nohup.out'
$ 

YES! I hear the sounds. Because the systemd bluealsa.service is owned by root I can log out, and the sound continues to play (unlike w/ pulseaudio & wireplumber).

Epilogue, 11 May,2024:

Despite the relatively small amount of processing power available on the RPi Zero 2W, I've had very good luck with bluez-alsa. I even compiled the bluez-alsa package on the Zero 2W without a lot of fuss.

Again, I can't say enough positive things about the technical support I've received through the bluez-alsa "Discussions" site. And the bluez-alsa documentation is likewise commendably excellent!

How am I using bluez-alsa?

I have the RPi Zero 2W and a cheap (~£20) Bluetooth speaker set up in my bedroom. I use it to play a "rainstorm" soundtrack I copped from YouTube using yt-dlp; I use mpg123 to play the rain soundtrack in a loop all night long 'cause it helps me sleep :)

I've found that the best sound (least interference) is obtained by shutting down the WiFi. I suspect this is due to the fact that BT and WiFi share the same PCB-fab 2.4 GHz antenna. I've done this using cron; here's the root crontab I use:

# ROUTINE start @ 11 PM: 1. stifle wifi, 2. start 'rainstorm'=>'mpg123'
0 23 * * * /usr/bin/nmcli radio wifi off
1 23 * * * /usr/local/bin/rainstorm >> /home/pi/rainstormlog.txt 2>&1
# ROUTINE stop @ 8 AM: 1. enable wifi, 2. kill 'rainstorm' & 'mpg123'
0 8 * * * /usr/bin/pkill rainstorm && /usr/bin/pkill mpg123 >> /home/pi/rainstormlog.txt 2>&1
1 8 * * * /usr/bin/nmcli radio wifi on


# on reboot, make sure wifi is on, and disable wifi power_save:
@reboot /usr/bin/nmcli radio wifi on
@reboot /usr/sbin/iw wlan0 set power_save off > /home/pi/power_save_log.txt 2>&1

The rainstorm script was written for me by one of the helpful chaps in the bluez-alsa GitHub Discussions area; I modified it slightly to make it more verbose for logging purposes:

#!/bin/bash
# exec &>/dev/null              # suppress all output
/usr/bin/echo "$(date); starting \/usr\/local\/bin\/rainstorm"
for device in $(/usr/bin/bluetoothctl devices Paired | /usr/bin/sed -n 's/^Device \([^ ]*\).*$/\1/p')
do
        /usr/bin/echo "$(date); loop 1, /usr/local/bin/rainstorm"
        /usr/bin/bluealsa-cli list-pcms | grep 'a2dpsrc/sink$' && break
        if /usr/bin/bluetoothctl info "$device" | /usr/bin/grep -i 0000110b ; then
                /usr/bin/bluetoothctl connect "$device"
        fi
done
while true; do
        /usr/bin/echo "$(date); loop 2, /usr/local/bin/rainstorm"
#       /usr/bin/mpg123 -o alsa -a bluealsa --quiet --no-control --loop -1 /home/pi/rainstorm.mp3
        /usr/bin/mpg123 -o alsa -a bluealsa --no-control --loop -1 /home/pi/rainstorm.mp3
#       /usr/bin/grep -q -m 1 '^PCMAdded.*a2dp.*sink' <(/usr/bin/bluealsa-cli monitor)
        /usr/bin/grep -m 1 '^PCMAdded.*a2dp.*sink' <(/usr/bin/bluealsa-cli monitor)
done
1

The pipewire solution:

I think I have this working finally...

NOTE: This project began on a bullseye 'Lite' RPi 3A, and wound up on the 64-bit bookworm 'Lite' in an effort to improve reliability. I hope this answer is generally useful to others, but based on past experience with Bluetooth on Raspberry Pi that is probably too much to hope for... :(

Before starting this exercise, I read in this Debian wiki that for Debian 11 (aka bullseye) pipewire was "experimental" and "unsupported". This led me to the decision that I should use pulseaudio to play sound through my old Flip 5 BT speaker. AIUI (not very well at all!) the alternative to pulseaudio was to deal more-or-less directly with the Bluetooth stack via ALSA. I've tried the ALSA route, but found it... x-confusing. OTOH, I had been successful using pulseaudio on another RPi under the buster version of RPi OS.

I still don't know what I did wrong with pulseaudio. I couldn't really troubleshoot this because I could not find any documentation - none that I was able to understand. There has been tons of stuff written on the subject, but everything I tried led to a dead-end or failure.

Through groping around in the dark, I eventually came to realize that using systemctl to check the status of the bluetooth.service was a reasonably good indicator as to how things were going to go. The lines in the listing below re:
Sap driver initialization failed, and
Failed to set privacy: Rejected
made no sense to me, but I found they were present at each failure.

$ systemctl status bluetooth.service
● bluetooth.service - Bluetooth service
     Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2024-04-08 04:08:13 UTC; 7s ago
       Docs: man:bluetoothd(8)
    Process: 1543 ExecStartPost=/usr/bin/sdptool add SP (code=exited, status=0/SUCCESS)
   Main PID: 1542 (bluetoothd)
     Status: "Running"
      Tasks: 1 (limit: 407)
        CPU: 191ms
     CGroup: /system.slice/bluetooth.service
             └─1542 /usr/libexec/bluetooth/bluetoothd -C

Apr 08 04:08:13 rpi3a bluetoothd[1542]: Bluetooth daemon 5.55
Apr 08 04:08:13 rpi3a bluetoothd[1542]: Starting SDP server
Apr 08 04:08:13 rpi3a bluetoothd[1542]: Bluetooth management interface 1.22 initialized
Apr 08 04:08:13 rpi3a bluetoothd[1542]: profiles/sap/server.c:sap_server_register() Sap driver initialization failed.
Apr 08 04:08:13 rpi3a bluetoothd[1542]: sap-server: Operation not permitted (1)
Apr 08 04:08:13 rpi3a bluetoothd[1542]: Failed to set privacy: Rejected (0x0b)
Apr 08 04:08:13 rpi3a sdptool[1543]: Serial Port service registered
Apr 08 04:08:13 rpi3a systemd[1]: Started Bluetooth service.
Apr 08 04:08:13 rpi3a bluetoothd[1542]: Endpoint registered: sender=:1.31 path=/MediaEndpoint/A2DPSink/sbc
Apr 08 04:08:13 rpi3a bluetoothd[1542]: Endpoint registered: sender=:1.31 path=/MediaEndpoint/A2DPSource/sbc

This repeated failure led me to reconsider my earlier decision to use pulseaudio instead of pipewire. However, I wanted to give pipewire the best chance of success - which meant using a more current version than the one available in bullseye.

I decided to check the "bullseye backports" branch of the repo for a later version. I was in luck: ver 0.3.65 (same as in Debian 12) was available. For help on how to set up backports, please see this Q&A.. I also relied on this page for pipewire installation instructions - as there are no instructions in the RPi documentation site.

The other thing that must be done to get Bluetooth audio working is to make sure that the RPi BT stack: 1. can "see" the speaker, 2. the speaker can be "paired" w/ the RPi's BT controller, and 3. the speaker is declared "trusted" by you. The bluetoothctl app can do all of this. You can run it interactively by simply entering bluetoothctl at the command prompt. In interactive mode, you will see a prompt [bluetooth]# . You can type help at the prompt to see all (most?) of the available commands.

Following is a sample dialog:

$ bluetoothctl
Agent registered
[CHG] Controller B8:27:EB:F3:8A:58 Pairable: yes 
[bluetooth]# power on
Changing power on succeeded
[bluetooth]# scan on
Discovery started
...
# unfortunately, you'll have to review all of these results to identify your speaker... 
# and you'll also need a lot of patience as this may take a while! 
# eventually, you may see something like this:
...
[NEW] Device B8:F6:53:AE:13:F1 JBL Flip 5

[bluetooth]# scan off 
[bluetooth]# devices
Device 5C:XX:XX:XX:XX:BF fumier
Device 00:XX:XX:XX:XX:5F SZG DW2450
Device B8:F6:53:AE:13:F1 JBL Flip 5
Device DC:XX:XX:XX:XX:97 rpi4b 
[bluetooth]# pair B8:F6:53:AE:13:F1 
Attempting to pair with B8:F6:53:AE:13:F1
[CHG] Device B8:F6:53:AE:13:F1 Paired: yes
...
Pairing successful
[bluetooth]#  trust B8:F6:53:AE:13:F1
[CHG] Device B8:F6:53:AE:13:F1 Trusted: yes
Changing B8:F6:53:AE:13:F1 trust succeeded
[bluetooth]# connect B8:F6:53:AE:13:F1 

Hopefully, you get a message that indicates the connection was successful. You may then leave bluetoothctl by typing exit at the prompt. It gets lost in the dialog above, but the sequence of commands in the interactive bluetoothctl session is as follows:

power on
scan on
scan off (following discovery of your target device/speaker
devices  (to list everything "discovered")
pair
trust
connect
help     (to list available commands)

Again, I found it useful to check w/ systemctl to get status of the bluetooth service before moving forward:

$ systemctl status bluetooth.service 
$ systemctl status bluetooth.service
● bluetooth.service - Bluetooth service
     Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2024-04-08 09:40:37 UTC; 17h ago
       Docs: man:bluetoothd(8)
   Main PID: 509 (bluetoothd)
     Status: "Running"
      Tasks: 1 (limit: 407)
        CPU: 176ms
     CGroup: /system.slice/bluetooth.service
             └─509 /usr/libexec/bluetooth/bluetoothd

Apr 08 09:45:06 rpi3a bluetoothd[509]: Endpoint registered: sender=:1.18 path=/MediaEndpoint/A2DPSource/aptx_ll_0
Apr 08 09:45:06 rpi3a bluetoothd[509]: Endpoint registered: sender=:1.18 path=/MediaEndpoint/A2DPSource/aptx_ll_duplex_1
Apr 08 09:45:06 rpi3a bluetoothd[509]: Endpoint registered: sender=:1.18 path=/MediaEndpoint/A2DPSource/aptx_ll_duplex_0
Apr 08 09:45:06 rpi3a bluetoothd[509]: Endpoint registered: sender=:1.18 path=/MediaEndpoint/A2DPSource/faststream
Apr 08 09:45:06 rpi3a bluetoothd[509]: Endpoint registered: sender=:1.18 path=/MediaEndpoint/A2DPSource/faststream_duplex
Apr 08 09:45:06 rpi3a bluetoothd[509]: Endpoint registered: sender=:1.18 path=/MediaEndpoint/A2DPSink/opus_05
Apr 08 09:45:06 rpi3a bluetoothd[509]: Endpoint registered: sender=:1.18 path=/MediaEndpoint/A2DPSource/opus_05
Apr 08 09:45:06 rpi3a bluetoothd[509]: Endpoint registered: sender=:1.18 path=/MediaEndpoint/A2DPSink/opus_05_duplex
Apr 08 09:45:06 rpi3a bluetoothd[509]: Endpoint registered: sender=:1.18 path=/MediaEndpoint/A2DPSource/opus_05_duplex
Apr 08 23:47:20 rpi3a bluetoothd[509]: /org/bluez/hci0/dev_B8_F6_53_9B_1A_97/fd1: fd(44) 
ready

ready - no bitching about SAP drivers, etc. We are lookin' good! :)

And so the moment of truth has arrived, and I start my player on a soundtrack glommed from YouTube:

$ nohup mpg123 --loop -1 rainstorm.mp3 &
[2] 28719
$

YES! I can hear it... the sound of falling rain!

Conclusion: I am beginning to believe some of the very positive things I've read about pipewire. G'night...


Epilogue & Conclusions:

9 Apr '24: FWIW:

This isn't a particularly helpful remark, but it may be useful for setting expectations. If you spend a week or so chasing Bluetooth problems on a Linux system, you begin to wonder: "Does Bluetooth on Linux just suck?" Unfortunately, I think the answer may be, "Yes, it does suck." I've played audio thru a BT speaker using my iPhone6 as the music/control source for days without an interrupt; the setup/connection process takes maybe 30 seconds. Using Linux/RPi as the music/control source I can occasionally manage a few hours of continuous play, while spending hours futzing with arcane programs to accomplish the setup. BT under Linux just sucks - you're going have to deal with that.

12 Apr '24:

One of the annoying things that you may be forced to deal with using pipewire/wireplumber is that the associated systemd service runs under user ownership. "What does this mean?", you may ask. It means that if you logout, your music stops.

As a workaround to this logout issue, I thought that I could use agetty to create a password-less console login for user pi, started from the root crontab. I was unable to get that idea working, but I found a solution that did work in the Debian forum.

However... after a few days the pipewire/wireplumber solution began to wear on me. I was not keen on the opacity of pipewire, and it proved to be less reliable than I hoped. After a couple of days, I tossed 'bullseye' and installed 'bookworm' on the RPi. Unfortunately that resulted in almost no improvement. When the music stopped, the only solution I could find to re-start it was to reboot the system. And finally, pipewire is probably gross overkill for my use-case: a Raspberry Pi and a single £75 Bluetooth speaker :)

10 Oct '24 (FINAL UPDATE):

Please note this will be the final update for this answer... This has turned into a saga. I'm still experimenting - and still learning - but I've been posting the results to my GitHub account.

After expressing some misgivings re the pipewire solution, I've flip-flopped again. Completing a 1,500-hour reliability test with pipewire had much to do with that! Additionally, I am now also using pipewire on an RPi 3A+, where I use cmus as the player. It has been remarkably reliable there also. If you'd like more details, feel free to follow the saga on GitHub :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.