Broadcaster Can’t Connect

Use this guide when shiloh-broadcaster connect fails to establish a session with the mixer.

The broadcaster goes through this handshake:

client                        mixer
  |── REGISTER_TX ──────────────▶|  (name, channel count, protocol version)
  |◀─ ACCEPT_TX or REJECT_TX ───|
  |── AUDIO_TX (stream) ────────▶|
  |── PING (every 1 s) ─────────▶|
  |◀─ PONG ─────────────────────|

Branch 1: DNS resolution failure

Symptom: Startup immediately prints an error like:

ERROR resolving stg-srv001.bq.shilohbv.com:5005: failed to lookup address information

or the process exits before printing accepted:.

Test reachability:

# Check DNS
host stg-srv001.bq.shilohbv.com

# Check UDP reachability (sends one packet, expects no response — that's fine)
nc -u stg-srv001.bq.shilohbv.com 5005
# Then Ctrl-C. No "connection refused" means the port is reachable.

# Or ping the IP directly
ping stg-srv001.bq.shilohbv.com

Common causes:

Cause Fix
Hostname typo Double-check --server argument
DNS not resolving on this host Check /etc/resolv.conf; try --server <IP>:5005
Firewall blocking UDP 5005 See firewall notes in Security
On a different network (WAN) Use WireGuard tunnel; see Security

Branch 2: Sender name not in allow-list

Symptom: Log on the mixer server shows:

WARN REJECT_TX unknown sender 'studio' from 192.168.1.50:XXXXX

What it means: The --name you passed to shiloh-broadcaster connect does not match any [[ingest.sender]] entry in ~/mixer/shiloh-mixer.toml.

Check the mixer reject log:

journalctl --user -u shiloh-mixer | grep REJECT

Fix — add the sender to the config:

Edit ~/mixer/shiloh-mixer.toml on the mixer server:

[ingest]
slot_count = 2   # must be >= sum of all sender channels

[[ingest.sender]]
name       = "studio"   # must match --name on the broadcaster
channels   = 2
start_slot = 0

Then add or update the channel that reads from this slot:

[[channel]]
id          = "studio"
ingest_slot = 0          # matches start_slot above

Restart the mixer to pick up the new config:

systemctl --user restart shiloh-mixer

Branch 3: Channel count mismatch

Symptom: Mixer log shows:

WARN REJECT_TX 'studio' wants 2ch, config 1ch

or vice versa.

What it means: The --channels argument passed to shiloh-broadcaster does not match the channels field for that sender in the TOML config.

Reject code: REJECT_CHANNEL_COUNT (code 0x05).

Fix: Either change --channels on the broadcaster to match the config, or update channels in [[ingest.sender]] and slot_count accordingly, then restart the mixer.


Branch 4: Sample rate mismatch

Symptom: Broadcaster prints a warning like:

WARN sample rate mismatch: local JACK = 44100 Hz, server = 48000 Hz — audio will be pitched

The connection still succeeds, but audio will play back at the wrong pitch and speed. A 44.1 → 48 kHz mismatch causes audio to play ~8.8% fast and about a semitone sharp.

What it means: Your local JACK/PipeWire graph is running at a different sample rate than the mixer server. The broadcaster sends raw S16LE frames; no resampling is done.

Fix — set local PipeWire to 48 kHz:

# Check current rate
pw-metadata -n settings 0 clock.rate

# Set to 48000
pw-metadata -n settings 0 clock.rate 48000

Make permanent in ~/.config/pipewire/pipewire.conf.d/rate.conf:

context.properties = {
  default.clock.rate = 48000
}

Then restart PipeWire:

systemctl --user restart pipewire pipewire-pulse wireplumber

Branch 5: Ring full / underruns

Symptom: With --verbose, the stats line shows non-zero ring_full or underruns:

[stat] 375 pps  underruns=0  ring_full=47

ring_full means the mixer’s ingest ring buffer is overflowing. The RT JACK thread on the mixer is not consuming samples fast enough relative to the network delivery rate.

underruns means the local JACK callback is not producing samples fast enough for the broadcaster’s TX loop. The TX loop emits silence to maintain cadence, which sounds like dropouts.

Tuning ring_frames (broadcaster side):

The broadcaster sizes its ring at frames * 8 by default (where frames is the mixer’s JACK period). Increase headroom by running with a larger local JACK buffer (see Mixer Won’t Start — xruns).

Diagnosing on the mixer server side:

journalctl --user -u shiloh-mixer | grep "ingest_drop"

If the mixer logs ingest_drop events, its ingest ring is overflowing. The fix is to increase the mixer’s broadcast_frames or reduce the number of concurrent ingest senders.


Branch 6: PipeWire null-sink creation failure

Symptom: Broadcaster exits immediately with:

ERROR loading PipeWire null-sink: ...

The broadcaster creates a PipeWire null-sink at startup (unless --no-sink is passed) so that applications can route audio to it.

Check existing sinks:

pactl list sinks short

Look for shiloh-broadcaster or the --sink-name you specified.

Check for duplicate sink name:

If a previous broadcaster run crashed without cleanup, the sink may still exist. List and remove it:

pactl list modules short | grep null-sink
# Find the module number for your sink, then:
pactl unload-module <module-number>

Restart PipeWire if the sink load still fails:

systemctl --user restart pipewire pipewire-pulse wireplumber

Skip the sink entirely (use an existing one):

shiloh-broadcaster connect --server HOST:PORT --name studio --channels 2 --no-sink

Then route audio to an existing PipeWire sink manually with pw-link or pavucontrol.