Stream-decode an audio file to AirPlay frames with bounded memory.
Runs ffmpeg as a port, reads its interleaved s16le stdout, slices it into
352-sample stereo frames, and hands them to AirPlay.Player on demand via
take/2. The alternative — decoding the whole file to one PCM buffer (see
AirPlay.Source.pcm/1) — costs ~2.4 GB for a 4-hour book; this keeps only a
few seconds of frames around at a time.
Flow control comes from ffmpeg's -re flag (read input at its native rate),
set by AirPlay.Source.stream_args/2: ffmpeg only produces PCM at ~1× real
time, which is the same rate Player drains it, so the buffer neither floods
the mailbox nor grows without bound.
Summary
Functions
Wait until the decoder has buffered at least min_frames frames, or until
ffmpeg exits before enough audio is available.
Returns a specification to start this module under a supervisor.
Start a decoder. Options
Take up to n buffered frames. Returns {frames, eos?}. frames may be
shorter than n (or empty) if decoding is briefly behind; eos? is true once
ffmpeg has finished and the buffer is drained.
Functions
@spec await_ready(pid(), pos_integer(), timeout()) :: {:ok, non_neg_integer()} | {:error, term()}
Wait until the decoder has buffered at least min_frames frames, or until
ffmpeg exits before enough audio is available.
Returns a specification to start this module under a supervisor.
See Supervisor.
Start a decoder. Options:
:args— full ffmpeg argument list (seeAirPlay.Source.stream_args/2):ffmpeg— ffmpeg binary (defaults to one found onPATH)
@spec take(pid(), non_neg_integer()) :: {[binary()], boolean()}
Take up to n buffered frames. Returns {frames, eos?}. frames may be
shorter than n (or empty) if decoding is briefly behind; eos? is true once
ffmpeg has finished and the buffer is drained.