Contributing

Repository structure

broadcaster/
├── Cargo.toml               # Workspace root
├── Cross.toml               # cross-rs target config
├── crates/
│   ├── protocol/            # Wire format constants, encode/parse helpers
│   ├── shiloh-mixer/        # JACK mix bus, relay fan-out, ingest, MIDI, OSC
│   ├── shiloh-broadcaster/  # PipeWire null-sink → JACK → UDP sender
│   ├── shiloh-relay/        # UDP → cpal relay receiver
│   ├── shiloh-web-relay/    # UDP → Opus → WebRTC/WHEP browser egress
│   └── shiloh-midi-sender/  # USB MIDI → UDP forwarder
├── server/
│   ├── systemd/             # Systemd unit files for the mixer server
│   ├── mixer_web/           # Phoenix LiveView mixer UI (Elixir)
│   └── shiloh-mixer.toml    # Example config
└── docs/                    # Documentation

Building

Prerequisites:

# Rust (stable, via rustup)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"

# Native build deps
sudo apt install libjack-jackd2-dev libasound2-dev

Build all Rust crates:

cargo build --release

Build a specific crate:

cargo build --release -p shiloh-mixer
cargo build --release -p shiloh-broadcaster

Code style

Rust

All Rust code must pass:

cargo fmt --check
cargo clippy -- -D warnings

Run before every commit:

cargo fmt
cargo clippy -- -D warnings

Conventions:

  • No unsafe in crates/protocol/ (#![forbid(unsafe_code)] is enforced).
  • RT-thread code (the JACK callback in shiloh-mixer/src/jack_io.rs and mix.rs) must contain:
    • No heap allocation (no Vec::push, HashMap inserts, Box::new, String::from, etc.)
    • No mutex locks (use AtomicBool, AtomicU64, or lock-free ring buffers)
    • No blocking I/O (no file reads, no thread::sleep)
    • No println! (use the log crate with Relaxed ordering guards if needed)
  • Non-RT code has no special restrictions beyond standard Rust idioms.

Elixir (mixer_web)

cd server/mixer_web
mix format
mix credo --strict

Running tests

# All crates
cargo test --workspace

# Single crate
cargo test -p shiloh-protocol
cargo test -p shiloh-mixer

Protocol crate tests: roundtrip encode/parse tests for every packet type. These run without any system dependencies.

Mixer integration tests: require a running JACK server. Set up PipeWire-JACK before running:

systemctl --user start pipewire pipewire-pulse wireplumber
cargo test -p shiloh-mixer -- --test-threads=1

Cross-compilation

The CI builds for aarch64-unknown-linux-gnu (Raspberry Pi) and x86_64-pc-windows-gnu (relay client only). Use cross locally:

cargo install cross --git https://github.com/cross-rs/cross

# Relay for Pi
cross build --release -p shiloh-relay --target aarch64-unknown-linux-gnu

# Relay for Windows
cross build --release -p shiloh-relay --target x86_64-pc-windows-gnu

Note: shiloh-mixer and shiloh-broadcaster are not cross-compiled for Windows — they depend on Linux-specific APIs (libjack, PipeWire).


CI

CI runs on every push to master and on all pull requests. The pipeline:

  1. cargo fmt --check
  2. cargo clippy -- -D warnings
  3. cargo test --workspace
  4. cargo build --release for x86_64-unknown-linux-gnu
  5. cross build --release -p shiloh-relay --target aarch64-unknown-linux-gnu
  6. Publish binaries to http://broadcaster.shilohbv.com/dist/

PRs that fail any step are not merged.


Pull request guidelines

  1. Open PRs against master on the Forgejo instance at git.shilohbv.com/shiloh/broadcaster.
  2. One logical change per PR. Large refactors should be split into preparatory + main change.
  3. Update docs/ if your change affects user-visible behaviour (ports, config keys, CLI flags).
  4. RT-thread changes require extra care — include a before/after xrun count from a 1-minute test run on real hardware.
  5. Protocol changes that break existing clients must bump PROTO_VERSION and document the migration in the PR description.

Protocol extension

If you need to add a new packet type:

  1. Assign a tag byte in crates/protocol/src/lib.rs. Tags 0x080x0F are reserved for future use.
  2. Add encode and parse functions, with roundtrip tests.
  3. If the change is backward-incompatible, increment PROTO_VERSION. Update PROTO_MIN only if you want to hard-reject old clients (rather than negotiating).
  4. Add dispatch in shiloh-mixer/src/broadcast.rs and the relevant client crate.

License

See LICENSE in the repository root.