At the start of the month I announced my plan to try and build my own whole home audio system using a handful of Raspberry Pis to act as the player and audio receivers. I’ve received all the stuff I need now, and I’m ready to get to building!
The first thing I’m doing is preparing the Pis and setting up networking. Next I’m going to install audio playing software with a web-interface on Pi number one, and thirdly I’ll adjust the setup so that this player sends it’s audio to the other two Pis (the receivers) instead of outputting it directly to its own speakers. You can follow the whole journey by following the #RPiWHA Project hashtag right here.
Raspbian is the Raspberry Pi’s recommended operating system. There’s plenty of guidance online on how to install it, so I won’t reiterate the whole process here. When I ran through Raspbian’s initial setup options on first boot I set my location, timezone and keyboard layout (in Internationalisation Options), set the memory split to 16mb for graphics (in Advanced Options – we can set this low because we won’t even be connecting a display) and finally expanded the filesystem (right from the main menu).
Minimizing SD Card Access
The Pi has no power button. If it’s plugged in then it’s on, and you turn it off by pulling the plug. I’ve read online that if the power is pulled while the system is in the process of writing to the Pi’s SD card (which is the only storage the system has) this can cause problems and possible corruption.
Linux systems do a lot of logging, most commonly to the folder /var/log. They also write stuff about running process to the folder /var/run. To minimize writes to the SD card, we’re going to mount these two folders in memory instead of on the card. Another cause of frequent writes is that linux systems store the time that a file was last accessed, so even if we’re just reading a file the system is actually writing back to the disk to update the time that the file was accessed. We’re going to change that behaviour too.
To make these changes, we’re going to edit the file /etc/fstab so that it looks like this:
proc /proc proc defaults 0 0 /dev/mmcblk0p1 /boot vfat defaults,noatime 0 2 /dev/mmcblk0p2 / ext4 defaults,noatime 0 1 none /var/run tmpfs size=1M,noatime 0 0 none /var/log tmpfs size=1M,noatime 0 0
The first two lines haven’t changed, but on the third line we’ve added the flag “noatime” to indicate that we don’t want to store the timestamp that the file was last accessed. The fourth and fifth lines are entirely new, and these create 1mb partitions in RAM to house the /var/run and /var/log folders respectively.
Setting Up Networking on Pi #1
The next step was to connect one of the Pis (and only one) to my existing home WiFi network. To do this I plugged in one of my USB WiFi adapters and modified the /etc/network/interfaces file to include the following:
auto wlan0 allow-hotplug wlan0 iface wlan0 inet static wpa-ssid MyHomeWiFiName wpa-key-mgmt WPA-PSK wpa-group CCMP TKIP wpa-pairwise CCMP TKIP wpa-psk MyHomeWiFiPassword address 192.168.1.71 netmask 255.255.255.0 gateway 192.168.1.254 dns-nameservers 192.168.1.53 192.168.1.254
Your setup will probably be slightly different, but essentially this connects to my home network, gives the pi a static IP address (192.168.1.71 in my case) and defines my two DNS servers.
You may be wondering why I’m only doing this on one of the Pis, given that they all need to be connected together. The reason is that this first pi (the player) is ultimately going to be sending audio out over the network as multicast packets. In other words, this data goes to every device on the network whether they want it or not.
The problem is that this is a lot of data flowing around, and a typical home WiFi network struggles under the load of it all. My solution is to have two WiFi networks. The one we’ve set up above will connect us to the internet (for streaming audio services) and other stuff on my network (like the fileserver where my music collection lives), but we’ll use a second, separate WiFi network to send the multicast audio to other Pis.
Let’s plug in a second USB WiFi adapter to the first Pi, and make some more additions to the /etc/network/interfaces file:
auto wlan1 allow-hotplug wlan1 iface wlan1 inet static address 192.168.5.1 netmask 255.255.255.0
This section is pretty minimal as you can see, but it’s setting a static IP address on the second wireless interface. The important part is that this uses a different subnet to the other WiFi network (in my case, 192.168.1.x is my existing network, 192.168.5.x is the dedicated network for the Pis).
This section of the /etc/network/interfaces file is so short because this Pi is going to act as a wireless access point that the others will connect to. To set this up we need an additional bit of software, called hostapd. Because I’m using WiFi adapters based on a Realtek 8188 chipset, I had to download and compile this myself - the version found in the debian software repositories wouldn’t work for me:
wget https://github.com/jenssegers/RTL8188-hostapd/archive/v1.1.tar.gz tar -zxvf v1.1.tar.gz cd RTL8188-hostapd-1.1/hostapd make sudo make install
Then edit the file /etc/hostapd/hostapd.conf to change the following three lines:
interface=wlan1 ssid=PiWHA wpa_passphrase=mySecurePassword
Finally, start the service and add it to the boot autostart services for future:
sudo /etc/init.d/hostapd start sudo update-rc.d hostapd enable
Setting Up Networking on the Other Pis
We want the other Pis to connect to the wireless network hosted by Pi #1. To do so, plug one USB WiFi adapter into each and modify the /etc/network/interfaces file on each to reflect the following:
auto wlan0 allow-hotplug wlan0 iface wlan0 inet static wpa-ssid PiWHA wpa-key-mgmt WPA-PSK wpa-group CCMP TKIP wpa-pairwise CCMP TKIP wpa-psk mySecurePassword address 192.168.5.2 netmask 255.255.255.0
The important point here is that the IP address for each must be unique, and must be on the same subnet (192.168.5.x) that we set on the first Pi.
Setting Up Time Synchronization
The Raspberry Pi has no real-time clock, and instead it gets the time from internet time servers at boot. Having the time synchronized on each of our Pis is going to be important to make sure that they play music in sync. Only the first Pi has a connection to the wider internet though, so we need to take some additional steps. On Pi #1, edit the file /etc/ntp.conf and uncomment (or add) the following line:
This tells the pi to broadcast a time signal out onto the network using a special multicast IP address that the other Pis will listen for.
On the other Pis edit the same file, but uncomment (or add) the following lines:
disable auth broadcastclient
We don’t need to tell the other Pis which multicast IP address to listen for – they already know as part of the NTP protocol.
And We’re Done! Or Are We?
That was a lot of setup work, but we should now have our Pis setup and networked together, with our player device having an additional connection to the wider internet.
The thing is… I don’t. The setup is all correct, but the cheap USB WiFi adapters I bought from China don’t properly support access point mode. Sometimes things work, sometimes they don’t.
I’ve read that I can download driver source-code from the adapter’s manufacturer and compile the driver myself, so I’m going to try this before I go further.