stevegattuso
This site is an always-in-progress repository for my thoughts and ideas. You'll generally find me writing about sustainability 🍃, urbanism 🏙️, programming 💾, vegan cooking 🍛, and whatever else pops into my mind.
Sonos ↔ Vinyl

I enjoy listening to music on records but unfortunately also enjoy having a wireless speaker system. This presents a problem, as Sonos speakers have no form of analog input without buying some absurdly expensive converter device (hundreds of dollars). No bueno.

Instead, I decided to take matters into my own hands by using a Raspberry Pi to convert my analog record signal into a digital stream. This stream can then be easily sent over to the Sonos speakers to play. This page is loosely based off of this guide by replyreb on Instructables, however I’ve cut out a bunch of the setup steps for simplicity and added a few tweaks of my own.

Hardware

This guide isn’t too resource intensive however you will need at least two things to make this work:

  1. Raspberry Pi
    • Through my experience I’ve found the original Raspberry Pi was too underpowered to handle streaming properly. Upon upgrading to a Raspberry Pi 4 everything seems to work great, with minimal latency and no interruptions so far.
  2. Behringer UCA202 or similar USB audio interface
    • I use this interface but I can imagine any kind of USB audio card with an RCA input will work just as well. Be sure to check for linux drivers before buying something different.

Before proceeding to the next step, ensure your Raspberry Pi is running Raspbian, you have SSH access, and your USB audio card is connected to both the Raspberry Pi and your record player.

Raspberry Pi Setup

With our equipment set up, let’s dive into the software. We’ll be using a combination of icecast2 and darkice to set up an HTTP audio stream that can be played on our Sonos (or any other device).

First you’ll need to SSH into your Raspberry Pi and install both packages:

$ sudo apt install icecast2 darkice

Next we’ll need to figure out the device identifier for our USB audio card. We’ll use the arecord -l which will list out each audio device available on the Pi:

$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 1: CODEC [USB Audio CODEC], device 0: USB Audio [USB Audio]
  Subdevices: 0/1
  Subdevice #0: subdevice #0

From this output we can see the ID is 1 (looking at card 1 for the number). Once you have this it’s a good idea to test out your setup by recording a sample .wav file to ensure the audio interface is working. Spin something on your record player and run the following command:

$ arecord -D plughw:1,0 -f cd temp.wav

ctrl+c out of it after 30 seconds or so of playback, copy the file to your local machine, and play it to see if you hear your record. If you don’t you may need to go back and ensure everything is connected properly/you have the right device selected.

If all looks good we can spin up icecast:

# Start icecast
$ sudo systemctl start icecast

# Ensure icecast starts each time the system reboots
$ sudo systemctl enable icecast

Next we’ll configure darkice. Save the following config to /etc/darkice.cfg:

[general]
duration        = 0      # duration in s, 0 forever
bufferSecs      = 1      # buffer, in seconds
reconnect       = yes    # reconnect if disconnected

[input]
device          = plughw:1,0 # Soundcard device for the audio input
sampleRate      = 44100   # sample rate 11025, 22050 or 44100
bitsPerSample   = 16      # bits
channel         = 2       # 2 = stereo

[icecast2-0]
bitrateMode     = cbr       # constant bit rate ('cbr' constant, 'abr' average)
#quality         = 1.0       # 1.0 is best quality (use only with vbr)
format          = mp3       # format. Choose 'vorbis' for OGG Vorbis
bitrate         = 320       # bitrate
server          = localhost # or IP
port            = 8000      # port for IceCast2 access
password        = helloWorld    # source password for the IceCast2 server
mountPoint      = turntable.mp3  # mount point on the IceCast2 server .mp3 or .ogg
name            = Turntable
highpass        = 18
lowpass         = 20000
description     = Turntable

We’ll also need to create a systemd script that starts darkice and loads the config file. Run mkdir -p ~/.config/systemd/user and create the following file at ~/.config/systemd/user/turntable.service. I chose to make this a user-level systemd unit because it works better with my particular setup but you can probably make it systemwide without issue. Just move the file to /etc/systemd/system.

[Unit]
Description=Turntable stream

[Service]
ExecStart=/usr/bin/darkice -c /etc/darkice.cfg

[Install]
WantedBy=default.target

If you decide to use the user-level service, make sure you enable lingering to ensure that the unit starts up when your system starts up (not when your user logs in):

loginctl enable-linger [your username]

If all looks good you should be able to spin up darkice like so:

$ systemctl --user start darkice
$ systemctl --user enable darkice

At this point you should be able to log into the icecast UI at http://[pi ip]:8000.

icecast UI

If you click on the M3U link in the top right you should be able to begin listening to your record player’s streaming audio. Awesome! If you’re on a Mac you can import this file into Music.app and stream to your Sonos via Airplay. This works, but can be a bit clunky since the M3U file won’t sync to other devices. Read on for more details…

iOS Shortcuts

I was a bit frustrated with the above setup as it was kind of annoying to have to use my laptop to connect my Sonos to the record player stream. After a while of being stuck, I finally came across a solution using a combination of iOS’ Shortcuts app and the soco library for Python.

In a nutshell, I’ve created a shortcut on my phone that will ssh into my Raspberry Pi and execute a Python script. This Python script then connects to the Sonos speaker I usually use and instructs it to connect to the turntable stream. Voila, a convenient one-button method to start listening to my record player without having to involve fussing with a laptop/tMusic.app.

Here’s the python script:

import soco
import time

x = soco.SoCo('[sonos IP address]')
x.play_uri('http://[pi IP address]:8000/turntable.mp3.m3u')

And here’s the iOS shortcut:

iOS shortcut