My car comes with a built-in Bluetooth hands-free but unfortunately it does not support audio streaming. Luckily there is an AUX input available which uses a regular 3,5 mm jack. Perfect opportunity for a DIY project. I built the Bluetooth DAC using Raspberry Pi Zero W and a DAC hat. This post depicts the details of this project.
For the software, I did the first iteration using Raspbian, and it was indeed fairly simple to get the device working. However, I wanted to see if it would be possible to create a small stripped down image just for this purpose. For this, I used Yocto. Both approaches are described below.
If you just want to get things working without the project details, you can skip directly to the end and grab a prebuilt ready-to-flash image with the Bluetooth DAC functionality.
For the hardware I decided to use Raspberry Pi Zero W accompanied with pHAT DAC for the audio output. Linux has good support for Bluetooth audio, so the small and affordable Zero W fits this project nicely even though a full-blown Linux might be a bit excessive for this task. Some smaller microcontroller could handle these tasks as well, but would probably require much more implementation effort for the firmware.
Normally Raspberry Pi hats are mounted on top of the mainboard. However, I decided to mount the DAC hat under the Zero W so the 3,5 mm jack does not stick out so much. Moreover, I soldered the boards directly to each other using a single male header to make a compact package (not going to use this Zero W for anything else anyway). I also added a piece of electrical tape on top of the 3,5 mm jack so the metal parts are isolated from the test pads under the Zero W.
Before the two boards were soldered together, I bent the debug serial port pins 90 degrees and did not solder them to the DAC hat. This way the debug serial was easily accessible and I did not need e.g. a network access to the Pi during development.
Finally, I added clear acrylic case to finish the hardware.
For the first iteration I used Raspbian Buster Lite (https://www.raspberrypi.org/downloads/raspbian/) as the base. I started with the DAC and followed the official tutorial (https://learn.pimoroni.com/tutorial/phat/raspberry-pi-phat-dac-install). When these steps were done, I tested the audio output using
aplay utility with headphones connected to the audio output.
For the Bluetooth audio part I found an existing guide that describes how to set up the Advanced Audio Distribution Profile (A2DP) and how to handle automatic pairing. The guide targeted a bit older Rasbian version (Stretch), but it worked more or less directly for Raspbian Buster also. Though, I did have to manually set the
bluealsa profile to sink as described in this comment. Otherwise the device was not recognized as audio device.
After going through these guides and with a bit of problem solving the device was working as a Bluetooth DAC. Still, I wanted to see if it would be possible to implement a more lightweight image for this purpose. One that would also be useful for others who are trying to get the Bluetooth DAC functionality working.
Custom image with Yocto
Yocto is a system building tool-set that allows to build customized Linux distributions. Large variety of hardware and devices are supported, including the different Raspberry Pi variants. Raspberry Pi support is implemented in a Board Support Package (BSP) layer, meta-raspberrypi, that extends the generic Yocto layers and provides hardware specific specializations (e.g. bootloaders and kernel configurations). This layer, with its dependencies, allows to build generic Linux images for different Raspberry Pis.
Following the footmarks of the Raspbian specific guide and the DAC guide, I implemented meta-rpi-bt-dac layer that adds the Bluetooth audio functionality and DAC support on top of the generic meta-raspberrypi layer. The project readme provides instructions to build the custom image.
The most important parts of the layer are:
- bluez-alsa_1.4.0.bb recipe that provides build instructions for the Bluetooth ALSA backend
- a2dp-agent which is C implementation for the dbus auto-pairing agent (no need for python dependency as in Raspbian guide)
- rpi-config_git.bbappend which appends the generated config.txt with DAC device tree overlay
- dac-config init script to configure the Bluetooth functionality
The default Yocto configuration for Raspberry Pi uses SysVinit as the init manager. Therefore the systemd service files from the Raspbian guides were converted to init scripts.
The project builds a ready-to-flash Linux image with all the necessary Bluetooth and DAC configurations in place. When the Pi is powered on, it will become discoverable with name “RPi-DAC”. The device accepts all pairings and does not require a pin. The device is recognized as Bluetooth audio device and the audio from the connecting device is streamed to the DAC output.
For this use case only the Bluetooth and audio parts are needed. Therefore the default Yocto image still contains a lot of unnecessary components. I added the following configuration to Yocto
local.conf to disable many of the unnecessary features:
MACHINE_FEATURES_remove = "apm wifi screen touchscreen" DISTRO_FEATURES_remove = "ipv4 ipv6 irda usbgadget usbhost wifi nfs zeroconf 3g nfc x11 wayland vulkan"
Furthermore, I also disabled networking init scripts and removed some unnecessary kernel features to improve the boot time. Measured from
dmesg, the start-up time for the device and Bluetooth (excluding the low level bootloader) is about 5 seconds.
... [ 3.962021] Bluetooth: Core ver 2.22 [ 3.962246] NET: Registered protocol family 31 [ 3.962263] Bluetooth: HCI device and connection manager initialized [ 3.969311] Bluetooth: HCI socket layer initialized [ 3.969361] Bluetooth: L2CAP socket layer initialized [ 3.969384] Bluetooth: SCO socket layer initialized [ 4.748779] Bluetooth: HCI UART driver ver 2.3 [ 4.748816] Bluetooth: HCI UART protocol H4 registered [ 4.748828] Bluetooth: HCI UART protocol Three-wire (H5) registered [ 4.751038] Bluetooth: HCI UART protocol Broadcom registered
These optimizations were quite easy and the boot time could certainly be optimized further. Though, I feel that the performance is sufficient for this case and I probably won’t spend much more time optimizing it.
The Yocto image with Bluetooth DAC functionality can be build with the instructions in the project README. Though, the full Yocto build can take several hours so a prebuilt image is also provided in the Releases section.
core-image-base-raspberrypi0-wifi.rootfs.rpi-sdimg file can be flashed directly to a SD card. The image is meant for Raspberry Pi Zero W hardware.