# rpi-sendspin A [sendspin](https://github.com/Sendspin/sendspin-go) 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-cat` and `pw-dump` in `$PATH` - `libopus` and `libopusfile` (for the sendspin dependency) **Build host** (dev packages, only needed to compile): ```bash # 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): ```bash sudo apt install libopus0 libopusfile0 libasound2 pipewire ``` ## Build ```bash 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. ```bash # 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. ```bash # 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/](dist/systemd/). Both run as a **user** service so they have access to the PipeWire session without any special privileges. ```bash # 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.