Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add Squeezelite sink documentation

+34 -4
+34 -4
CLAUDE.md
··· 2 2 3 3 ## Project overview 4 4 5 - Rockbox Zig is a modern wrapper around the [Rockbox](https://www.rockbox.org) open-source audio player firmware. It adds Rust/Zig services on top of the C firmware to expose gRPC, GraphQL, HTTP, and MPD APIs, a Typesense-backed search engine, Chromecast/AirPlay/Snapcast output sinks, and a desktop/web UI. 5 + Rockbox Zig is a modern wrapper around the [Rockbox](https://www.rockbox.org) open-source audio player firmware. It adds Rust/Zig services on top of the C firmware to expose gRPC, GraphQL, HTTP, and MPD APIs, a Typesense-backed search engine, Chromecast/AirPlay/Snapcast/Squeezelite output sinks, and a desktop/web UI. 6 6 7 7 The binary is called **`rockboxd`**. It is a single executable built by Zig that links: 8 8 - The Rockbox C firmware (compiled by Make into `build-lib/libfirmware.a` and friends) ··· 18 18 build-lib/ Out-of-tree Make build directory (generated; do not edit) 19 19 crates/ Rust workspace 20 20 airplay/ ALAC encoder + RAOP/RTP sender (AirPlay 1 output) 21 + slim/ Slim Protocol + HTTP broadcast server (Squeezelite multi-room output) 21 22 cli/ Entry point compiled to librockbox_cli.a (staticlib) 22 23 server/ gRPC / HTTP server 23 24 settings/ load_settings() — reads settings.toml, applies sinks ··· 87 88 audio_output = "airplay" 88 89 airplay_host = "192.168.1.x" # RAOP receiver IP 89 90 airplay_port = 5000 # optional, default 5000 91 + 92 + audio_output = "squeezelite" 93 + squeezelite_port = 3483 # optional, Slim Protocol port (default 3483) 94 + squeezelite_http_port = 9999 # optional, HTTP PCM stream port (default 9999) 95 + ``` 96 + 97 + Run one or more squeezelite clients pointing at rockboxd for multi-room: 98 + ```sh 99 + squeezelite -s localhost -n "Living Room" 100 + squeezelite -s localhost -n "Kitchen" 90 101 ``` 91 102 92 103 ## PCM sink architecture ··· 95 106 96 107 | Enum constant | Value | Implementation file | 97 108 |--------------------|-------|---------------------------------------------| 98 - | `PCM_SINK_BUILTIN` | 0 | `firmware/target/hosted/sdl/pcm-sdl.c` | 99 - | `PCM_SINK_FIFO` | 1 | `firmware/target/hosted/pcm-fifo.c` | 100 - | `PCM_SINK_AIRPLAY` | 2 | `firmware/target/hosted/pcm-airplay.c` | 109 + | `PCM_SINK_BUILTIN` | 0 | `firmware/target/hosted/sdl/pcm-sdl.c` | 110 + | `PCM_SINK_FIFO` | 1 | `firmware/target/hosted/pcm-fifo.c` | 111 + | `PCM_SINK_AIRPLAY` | 2 | `firmware/target/hosted/pcm-airplay.c` | 112 + | `PCM_SINK_SQUEEZELITE` | 3 | `firmware/target/hosted/pcm-squeezelite.c` | 101 113 102 114 `crates/settings/src/lib.rs:load_settings()` reads `audio_output` and calls `pcm::switch_sink()`. 103 115 ··· 120 132 - `rtsp.rs` — synchronous RTSP client: ANNOUNCE (SDP) → SETUP → RECORD 121 133 - `pcm_airplay_connect()` is called once per `sink_dma_start()` (idempotent if already connected). 122 134 - The `rockbox-airplay` rlib must be force-included in `librockbox_cli.a` via the `use rockbox_airplay::_link_airplay as _` shim in `crates/cli/src/lib.rs`. 135 + 136 + ### Squeezelite sink (Slim Protocol + HTTP broadcast) 137 + - `crates/slim/` implements a Slim Protocol TCP server and an HTTP PCM broadcast server, both in pure Rust. 138 + - `slimproto.rs` — accepts squeezelite connections; sends `STRM 's'` pointing at the HTTP port; replies to every `STMt` heartbeat with `audg` to prevent squeezelite's 36-second watchdog from firing. 139 + - `http.rs` — concurrent HTTP server (one thread per client); each client gets an independent `BroadcastReceiver` cursor into the shared buffer, enabling true multi-room playback. 140 + - `lib.rs` — `BroadcastBuffer`: sequence-numbered chunks, per-reader cursors, 4 MB cap with oldest-first eviction; lagging readers skip forward rather than blocking the writer. 141 + - `firmware/target/hosted/pcm-squeezelite.c` paces the DMA loop to real time using `CLOCK_MONOTONIC`. **Use `int64_t` for the nanosecond diff** — unsigned subtraction wraps catastrophically when `tv_nsec` rolls over. 142 + - The `rockbox-slim` rlib must be force-included via `use rockbox_slim::_link_slim as _` in `crates/cli/src/lib.rs`. 143 + - **Slim Protocol framing**: client→server is `opcode[4] + u32_t length BE + payload`; server→client is `u16_t length BE + opcode[4] + payload` (length does NOT include the 2-byte length field itself). 144 + - **ASCII-encoded PCM fields in STRM**: squeezelite subtracts `'0'` from `pcm_sample_size`, `pcm_sample_rate`, `pcm_channels`, `pcm_endianness`. Correct values: `'1'` (16-bit), `'3'` (44100 Hz), `'2'` (stereo), `'1'` (little-endian). 123 145 124 146 ## Key cross-cutting concerns 125 147 ··· 175 197 # Verify AirPlay symbols are present 176 198 nm zig/zig-out/bin/rockboxd | grep pcm_airplay 177 199 200 + # Verify squeezelite symbols are present 201 + nm zig/zig-out/bin/rockboxd | grep pcm_squeezelite 202 + 178 203 # Verify a crate is in the staticlib 179 204 ar t target/release/librockbox_cli.a | grep airplay 205 + ar t target/release/librockbox_cli.a | grep slim 206 + 207 + # Multi-room squeezelite test 208 + squeezelite -s localhost -n "Room 1" 209 + squeezelite -s localhost -n "Room 2" 180 210 ```