Decodes one source to PCM and paces it out as timestamped WireChunks.
ffmpeg is used purely as a decoder: it floods raw signed little-endian PCM
into a buffer as fast as it likes. The pacer owns the audio timeline — chunk N
is stamped with start + N * chunk_ms (server clock) and emitted once realtime
is within bufferMs of that play time. Because the server assigns the
timestamps (not arrival order), there is no producer/consumer drift: the only
requirement is to send a chunk before its play deadline, and the bufferMs
lead absorbs all jitter.
source is a binary path/URL, or a 0-arity function returning one (resolved when
the stream starts, e.g. for short-lived signed URLs).
Summary
Functions
Returns a specification to start this module under a supervisor.
The next timestamp this stream will use (µs), so a successor can continue the timeline.
PCM payload as snapcast expects it on the wire for the given bit depth.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
The next timestamp this stream will use (µs), so a successor can continue the timeline.
PCM payload as snapcast expects it on the wire for the given bit depth.
Snapcast has no packed 3-byte PCM format: its shared SampleFormat forces a
4-byte sample for 24-bit (common/sample_format.cpp sets sample_size_ = 4
when bits == 24) — S24_LE carried in a 32-bit word. Crucially, the client's
software volume scales each 4-byte sample as an int32_t
(player.cpp adjustVolume<int32_t> for sampleSize() == 4), so the 24-bit
value must be sign-extended into a valid little-endian int32: the low
3 bytes carry the sample (what the audio backend reads as 24-bit), the high
byte is the sign. ffmpeg emits packed 3-byte s24le, so we widen each sample
to a sign-extended 32-bit word here.
Sending packed 3-byte samples while advertising 24 bits produced static (frame size mismatch); zero-padding the high byte instead produced garbled audio (negative samples read as large positive int32s once volume ≠ 1.0). 16- and 32-bit already match snapcast's sample width and pass through untouched.