MultiRoomAudio

On this page... (hide)

  1. 1. Requirements
    1. 1.1 Options
  2. 2. Solutions
  3. 3. Components
    1. 3.1 Server
    2. 3.2 Renderer
    3. 3.3 Renderer-Controllers
    4. 3.4 Amplifiers and Speakers
  4. 4. Research
    1. 4.1 Amplifiers
    2. 4.2 Onkyo
    3. 4.3 Renderer-Controllers
  5. 5. Software
    1. 5.1 mopidy
    2. 5.2 snapcast
    3. 5.3 librespot
    4. 5.4 shairport-sync
    5. 5.5 upmpdcli

1.  Requirements

  • Multi-room audio distribution
  • 3+ zone
  • Reliable (wired) audio rendering
  • Allow ipod/mp3 player input
  • Remote power trigger for Amplifier

1.1  Options

  • Bidirectional streaming? (ipod in bedroom streams to whole house?)
  • Synchronization (it's hard!)
    • Logitech Media Server
    • Snapcast
  • Home Automation integration - see Network Receivers
    • Remote volume control

2.  Solutions

| Amp | Speakers | Renderer Controller | Notes | | ---------------------------- | -------------------------- | ----------------------------- | -------------- | | Clever Acoustics CPA40 | Wharfedale Diamond 9 | Kindle Fire 7 | Power trigger! | | Medialabs FC330 | Raspberry Pi + Kodi | USB-OTG eth, no power trigger | | Squeezebox Duet | no power trigger | | Squeezebox Radio | Mono only |

3.  Components

  • Server (1)
  • Amp & Speakers (1 set per zone)
  • Renderer (1 per zone) - ethernet, audio decoding
  • Controller (1 per zone + mobile controllers) - user interface

3.1  Server

3.2  Renderer

  • mmpc
  • media streamer (from Nokia)
  • Kodi

3.3  Renderer-Controllers

3.4  Amplifiers and Speakers


4.  Research

4.1  Amplifiers

4.2  Onkyo

Automation : HA Onkyo (power, volume, source)

Yamaha

Automation : OpenHAB Yamaha (power, volume, mute, source)

  • Yamaha RXV-475
  • RXV-379 (2015, 5.1 only)

Denon

Automation : OpenHAB Denon

4.3  Renderer-Controllers


5.  Software

Components:

  • mopidy
  • snapcast
  • shairport-sync
  • upmpdcli

5.1  mopidy

5.2  snapcast

Install snapclient on all media player nodes:

Releases : https://github.com/badaix/snapcast/releases

Server : amd64 deb

Clients : Android, RPi

No iOS equivalent?

Note that snapclient on volumio is symlinked to /usr/sbin/snapclient. The default snapclient is very old (~0.2) and won't work with recent snapservers (0.11+).

Snapserver config

  • Don't daemonize. systemd does it for you.
  • Use the same or separate streams for mopidy and airport?
  • Depends on librespot@.service templates for multiple instances of librespot service

/etc/defaults/snapserver:

USER_OPTS="--user snapserver:snapserver"

SNAPSERVER_OPTS=" \
    -s 'pipe:///tmp/snapfifo0?name=Mopidy&sampleformat=44100:16:2&codec=flac' \
    -s 'pipe:///tmp/snapfifo1?name=Airport&sampleformat=44100:16:2&codec=flac' \
    -s 'pipe:///tmp/librespot1?name=Spotify-1&sampleformat=44100:16:2&codec=flac' \
    -s 'pipe:///tmp/librespot2?name=Spotify-2&sampleformat=44100:16:2&codec=flac' \
    -s 'pipe:///tmp/librespot3?name=Spotify-3&sampleformat=44100:16:2&codec=flac' \

"

Multi-instance snapclient systemd service

/etc/systemd/system/snapclient@.service:

# Multi-instance snapclient service file
[Unit]
Description=Snapcast client
After=network-online.target sound.target
Requires=network-online.target
Wants=avahi-daemon.service

[Service]
# Uses a per-instance defaults file to specify the soundcard device
EnvironmentFile=-/etc/default/snapclient-%i
Type=forking
ExecStart=/usr/bin/snapclient -d $USER_OPTS -i %i $SNAPCLIENT_OPTS
PIDFile=/var/run/snapclient/pid-%i
Restart=always

[Install]
WantedBy=multi-user.target

/etc/default/snapclient-x:

# Legacy?
START_SNAPCLIENT=true

USER_OPTS="--user snapclient:audio"
SNAPSERVER_HOSTNAME=media

# Don't specify -i here, it's added by the systemd service
# RPi HDMI soundcard
SNAPCLIENT_OPTS="-h $SNAPSERVER_HOSTNAME -s CARD=ALSA,DEV=1"

Install with:

sudo systemctl enable snapclient@1
sudo systemctl enable snapclient@2
...etc..

$[Get Code]51

5.3  librespot

Spotify daemon.

Multi-instance librespot systemd service

Depends on snapserver. Using TCP ports 22120-22129.

/etc/systemd/system/librespot@.service:

[Unit]
Description=Librespot
Requires=snapserver.service
After=network.target storage.target snapserver.service

[Service]
#EnvironmentFile=/etc/default/librespot
User=snapserver
Group=audio
Restart=always
RestartSec=10
PermissionsStartOnly=true
Environment="CACHE_DIR=/path/to/librespot-cache"

ExecStartPre=/bin/mkdir -m 1755 -p ${CACHE_DIR}/%i
ExecStartPre=-/bin/chown snapserver:audio ${CACHE_DIR}/%i

# Create the fifo for snapserver to read
ExecStartPre=-/usr/bin/mkfifo /tmp/librespot%i
ExecStartPre=-/bin/chown snapserver:audio /tmp/librespot%i

Environment="DEVICE_NAME=Spotify-%I"
Environment="BITRATE=96"
Environment="CACHE_ARGS=--cache ${CACHE_DIR}/%i"
Environment="VOLUME_ARGS=--enable-volume-normalisation --linear-volume --initial-volume=100"
Environment="BACKEND_ARGS=--backend pipe --device /tmp/librespot%i"
## Abuse the instance ID to open a known port (for firewalling)
Environment="ZEROCONF_ARGS=--zeroconf-port 2212%i"
ExecStart=/usr/local/bin/librespot --name ${DEVICE_NAME} $BACKEND_ARGS --bitrate ${BITRATE} $CACHE_ARGS $VOLUME_ARGS $ZEROCONF_ARGS $OPTIONS

[Install]
WantedBy=multi-user.target snapserver.service

Install with:

sudo systemctl enable librespot@1
sudo systemctl enable librespot@2
...etc..

$[Get Code]52

5.4  shairport-sync

5.5  upmpdcli

Available for armhf Jessie-based Volumio but not for Stretch-based OSMC.

Packages available from: https://www.lesbonscomptes.com/upmpdcli/downloads.html#debian

Install

Depends on libjsoncpp0:

echo "deb http://archive.raspbian.org/raspbian/ jessie main contrib non-free rpi" >> /etc/apt/sources.list.d/raspbian.list
apt-key adv --keyserver pool.sks-keyservers.net --recv-keys F8E3347256922A8AE767605B7808CE96D38B9201
echo "deb http://www.lesbonscomptes.com/upmpdcli/downloads/raspbian/ stretch main" > /etc/apt/sources.list.d/upmpdcli.list
apt-get update
apt-get install upmpdcli

$[Get Code]53

Configure

Edit /etc/upmpdcli.conf (and for Volumio, copy it to /tmp/upmpdcli.conf):

Two settings needed:

friendlyname = my-hostname
upnpiface = eth0  # or wlan0, or whatever