BabelPod on Github

The HomePod has great sound quality, but right now it’s limited to playing audio from Apple Music or AirPlay clients like the iPhone or iPad. But what if you want to play audio from other sources? Ideally the HomePod would have a line-in port, show up as a Bluetooth speaker, and support other streaming services like Spotify. But Apple decided not to include a line-in port, hasn’t yet implemented Bluetooth speaker support in the OS, and hasn’t yet natively supported other streaming services.

Hopefully Apple will eventually address these shortcomings on the HomePod itself, but for now I’ve come up with my own solution. I’ve taken a Raspberry Pi Zero W (a tiny single-board computer that costs $10 on its own or $40 with all of the parts I needed) and written software that takes audio input from line-in or Bluetooth and outputs it wirelessly to the HomePod via Airplay. I call it BabelPod since it acts as a universal translator between audio devices.

BabelPod with HomePod

BabelPod has a web interface so you can choose the source and destination from any computer or phone. It auto-detects all of the audio input devices that are available.

BabelPod web interface on Mac Safari BabelPod web interface on iPhone

It shows up just like any standard Bluetooth speaker.

iPhone playing connecting to BabelPod via Bluetooth iPhone playing Music to BabelPod via Bluetooth

Note that this solution takes some technical skills to get up and running as you’ll see below. But even if you’re not familiar with this stuff it could be a fun project to learn some new skills, and there are a ton of other projects you can build based on the Raspberry Pi.

How well does it work?

There are some gotchas with this solution. Since it’s streaming audio using AirPlay, there is a 2 second delay between when the audio input is received and when it is played on the HomePod, which means BabelPod won’t work well for video or gaming.

Right now there are also some issues where AirPlay will suddenly disconnect, and other stability issues. I’ll try to improve these over time, and I would gladly welcome any submissions on GitHub.

Finally, keep in mind that the output audio quality is limited by the quality of the input. So if you’re using a cheap line-in USB adapter like I am, that may limit the quality (there are better sound cards available like Pisound and Audio Injector, but I haven’t yet tried any of them myself). Also the Bluetooth audio quality is limited by the fact that it is compressed, although it may be possible to change the standard SBC compression to use a higher bitrate or switch to a better compression algorithm like AAC or AptX.

How can I make my own BabelPod?

  • You’ll need a Raspberry Pi Zero W ($34.50 for a Budget Pack), or a larger and more expensive but more powerful Raspberry Pi 3. Alternatively, you could run the BabelPod software on another computer (I had it partially working on my Mac), but the software was targeted to work on the Raspberry Pi. If you want 3.5mm line-in and line-out you’ll also want something like this $5 USB audio adapter.
  • Setup the hardware and install the OS (I used the “Download and image Raspbian directly” method).
  • Connect the Raspberry Pi to your WiFi network.
  • (optional) Setup SSH and VNC so you can control the BabelPod without needing to plug it into its own keyboard, mouse, and monitor. This can be done via the Raspberry Pi Configuration app or by adding a ssh file to the root of the SD card so that it knows to enable it on boot (then you can enable VNC via SSH by running “sudo raspi-config”).

Raspberry Pi Configuration app location Raspberry Pi Configuration app SSH and VNC settings

  • Find the local IP address of your Raspberry Pi (in my case 192.168.1.16):
$ ifconfig
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
	inet 192.168.1.16  netmask 255.255.255.0  broadcast 192.168.1.255
  • Install NodeJS 9. First I needed to remove the old default version of NodeJS:
$ sudo apt-get remove node
  • The normal way of installing NodeJS on Linux didn’t seem to work because of the particular ARM processor used on the RaspberryPi Zero, so I needed to download the armv6 binary directly and then install using these instructions:
$ wget https://nodejs.org/dist/v9.8.0/node-v9.8.0-linux-armv6l.tar.xz
$ sudo mkdir /usr/local/lib/nodejs
$ sudo tar -xJvf node-v9.8.0-linux-armv6l.tar.xz -C /usr/local/lib/nodejs
$ sudo mv /usr/local/lib/nodejs/node-v9.8.0-linux-armv6l/ /usr/local/lib/nodejs/node-v9.8.0
$ nano ~/.profile
  • Add this to the bottom of .profile:
# Nodejs
export NODEJS_HOME=/usr/local/lib/nodejs/node-v9.8.0
export PATH=$NODEJS_HOME/bin:$PATH
  • Load the updated .profile:
source ~/.profile
  • Install the airtunes Node library (I created a fork to work around a bug):
pi@raspberrypi:~/ $ git clone -b fix_port_0_error https://github.com/afaden/node_airtunes.git
pi@raspberrypi:~/ $ cd node_airtunes
pi@raspberrypi:~/node_airtunes $ npm install
pi@raspberrypi:~/node_airtunes $ cd ..
  • Install and start BabelPod:
pi@raspberrypi:~ $ git clone https://github.com/afaden/babelpod.git
pi@raspberrypi:~ $ cd babelpod
pi@raspberrypi:~/babelpod $ npm install
pi@raspberrypi:~/babelpod $ node index.js
  • At this point you should be able to open the BabelPod web UI from a computer or phone on your WiFi network by going to http://[raspberry_pi_ip_address]:3000/ (in my case http://192.168.1.16:3000/). Line-in should be available as an input (in my case it appeared as “USB Audio”), and your HomePod (and other local AirPlay devices) should be available as output (in my case it appeared as “Airplay: Office”).
  • There are some more steps if you also want to get Bluetooth input working:
sudo nano /etc/bluetooth/main.conf
  • Add this to main.conf:
Class = 0x00041C
Enable=Source,Sink,Media
DiscoverableTimeout = 0
PairableTimeout = 0
  • Load the updated main.conf:
sudo service bluetooth restart
  • Make the Raspberry Pi discoverable via Bluetooth:

Raspberry Pi Bluetooth discoverable

  • The BabelPod should now show up as “raspberrypi” when you scan for Bluetooth devices on your phone or computer (this name can be changed by opening bluetoothctl and running “system-alias BabelPod”). When you try to connect the Raspberry Pi needs to be set to trust your device. You can do this from the desktop interface, or from the terminal.

Raspberry Pi Bluetooth accept

$ bluetoothctl
[bluetooth]# paired-devices
Device [address] [name]
[bluetooth]# trust [address]
  • Now you should be able to connect successfully and choose it as the audio output on your device.
  • In the BabelPod web UI you should now be able to select your Bluetooth device as input and output it to your HomePod via AirPlay!

How does BabelPod work?

The BabelPod software consists of a web frontend and backend Node code that pipes together different audio inputs and outputs. A huge thanks to the people who have made those inputs and outputs possible:

  • airtunes: used to output to AirPlay speakers like the HomePod.
  • mdns-js: used to discover what AirPlay speakers are available on your local network.
  • bluetoothctl: This is a Node wrapper of the bluetoothctl tool, which is used to list what Bluetooth input devices are available.
  • BlueALSA: This makes Bluetooth audio devices available as an ALSA interface, so that you can use them via arecord and aplay.
  • express: The framework used to run the web UI.
  • socket.io: Used this to keep the backend and web UI in sync via WebSockets (or long-polling as a fallback).

Also thanks to all of the people who have written guides that helped me figure out how to make this work:

Piping System Audio to Airplay (updated September 3rd, 2018)

vespino asked on GitHub whether it was possible to pipe the Raspberry Pi’s system audio (e.g. from a streaming audio app) to the Airplay speaker, rather than using input from a USB soundcard or Bluetooth. I did some digging and it turns out that this can be done by adding a loopback device like this:

$ modprobe snd-aloop
$ aplay -l
...
card 2: Loopback [Loopback], device 0: Loopback PCM [Loopback PCM]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7
card 2: Loopback [Loopback], device 1: Loopback PCM [Loopback PCM]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7

It seems that any audio you output to loopback device 0 is sent to loopback device 1, which you can use as an input. You can set your system audio to output to loopback device 0 like this:

$ nano ~/.asoundrc

Paste the following (change the card # to whatever one aplay -l said was your loopback device):

pcm.!default {
	type hw
	card 2
}

ctl.!default {
	type hw
	card 2
}

To load this new configuration, you can either restart your system, or just restart the alsa service:

$ /etc/init.d/alsa-utils restart

Now when an app (e.g. the browser) on your Raspberry Pi plays audio, it will go to the loopback device. And when you run BabelPod, you should be able to select “Loopback PCM” as the input (I had two show up with the same name, the second one worked for me), and pipe the audio wherever you want (e.g. your Airplay speaker).

Running as a background service on startup (updated September 3rd, 2018)

djehrenr on GitHub described a way to run BabelPod as a background service whenever the Raspberry Pi boots, which makes it a lot more convenient to use.

$ sudo nano /etc/systemd/system/babelpod.service

Paste the following (note that the node path should match whatever is returned by which node):

[Service]
# need to specify the full path to node
ExecStart=/usr/local/lib/nodejs/node-v9.8.0/bin/node /home/pi/babelpod/index.js
StandardOutput=journal

Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

Then run the following to set up the service:

$ sudo systemctl daemon-reload
$ sudo systemctl enable babelpod
$ sudo systemctl start babelpod
$ sudo systemctl status babelpod

The status command should return something like this:

● babelpod.service
   Loaded: loaded (/etc/systemd/system/babelpod.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2018-09-03 22:35:00 UTC; 25min ago
 Main PID: 274 (node)
   CGroup: /system.slice/babelpod.service
           ├─274 /usr/local/lib/nodejs/node-v9.8.0/bin/node /home/pi/babelpod/index.js
           ├─564 bash
           ├─579 bluetoothctl

Sep 03 22:35:00 raspberrypi systemd[1]: Started babelpod.service.
Sep 03 22:35:18 raspberrypi node[274]: listening on *:3000
Sep 03 22:35:18 raspberrypi node[274]: bluetooth controller exists

Then you can look at the console output log like this:

$ journalctl -u babelpod.service

What’s Next?

I’d like to make these improvements:

  • Improve audio streaming stability

    (fixed)

  • Run the BabelPod software as a background process when you power on the Raspberry Pi

    (fixed, see above)

  • Avoid duplicate AirPlay devices
  • Auto-trust any Bluetooth device that connects (or maybe require a PIN)
  • Support higher-quality Bluetooth audio input
  • Try a higher-quality sound card
  • Create a nice case that includes the sound card (maybe it could double as a HomePod coaster 😈)

If you’d like to help out I welcome contributions on GitHub.

I’d also like to get BabelPod to run Alexa and Google Assistant. The device will need to use its own microphone rather than the HomePod’s, but the resulting experience should be that you can address the HomePod using any of the three voice assistants (“Hey Siri”, “Alexa”, or “OK Google”) and the right one will kick in and respond to your query. This will allow you to use other streaming services like Spotify.

My ultimate goal is to demonstrate to Apple that their customers want the HomePod to support audio sources outside the Apple ecosystem. So if you build a BabelPod, please spread the word so we can make sure Apple hears the message load and clear. I am hoping that they will enable Bluetooth speaker support with an OS update. I’d also like to see them enable developers (like Spotify) to deploy native apps to the Homepod. This is a real stretch, but it would be much appreciated if future hardware revisions of the HomePod added a line-in port. Native support for those three would have the huge advantage of reducing or eliminating the 2+ second lag that you get with AirPlay, and avoiding the need for a separate device. For now though, I hope that BabelPod will allow more people to enjoy the HomePod.