PipedMediaIo
A bounded pipe for bytes that arrive by push: a socket you read yourself, a decryptor, or a download in flight. Your code calls write, then finish or fail. The engine reads.
It reads like a live stream. Its size is unknown and it cannot seek, so the player cannot seek in it or switch its video track. It holds capacityChunks chunks of up to 256 KiB, which is 4 MiB by default, and write waits while it is full.
A pipe is read once. A track switch, a loop or a recovery opens the item again, and that open needs a new pipe with its own producer. So a factory that can reopen makes a new pipe per call:
val item = MediaItem.from(MediaIoFactory { PipedMediaIo().also { scope.launch { produce(it) } } }, "live")Properties
The media type the bytes arrived with, such as the Content-Type of an HTTP response, or null when the reader does not know it. The backend uses it to recognise an HLS playlist whose address does not end in .m3u8.
The address these bytes came from, after any redirect, or null when the reader has none. The backend resolves the relative addresses inside the media against it, such as the segments of an HLS playlist. A reader that sets it should implement openRelated too.
Functions
How fast the network delivers this reader's bytes, in bits per second, or null when the reader does not measure it or has not measured enough yet. The default answers null.
A new reader for uri, an absolute address that this reader's media names, or null to refuse it. An HLS playlist names its variant playlists, segments and keys this way, and the backend opens each one through here. The addresses come from the media, which is untrusted input, so open only the schemes and hosts you expect. The caller closes the reader. The default refuses every address.
Where this reader reports a problem that it recovered from, such as a dropped connection that it opened again. The engine installs its warning reporter here before the first read, and the warnings reach KitePlayer.events. The sink may be called from any thread and must stay cheap. The default ignores it, for a reader with nothing to report.
A server's refusal of an address this reader, or one it opened, had been reading, once, or null, the default (#453). A signed address that expired gets one: the server answers 401 or 403 to the next segment, the next playlist reload or the next range of the file, after the item had opened. The engine asks on its own passes and opens the item again through its resolver or its io factory, which hand out a fresh address, at the position it reached.
The tags the bytes of the last read brought, or null, the default, when it brought none (#423): above all the song an internet radio station names in a title block between its audio bytes. The backend asks after every read that returned bytes, on the thread that read, and the tags belong at the first byte of that read, so a reader that stops each read where its next tags belong places them exactly.