Operations Overview

This section covers day-to-day operation of the Shiloh Broadcaster system.

Sections

  • Systemd Units — user-mode units, linger, dependency ordering, socket activation
  • Monitoring & Logs — log locations, verbose stats, health checks, alerting
  • Security — firewall, WireGuard, allow-lists, control plane isolation
  • Performance Tuning — JACK buffers, CPU priority, network socket tuning

Ports

Port Protocol Service Notes
UDP 5005 UDP shiloh-mixer Relay fan-out + broadcaster ingest (same socket)
UDP 127.0.0.1:19997 UDP shiloh-mixer control plane mixer_web → mixer; loopback only
UDP 0.0.0.0:19999 UDP shiloh-mixer MIDI listener shiloh-midi-sender → mixer
UDP 127.0.0.1:3819 UDP Ardour OSC mixer → Ardour
UDP 0.0.0.0:3820 UDP Ardour OSC feedback Ardour → mixer
TCP 8889 HTTP mixer_web (Phoenix LiveView) Public or LAN-facing web UI
TCP 127.0.0.1:8890 HTTP shiloh-web-relay (WHEP) Proxied via :8889/whep/* by mixer_web
UDP ephemeral WebRTC media shiloh-web-relay One per PeerConnection; high port range 32768–65535
TCP 6600 MPD Mopidy Optional; only if Mopidy is installed

State files

All files live in ~/mixer-state/ by default (override in the TOML).

File Written by Purpose Rate
meters.json shiloh-mixer [id, peak_l, peak_r] per channel ~10 Hz
sessions.json shiloh-mixer Active UDP relay + ingest sessions ~5 Hz
scenes.dets mixer_web Named scene snapshots (DETS store) On save
relay-assignments.json shiloh-mixer Client name → feed (main/monitor/cue) mapping On change
midi-state.json shiloh-mixer Current MIDI modal state + recent keys On key event

These files are the only coupling between shiloh-mixer and mixer_web. There is no inter-process socket between them.

systemd units (user-mode)

All services run as the shiloh user with systemctl --user. No root or sudo is required for day-to-day operation.

Starting / stopping

# Start all services
systemctl --user start shiloh-mixer shiloh-web-relay mixer_web

# Stop all services
systemctl --user stop shiloh-mixer shiloh-web-relay mixer_web

# Restart a single service
systemctl --user restart shiloh-mixer

# Enable auto-start on login
systemctl --user enable shiloh-mixer shiloh-web-relay mixer_web

Logs

# Follow live
journalctl --user -u shiloh-mixer -f
journalctl --user -u shiloh-web-relay -f
journalctl --user -u mixer_web -f

# Last 50 lines
journalctl --user -u shiloh-mixer -n 50

# Since a specific time
journalctl --user -u shiloh-mixer --since "30 min ago"

Unit locations

~/.config/systemd/user/shiloh-mixer.service
~/.config/systemd/user/shiloh-web-relay.service
~/.config/systemd/user/mixer_web.service

After editing a unit file: systemctl --user daemon-reload.

Updating binaries

Mixer server update

# Binary (built locally or downloaded)
systemctl --user stop shiloh-mixer
cp target/release/shiloh-mixer ~/mixer/shiloh-mixer-linux-x86_64
systemctl --user start shiloh-mixer

# Web relay binary
systemctl --user stop shiloh-web-relay
cp target/release/shiloh-web-relay ~/mixer/shiloh-web-relay-linux-x86_64
systemctl --user start shiloh-web-relay

# mixer_web Phoenix release
# (deploy method depends on your CI; typically tar extract to ~/mixer_web/)
systemctl --user restart mixer_web

NOTE: shiloh-mixer sends BYE to all connected relay clients when it stops cleanly. They reconnect automatically within the backoff window (1–30 s). Broadcaster senders also reconnect automatically.

Relay client update

# On the relay machine
cp new/shiloh-relay ~/.local/bin/shiloh-relay
systemctl --user restart shiloh-relay  # if running as a service
# or kill and restart manually

WirePlumber: keep hardware devices awake

PipeWire suspends ALSA devices after ~5 s of inactivity. When the device sleeps, the JACK graph has no hardware clock driver and all processing stalls — VU meters show 0.0 even though JACK connections look correct.

Drop this into ~/.config/wireplumber/wireplumber.conf.d/53-keep-devices-awake.conf (adjust node.name patterns to match your hardware — check names with pactl list short sinks):

monitor.alsa.rules = [
  {
    matches = [
      { node.name = "~alsa_(output|input).usb-Burr-Brown.*" }
      { node.name = "~alsa_(output|input).usb-Focusrite_Scarlett.*" }
    ]
    actions = {
      update-props = {
        session.suspend-timeout-seconds = 0
      }
    }
  }
]

Apply: systemctl --user restart wireplumber

Verify: timeout 2 pw-top -b -n 3 — at least one ALSA node should show status R with non-zero QUANT/RATE.

Desktop audio null sink (PipeWire)

To route Firefox, VLC, and other PulseAudio apps into the mixer, create a persistent PipeWire null sink. Create ~/.config/pipewire/pipewire.conf.d/desktop-audio-sink.conf:

context.objects = [
  { factory = adapter
    args = {
      factory.name     = support.null-audio-sink
      node.name        = desktop-audio
      node.description = "Desktop Audio"
      media.class      = Audio/Sink
      audio.position   = [ FL FR ]
      monitor.channel-volumes = true
      object.linger    = true
    }
  }
]

NOTE: Do not add an adapter.auto-port-config block. WirePlumber negotiates the adapter’s port-config and a pre-applied auto-port-config deadlocks WpSiAudioAdapter activation. Symptom: apps are stuck at Corked: yes in pavucontrol and every stream goes to Sink: 4294967295.

Apply: systemctl --user restart pipewire pipewire-pulse wireplumber

MIDI control

shiloh-midi-sender reads a USB MIDI keyboard and forwards note-on events as raw UDP to the mixer’s MIDI listener on port 19999. The mixer runs a modal state machine to translate key presses into fader/mute/scene actions and Ardour OSC transport commands.

Running the MIDI sender

shiloh-midi-sender --device "USB MIDI" --server stg-srv001.bq.shilohbv.com:19999

Key map (default config)

Mode entry (C3 octave):

Note MIDI # Effect
A3 57 Reset to Idle from any mode
C3 48 Enter ChannelSelect
G3 55 Enter Transport (sticky)

Channel navigation (in ChannelSelect / ChannelControl):

Note MIDI # Action
C4 60 Previous channel
D4 62 Next channel

Channel actions (C5 octave, in ChannelControl):

Note MIDI # Action
C5 72 Fader down (−0.05)
D5 74 Fader up (+0.05)
E5 76 Mute toggle

Transport (C6 octave, in Transport mode):

Note MIDI # Ardour OSC
C6 84 Play
D6 86 Stop
E6 88 Record enable toggle
F6 89 Goto start
G6 91 Goto end
A6 93 Previous marker
B6 95 Next marker
C7 96 Add marker

The MIDI panel in the web UI shows the current mode, the last 8 keys pressed, and the action each key triggered. Keys that produced no action (not mapped in the current mode) show .

Key mappings are configured in [midi.*] blocks in shiloh-mixer.toml. After changing them, redeploy the TOML and restart the mixer.

Ardour integration

shiloh-mixer can control and receive feedback from Ardour over OSC and Ardour’s WebSocket surface.

One-time Ardour setup

  1. Edit → Preferences → Control Surfaces → Open Sound Control → Show Protocol Settings
  2. Enable OSC, listen port: 3819
  3. Reply port: 3820, enable feedback on strips and master (fader + mute)
  4. Click Apply

Install / update the Ardour session template

The template is generated live from the running mixer config:

mkdir -p ~/.config/ardour8/templates/shiloh-broadcast
curl http://localhost:8889/ardour/template \
  -o ~/.config/ardour8/templates/shiloh-broadcast/shiloh-broadcast.template

Re-run after changing the channel layout.

Recovery after PipeWire upgrade

PipeWire upgrades can reset JACK port state. Restart the mixer and web UI:

systemctl --user restart shiloh-mixer mixer_web

If the graph doesn’t recover (all meters at 0.0):

systemctl --user restart pipewire pipewire-pulse wireplumber
# then:
systemctl --user restart shiloh-mixer