I was very happy to find two guides to setting up a Raspberry Pi to stream music from a turntable with a USB output, so we could listen to it on our existing Sonos speakers and via a network-connected receiver in a different room.
I adapted the two guides and learned a few things along the way – this is mostly a record for my own reference, but perhaps it will be of help to someone else too.
- Used Raspbian Stretch (no changes needed)
- Use stock darkice binaries from the repository
- darkice init script tweaks
- Stream from port 80 so you don’t have to specify a port
- Power control from a mobile via a URL
coreyk compiles darkice from source, to add AAC+ support. I don’t need this, as on a local network the suggestion of doing fixed 320kbps MP3 encoding is fine.
basdp provides their own .deb. This is fragile (what versions of raspbian will it work with?) and there’s no way to tell if it’s trustworthy.
I had no issues with the stock darkice. This meant the only packages I needed to install were darkice and icecast2 (and vim!).
darkice init script tweaks
I followed coreyk’s guide, but instead of deleting the pidfile with
rm, you can pass
start-stop-daemon when stopping.
To get logging output from darkice, I changed the start invocation to make use of
LOGFILE="$LOGDIR/$NAME.log" ... start-stop-daemon --start --quiet --make-pidfile --pidfile $PIDFILE \ --background --chuid $USER:$GROUP --no-close \ --exec $DAEMON -- $DAEMON_OPTS >> $LOGFILE 2>&1
Not directly related to the init script, but note that darkice is being run as nobody:nobody. This user can’t set the realtime scheduling priority requests in darkice’s configuration file, so we give the binary that capability:
sudo setcap cap_sys_nice=+ep `which darkice`
Both guides suggest setting up icecast to listen on port 8000. This is fine, but makes the URL slightly ugly.
With port 80, you can stream from
The port can easily be changed in
/etc/icecast2/icecast.xml, the trick is to give icecast the capability to bind to port 80:
sudo setcap 'cap_net_bind_service=+ep' `which icecast2`
Reboot and shutdown from a mobile
To provide a clean shutdown option, I wrote this little script to listen for web requests. A shortcut to the URL alongside the Sonos app on my phone’s launcher then provides a convenient way to cleanly shut it down. I don’t know what the risk of SD card corruption is from hard power-offs, but this eases my mind.
It’s called from /etc/rc.local so it should always be running when the Pi is. This also means it runs as root - not generally a good idea for a web server, to say the least, but in this case it’s quite convenient as that gives it permission to shutdown and reboot.
#!/usr/bin/env python3 from http.server import BaseHTTPRequestHandler, HTTPServer from urllib import parse import subprocess # HTTPRequestHandler class class handler(BaseHTTPRequestHandler): def do_GET(self): parsed_path = parse.urlparse(self.path).path if parsed_path in ['/reboot','/restart']: code = 200 message = "Rebooting..." subprocess.Popen(["shutdown", "-r", "now"]) # will run concurrently elif parsed_path in ['/halt','/shutdown','/stop']: code = 200 message = "Shutting down..." subprocess.Popen(["shutdown", "-h", "now"]) # will run concurrently else: code = 404 message = "Not found. Available paths: /reboot, /halt\n" self.send_response(code) self.send_header('Content-type','text/html') self.end_headers() # Send response to client as utf8 self.wfile.write(bytes(message, "utf8")) return def run(): # bind to all addresses, unprivileged port server_address = ('', 8000) httpd = HTTPServer(server_address, handler) print('running server...') httpd.serve_forever() run()