Skip to content

sholiday/musicbox

Repository files navigation

Musicbox

Rust

Musicbox is an NFC‑triggered music player aimed at running on a Raspberry Pi (32‑bit OS on Pi 2/3). It is being built with TDD and commits should remain small and frequent.

Looking for setup and day-to-day usage instructions? Visit the mdBook-based Musicbox User Guide or build it locally with mdbook serve docs.

Developer Notes

Current Architecture

  • controller: Pure domain logic mapping card UIDs to tracks. Works with any AudioPlayer implementation so we can exercise it thoroughly in unit tests without bringing hardware along.
  • config: Loads card→track mappings from a TOML file and produces a Library.
  • audio: Optional backends implementing AudioPlayer. RodioPlayer is enabled via the audio-rodio Cargo feature; otherwise a silent stub is available, letting the app boot in CI or on dev laptops without ALSA.
  • reader: Defines the NfcReader trait. A PC/SC implementation behind the nfc-pcsc feature polls an attached ACR122U reader; a noop reader is used otherwise so we can still run and observe telemetry on machines without the hardware.
  • app: Glue code that loads config, wires the controller to a reader, and runs the event loop with callback hooks. Also hosts the optional debug dashboard when enabled.
  • main: CLI entry point built on clap. Allows selecting reader backend, poll interval, config path, and silent mode so the same binary can serve development, test rigs, and the Pi image.

Key Commands

# Run tests (default features only; no audio/NFC backends required)
cargo test

# Map a new card to a track (use either explicit --config or positional CONFIG)
./bin/musicbox add --config config/demo.toml --track songs/track.mp3 --card deadbeef
./bin/musicbox config/demo.toml add --track songs/track.mp3 --card deadbeef

# On laptops without a reader, omit --card to generate a synthetic UID automatically.
./bin/musicbox add --config config/demo.toml --track songs/track.mp3 --reader noop

# Cross-compile for Raspberry Pi (armv7)
scripts/build-armv7.sh --release
# Include optional features when needed
CARGO_FEATURES="audio-rodio nfc-pcsc" scripts/build-armv7.sh --release
# Enable the debug HTTP surface while cross-compiling
CARGO_FEATURES="debug-http" scripts/build-armv7.sh --release

# Trigger playback without an NFC reader (manual test on Pi)
./bin/musicbox manual trigger --config config/demo.toml deadbeef

# Launch the debug JSON API + dashboard (requires `debug-http` feature)
./bin/musicbox --debug-http 0.0.0.0:3000 --reader noop --silent config/demo.toml

# Visit http://<host>:3000/ for the Tailwind dashboard (status, config editor, controls)

Prebuilt Releases

Tagged builds publish tarballs for both x86_64-unknown-linux-gnu (developer laptops) and armv7-unknown-linux-gnueabihf (Raspberry Pi). Each archive ships with the musicbox binary, config.example.toml, and the sample systemd unit so you can drop the bundle straight onto a Pi or run it locally without compiling from source.

  1. Download the assets from the GitHub Releases page:
    curl -LO https://github.com/sholiday/musicbox/releases/download/v0.1.0/musicbox-v0.1.0-armv7-unknown-linux-gnueabihf.tar.gz
    curl -LO https://github.com/sholiday/musicbox/releases/download/v0.1.0/musicbox-v0.1.0-armv7-unknown-linux-gnueabihf.tar.gz.sha256
  2. Verify the checksum and unpack:
    sha256sum -c musicbox-v0.1.0-armv7-unknown-linux-gnueabihf.tar.gz.sha256
    tar -xzf musicbox-v0.1.0-armv7-unknown-linux-gnueabihf.tar.gz
  3. Copy musicbox into ~/musicbox/bin/, and place the bundled config/service files wherever your deployment expects them.

Substitute the desired version/tag and target architecture in the commands above. The x86_64 tarball is convenient for quick local smoke tests with the noop reader, while the armv7 build includes the ALSA and PC/SC backends required on the Pi.

Deploy to a Raspberry Pi

# Copy the binary and sample config to the Pi (host `carter` shown here)
scp target/armv7-unknown-linux-gnueabihf/release/musicbox carter:~/musicbox/bin/musicbox
scp examples/config.example.toml carter:~/musicbox/config/demo.toml

# Start the service with the debug HTTP endpoint exposed
ssh carter 'cd ~/musicbox && ./bin/musicbox --debug-http 0.0.0.0:3000 --reader noop --silent ./config/demo.toml'

# Confirm the server is reachable (or open http://carter:3000/status in a browser)
ssh carter 'curl http://127.0.0.1:3000/status'
# Run with Rodio audio support (requires system audio libs)
cargo test --features audio-rodio

# Run with PC/SC reader support (requires libpcsclite headers)
cargo test --features nfc-pcsc

# Combine features as needed
cargo test --features "audio-rodio nfc-pcsc"

# Include the optional debug HTTP server
cargo test --features "audio-rodio nfc-pcsc debug-http"

Git Hooks

To automatically run the test suite before every commit, point Git at the bundled hooks:

git config core.hooksPath .githooks

Documentation

  • mdBook sources live in docs/src. Install mdBook with cargo install mdbook if it is not already available.
  • Use mdbook serve docs for a live-reloading preview while editing.
  • .github/workflows/docs.yml builds the book and publishes it to GitHub Pages on pushes to main.

Binary Usage

# Example using clap CLI options
cargo run --release --features "audio-rodio nfc-pcsc" -- \
  --poll-interval-ms 200 \
  --reader auto \
  --silent \
  /path/to/config.toml

Options:

  • CONFIG (positional): path to the TOML config mapping card UIDs to tracks.
  • --poll-interval-ms: adjust NFC polling interval (default 200 ms).
  • --reader {auto|pcsc|noop}: force reader choice; auto tries PC/SC then falls back to noop.
  • --silent: skip audio playback regardless of backend availability.
  • --debug-http <addr> (requires debug-http feature): expose telemetry via Axum (e.g. 127.0.0.1:3000).

A starter config can be found in examples/config.example.toml.

Quiet-Hours Volume

Add a [volume] table to the config to control playback levels throughout the day. The default value (0.0–1.0) is applied during normal hours, while one or more [[volume.quiet_hours]] entries can override the volume between a start and end time (24-hour HH:MM format). Windows may span midnight, and each entry must declare its own volume multiplier. Example:

[volume]
default = 1.0

[[volume.quiet_hours]]
start = "19:30"
end = "07:00"
volume = 0.4

With this configuration, every track will play at 40% volume after 7:30 PM until 7:00 AM; outside of that window playback returns to the default level automatically.

Why the optional features?

The binary needs to run in a few different contexts:

  • CI / developer laptops – usually missing ALSA and PC/SC headers. The default build therefore avoids those dependencies so cargo test stays fast and hermetic.
  • Raspberry Pi image – supply --features "audio-rodio nfc-pcsc" so the concrete Rodio player and PC/SC reader are compiled in and the hardware works at runtime.
  • Debug rigs – when you want the Axum status surface or UI, enable debug-http and pass --debug-http <addr> on the CLI. The server lives on a separate thread to avoid blocking the reader loop.

Keeping these concerns behind feature flags lets us ship one codebase while still producing lightweight binaries for automated pipelines.

Raspberry Pi Targets

  • Build everything from your dev machine; the Pi only needs the deployed binaries. Use scripts/build-armv7.sh to produce the armv7-unknown-linux-gnueabihf artifacts and copy the resulting files under target/armv7-unknown-linux-gnueabihf/{debug,release} to the Pi (e.g., via rsync). The script wires up the required pkg-config environment so ALSA and PC/SC libraries resolve correctly when optional features are enabled.
  • For on-device testing without installing Rust, cross-compile the test harnesses with scripts/build-armv7.sh --tests, copy the executables from target/armv7-unknown-linux-gnueabihf/debug/deps/ to the Pi, and run them there.
  • Until the NFC reader is connected, invoke the manual trigger subcommand to play tracks straight from the command line: ./bin/musicbox manual trigger --config <path/to/config> <card_uid>.
  • Pi 2/3, standard 32‑bit Raspberry Pi OS.
  • NFC reader: ACR122U (PC/SC).
  • Audio: Raspberry Pi audio output via Rodio/CPAL (requires ALSA).

When cross-compiling, ensure the appropriate system libraries (libpcsclite, ALSA) are available in the target sysroot if the corresponding features are enabled.

Development Practices

  • Use tests to drive new behavior (cargo test runs quickly without hardware).
  • Commit early and often with descriptive messages.
  • Avoid mocks unless hardware interaction cannot be reasonably replicated.
  • If external libraries are missing on the dev machine, prefer optional features so the default build stays portable.

Next Steps (as of latest cadence)

  1. Implement a real PC/SC reader loop on the Pi and validate with --features nfc-pcsc.
  2. Integrate Rodio playback on the Pi (--features audio-rodio), handling error reporting for missing audio devices.
  3. Extend configuration (TOML or CLI) to control logging/debug output and prep the Axum-based status UI.

About

NFC tag operated jukebox

Resources

Stars

Watchers

Forks

Packages

No packages published