3.7 KiB
rpi-sendspin
A sendspin client and server with native PipeWire node selection.
Audio is routed through pw-cat, so any PipeWire source or sink can be targeted by name — no ALSA/PulseAudio compatibility layer needed.
Requirements
- Go 1.22+
- PipeWire with
pw-catandpw-dumpin$PATH libopusandlibopusfile(for the sendspin dependency)
Build host (dev packages, only needed to compile):
# Arch
sudo pacman -S pipewire opus opusfile
# Debian/Ubuntu
sudo apt install libopus-dev libopusfile-dev libasound2-dev
Raspberry Pi (runtime only, no dev packages needed):
sudo apt install libopus0 libopusfile0 libasound2 pipewire
Build
make # builds bin/sendspin-client and bin/sendspin-server (native)
make rpi # cross-compiles for RPi via Docker → bin/*-armhf and bin/*-arm64
make clean
make rpi requires Docker. It builds a Debian image with ARM cross-compilers and the ARM versions of libopus/libasound, then copies the four binaries into bin/. No toolchain installation needed on the host.
Usage
Server
Captures audio from a PipeWire source node and streams it to connected clients.
# List available capture sources
./bin/sendspin-server --list-sources
# Stream from a specific source
./bin/sendspin-server --source alsa_input.usb-JBL_Quantum810-00.pro-input-0
# Options
./bin/sendspin-server --help
-source string PipeWire source node name
-port int listen port (default 8927)
-name string server name (default "Sendspin Server")
-rate int capture sample rate (default 48000)
-channels int capture channels (default 2)
Client
Connects to a sendspin server and plays audio on a PipeWire sink.
# List available playback sinks
./bin/sendspin-client --list-devices
# Play on a specific sink (omit --device to use the system default)
./bin/sendspin-client --server rpi.local:8927 --device alsa_output.usb-JBL_Quantum810-00.pro-output-0
# Options
./bin/sendspin-client --help
-server string server address (default "localhost:8927")
-device string PipeWire sink node name (default: system default)
-name string player name (default: hostname)
-volume int initial volume 0-100 (default 80)
Running as a systemd user service
Example unit files are in dist/systemd/. Both run as a user service so they have access to the PipeWire session without any special privileges.
# 1. Copy the binary
install -Dm755 bin/sendspin-client-arm64 ~/.local/bin/sendspin-client
# 2. Edit the unit file — set --server, --device, --name to your values
cp dist/systemd/sendspin-client.service ~/.config/systemd/user/
# 3. Enable and start
systemctl --user daemon-reload
systemctl --user enable --now sendspin-client
# Logs
journalctl --user -u sendspin-client -f
The unit files use %H (hostname) for --name and %h (home dir) for the binary path. Replace the placeholder --device / --source values — use --list-devices / --list-sources to find the right node name first.
Architecture
PipeWire source node
│
pw-cat --capture
│ int32 PCM
sendspin server ──── network ──── sendspin client
│ int32 PCM
pw-cat --playback
│
PipeWire sink node
internal/pipewire/source.go wraps pw-cat --capture as an AudioSource.
internal/pipewire/output.go wraps pw-cat --playback as an Output.
internal/pipewire/nodes.go parses pw-dump JSON to enumerate nodes.