We're hiring!
*

Using a Raspberry Pi as a Bluetooth speaker with PipeWire

Frederic Danis avatar

Frederic Danis
September 02, 2022

Share this post:

Do you have an old pair of PC speakers, or an old Hi-Fi, that you would like to convert into a pair of Bluetooth® speakers to play music from your phone? A Raspberry Pi can be easily used as an audio bridge between a Bluetooth® device and an analog speaker system, to make this possible. In this quick guide, I will show you how to set up the software on a Pi, using PipeWire, to achieve this.

In my demonstration setup, I am using a Raspberry Pi 3, which embeds a Bluetooth® chipset, and I am connecting an analog speaker to the 3.5mm jack. For the software, I am using RaspberryPi OS Lite with a recent PipeWire version installed from the Debian testing (Bookworm) repositories, as the version included in RaspberryPi OS (which is based on Debian Bullseye) is too old to support this use case.

PipeWire is able to output sound to the internal audio chipset without any special configuration. It provides Bluetooth® A2DP support with optional codecs (SBC-XQ, LDAC, aptX, aptX HD, aptX-LL, FastStream) out of the box. At the same time, WirePlumber automatically creates the connection between the A2DP source and the audio chipset when a remote device, like a phone or a laptop, connects. This makes the configuration very easy, as PipeWire will work out of the box. We will only need to set up BlueZ to make the system headless.

Let's see how this is done.

First, install RaspberryPi OS Lite (64-bit) to your SD card (assuming /dev/sdb is the SD card device on your PC/laptop):

$  xzcat 2022-04-04-raspios-bullseye-arm64-lite.img.xz | sudo dd of=/dev/sdb bs=1M status=progress

Connect the Raspberry Pi to a display & keyboard, boot it from this SD card, and complete the OS configuration.

After the OS configuration is complete, install PipeWire and WirePlumber from the testing (Bookworm) repository:

$ echo 'APT::Default-Release "stable";' | sudo tee /etc/apt/apt.conf.d/99defaultrelease
$ echo "deb http://ftp.de.debian.org/debian/ testing main contrib non-free" | sudo tee /etc/apt/sources.list.d/testing.list
$ sudo apt update
$ sudo apt -t testing install pipewire wireplumber libspa-0.2-bluetooth

The RaspberryPi OS Lite version automatically logs in the user created during the setup and this will automatically start PipeWire and WirePlumber. This is all that's needed for setting up PipeWire.

Next, we will need to set up a BlueZ pairing agent to accept pairings and A2DP connections. The reason we are doing this is because the target system is not going to have a user interface and we don't want to connect to it using ssh and type commands every time we want to pair a new device to it.

As this will require the DBus Python support, let's install this first:

$ sudo apt install python3-dbus

Then, copy the speaker-agent.py python script and its related systemd unit file from GitHub pw_wp_bluetooth_rpi_speaker to your user home directory on the Raspberrry Pi.

The speaker-agent.py python script, also shown below, will set the Raspberry Pi Bluetooth® adapter as always discoverable and will allow pairing and A2DP connections:

#!/usr/bin/python3
# SPDX-License-Identifier: LGPL-2.1-or-later

import dbus
import dbus.service
import dbus.mainloop.glib
from gi.repository import GLib

BUS_NAME = 'org.bluez'
AGENT_INTERFACE = 'org.bluez.Agent1'
AGENT_PATH = "/speaker/agent"

A2DP = '0000110d-0000-1000-8000-00805f9b34fb'
AVRCP = '0000110e-0000-1000-8000-00805f9b34fb'

bus = None


class Rejected(dbus.DBusException):
    _dbus_error_name = "org.bluez.Error.Rejected"


class Agent(dbus.service.Object):
    exit_on_release = True

    def set_exit_on_release(self, exit_on_release):
        self.exit_on_release = exit_on_release

    @dbus.service.method(AGENT_INTERFACE,
                         in_signature="", out_signature="")
    def Release(self):
        print("Release")
        if self.exit_on_release:
            mainloop.quit()

    @dbus.service.method(AGENT_INTERFACE,
                         in_signature="os", out_signature="")
    def AuthorizeService(self, device, uuid):
        # Always authorize A2DP and AVRCP connection
        if uuid in [A2DP, AVRCP]:
            print("AuthorizeService (%s, %s)" % (device, uuid))
            return
        else:
            print("Service rejected (%s, %s)" % (device, uuid))
        raise Rejected("Connection rejected by user")

    @dbus.service.method(AGENT_INTERFACE,
                         in_signature="", out_signature="")
    def Cancel(self):
        print("Cancel")


if __name__ == '__main__':
    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

    bus = dbus.SystemBus()

    agent = Agent(bus, AGENT_PATH)

    mainloop = GLib.MainLoop()

    # By default Bluetooth adapter is not discoverable and there's
    # a 3 min timeout
    # Set it as always discoverable
    adapter = dbus.Interface(bus.get_object(BUS_NAME, "/org/bluez/hci0"),
                             "org.freedesktop.DBus.Properties")
    adapter.Set("org.bluez.Adapter1", "DiscoverableTimeout", dbus.UInt32(0))
    adapter.Set("org.bluez.Adapter1", "Discoverable", True)

    print("RPi speaker discoverable")

    # As the RPi speaker will not have any interface, create a pairing
    # agent with NoInputNoOutput capability
    obj = bus.get_object(BUS_NAME, "/org/bluez")
    manager = dbus.Interface(obj, "org.bluez.AgentManager1")
    manager.RegisterAgent(AGENT_PATH, "NoInputNoOutput")

    print("Agent registered")

    manager.RequestDefaultAgent(AGENT_PATH)

    mainloop.run()

The systemd unit starts the speaker agent on boot as RaspberryPi OS Lite automatically logs in the user:

[Unit]
Description=Bluetooth speaker agent

[Service]
ExecStart=python speaker-agent.py

[Install]
WantedBy=default.target

This systemd unit will need to be placed in ~/.config/systemd/user/ and enabled manually using:

$ systemctl --user enable speaker-agent.service

Finally, configure the BlueZ daemon to allow re-pairing without user interaction:

$ sudo sed -i 's/#JustWorksRepairing.*/JustWorksRepairing = always/' /etc/bluetooth/main.conf

Now, connect the audio output of your Raspberry Pi to a speaker or your Hi-Fi system, reboot, pair, and connect your phone.

Enjoy the sound! ;)

Comments (23)

  1. tino:
    Sep 02, 2022 at 06:16 PM

    With how cheap Bluetooth speakers are, don't waste a raspberry on this, Especially considering that there is a great lack of Raspberry in the market

    Reply to this comment

    Reply to this comment

    1. Arien:
      Sep 02, 2022 at 11:31 PM

      It's a tech demo, chill out :)
      Also, nothing else will do literally all relevant codecs and even opus over bluetooth for highest possible quality.
      Also, you don't need to run this on a pi an nothing will stop you from doing lots of other stuff with it in parallel. It's a computer, after all.
      I really like pipewire and I'm amazed at the pace of development.

      Reply to this comment

      Reply to this comment

    2. J:
      Sep 03, 2022 at 01:51 AM

      I'd like to know what Bluetooth compatible speaker you would recommend? I'd like to have audio quality on par with or surpassing a proper bookshelf speaker or "studio monitor." Don't get me wrong, most conventional "Bluetooth speakers" nowadays have decent audio quality and are very appealing, but they still cannot compete with even a decent low-end monitor such as the JBL LSR305. I personally run a simple $10 Bluetooth dongle with some older bookshelf speakers in my garage and at our community pool and people are blown away because they're used to these cheap Bluetooth speakers. Expanding my setup to something like what this post is suggesting makes a lot of sense to me, even if it's using Raspberry Pis.

      Reply to this comment

      Reply to this comment

      1. Frédéric Danis:
        Sep 06, 2022 at 05:12 PM

        I'm not sure to understand your question.
        The idea of this blog post is to use a non Bluetooth speaker and to transform it into a Bluetooth speaker with a Raspberry Pi.
        If you want better sound quality you may add an audio card to the RaspberryPi, USB or HAT.

        Reply to this comment

        Reply to this comment

        1. Paul Norris:
          Sep 13, 2022 at 03:23 PM

          How do you configure the software to use the DAC HAT, rather than the 3.5mm jack for output?

          Reply to this comment

          Reply to this comment

      2. tino:
        Sep 07, 2022 at 01:46 PM

        if you are looking for "studio audio quality", the Bluetooth way is not the right one, a good DAC and semi-pro headphones with cables are better

        Reply to this comment

        Reply to this comment

    3. Tony:
      Sep 03, 2022 at 04:14 AM

      I have a nice B&O speaker that has an unreliable Wi-Fi connection that will now get a new lease on life using this idea.
      I also have a spare RP3 available.

      Reply to this comment

      Reply to this comment

  2. V:
    Sep 02, 2022 at 10:27 PM

    Thanks for this, I'll try it out for sure. I attempted something like this a few years back and it was just too unreliable, as I was routing everything manually, basically.

    Reply to this comment

    Reply to this comment

  3. Aidan Macgregor:
    Sep 04, 2022 at 09:07 PM

    Not to try this on armbian on amlogic or rockchip boxes!

    Reply to this comment

    Reply to this comment

  4. void:
    Sep 05, 2022 at 10:31 PM

    Thanks for the guide! Just a question, what would the necessary changes be in order to avoid allow pairing from any device? I don't mind going into bluetoothctl and pair/trust a device when I want it to be able to stream music to my rpi.

    Reply to this comment

    Reply to this comment

    1. Frédéric Danis:
      Sep 06, 2022 at 05:17 PM

      This is done by the "speaker-agent.py" python script, see the second part of the blog post.

      Reply to this comment

      Reply to this comment

  5. Stuart Naylor:
    Sep 10, 2022 at 02:41 AM

    Does anyone know if pipewire supports the new Bluetooth LE broadcast audio protocols.

    PS
    A Pi Zero2 makes a great audio platform with a cheap DAC module and as someone mentioned earlier converting a decent pair of 2nd user bookshelf speakers can make Sonos challenging audio quality.

    Reply to this comment

    Reply to this comment

    1. Olivier Crete:
      Sep 10, 2022 at 07:47 AM

      Work is ongoing to support the new Bluetooth LE broadcast audio protocols.

      Reply to this comment

      Reply to this comment

      1. Stuart Naylor:
        Sep 10, 2022 at 08:38 PM

        Would you have a link to a repo or group as quite interested in LE Auracast and if it can time sync clients to the level of say Snapcast which does a great in that respect over wifi.

        I am trying to work out whether to have a single bluetooth input and relay via snapcast over wifi for multichannel time sync or just use Auracast but like 'work in progress' apart from the SIG info I can find nothing about any Linux adoption of Auracast.

        Also with the Raspberry Pi the WiFi/BT combo chips are near useless in dual mode where if you google you will find a huge history of a huge rake of problems where the solution is don't mix and match just use one or the other.
        For most operations WiFi & BT can multiplex but a constant stream on both on a Pi is not a tasty pie to consume.
        I disable BT use the wifi and add a single BT dongle and works great but it took some hair pulling and actually reading what others say to realise.

        So I really like snapcast also that is a great tcp/ip multichannel with choice of codec casting software and I am really struggling to choose a roadmap between it and Auracast.

        PS is anyone interested in creating an interest forum / repo(s) as would be really interested in other thoughts and collaboration?

        Reply to this comment

        Reply to this comment

        1. Frédéric Danis:
          Sep 16, 2022 at 04:46 PM

          Bluetooth LE Audio is work in progress in both BlueZ and PipeWire, but it's hard to find compatible Bluetooth adapters.
          Currently the Connected stream support has been merged upstream for both BlueZ and PipeWire.
          Auracast is not yet supported by BlueZ.

          Reply to this comment

          Reply to this comment

    2. Stuart Naylor:
      Sep 16, 2022 at 02:20 PM

      I posted on the BlueZ github and kindly got a replay and much will be implemented in the Linux kernel 6.0 release so maybe next release or subsequent I am guessing for bluetooth broadcast audio

      Reply to this comment

      Reply to this comment

  6. Sorin:
    Sep 16, 2022 at 08:04 AM

    What about a native protocol, to connect over ethernet or wifi like pulseaudio, so that one does not pollute the environment with additional bluetooth noise?
    I also would like a pin authentication for bluetooth connections instead of no authentication: I live in an apartment bloc and somone nearby can connect to my audio system and play a loud sound in the middle of the night, to have some fun.
    bluez-tools is offering some authentication agents, one of them allows no authentication with the bt-agent program.

    Reply to this comment

    Reply to this comment

    1. Stuart Naylor:
      Sep 16, 2022 at 09:14 AM

      Likely the reason they have done bluetooth is because there is a plethora of RTP but very few common ones on media devices.
      Apple airplay 1 has opensource such as https://github.com/mikebrady/shairport-sync
      Chromecast I think is proprietary and Google are not releasing that but there is https://www.airserver.com/
      Spotify cast requires a premium subscription with there recent api changes.

      So bluetooth may have its downsides but if you want wide compatibility and ease then its likely why that option was chosen.
      The code shows how to auto accept connections but equally pin codes can be used and its all documented via bluez
      Also the Pi has a problem as those Broadcom combo wifi/bt combo units are not great and its best to use solely one or the other but not both at the same time.
      If you google you will find a huge history of woe with concurrent use where often its better to blacklist or dtoverlay diable the bt and just add a cheap dongle to stop the many errors that can occur.

      Snapcast is a great NTP sync multi room wifi cast opensource but its finding sources that you may even use bluetooth to the server then transmit over wifi to clients https://github.com/badaix/snapcast

      Reply to this comment

      Reply to this comment

      1. Sorin:
        Sep 20, 2022 at 07:52 PM

        Pulseaudio has its own open source protocol for transmitting audio over eth or wifi and I'm using it to send audio from various linux sources to an audio server running on odroid, connected to a USB balanced audio and Yamaha HS8. It also accepts 2 concurrent bluetooth A2DP connections via 2 USB bluetooth dongles. The USB audio also has input which is connected to a TOS link converter and by an optical cable to a TV.

        Reply to this comment

        Reply to this comment

      2. Sorin:
        Sep 20, 2022 at 08:01 PM

        You can connect the Pi via eth, as it's a server. It will receive audio via the wifi router either from an eth or a wifi source. As for bt, you can use an USB dongle. I usually disable the 2.4 GHz radio on the router and only keep higher frequencies to not interfere with bt.

        Reply to this comment

        Reply to this comment

        1. Stuart Naylor:
          Sep 20, 2022 at 08:56 PM

          Its not the freq its the combo chip sharing the SDIO / gSP from broadcom that on the Pi has never truly coexited.
          If you want both and 100% be sure disable one and get a dongle or join the plethora of Pi posts of woe.

          Reply to this comment

          Reply to this comment

    2. Aidan Macgregor:
      Sep 16, 2022 at 03:22 PM

      i currently use amlogic TV box, i still have to try this set up on armbian on some of my boxes, but currently have a set up with android TV (My Custom ROM) i have installed"smart tube next" (Manually as my rom clean and empty) this allows me to cast youtube (by pin connect) & i also have modded spotify APKs as both a Phone version & an android TV version that both work with spotify connect With Each Other Ad Free (Still Works Tested Today, if you are premium it will work Downloading Both Spotifys From The Play Store), I also used macrodroid to ensure both apps start at boot so connection can happen in background without user interaction :)

      Reply to this comment

      Reply to this comment

  7. iplakora:
    Sep 19, 2022 at 11:26 AM

    Buy bluetooth speakers in Ghana Buy Bluetooth Speakers in Ghana. There are many options when it comes to choosing Bluetooth speakers. Stud100 from Kora is the best speaker and travel friendly. You can carry it anywhere with you

    Reply to this comment

    Reply to this comment


Add a Comment






Allowed tags: <b><i><br>Add a new comment:


Search the newsroom

Latest Blog Posts

Open source machine learning for video compression

14/09/2022

Using open source software, Collabora has developed an efficient compression pipeline that enables a face video broadcasting system that…

Improving Vulkan graphics state tracking in Mesa

07/09/2022

Introducing new common code for Mesa Vulkan drivers to support a new Vulkan extension, making it easier for app and game authors to manage…

Using a Raspberry Pi as a Bluetooth speaker with PipeWire

02/09/2022

Using PipeWire, WirePlumber and a Raspberry Pi, you can create an audio bridge between a Bluetooth® device and an analog speaker system,…

Introducing the r600/NIR back-end

07/07/2022

Adventures in NIR-land: the past, the present, and what's lies ahead for the native NIR back-end for Mesa's R600 driver.

Adding secondary command buffers to PanVk

15/06/2022

Getting PanVk, an open source driver for Arm Mali Midgard and Bifrost GPUs, closer to conformancy by implementing one of the core Vulkan…

Bridging the synchronization gap on Linux

09/06/2022

After fighting with the divide between implicit and explicit synchronization with Vulkan on Linux for over seven years, we may finally have…

Open Since 2005 logo

We use cookies on this website to ensure that you get the best experience. By continuing to use this website you are consenting to the use of these cookies. To find out more please follow this link.

Collabora Ltd © 2005-2022. All rights reserved. Privacy Notice. Sitemap.