Multi-Site Setup
A single shiloh-mixer instance supports multiple relay clients simultaneously. Each
client subscribes to exactly one feed (main, monitor, or cue) and the mixer fans out
independently to each.
Running Multiple Pi Relays from One Mixer
Start each relay with a unique --name. The mixer tracks relay sessions by name and
persists feed assignments between restarts.
# Pi at stage left — main feed
shiloh-relay connect \
--server stg-srv001:5005 \
--name stage-left \
--device "hw:0,0" \
--buffer-ms 30
# Pi at front-of-house — main feed, higher buffer for wired Ethernet drop
shiloh-relay connect \
--server stg-srv001:5005 \
--name foh \
--device "hw:1,0" \
--buffer-ms 50
# Laptop in the monitor position — monitor feed
shiloh-relay connect \
--server stg-srv001:5005 \
--name monitor-mix \
--buffer-ms 30
Each relay connects, registers, and receives its assigned feed independently. The mixer
sends a separate UDP stream to each client address. There is no multicast — bandwidth
scales linearly with client count (~1.6 Mbit/s per stereo client at 48 kHz / 128 frames).
Per-Bus Relay Assignment
Each relay client is assigned to one feed. Assignments persist by name in
~/mixer-state/relay-assignments.json.
Assign from the web UI
In mixer_web at the sessions panel, find the relay client row and click the feed
selector to switch between main / monitor / cue. The change is applied immediately
without disconnecting the client.
Assign via control plane (UDP JSON)
echo '{"op":"set_relay_assignment","name":"stage-left","feed":"main"}' \
| nc -u 127.0.0.1 19997
Valid feed values: "main", "monitor", "cue".
Default assignment
If a client connects with a name that has no saved assignment, it defaults to the
main feed. You can change this by adjusting relay-assignments.json before the
client connects, or by reassigning from the UI after it appears.
Three-Bus Example
A typical live setup with three relay destinations:
| Client name | Feed | Purpose |
|---|---|---|
pi-main |
main | FOH speakers (full mix, with mutes) |
pi-monitor |
monitor | Stage monitor wedges (mute-exempt mix) |
pi-cue |
cue | Individual channel cue for soundcheck |
web-relay-main |
main | Browser listen page for remote audience |
In shiloh-mixer.toml, each channel has independent main_gain, monitor_gain, and
cue_gain faders, so the monitor and cue mixes can differ substantially from main.
[[channels]]
id = "bcast1"
label = "Studio"
kind = "stereo"
main_gain = 1.0
monitor_gain = 0.8 # slightly lower in monitors
cue_gain = 1.2 # louder in cue for isolated listening
Redundancy Considerations
shiloh-relay has a built-in reconnect loop with exponential backoff. If the mixer
restarts:
- Relay sessions evict from the mixer after 5 s of no PING (the relay’s heartbeat interval
is 1 s, so the server times out within five missed PINGs). - The relay detects no audio for > 3 s (its internal watchdog), then reconnects.
- After reconnect, feed assignment is restored from
relay-assignments.json.
Total reconnect window: typically 5–10 s after a mixer restart.
For critical applications (broadcast transmission), run shiloh-relay under systemd
with Restart=always and RestartSec=1:
[Service]
ExecStart=/home/pi/bin/shiloh-relay connect \
--server 10.0.0.1:5005 --name pi-main
Restart=always
RestartSec=1
There is no active/standby failover to a second mixer instance. If the mixer host fails,
all relay clients reconnect when it recovers. Plan for maintenance windows during off-peak
times.
Bandwidth Planning
| Clients | Bandwidth from mixer (aggregate) |
|---|---|
| 1 | ~1.6 Mbit/s |
| 4 | ~6.4 Mbit/s |
| 8 | ~12.8 Mbit/s |
| 16 | ~25.6 Mbit/s |
The mixer’s default max_clients compile-time limit is 16. At 8 clients on a 100 Mbit
LAN uplink, utilisation is < 15% — negligible. On a 1 Gbit switch, 16 clients is
trivial.
shiloh-web-relay adds 3 more relay sessions (one per feed) but these are server-side;
the browser-facing bandwidth is Opus RTP (128 kbps per WebRTC session) rather than raw
S16LE.