From dd641c1979166ee3cca1f86dd16e103fa6cfed22 Mon Sep 17 00:00:00 2001 From: Colin Kho Date: Thu, 6 Feb 2025 23:23:42 -0800 Subject: [PATCH] Add lastRebufferRealtimeMs to LoadControl.Parameters --- .../exoplayer/ExoPlayerImplInternal.java | 9 +- .../media3/exoplayer/LoadControl.java | 18 ++- .../exoplayer/DefaultLoadControlTest.java | 126 ++++++++++++------ 3 files changed, 107 insertions(+), 46 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java index af9133ee22..f1b3d2da87 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java @@ -2168,7 +2168,8 @@ import java.util.concurrent.atomic.AtomicBoolean; mediaClock.getPlaybackParameters().speed, playbackInfo.playWhenReady, isRebuffering, - targetLiveOffsetUs)); + targetLiveOffsetUs, + lastRebufferRealtimeMs)); } private boolean isTimelineReady() { @@ -2888,7 +2889,8 @@ import java.util.concurrent.atomic.AtomicBoolean; mediaClock.getPlaybackParameters().speed, playbackInfo.playWhenReady, isRebuffering, - targetLiveOffsetUs); + targetLiveOffsetUs, + lastRebufferRealtimeMs); boolean shouldContinueLoading = loadControl.shouldContinueLoading(loadParameters); MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod(); if (!shouldContinueLoading @@ -3146,7 +3148,8 @@ import java.util.concurrent.atomic.AtomicBoolean; mediaClock.getPlaybackParameters().speed, playbackInfo.playWhenReady, isRebuffering, - targetLiveOffsetUs), + targetLiveOffsetUs, + lastRebufferRealtimeMs), trackGroups, trackSelectorResult.selections); } diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/LoadControl.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/LoadControl.java index 758b392c42..362d973d3a 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/LoadControl.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/LoadControl.java @@ -15,6 +15,7 @@ */ package androidx.media3.exoplayer; +import android.os.SystemClock; import androidx.media3.common.C; import androidx.media3.common.Player; import androidx.media3.common.Timeline; @@ -80,6 +81,18 @@ public interface LoadControl { */ public final long targetLiveOffsetUs; + /** + * Sets the time at which the last rebuffering occurred, in milliseconds since boot including + * time spent in sleep. + * + *

The time base used is the same as that measured by {@link SystemClock#elapsedRealtime}. + * + *

Note: If rebuffer events are not known when the load is started or continued, or if + * no rebuffering has occurred, or if there have been any user interactions such as seeking or + * stopping the player, the value will be set to {@link C#TIME_UNSET}. + */ + public final long lastRebufferRealtimeMs; + /** * Creates parameters for {@link LoadControl} methods. * @@ -92,6 +105,7 @@ public interface LoadControl { * @param playWhenReady See {@link #playWhenReady}. * @param rebuffering See {@link #rebuffering}. * @param targetLiveOffsetUs See {@link #targetLiveOffsetUs}. + * @param lastRebufferRealtimeMs see {@link #lastRebufferRealtimeMs} */ public Parameters( PlayerId playerId, @@ -102,7 +116,8 @@ public interface LoadControl { float playbackSpeed, boolean playWhenReady, boolean rebuffering, - long targetLiveOffsetUs) { + long targetLiveOffsetUs, + long lastRebufferRealtimeMs) { this.playerId = playerId; this.timeline = timeline; this.mediaPeriodId = mediaPeriodId; @@ -112,6 +127,7 @@ public interface LoadControl { this.playWhenReady = playWhenReady; this.rebuffering = rebuffering; this.targetLiveOffsetUs = targetLiveOffsetUs; + this.lastRebufferRealtimeMs = lastRebufferRealtimeMs; } } diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/DefaultLoadControlTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/DefaultLoadControlTest.java index b0185a9f42..c49a549d27 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/DefaultLoadControlTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/DefaultLoadControlTest.java @@ -86,7 +86,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); assertThat( loadControl.shouldContinueLoading( @@ -99,7 +100,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); assertThat( loadControl.shouldContinueLoading( @@ -112,7 +114,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); } @@ -142,7 +145,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET)); + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET)); // Second player fell below min size and starts loading until max size is reached. loadControl.shouldContinueLoading( new LoadControl.Parameters( @@ -154,7 +158,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET)); + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET)); assertThat( loadControl.shouldContinueLoading( @@ -167,7 +172,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldContinueLoading( @@ -180,7 +186,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); assertThat( loadControl.shouldContinueLoading( @@ -193,7 +200,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldContinueLoading( @@ -206,7 +214,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); } @@ -230,7 +239,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldContinueLoading( @@ -243,7 +253,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldContinueLoading( @@ -256,7 +267,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldContinueLoading( @@ -269,7 +281,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); } @@ -293,7 +306,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldContinueLoading( @@ -306,7 +320,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldContinueLoading( @@ -319,7 +334,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); } @@ -345,7 +361,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); assertThat( loadControl.shouldContinueLoading( @@ -358,7 +375,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); assertThat( loadControl.shouldContinueLoading( @@ -371,7 +389,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldContinueLoading( @@ -384,7 +403,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); } @@ -406,7 +426,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); makeSureTargetBufferBytesReached(); @@ -421,7 +442,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldContinueLoading( @@ -434,7 +456,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldContinueLoading( @@ -447,7 +470,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldContinueLoading( @@ -460,7 +484,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); } @@ -485,7 +510,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); // At double playback speed, we continue loading. assertThat( @@ -499,7 +525,8 @@ public class DefaultLoadControlTest { /* playbackSpeed= */ 2f, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); } @@ -517,7 +544,8 @@ public class DefaultLoadControlTest { /* playbackSpeed= */ 1f, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET), + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET), TrackGroupArray.EMPTY, new ExoTrackSelection[0]); @@ -532,7 +560,8 @@ public class DefaultLoadControlTest { /* playbackSpeed= */ 1f, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); } @@ -551,7 +580,8 @@ public class DefaultLoadControlTest { /* playbackSpeed= */ 100f, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); } @@ -570,7 +600,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ true, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); } @@ -595,7 +626,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ true, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldStartPlayback( @@ -608,7 +640,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ true, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); } @@ -632,7 +665,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ true, /* rebuffering= */ true, - /* targetLiveOffsetUs= */ 1_000_000L))) + /* targetLiveOffsetUs= */ 1_000_000L, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldStartPlayback( @@ -645,7 +679,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ true, /* rebuffering= */ true, - /* targetLiveOffsetUs= */ 1_000_000L))) + /* targetLiveOffsetUs= */ 1_000_000L, + C.TIME_UNSET))) .isTrue(); } @@ -670,7 +705,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ true, /* rebuffering= */ true, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldStartPlayback( @@ -683,7 +719,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ true, /* rebuffering= */ true, - /* targetLiveOffsetUs= */ C.TIME_UNSET))) + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET))) .isTrue(); } @@ -707,7 +744,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ true, /* rebuffering= */ true, - /* targetLiveOffsetUs= */ 1_000_000L))) + /* targetLiveOffsetUs= */ 1_000_000L, + C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldStartPlayback( @@ -720,7 +758,8 @@ public class DefaultLoadControlTest { SPEED, /* playWhenReady= */ true, /* rebuffering= */ true, - /* targetLiveOffsetUs= */ 1_000_000L))) + /* targetLiveOffsetUs= */ 1_000_000L, + C.TIME_UNSET))) .isTrue(); } @@ -763,7 +802,8 @@ public class DefaultLoadControlTest { /* playbackSpeed= */ 1.0f, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET), + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET), videoTrackGroupArray, new ExoTrackSelection[] {new FixedTrackSelection(videoTrackGroup, /* track= */ 0)}); loadControl.onTracksSelected( @@ -776,7 +816,8 @@ public class DefaultLoadControlTest { /* playbackSpeed= */ 1.0f, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET), + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET), audioTrackGroupArray, new ExoTrackSelection[] {new FixedTrackSelection(audioTrackGroup, /* track= */ 0)}); @@ -817,7 +858,8 @@ public class DefaultLoadControlTest { /* playbackSpeed= */ 1.0f, /* playWhenReady= */ false, /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET), + /* targetLiveOffsetUs= */ C.TIME_UNSET, + C.TIME_UNSET), /* trackGroups= */ null, /* trackSelections= */ null); }