The audio output abstraction lives inDocumentation Index
Fetch the complete documentation index at: https://rockboxzig.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
firmware/export/pcm_sink.h. Each
sink implements a pcm_sink_ops vtable:
Built-in sinks
| Enum constant | Value | Implementation |
|---|---|---|
PCM_SINK_BUILTIN | 0 | firmware/target/hosted/sdl/pcm-sdl.c |
PCM_SINK_FIFO | 1 | firmware/target/hosted/pcm-fifo.c |
PCM_SINK_AIRPLAY | 2 | firmware/target/hosted/pcm-airplay.c |
PCM_SINK_SQUEEZELITE | 3 | firmware/target/hosted/pcm-squeezelite.c |
PCM_SINK_CHROMECAST | 4 | firmware/target/hosted/pcm-chromecast.c |
PCM_SINK_SNAPCAST_TCP | 5 | firmware/target/hosted/pcm-snapcast-tcp.c |
PCM_SINK_UPNP | 6 | firmware/target/hosted/pcm-upnp.c |
crates/settings/src/lib.rs:load_settings(),
which reads audio_output and calls pcm::switch_sink(). Rust-side
constants and helpers live in crates/sys/src/sound/pcm.rs.
FIFO sink details (Snapcast)
- Pre-creates the named FIFO with
O_RDWR|O_NONBLOCKinpcm_fifo_set_path()then clearsO_NONBLOCK. Holding a write reference prevents readers from seeing premature EOF between tracks. sink_dma_stop()does not close the fd; it stays open across track transitions.- Startup order matters: rockboxd must start before snapserver.
AirPlay sink details
pcm_airplay_connect()is called once persink_dma_start()and is idempotent if already connected.- The
rockbox-airplayrlib is force-included viause rockbox_airplay::_link_airplay as _incrates/cli/src/lib.rs. Without that shim the linker would garbage-collect the symbols.
Squeezelite sink details
- The DMA loop in
pcm-squeezelite.cpaces output to real time usingCLOCK_MONOTONIC. - Use
int64_tfor the nanosecond diff — unsigned subtraction wraps catastrophically whentv_nsecrolls over. This is a real bug we hit; if you touch this code, keep it signed. - The
rockbox-slimrlib is force-included viause rockbox_slim::_link_slim as _.
Adding a new sink
- Create
firmware/target/hosted/pcm-<name>.c— model onpcm-fifo.c. - Add
PCM_SINK_<NAME>to the enum infirmware/export/pcm_sink.h. - Register
&<name>_pcm_sinkin thesinks[]array infirmware/pcm.c. - Add
target/hosted/pcm-<name>.cinside the#if PLATFORM_HOSTEDblock infirmware/SOURCES. - Add a Rust constant
PCM_SINK_<NAME>: i32incrates/sys/src/sound/pcm.rs. - Add a
set_<name>_*wrapper if configuration is needed. - Handle the new sink in
crates/settings/src/lib.rs:load_settings(). - If it has a Rust implementation in a new crate: add a
_link_<name>()dummy fn and reference it fromcrates/cli/src/lib.rsto force inclusion in the staticlib.
Logging from a sink
Always usetracing from Rust. Never eprintln!/println! — they bypass
the structured log filter and pollute stdout (which breaks FIFO mode).
RUST_LOG, e.g.
RUST_LOG=rockbox_airplay=debug,info rockboxd.