Adapts a single concrete file/stream (Arduino's File, or anything else exposing position(), seek(size_t) and a readBytes(size_t) overload) to SeekableSource, and also drives feeding that same file's bytes into a DemuxerMP4 (or any other AudioWriter with a setSeekSource(SeekableSource&) method) via copy() - replacing the separate CodecCopy/StreamCopy a sketch would otherwise need, and letting this class use just one File for everything instead of requiring two independent handles (one for sequential forward reads, one for the out-of-band seeks SourceSeekSampleTableStore performs).
More...
template<typename FileT, typename WriterT>
class audio_tools::FileSeekableSource< FileT, WriterT >
Adapts a single concrete file/stream (Arduino's File, or anything else exposing position(), seek(size_t) and a readBytes(size_t) overload) to SeekableSource, and also drives feeding that same file's bytes into a DemuxerMP4 (or any other AudioWriter with a setSeekSource(SeekableSource&) method) via copy() - replacing the separate CodecCopy/StreamCopy a sketch would otherwise need, and letting this class use just one File for everything instead of requiring two independent handles (one for sequential forward reads, one for the out-of-band seeks SourceSeekSampleTableStore performs).
That's safe because seek()/readBytes() always come in a matched pair (SourceSeekSampleTableStore::get() never calls one without the other)
- seek() remembers the file's current position before jumping away, and readBytes() restores it immediately after reading, so copy()'s own sequential progress through the file is never disturbed by a table lookup happening in between two copy() calls.
This is the one place the concrete file type appears, isolating SD.h/FS.h's include-order requirements to wherever the including sketch instantiates this adapter (after it has already included SD.h), rather than to this header or to DemuxerMP4 itself.
WriterT is templated (duck-typed on write()+setSeekSource(), rather than a fixed AudioWriter&/DemuxerMP4&) purely to avoid this header having to depend on ContainerMP4.h, which itself depends on this header - a hard circular include otherwise.
'quickStart' (constructor arg, default true): if WriterT has a quickStart() method (e.g. DemuxerMP4's), the first copy() call invokes it automatically. No-op for any WriterT without one. Set to false to skip that check or call writer.quickStart() manually yourself.
template<typename FileT , typename WriterT >
Reads the next chunk from the file and feeds it to the configured AudioWriter, retrying on a partial write - the same contract CodecCopy/StreamCopy follow, since DemuxerMP4::write() (like most Print::write() implementations) may accept fewer bytes than requested in one call. Returns 0 once the file is exhausted.
On the first call, if enabled (see 'quickStart'), runs writer.quickStart() first - not done in the constructor since it must run after writer.begin(), which typically hasn't happened yet at construction time.