Nov 7, 2022 Tags: howto, music, workflow
This post is the third in a series of posts on my music setup:
Where the last two posts were primarily about software
(Navidrome and beets
, respectively),
this post will be more about hardware (and a bit of software to control it). Hopefully
it’ll be useful to others with older sound hardware, especially those who are compelled
(as I am) to avoid buying a “connected” device that’ll stop working after just a few
years1.
TL;DR: I used a spare Raspberry Pi (version 3, Model B), an old USB DAC,
and HiFiBerryOS with some unauthorized
patches. As a result, I can now stream to my 1980s speakers from any device on my
LAN, including anything that speaks AirPlay or
DLNA! To tie things
together, I use pulseaudio-dlna
on my desktop
to play music from my Navidrome instance via Sonixd.
A couple of months ago, a relative gave me their old sound system: a pair of KEF C30s (circa 1985) and a Yamaha RX-495 receiver (circa late 1990s, I think?).
As far as speaker tech goes, these are pretty barebones: the C30s are passive monitors, with a single connector (two binding post terminals for banana plugs).
The receiver is slightly fancier: it can hop between radio stations based on signal quality (fancy!) and has support for 4 “programmable” presets. Nothing compared to modern receivers, but not the simplest either.
I have fond memories of listening to these speakers as a kid, and I’m loathe to let perfectly good2 hardware get thrown away just because it’s considered obsolete. I also run my own music server and curate it obsessively, so I thought it would be nice to have a “serious” listening setup that could stream from my server.
Thus, the plan:
…and, critically, to do it all with only equipment I already own3.
This was my first thought: I could just leave a laptop on the same table as the receiver, connect it as the “aux” source, and people could queue up music as they like.
I didn’t have a spare laptop (they’re all in use), so I pulled my Asus Eee 701 netbook4 out of the closet and tried to set that up.
(This thing. Not my picture.)
This didn’t go well:
It turns out that nothing really runs well on a 32-bit x86 machine anymore, including major Linux distributions and web browsers. Just getting Linux installed was a massive pain, much worse than it was the last time I tried (probably around 2016).
Nobody actually wants to mess around with a plastic netbook to queue up music.
This attempt ended pretty fast.
The receiver has an FM mode and an FM antenna, and I happen to have a short-range FM transmitter5. It should have a range of a few dozen feet, so I can set it up in my office and have it reach the receiver without any problems.
(Again, not my picture, just the same model.)
From there, I just need to send music to the transmitter: it has RCA inputs, so I can adapt those to 3.5mm and adapt to anything common from there.
This worked surprisingly well for my own purposes: I transmitted for a couple of weeks, using either my computer or my phone as the music source. Still, there were downsides:
Pausing playback didn’t actually stop playback: it would stop whatever music I was listening to, but the FM transmitter would continue to transmit an empty signal and the receiver would happily “play” it. This led to me forgetting to turn the receiver off when I wasn’t using it, which in turn led to me spooking myself whenever I’d turn the transmitter off and FM static would suddenly fill my apartment.
The signal quality was unreliable: normally it was fine, but I could occasionally hear low static seeping in. I also had to regularly adjust the gain on the transmitter itself: on some days, I could hear it clipping slightly. I don’t know enough about radio to understand why either of these would vary, especially in an apartment interior with relatively thick exterior walls.
Again, nobody wanted to use it. They were amused by the FM transmitter, but still had to go into another room and physically connect their phone to it in order to use it, both of which were dealbreakers.
At this point I remembered that (1) I own a couple of Raspberry Pis, and (2) that they have onboard audio. I had no idea if that onboard audio is good or not6, but surely someone has tried to use a Raspberry Pi as an audio receiver before?
Google confirms that someone indeed has: Nico Kaiser has a project that does exactly that. It even includes all kinds of goodies that are ideal for guest use, including Bluetooth7, AirPlay, and Spotify Connect support!
There seem to be a decent number of happy users of rpi-audio-receiver
on the Internet,
but I didn’t end up as one of them. Instead, rpi-audio-receiver
’s README led me
to the repository for HiFiBerryOS,
which in turn led me to the HiFiBerry website.
This looked like exactly what I wanted: a tiny, minimal-configuration distribution that accepts any number of sound sources and turns them all into a simple analog signal for my receiver.
To get started, I performed the standard dance of flashing an SD card for my Pi:
1
2
3
4
5
$ # taken from https://github.com/hifiberry/hifiberry-os/releases
$ wget https://github.com/hifiberry/hifiberry-os/releases/download/v20221028/hifiberryos-pi3.zip
$ unzip hifiberryos-pi3.zip
$ # /dev/sdc is my flash medium
$ dd if=hifiberryos-20221028-pi3.img of=/dev/sdc bs=4M
Once flashed, I booted the Pi and followed HiFiBerry’s
WiFi configuration
steps. This was incredibly nice, since I didn’t need to muck around with an Ethernet cord
or special configuration files8 — I simply connected to the temporary WiFi
network being broadcast by the Pi itself, gave it a name (“leben”), configured a new WiFi network,
and told HiFiBerryOS to forget its own network. It obeyed dutifully, and about a minute later I
had http://hifiberry.local
available on my LAN9.
Critically, I did all of this configuration from my phone, which still astounds me: I’ve never had such a painless experience configuring an OS and hardware before, much less a free OS running on a dinky little Raspberry Pi.
At this point, I could actually see the Pi on my network, available as an AirPlay device:
I connected to it successfully, hit play on a song, and…nothing happened.
More precisely, the Pi’s little web UI claimed that something was playing (the metadata is even correct!), but no sound was being produced:
I initially assumed this was a problem with the Pi’s onboard audio (I’d never used it before), so I switched to a cheap Griffin “iMic” USB DAC that I’ve had floating around for years:
…and still no audio. I knew that the DAC and the speakers/receiver themselves were working, so it had to be something about either AirPlay (unlikely, since discovery and metadata exchange were both working) or HiFiBerryOS itself.
A little bit of Googling later, and I found the reason: HiFiBerryOS intentionally does not support either onboard audio:
This is an understandable position on their part: their revenue seems to derive primarily from sales of their own sound cards and related equipment, which they’ve designed and tested to meet their own quality and reliability standards. Supporting whatever junk people happen to plug in would inevitably require dedicated engineering resources, as well as fielding support to frustrated “customers” who haven’t actually bought anything.
As understandable as it is, I was still disappointed — I was so close to completing a sound setup without having to buy any new equipment.
I also knew that this limitation in HiFiBerryOS had to be in software, not hardware: it’s all just Linux (and probably ALSA) under the hood, meaning that USB audio should work right out of the box10. So, I resolved to hack it together.
Fortunately for me, HiFiBerryOS comes with a SSH server installed and running
by default, with default credentials of root:hifiberry
.
I shelled in, and confirmed that Linux had indeed registered my USB DAC correctly:
1
2
3
4
5
# lsusb
Bus 001 Device 004: ID 077d:07af Griffin Technology, Inc iMic USB audio system
Bus 001 Device 003: ID 0424:ec00
Bus 001 Device 002: ID 0424:9514
Bus 001 Device 001: ID 1d6b:0002 Linux 5.15.72-v7 dwc_otg_hcd DWC OTG Controller
I also confirmed my ALSA theory by checking for the “standard” ALSA command-line tools:
1
2
3
4
5
6
7
8
9
10
11
# which aplay amixer
/bin/aplay
/bin/amixer
# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: system [iMic USB audio system], device 0: USB Audio [USB Audio]
Subdevices: 0/1
Subdevice #0: subdevice #0
card 1: sndrpihifiberry [snd_rpi_hifiberry_dac], device 0: HifiBerry DAC HiFi pcm5102a-hifi-0 [HifiBerry DAC HiFi pcm5102a-hifi-0]
Subdevices: 1/1
Subdevice #0: subdevice #0
So, in principle, all I needed to do was figure out how HiFiBerryOS was configuring
ALSA, and tell it to use card 0
instead of card 1
(which is presumably where the
HiFiBerry would be, if one was installed).
Fortunately, someone on HiFiBerry’s forums
had already figured this out:
there’s a shell script at /opt/hifiberry/bin/reconfigure-players
that contains
a detect_hw
function like this:
1
2
3
4
5
6
7
# Find the correct input and output hardware devices
# this is important if additional USB hardware is connected
detect_hw () {
HW=`aplay -l | grep hifiberry | awk -F: '{print $1}'`
HW_SHORT=`echo $HW | awk '{print $2}'`
fix_asound_hw
}
…which would normally detect their hat-style DAC on card 1
:
1
2
# aplay -l | grep hifiberry | awk -F: '{print $1}'
card 1
To “fix” it, all I had to do was patch detect_hw
to discover card 0
instead,
which I did by grep
ing for the “iMic” string instead of “hifiberry”:
1
2
3
4
5
6
7
# Find the correct input and output hardware devices
# this is important if additional USB hardware is connected
detect_hw () {
HW=`aplay -l | grep iMic | awk -F: '{print $1}'`
HW_SHORT=`echo $HW | awk '{print $2}'`
fix_asound_hw
}
I saved the file, used the HiFiBerry OS Web UI to reboot the Pi, tried playing a song again and…it worked!
This made me very happy: I could now stream from my phone, as could anybody else on my home LAN.
macOS also worked right out of the box, presumably via the same kind of AirPlay discovery.
That only leaves my desktop, which runs Linux (specifically, Ubuntu LTS). I already have a nice local player setup there (streaming from Navidrome using Sonixd), and I’d ideally I’d reuse it without any substantial changes.
As far as Linux audio goes, the solution here was shockingly easy:
I use PulseAudio for my desktop audio and HiFiBerryOS supports DLNA streaming,
so I installed pulseaudio-dlna
and ran it:
1
2
$ sudo apt install -y pulseaudio-dlna
$ pulseaudio-dlna
This immediately discovered the Pi and added it to my PulseAudio sinks,
allowing me to set it as my default via pavucontrol
:
Once again, I played a song…and everything worked again! The latency between play/pause toggles is noticeable (about 1.5 seconds), but that’s not a dealbreaker for me.
As a curiosity, streaming via pulseaudio-dlna
makes HiFiBerryOS think it’s receiving
from a Chromium instance:
(This again doesn’t matter to me, since I don’t plan on checking the Web UI much. But it’s funny.)
To summarize, I now have:
The end result: anybody on my network (including friends and family during parties) can take over the “aux” without needing to find the cable, mess with Bluetooth pairings, &c — all they need is to be on my WiFi. An of course, selfishly and lazily, I no longer have to move 20 feet to change the music. Progress!
I’ve been working on and using open source software for a while now, but this little weekend project really drove home the value of open standards and free, pluggable, reusable work from hobbyists (like myself): I was able to do reuse hardware and software that I already owned and had configured, without having to worry about planned obsolescence or woeful security practices by random companies that feel the need to add “smarts” or Internet connectivity to their products11.
There are still some things I’d like to do:
pulseaudio-dlna
is working very nicely for me, but (based on development
activity) it seems to be mostly inactive. It’s probably not a long-term
solution for me (although there is an active fork).
Longer term, instead, I’d like to unify on AirPlay for all my devices. It looks like there’s some support for this in PulseAudio already, via the RAOP modules for streaming and the Zeroconf discovery module.
Maybe I’ll try and get Bluetooth working as well. This will probably need a separate dongle and it’s not clear that HiFiBerryOS supports it on my Pi model, but we’ll see.
The receiver has its own volume control (naturally), along with an IR remote that can control it. It’d be interesting to try and clone the signals for volume control, so that I can also control the volume remotely.
I got a kick out of hacking around HiFiBerry’s own hardware restrictions, but I feel bad about it: they’ve put an incredible amount of effort into both their hardware and software, and I’m using it for free in a way they didn’t intend (even if it’s within my rights). Also, while it was nice to get things working with the USB DAC, it’s very crappy and not a long-term solution.
As such, I’m going to buy one of HiFiBerry’s own in-house DACs, as well as a case to house the whole setup. I encourage anybody else who reads this post to do the same, circumstances permitting.
I’ll probably do a successor post for those, at some point.
Finally, I’m going to plug the Ko-fi donation pages for the maintainers of Navidrome and Sonixd:
Read: when the company that makes it no longer has any financial incentive to support their older products. ↩
As it turns out, the woofer in one of the speakers is broken. But that will hopefully be an easy fix. ↩
In an effort to reduce frivolous tech purchases on my part (and have some fun with junk in my closet). ↩
Remember netbooks? ↩
Specifically, I have the CZH-05B. I kept it on the lowest possible power mode and confirmed that it never exceeded FCC Section 15 limits (200 feet). ↩
I still don’t. ↩
Apparently it doesn’t work well at all with the Pi’s onboard Bluetooth. I don’t have an external Bluetooth dongle, so this wouldn’t have worked for me anyways. ↩
I’m still salty about Raspbian’s manual user and SSH configuration, much less WiFi. ↩
This was just for initial testing purposes. I subsequently plugged it into my network via Ethernet, and everything there was automatic. ↩
Insofar as audio on Linux can ever be said to work “right out of the box.” ↩
This isn’t to claim that any of this is particularly secure, by default (see e.g. the default SSH credentials for HiFiBerryOS). But I’d wager that it isn’t that different from the woeful state of commercial IoT security, minus the incentives for neglect (loss center) and obsolescence. Plus I can secure it myself, rather than treating NAT as a security boundary. ↩