Minimal FLAC bitstream framing for Snapcast's flac transport.
Snapcast does not send a .flac file: it sends the FLAC stream header once (as a
flac CodecHeader) and then the audio split into whole FLAC frames, each in its
own timestamped WireChunk. The client's decoder resets its input on every chunk and
loops process_single until the chunk is drained, so a frame may never span two
chunks — every chunk payload must be a whole number of frames
(client/decoder/flac_decoder.cpp).
This module turns the raw FLAC byte stream produced by ffmpeg into exactly that:
take_header/1peels offfLaC+ the metadata blocks (through the last-metadata-block flag) — the CodecHeader payload.take_frame/2peels off one whole audio frame at a time, reporting its blocksize (sample count) so the caller can stamp each WireChunk on the server clock.
Frame boundaries are found the way libFLAC finds them: scan for the 14-bit frame sync, then accept the candidate only if its frame header's CRC-8 checks out.
Summary
Functions
Parse a FLAC frame header at the front of bin.
Peel one whole FLAC audio frame off the front of buf (which must start at a frame
boundary).
Split off the FLAC metadata header (fLaC + metadata blocks through the
last-metadata-block) from the front of data.
Functions
Parse a FLAC frame header at the front of bin.
Returns {:ok, blocksize, header_len} (sample count + header byte length),
:need_more, or :invalid.
Peel one whole FLAC audio frame off the front of buf (which must start at a frame
boundary).
{:ok, frame, blocksize, rest}—frameis a whole frame decoding toblocksizesamples;restis the remaining bytes.:incomplete— the next frame boundary is not yet visible; supply more bytes.{:error, :not_frame_aligned}—bufdoes not start with a valid frame header.
eof? true means no more bytes will arrive, so the trailing bytes are the final
frame.
Split off the FLAC metadata header (fLaC + metadata blocks through the
last-metadata-block) from the front of data.
Returns {:ok, header, rest} once the whole header is present, :incomplete if more
bytes are needed, or :error if data is not a FLAC stream.