MediaSourceReader typedef

MediaSourceReader = FutureOr<Stream<List<int>>> Function(int start, int end)

Reads a byte range from a MediaSource.

start is inclusive and end is exclusive, matching File.openRead. A source is asked for ranges whenever the cast device seeks, so this must be able to start from an arbitrary offset — returning the whole payload and ignoring the arguments will break seeking.

May return the stream directly, or a Future of one for sources that have to open something first — an Android content:// URI, a network handle, a decrypt handshake. An async function satisfies this directly:

read: (start, end) async {
  final handle = await openSomething();
  return handle.readRange(start, end - start);
}

An async* reader needs a declared return type — an inline async* closure infers against this typedef as Stream<FutureOr<Stream<List<int>>>> and will not compile. Give it a signature instead:

Stream<List<int>> readRange(int start, int end) async* {
  var remaining = end - start;
  final stream = await openStreamAt(start);
  await for (final chunk in stream) {
    if (remaining <= 0) break;      // break also closes the upstream
    yield chunk.length <= remaining ? chunk : chunk.sublist(0, remaining);
    remaining -= chunk.length;
  }
}

The stream must contain exactly end - start bytes. The proxy has already sent that as Content-Length and does not truncate. A source that streams to end-of-file regardless of end — which is the default behaviour of most "open a stream at this offset" APIs — will corrupt the response and break seeking.

Implementation

typedef MediaSourceReader =
    FutureOr<Stream<List<int>>> Function(int start, int end);