MediaIo
Reads media bytes from anywhere Kotlin can reach.
This is how an application plays from its own HTTP client with its own authentication, from an Android content:// URI, from KiteTorrent, from an encrypted store, or from a byte array it already holds.
Threading: called from the demux worker only, one call at a time, never concurrently. Implementations do not need to be thread safe. They may suspend.
Implemented by the FFmpeg backend since the custom AVIO bridge, and accepted at both MediaItem.io and SubtitleSource.io. The demux worker waits on read. When no byte arrives for BufferPolicy.stallTimeout, the engine interrupts the source and the session ends with PlaybackError.SourceStalled. A backend interrupts a read by cancelling its coroutine, so read and seek must suspend in a way that cancellation can end. A read that blocks its thread instead cannot be stopped.
Inheritors
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
Releases whatever this reader holds. Called exactly once by the engine per reader it made, and it must tolerate being called twice: an open that fails part way is unwound from both sides, and a reader that throws on a second close turns a handled failure into a new one.
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.