Skip to content

Instantly share code, notes, and snippets.

@wiking-at
Created January 11, 2026 15:23
Show Gist options
  • Select an option

  • Save wiking-at/d7789afb9107c3f6a16501e1914bbe41 to your computer and use it in GitHub Desktop.

Select an option

Save wiking-at/d7789afb9107c3f6a16501e1914bbe41 to your computer and use it in GitHub Desktop.

Documentation: Multi-Zone Audio Setup (Sendspin Variant) Target System: Ubuntu 24.04 (Minimal VM) on Proxmox Hardware: Wondom KAB9 (8-Channel USB Audio) Software: ALSA, Sendspin (Client), Music Assistant (Docker)

  1. Prerequisites & Installation Kernel Drivers (USB Audio) In minimal Ubuntu images, audio modules are often missing. These must be installed and permanently loaded.
# Install driver modules
sudo apt update
sudo apt install linux-modules-extra-$(uname -r) -y

# Load module permanently
echo "snd-usb-audio" | sudo tee -a /etc/modules
sudo modprobe snd-usb-audio

Required Packages We follow the official installer and use uv as well as libportaudio2.

# 1. Install system dependencies
sudo apt install alsa-utils libasound2-plugins libportaudio2 curl -y

# 2. Install uv (Modern Python Package Manager)
# NOTE: Please DO NOT install uv via Snap! Sandboxing often prevents
# correct function (e.g., venv creation, access to /mnt).
if ! command -v uv &> /dev/null;
then
    # Official installer
    curl -LsSf https://astral.sh/uv/install.sh | sh
    
    # Load path for the current session (installer usually makes it permanent)
    if [ -f "$HOME/.local/bin/env" ]; then
        source "$HOME/.local/bin/env"
elif [ -f "$HOME/.cargo/env" ]; then
        source "$HOME/.cargo/env"
    else
        # Fallback: Set paths manually
        export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"
    fi
fi

# 3. Install sendspin via uv
# Note: If you are working as root, this will be installed to /root/.local/bin.
uv tool install sendspin

# 4. Determine path to binary
# We need this path for the systemd service file shortly.
# Note the output! (e.g., /root/.local/bin/sendspin or /home/user/.local/bin/sendspin)
uv tool dir --bin | xargs -I{} echo {}/sendspin
  1. Audio Configuration (ALSA) The /etc/asound.conf file splits the 8 physical channels of the sound card into 4 virtual stereo zones.

File: /etc/asound.conf

# 1. Hardware Abstraction with dmix (Allows sharing of the 8 channels)
pcm.card_0 {
    type dmix
    ipc_key 2047
    ipc_key_add_uid yes
    slave {
        pcm "hw:0,0"
        rate 48000
        period_time 0
        period_size 1024
        buffer_size 8192
        channels 8
    }
    bindings {
        0 0
        1 1
        2 2
        3 3
        4 4
        5 5
        6 6
        7 7
    }
}

# 2. Multi-Device Bridge
pcm.multi {
    type multi
    slaves.a {
        pcm "card_0"
        channels 8
    }
    bindings.0.slave a
    bindings.0.channel 0
    bindings.1.slave a
    bindings.1.channel 1
    bindings.2.slave a
    bindings.2.channel 2
    bindings.3.slave a
    bindings.3.channel 3
    bindings.4.slave a
    bindings.4.channel 4
    bindings.5.slave a
    bindings.5.channel 5
    bindings.6.slave a
    bindings.6.channel 6
    bindings.7.slave a
    bindings.7.channel 7
}

# 3. Zone Definitions (Stereo Pairs)
pcm.zone1 {
    type plug
    slave { pcm "multi" channels 8 }
    ttable.0.0 1
    ttable.1.1 1
}

pcm.zone2 {
    type plug
    slave { pcm "multi" channels 8 }
    ttable.0.2 1
    ttable.1.3 1
}

pcm.zone3 {
    type plug
    slave { pcm "multi" channels 8 }
    ttable.0.4 1
    ttable.1.5 1
}

pcm.zone4 {
    type plug
    slave { pcm "multi" channels 8 }
    ttable.0.6 1
    ttable.1.7 1
}
  1. Player Configuration (Sendspin) We use a systemd template to start multiple player instances in daemon mode.

Note on Root vs. User: If you run everything as root (typical for minimal audio VMs), you can omit the User= parameter or set it to User=root. The paths will then point to /root/.local/bin/sendspin. For normal user installations (recommended for desktop systems), set User=your_username and adjust the paths accordingly.

Step A: Identify Audio Devices Before configuring the services, we need to know how Sendspin (via PortAudio) names the ALSA zones.

# List all available audio devices
sendspin --list-audio-devices

# Look for entries like "zone1", "zone2", etc.
# Note the exact name (or index).

Step B: Create Systemd Template Adjust the variables USER_NAME and SENDSPIN_BIN according to your installation.

File: /etc/systemd/system/sendspin@.service

[Unit]
Description=Sendspin Player %I
After=network-online.target sound.target
Wants=network-online.target

[Service]
Type=simple
# Case A: Root Installation (Standard on minimal VMs)
User=root
# Adjust path: usually /root/.local/bin/sendspin
Environment="SENDSPIN_BIN_PATH=/root/.local/bin/sendspin"

# Case B: User Installation (Remove comment and adjust)
# User=my_linux_user
# Environment="SENDSPIN_BIN_PATH=/home/my_linux_user/.local/bin/sendspin"

EnvironmentFile=/etc/sendspin.d/%i.conf

# We use bash exec to cleanly expand variables
ExecStart=/bin/bash -c 'exec ${SENDSPIN_BIN_PATH} daemon \
    ${SENDSPIN_CLIENT_NAME:+--name "${SENDSPIN_CLIENT_NAME}"}
    ${SENDSPIN_AUDIO_DEVICE:+--audio-device "${SENDSPIN_AUDIO_DEVICE}"}
    --id "sendspin-%i" \
    --static-delay-ms ${SENDSPIN_STATIC_DELAY_MS:-0}
    ${SENDSPIN_ARGS}'

Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal

# Security Hardening (optional, can cause issues with root operation if too strict)
# NoNewPrivileges=true
# PrivateTmp=true
# ProtectSystem=strict
# ProtectHome=read-only

[Install]
WantedBy=multi-user.target

Step C: Instance Configuration (Example Living Room) Create the directory for configurations:

mkdir -p /etc/sendspin.d/

File: /etc/sendspin.d/wohnzimmer.conf

# Friendly Name for Music Assistant
SENDSPIN_CLIENT_NAME="Wohnzimmer"

# The ALSA device (Name or Index from 'sendspin --list-audio-devices')
SENDSPIN_AUDIO_DEVICE="zone1"

# Optional: Delay in ms (if synchronization issues occur)
SENDSPIN_STATIC_DELAY_MS=0

# Optional: Additional arguments
SENDSPIN_ARGS=""
  1. Service Management
# Load and start new instance
systemctl daemon-reload
systemctl enable --now sendspin@wohnzimmer
  1. Integration into Music Assistant Web UI: Open Music Assistant (Port 8095).

Provider: Go to Settings -> Providers. Sendspin is the native protocol of Music Assistant. Ensure the "Sendspin" provider is enabled (if present) or that players are automatically detected.

Result: The player "Wohnzimmer" should appear in the player list.

Helpful Debugging Commands

# Check logs
journalctl -u sendspin@wohnzimmer -f

# Test sound card
speaker-test -D zone1 -c 2

# Check usage
fuser -v /dev/snd/*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment