{
"path": "/3mkjx5kshds2s",
"site": "at://did:plc:7vdlgi2bflelz7mmuxoqjfcr/site.standard.publication/3maigovix422i",
"tags": [],
"$type": "site.standard.document",
"title": "Rockbox -> Snapcast : FIFO & TCP PCM Sinks",
"content": {
"$type": "pub.leaflet.content",
"pages": [
{
"id": "019dd2b9-4b25-7dd4-8edd-14bf9c422825",
"$type": "pub.leaflet.pages.linearDocument",
"blocks": [
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "This document traces every hop an audio frame takes from the Rockbox C firmware through the Snapcast PCM sinks to a Snapcast server."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Two complementary sinks are available:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 35,
"byteStart": 14
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 68,
"byteStart": 61
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "FIFO / pipe | audio_output = \"fifo\" | Named FIFO or stdout | pipe:// "
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 44,
"byteStart": 15
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 66,
"byteStart": 60
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "TCP (direct) | audio_output = \"snapcast_tcp\" | TCP socket | tcp:// |"
}
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 13,
"byteStart": 4
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
},
{
"index": {
"byteEnd": 51,
"byteStart": 43
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 110,
"byteStart": 102
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "The FIFO sink is the traditional approach: rockboxd writes to a named pipe that snapserver reads. The TCP sink connects directly to snapserver's TCP source port — no FIFO, no filesystem dependency, auto-discoverable via mDNS."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.horizontalRule"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Table of contents"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.orderedList",
"children": [
{
"$type": "pub.leaflet.blocks.orderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 8,
"byteStart": 0
},
"features": [
{
"uri": "#overview",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Overview"
}
},
{
"$type": "pub.leaflet.blocks.orderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 20,
"byteStart": 0
},
"features": [
{
"uri": "#choosing-fifo-vs-tcp",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Choosing FIFO vs TCP"
}
},
{
"$type": "pub.leaflet.blocks.orderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 9,
"byteStart": 0
},
"features": [
{
"uri": "#fifo-sink",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "FIFO sink"
},
"unorderedListChildren": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 9,
"byteStart": 0
},
"features": [
{
"uri": "#fifo-layer-map",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Layer map"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 15,
"byteStart": 0
},
"features": [
{
"uri": "#pcm-sink-vtable-pcm-fifoc",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "PCM sink vtable"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 14,
"byteStart": 0
},
"features": [
{
"uri": "#the-dma-thread",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "The DMA thread"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 22,
"byteStart": 0
},
"features": [
{
"uri": "#fifo-pre-open-strategy",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "FIFO pre-open strategy"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 11,
"byteStart": 0
},
"features": [
{
"uri": "#stdout-mode",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "stdout mode"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 36,
"byteStart": 0
},
"features": [
{
"uri": "#track-transitions-and-eof-prevention",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Track transitions and EOF prevention"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 13,
"byteStart": 0
},
"features": [
{
"uri": "#startup-order-fifo",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Startup order"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 24,
"byteStart": 0
},
"features": [
{
"uri": "#snapserver-configuration-fifo",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Snapserver configuration"
}
}
]
}
},
{
"$type": "pub.leaflet.blocks.orderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 8,
"byteStart": 0
},
"features": [
{
"uri": "#tcp-sink",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "TCP sink"
},
"unorderedListChildren": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 9,
"byteStart": 0
},
"features": [
{
"uri": "#tcp-layer-map",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Layer map"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 15,
"byteStart": 0
},
"features": [
{
"uri": "#pcm-sink-vtable-pcm-tcpc",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "PCM sink vtable"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 20,
"byteStart": 0
},
"features": [
{
"uri": "#connection-lifecycle",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Connection lifecycle"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 18,
"byteStart": 0
},
"features": [
{
"uri": "#reconnect-on-error",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Reconnect on error"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 13,
"byteStart": 0
},
"features": [
{
"uri": "#startup-order-tcp",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Startup order"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 24,
"byteStart": 0
},
"features": [
{
"uri": "#snapserver-configuration-tcp",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Snapserver configuration"
}
}
]
}
},
{
"$type": "pub.leaflet.blocks.orderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 23,
"byteStart": 0
},
"features": [
{
"uri": "#auto-discovery-via-mdns",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Auto-discovery via mDNS"
}
},
{
"$type": "pub.leaflet.blocks.orderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 14,
"byteStart": 0
},
"features": [
{
"uri": "#ffi-boundary-cratessys",
"$type": "pub.leaflet.richtext.facet#link"
}
]
},
{
"index": {
"byteEnd": 24,
"byteStart": 14
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
},
{
"uri": "#ffi-boundary-cratessys",
"$type": "pub.leaflet.richtext.facet#link"
}
]
},
{
"index": {
"byteEnd": 25,
"byteStart": 24
},
"features": [
{
"uri": "#ffi-boundary-cratessys",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "FFI boundary (crates/sys)"
}
},
{
"$type": "pub.leaflet.blocks.orderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 22,
"byteStart": 0
},
"features": [
{
"uri": "#settings-and-startup-cratessettings",
"$type": "pub.leaflet.richtext.facet#link"
}
]
},
{
"index": {
"byteEnd": 37,
"byteStart": 22
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
},
{
"uri": "#settings-and-startup-cratessettings",
"$type": "pub.leaflet.richtext.facet#link"
}
]
},
{
"index": {
"byteEnd": 38,
"byteStart": 37
},
"features": [
{
"uri": "#settings-and-startup-cratessettings",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Settings and startup (crates/settings)"
}
},
{
"$type": "pub.leaflet.blocks.orderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 20,
"byteStart": 0
},
"features": [
{
"uri": "#other-pipe-consumers",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Other pipe consumers"
}
},
{
"$type": "pub.leaflet.blocks.orderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 24,
"byteStart": 0
},
"features": [
{
"uri": "#gotchas-and-known-limits",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "Gotchas and known limits"
}
}
],
"startIndex": 1
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.horizontalRule"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Overview"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 49,
"byteStart": 21
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "Both sinks write raw S16LE stereo PCM at 44100 Hz — the same byte stream snapserver expects regardless of source type. There is no Rust crate involved, both are pure-C PCM sinks with a thin Rust FFI wrapper for configuration."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.horizontalRule"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Choosing FIFO vs TCP"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "| | FIFO sink | TCP sink |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "|---|---|---|"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 48,
"byteStart": 35
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| Filesystem entry required | Yes (/tmp/snapfifo) | No |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 34,
"byteStart": 27
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 43,
"byteStart": 37
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| Snapserver source type | pipe:// | tcp:// |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "| Startup order sensitive | Yes — rockboxd first | Yes — snapserver first |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "| Reconnect on snapserver restart | No (FIFO stays open) | Yes (auto on next play) |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 86,
"byteStart": 65
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| Auto-discovered in UI | No (static virtual device) | Yes (mDNS _snapcast._tcp.local.) |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 44,
"byteStart": 29
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| stdout pipe support | Yes (fifo_path = \"-\") | No |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 20,
"byteStart": 11
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 40,
"byteStart": 23
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 60,
"byteStart": 43
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| Config | fifo_path | snapcast_tcp_host + snapcast_tcp_port |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 8,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "Use FIFO when you want stdout piping or prefer the traditional pipe model."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 7,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "Use TCP when you want UI-based auto-discovery, multiple snapservers, or don't want a filesystem dependency."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.horizontalRule"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "FIFO sink"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "FIFO layer map"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "plaintext",
"plaintext": "\n┌────────────────────────────────────────────────────────┐\n│ Rockbox C firmware (pcm.c, audio thread) │\n│ pcm_play_data() → sink.ops.play() │\n│ pcm_play_dma_complete_callback() per chunk │\n└───────────────────┬────────────────────────────────────┘\n │ raw S16LE stereo PCM chunks\n┌───────────────────▼────────────────────────────────────┐\n│ firmware/target/hosted/pcm-fifo.c │\n│ pcm_fifo_set_path() — pre-creates FIFO, opens fd │\n│ sink_dma_start() — spawns fifo_thread │\n│ fifo_thread() — blocking write() loop │\n│ sink_dma_stop() — signals thread, keeps fd │\n└───────────────────┬────────────────────────────────────┘\n │ blocking write() to FIFO or stdout\n┌───────────────────▼────────────────────────────────────┐\n│ Named FIFO (/tmp/snapfifo) or stdout │\n└───────────────────┬────────────────────────────────────┘\n │ read()\n┌───────────────────▼────────────────────────────────────┐\n│ snapserver (pipe:// source) │\n│ — or — │\n│ ffplay / aplay / custom consumer │\n└────────────────────────────────────────────────────────┘\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"facets": [
{
"index": {
"byteEnd": 27,
"byteStart": 17
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "PCM sink vtable (pcm-fifo.c)"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 33,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 60,
"byteStart": 45
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "firmware/target/hosted/pcm-fifo.c implements struct pcm_sink:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "| Op | Implementation |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "|-------------------|-------------------------------------------------------------|"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 6,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 27,
"byteStart": 9
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| init | pthread_mutex_init (recursive) |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 10,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| postinit | no-op |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 10,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| set_freq | no-op (output is always 44100 Hz; snapserver must match) |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 6,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 15,
"byteStart": 9
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 43,
"byteStart": 18
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| lock / unlock | pthread_mutex_lock/unlock |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 6,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 23,
"byteStart": 9
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 66,
"byteStart": 55
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| play | sink_dma_start — opens fd if needed, spawns fifo_thread |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 6,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 22,
"byteStart": 9
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| stop | sink_dma_stop — signals thread, joins; keeps fd open |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 13,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 54,
"byteStart": 37
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 72,
"byteStart": 58
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "fifo_pcm_sink is registered at index PCM_SINK_FIFO = 1 in firmware/pcm.c."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "The DMA thread"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 26,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 105,
"byteStart": 94
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "sink_dma_start(addr, size) stores the initial PCM pointer/length under the mutex, then spawns fifo_thread. The thread mimics a hardware DMA interrupt"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "loop:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "plaintext",
"plaintext": "\nwhile not stopped:\n\n 1. lock → grab (data, size) → clear pcm_data/pcm_size → unlock\n\n 2. while size > 0 and not stopped:\n\n n = write(fifo_fd, data, size)\n\n handle EINTR/EAGAIN (retry)\n\n advance data pointer, decrement size\n\n 3. lock → pcm_play_dma_complete_callback(OK, &pcm_data, &pcm_size) → unlock\n\n 4. if no more data: break\n\n 5. pcm_play_dma_status_callback(STARTED)\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Pacing comes naturally from the blocking FIFO write — the kernel suspends the"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "thread until the reader drains data, locking throughput to the consumer's rate."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "FIFO pre-open strategy"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 23,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "pcm_fifo_set_path(path) is called once at startup:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 4,
"plaintext": "1. Create the FIFO"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "c",
"plaintext": "\nmkfifo(path, 0666); // EEXIST is ignored\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 4,
"plaintext": "2. Open with a permanent writer reference"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "c",
"plaintext": "\nfd = open(path, O_RDWR | O_NONBLOCK);\n\n// then clear O_NONBLOCK:\n\nfcntl(fd, F_SETFL, flags & ~O_NONBLOCK);\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 4,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
},
{
"index": {
"byteEnd": 10,
"byteStart": 4
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
},
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
},
{
"index": {
"byteEnd": 11,
"byteStart": 10
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
},
{
"index": {
"byteEnd": 28,
"byteStart": 20
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 70,
"byteStart": 63
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Why O_RDWR? Opening O_WRONLY blocks until a reader is present. O_RDWR succeeds immediately and keeps the open-writer-count at ≥1 for the process lifetime — snapserver never sees premature EOF between tracks."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 10,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
},
{
"index": {
"byteEnd": 20,
"byteStart": 10
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
},
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
},
{
"index": {
"byteEnd": 21,
"byteStart": 20
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
},
{
"index": {
"byteEnd": 123,
"byteStart": 113
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 149,
"byteStart": 142
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Why clear O_NONBLOCK? Writes must block when the kernel buffer is full to provide natural back-pressure. Leaving O_NONBLOCK set would produce EAGAIN and corrupt the stream."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "stdout mode"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 20,
"byteStart": 5
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "When fifo_path = \"-\", the sink writes to stdout:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "sh",
"plaintext": "\nrockboxd | ffplay -f s16le -ar 44100 -ac 2 -\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 22,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 94,
"byteStart": 86
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "pcm_fifo_set_path(\"-\") redirects fd 1 to stderr before any PCM is written so internal printf() output never pollutes the PCM stream."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "Track transitions and EOF prevention"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 15,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 24,
"byteStart": 21
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
},
{
"index": {
"byteEnd": 38,
"byteStart": 31
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 142,
"byteStart": 135
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "sink_dma_stop() does not close fifo_fd. On POSIX, a named FIFO's read end sees EOF only when all write-side fds are closed. By keeping fifo_fd open across track boundaries, snapserver sees a continuous stream with no gaps."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "Startup order (FIFO)"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 38,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "rockboxd must start before snapserver."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "plaintext",
"plaintext": "\n1. rockboxd starts → pcm_fifo_set_path() → FIFO created, O_RDWR fd held\n\n2. snapserver starts → opens FIFO O_RDONLY → blocks until data flows\n\n3. Playback begins → fifo_thread writes → snapserver distributes to clients\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "Snapserver configuration (FIFO)"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "ini",
"plaintext": "\n# /etc/snapserver.conf (or /usr/local/etc/snapserver.conf on macOS)\n\n[stream]\n\nsource = pipe:///tmp/snapfifo?name=default&sampleformat=44100:16:2\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.blockquote",
"facets": [
{
"index": {
"byteEnd": 47,
"byteStart": 45
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "On macOS, snapserver ≥ v0.35.0 ignores the -s CLI flag. Use the config"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.blockquote",
"plaintext": "file."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.horizontalRule"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "TCP sink"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "TCP layer map"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "plaintext",
"plaintext": "\n┌────────────────────────────────────────────────────────┐\n│ Rockbox C firmware (pcm.c, audio thread) │\n│ pcm_play_data() → sink.ops.play() │\n│ pcm_play_dma_complete_callback() per chunk │\n└───────────────────┬────────────────────────────────────┘\n │ raw S16LE stereo PCM chunks\n┌───────────────────▼──────────────────────────────────────┐\n│ firmware/target/hosted/pcm-tcp.c │\n│ pcm_tcp_set_host() / pcm_tcp_set_port() │\n│ sink_dma_start() — connects if needed, spawns thread │\n│ tcp_thread() — blocking write() loop │\n│ sink_dma_stop() — signals thread, keeps socket │\n└───────────────────┬──────────────────────────────────────┘\n │ blocking write() over TCP\n┌───────────────────▼────────────────────────────────────┐\n│ TCP socket (snapserver host:port) │\n└───────────────────┬────────────────────────────────────┘\n │ recv()\n┌───────────────────▼────────────────────────────────────┐\n│ snapserver (tcp:// source, server mode) │\n│ │ │\n│ ┌───┴──────┬──────────┐ │\n│ ▼ ▼ ▼ │\n│ snapclient snapclient snapclient │\n└────────────────────────────────────────────────────────┘\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"facets": [
{
"index": {
"byteEnd": 26,
"byteStart": 17
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "PCM sink vtable (pcm-tcp.c)"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 32,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 59,
"byteStart": 44
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "firmware/target/hosted/pcm-tcp.c implements struct pcm_sink:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "| Op | Implementation |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "|-------------------|-------------------------------------------------------------|"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 6,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 27,
"byteStart": 9
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| init | pthread_mutex_init (recursive) |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 10,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| postinit | no-op |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 10,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| set_freq | no-op (output is always 44100 Hz; snapserver must match) |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 6,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 15,
"byteStart": 9
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 43,
"byteStart": 18
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| lock / unlock | pthread_mutex_lock/unlock |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 6,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 23,
"byteStart": 9
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 65,
"byteStart": 55
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| play | sink_dma_start — connects if needed, spawns tcp_thread |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 6,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 22,
"byteStart": 9
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| stop | sink_dma_stop — signals thread, joins; keeps socket open |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 12,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 61,
"byteStart": 36
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "tcp_pcm_sink is registered at index PCM_SINK_SNAPCAST_TCP = 6 in"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 14,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "firmware/pcm.c."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "Connection lifecycle"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 16,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 41,
"byteStart": 23
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 55,
"byteStart": 45
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "sink_dma_start() calls tcp_connect_once() if tcp_fd < 0:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "c",
"plaintext": "\nstatic int tcp_connect_once(void)\n\n{\n\n // getaddrinfo(tcp_host, port) → socket() → connect()\n\n // returns fd on success, -1 on failure (logs error, drops audio)\n\n}\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 37,
"byteStart": 31
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 48,
"byteStart": 42
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "The socket is kept open across stop() → play() transitions, just as the FIFO fd is. snapserver's reader sees a continuous stream between tracks."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "Reconnect on error"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 10,
"byteStart": 3
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 38,
"byteStart": 33
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 50,
"byteStart": 40
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 70,
"byteStart": 59
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 100,
"byteStart": 89
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 126,
"byteStart": 111
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 160,
"byteStart": 144
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 177,
"byteStart": 167
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 208,
"byteStart": 199
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "If write() returns a hard error (EPIPE, ECONNRESET, etc.), tcp_thread closes the socket (tcp_fd = -1) and sets tcp_stop = true. The next call tosink_dma_start() finds tcp_fd < 0 and attempts a fresh connect(). This handles snapserver restarts gracefully — the connection is re-established automatically on the next track or resume."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "Startup order (TCP)"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 64,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "snapserver must be running and listening before playback starts."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "plaintext",
"plaintext": "\n1. snapserver starts → listens on tcp://0.0.0.0:4953\n\n2. rockboxd starts → pcm_tcp_set_host/port() stores config\n\n3. Playback begins → sink_dma_start() → tcp_connect_once() → connects\n\n4. tcp_thread writes → snapserver receives → distributes to clients\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 110,
"byteStart": 104
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Unlike the FIFO sink there is no permanent pre-connection at startup. The socket is opened on the first play() call."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "Snapserver configuration (TCP)"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "ini",
"plaintext": "\n# /etc/snapserver.conf (or /usr/local/etc/snapserver.conf on macOS)\n\n[stream]\n\nsource = tcp://0.0.0.0:4953?name=default&sampleformat=44100:16:2\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 13,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "settings.toml (manual config, not needed when selecting from the UI):"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "toml",
"plaintext": "\naudio_output = \"snapcast_tcp\"\n\nsnapcast_tcp_host = \"192.168.1.x\" # IP of the machine running snapserver\n\nsnapcast_tcp_port = 4953 # default snapserver TCP source port\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.horizontalRule"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Auto-discovery via mDNS"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 62,
"byteStart": 41
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "snapserver advertises itself via mDNS as _snapcast._tcp.local.. rockboxd"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 61,
"byteStart": 38
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "scans for this service at startup via scan_snapcast_servers() in"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 25,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 62,
"byteStart": 41
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "crates/server/src/scan.rs, which browses _snapcast._tcp.local. using the"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 7,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "mdns-sd crate and adds discovered servers to the shared devices list."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Discovered servers appear immediately in:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 6,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "Web UI — the device picker in the control bar (lime-green radio icon)"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 18,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "Desktop app (GPUI) — the device picker popup"
}
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 59,
"byteStart": 35
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Clicking a discovered server calls PUT /devices/:id/connect, which:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.orderedList",
"children": [
{
"$type": "pub.leaflet.blocks.orderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 33,
"byteStart": 6
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 67,
"byteStart": 38
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Calls pcm_tcp_set_host(device.ip) and pcm_tcp_set_port(device.port)."
}
},
{
"$type": "pub.leaflet.blocks.orderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 44,
"byteStart": 6
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Calls pcm_switch_sink(PCM_SINK_SNAPCAST_TCP)."
}
},
{
"$type": "pub.leaflet.blocks.orderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 38,
"byteStart": 9
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 57,
"byteStart": 40
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Persists audio_output = \"snapcast_tcp\", snapcast_tcp_host, and"
}
}
],
"startIndex": 1
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 23,
"byteStart": 10
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "No manual settings.toml editing is needed when using the UI."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.horizontalRule"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"facets": [
{
"index": {
"byteEnd": 24,
"byteStart": 14
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "FFI boundary (crates/sys)"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "FIFO"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "rust",
"plaintext": "\n// crates/sys/src/lib.rs\n\nextern \"C\" { fn pcm_fifo_set_path(path: *const c_char); }\n\n\n// crates/sys/src/sound/pcm.rs\n\npub fn fifo_set_path(path: &str) {\n\n let cpath = CString::new(path).expect(\"path must not contain null bytes\");\n\n unsafe { crate::pcm_fifo_set_path(cpath.as_ptr()) }\n\n std::mem::forget(cpath); // C code stores and re-reads pointer at runtime\n\n}\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "TCP"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "rust",
"plaintext": "\n// crates/sys/src/lib.rs\n\nextern \"C\" {\n\n fn pcm_tcp_set_host(host: *const c_char);\n\n fn pcm_tcp_set_port(port: c_ushort);\n\n}\n\n\n// crates/sys/src/sound/pcm.rs\n\npub fn tcp_set_host(host: &str) {\n\n let chost = CString::new(host).expect(\"host must not contain null bytes\");\n\n unsafe { crate::pcm_tcp_set_host(chost.as_ptr()) }\n\n std::mem::forget(chost);\n\n}\n\n\npub fn tcp_set_port(port: u16) {\n\n unsafe { crate::pcm_tcp_set_port(port) }\n\n}\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 16,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 118,
"byteStart": 104
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "std::mem::forget is used in both cases because the C code stores the raw pointer and reads it later (in sink_dma_start's connect / fallback path)."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 20,
"byteStart": 13
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Dropping the CString would free the memory while C holds a dangling pointer."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Since these are startup-time config calls, leaking is acceptable."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.horizontalRule"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"facets": [
{
"index": {
"byteEnd": 37,
"byteStart": 22
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Settings and startup (crates/settings)"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 42,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "crates/settings/src/lib.rs:load_settings() handles both sinks:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "rust",
"plaintext": "\nSome(\"fifo\") => {\n\n let path = settings.fifo_path.as_deref().unwrap_or(\"/tmp/rockbox.fifo\");\n\n pcm::fifo_set_path(path);\n\n pcm::switch_sink(pcm::PCM_SINK_FIFO);\n\n}\n\nSome(\"snapcast_tcp\") => {\n\n if let Some(ref host) = settings.snapcast_tcp_host {\n\n let port = settings.snapcast_tcp_port.unwrap_or(4953);\n\n pcm::tcp_set_host(host);\n\n pcm::tcp_set_port(port);\n\n pcm::switch_sink(pcm::PCM_SINK_SNAPCAST_TCP);\n\n }\n\n}\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "All Snapcast settings keys"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "| Key | Type | Default | Sink | Description |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "|----------------------|--------|-----------------------|-------|------------------------------------------|"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 14,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 35,
"byteStart": 26
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 51,
"byteStart": 45
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 69,
"byteStart": 55
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| audio_output | string | \"builtin\" | both | \"fifo\" or \"snapcast_tcp\" |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 11,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 42,
"byteStart": 23
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 69,
"byteStart": 66
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| fifo_path | string | \"/tmp/rockbox.fifo\" | FIFO | FIFO path, or \"-\" for stdout |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 19,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| snapcast_tcp_host | string | — | TCP | IP / hostname of the snapserver machine |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 19,
"byteStart": 2
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 32,
"byteStart": 28
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "| snapcast_tcp_port | u16 | 4953 | TCP | snapserver TCP source port |"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.horizontalRule"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Other pipe consumers"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Since both sinks carry raw S16LE stereo 44100 Hz PCM, the FIFO sink works with any tool that accepts that format:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "sh",
"plaintext": "\n# Play directly with ffplay (stdout mode)\n\nrockboxd | ffplay -f s16le -ar 44100 -ac 2 -\n\n\n# Encode on the fly\n\nrockboxd | ffmpeg -f s16le -ar 44100 -ac 2 -i - output.mp3\n\n\n# Play with sox\n\nrockboxd | play -t raw -r 44100 -e signed -b 16 -c 2 -\n\n\n# Inspect levels with aplay (Linux)\n\nrockboxd | aplay -f S16_LE -r 44100 -c 2\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 36,
"byteStart": 21
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "All of these require fifo_path = \"-\" and are only available with the FIFO sink. The TCP sink does not support stdout mode."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.horizontalRule"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Gotchas and known limits"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "1. Startup order is critical for both sinks"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 4,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "FIFO: rockboxd must open the FIFO before snapserver. Reverse order causes"
}
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 3,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "TCP: snapserver must be listening before playback starts. If snapserver"
}
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "2. Fixed 44100 Hz, S16LE stereo"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 32,
"byteStart": 24
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Neither sink resamples. set_freq is a no-op. The firmware resamples tracks internally before they reach the sink, but the output is always 44100 Hz."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 33,
"byteStart": 10
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Configure sampleformat=44100:16:2 on the snapserver side."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "3. No volume control through the sink"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Volume is applied by the Rockbox DSP pipeline before PCM reaches the sink."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Adjust volume through the Rockbox API or client applications."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "4. Consumer back-pressure controls playback speed"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 31,
"byteStart": 24
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Both sinks use blocking write(). A slow or stalled consumer stalls"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 7,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "write(), which stalls the DMA callback loop, which pauses decoding. This is correct for synchronized output but means a crashed consumer freezes"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "playback. Restart snapserver to recover."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"facets": [
{
"index": {
"byteEnd": 24,
"byteStart": 9
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "5. macOS snapserver.conf vs CLI flag"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 6,
"byteStart": 4
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "The -s flag to snapserver is silently ignored on macOS (≥ v0.35.0)."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 43,
"byteStart": 36
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 54,
"byteStart": 48
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Always use the config file for both pipe:// and tcp:// sources."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"plaintext": "6. TCP reconnect drops in-flight buffer"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 33,
"byteStart": 28
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "When the write loop detects EPIPE it closes the socket immediately. The current audio buffer is discarded. Reconnection happens on the next"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 16,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "sink_dma_start() call, so there will be a brief audio gap when snapserver restarts."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 3,
"facets": [
{
"index": {
"byteEnd": 23,
"byteStart": 16
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 39,
"byteStart": 31
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "7. Logging uses tracing, never println!"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 55,
"byteStart": 48
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 65,
"byteStart": 57
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 79,
"byteStart": 70
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 189,
"byteStart": 166
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "All Rust-side diagnostic output must go through tracing. println! and eprintln! bypass the log filter and — in stdout/FIFO mode — can corrupt the PCM stream. Use RUST_LOG=debug rockboxd to see debug output on stderr.\n\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.horizontalRule"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 40,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
},
{
"index": {
"byteEnd": 72,
"byteStart": 40
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
},
{
"uri": "https://github.com/tsirysndr/rockbox-zig",
"$type": "pub.leaflet.richtext.facet#link"
}
]
},
{
"index": {
"byteEnd": 73,
"byteStart": 72
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
}
],
"plaintext": "The full implementation is available at github.com/tsirysndr/rockbox-zig."
}
}
]
}
]
},
"bskyPostRef": {
"cid": "bafyreielexybiprmjp22f3ofkgy7xpikauw5tx3z4ev6fovs6dxuf2bea4",
"uri": "at://did:plc:7vdlgi2bflelz7mmuxoqjfcr/app.bsky.feed.post/3mkjx5pisuk2m",
"commit": {
"cid": "bafyreia4troau77hmsijgoq4pidoyyqthfhy7q4jvgybnjxeectojtvsfu",
"rev": "3mkjx5pkf5o2w"
},
"validationStatus": "valid"
},
"description": "",
"publishedAt": "2026-04-28T06:24:02.128Z"
}