feat: expose buffered ranges on VideoPlayerState across all platforms - #244
Open
itboy87 wants to merge 3 commits into
Open
feat: expose buffered ranges on VideoPlayerState across all platforms#244itboy87 wants to merge 3 commits into
itboy87 wants to merge 3 commits into
Conversation
Adds a buffering API to VideoPlayerState so consumers can draw a buffer
indicator on the seek bar:
- bufferedRanges: buffered spans in seconds, sorted and merged
- bufferedPercentage: buffered ahead of the playhead, 0..100 of duration
- bufferedSliderPos: the same value on the 0..1000 sliderPos scale
- isBufferedRangeSupported: whether the backend can report buffering at all
All members have default implementations, so external VideoPlayerState
implementations keep compiling.
Backends:
- Android: ExoPlayer bufferedPosition/bufferedPercentage (single range)
- iOS/macOS: AVPlayerItem.loadedTimeRanges (multi-range)
- Web: HTMLMediaElement.buffered (multi-range)
- Linux: GStreamer buffering query, percent ranges scaled by duration;
local files report the whole duration
- Windows: IMFMediaEngine.GetBuffered for HLS, whole duration for local
files. Progressive network playback runs on IMFSourceReader, which
exposes no buffering data, so isBufferedRangeSupported is false there.
Buffering is polled on a dedicated job on every backend since the buffer
keeps filling while playback is paused.
The Windows native API version is bumped to 3; the macOS and Linux bridges
degrade to "unsupported" if loaded against a native library that predates
nGetBufferedRanges.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add a new `bufferedSummary` function to PlayerScreen displaying buffering details beneath the current playback position. This includes the buffered percentage and time ranges to improve visibility of buffering state, especially during testing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a cross-platform buffering API to
VideoPlayerState, so consumers can draw a bufferindicator behind the seek bar instead of guessing how much media is ready to play.
Every backend funnels its raw values through a shared
normalizeBufferedRangeshelper, socallers get one predictable shape: sorted, non-overlapping, clamped to the duration, with
empty/non-finite entries dropped.
API
New in
commonMain:BufferedRange(start, end)— an@Immutablespan in seconds, withdurationandcontains.VideoPlayerState.bufferedRanges: List<BufferedRange>— the buffered spans, sorted and merged.VideoPlayerState.bufferedPercentage: Float— how far the media is buffered ahead of thecurrent position,
0f..100f.VideoPlayerState.bufferedSliderPos: Float— the same value on the0f..1000fscale used bysliderPos, so it can be drawn directly under the seek bar.VideoPlayerState.isBufferedRangeSupported: Boolean— whether the backend can report bufferingat all. Check it first:
falsemeans "unknown", not "nothing buffered".List<BufferedRange>.bufferedEndAt(position)/.bufferedPercentageAt(position, duration).All members have interface defaults (
false/emptyList()/0f), so this is source-compatiblefor anyone implementing
VideoPlayerState.PreviewableVideoPlayerStategained matchingconstructor parameters for previews and tests.
Platform implementations
Player.getBufferedPositionAVPlayerItem.loadedTimeRangesAVPlayerItem.loadedTimeRangesnGetBufferedRangesJNI entry pointnGetBufferedRangesJNI entry point; local files report the whole durationIMFMediaEnginebuffered rangesisBufferedRangeSupportedisfalseHTMLMediaElement.bufferedprogress,seeked,loadedmetadata,timeupdate; reset onemptiedImplementation details worth flagging:
from the position-update loop — the buffer keeps filling while playback is paused, but the
position loop is stopped in that state.
UnsatisfiedLinkErrorfromnGetBufferedRangesand permanently flipisBufferedRangeSupportedtofalse, so a bundlednative library that predates this change reports "unsupported" instead of throwing on every poll.
bufferedRangesAvailableis backed bymutableStateOfso that flip recomposes.DefaultVideoPlayerStateforwards all three members explicitly to its platformdelegate — because they have interface defaults, omitting them would silently report "no
buffering support".
[start0, end0, start1, end1, …]DoubleArraycapped at 16 ranges, decoded by a shared
decodeNativeBufferedRangeshelper.TimeRangesindexing is guarded, since the browser can mutate the object between the lengthcheck and the read.
Native changes
New
nGetBufferedRangesJNI entry points and their implementations for Linux(
NativeVideoPlayer.c/jni_bridge.c), macOS (NativeVideoPlayer.swift/jni_bridge.c) andWindows (
NativeVideoPlayer.cpp/HLSPlayer.cpp/jni_bridge.cpp). The prebuilt nativelibraries need to be rebuilt for the desktop backends to report ranges; until then they fall
back to "unsupported" rather than failing.
Sample app
The sample's seek bar now draws the buffered ranges as a track behind the slider (the inactive
track was made more translucent so they stay readable), plus a one-line readout under the position
text — e.g.
Buffered 42% · 0:00–1:12— which distinguishes "nothing buffered yet" from "thisbackend cannot report buffering".
Tests
BufferedRangeTest(commonTest, 11 tests) coversduration/contains,bufferedEndAtincludinggaps and empty lists, percentage clamping and unknown/NaN durations, and normalization: sorting,
merging overlapping and touching ranges, dropping empty and non-finite entries, and clamping to
the duration.
Docs
README_VIDEO.MDgains a Buffered Ranges section with a usage snippet, a property table andthe per-platform support table above, plus a feature-list bullet and a TOC entry.