Adventures in network audio streaming

Wireless routers are wonderful devices. For under $50, you get an embedded Linux system with at least a network port (or five), and maybe one or two serial ports. Lately, more and more routers have also included USB ports, which opens up a whole range of possibilities, like cheap IP cameras (but that’s for another day) or NAS devices.

Today’s story starts a month or so ago, when my mom was blaring iTunes across the house, from her computer speakers, so she could hear her music in the kitchen. The radios in the two adjacent rooms worked well enough, but I hadn’t thought to put in audio tie lines to computer locations when I pulled CAT 5. Whoops. I decided that fixing this would make a good Christmas gift.

Previously, I had installed an Asus WL-520gU wireless router (with the aforementioned USB port) in the basement under the living room, where one radio was installed. Years ago, we’d run a tie line to the bigger stereo across the house so the radio could play back CD music. (Apparently, CD players were expensive back then.)  This tie line happened to run right by the router’s location, so I could avoid pulling new cable through the walls.

I picked up a Turtle Beach Audio Advantage Micro 2 USB adapter for a modest sum from Newegg, and compiled OpenWRT trunk for the router, making sure to include inetd, alsa-utils, and the relevant kernel modules. I’d like to say that this went without a hitch; while most problems were easy to solve, things didn’t go 100% smoothly. First, the aplay program wouldn’t run because the build system didn’t recognize that it depended on librt being installed. The router also got very angry at OpenWRT’s default choice of microcode for the wireless adapter. This was easy enough to fix once I knew what the problem was, but the only symptom was mysterious crashes whenever WiFi was turned on. (Reading all the way to the end of the OpenWRT wiki page the first time around might have saved me the headache…) Considering that OpenWRT got me from zero to a mostly-working, custom-built flash image in about half an hour, these complaints seem minor.

On the Mac side of things, I knew that Soundflower would allow looping the audio from iTunes back to another process where it could be recorded; from there, getting it to the router was straightforward.

On the router, I created an inetd.conf like this, and a corresponding /etc/services entry, to take in raw 44.1kHz PCM data on TCP port 12347:

audio-stream    stream    tcp    nowait    root    /usr/bin/aplay    aplay -D front:CARD=Device,DEV=0 -r 44100 -c 2 -f s16_le

On the Mac, I used MacPorts to install esound, then did:

esd &
esdrec | nc 12347

from a terminal window. Route sound output to Soundflower instead of the onboard speaker, fire up iTunes and away I go? Not so fast, my left channel has nothing on it! Fired up alsamixer on the router and everything looked fine, so I plugged the USB dongle into my laptop. Same problem there, but it went away after I bumped the levels up and down a bit in alsamixer and added that “-D xxx” switch to aplay. Not sure why this was a problem but at least the fix was easy. Wrap up the shell commands in something easily clickable, and it’s good to go, networked iTunes streaming without having to buy an AirPort Express (or make it play nice with the existing network…)