Merge pull request #2113 from colinkho:lastrebufferinssp

PiperOrigin-RevId: 730919539
(cherry picked from commit 2c866ce50be132858d9cb4c30c174790577f7560)
This commit is contained in:
Copybara-Service 2025-02-25 09:38:40 -08:00 committed by oceanjules
parent c4a77475c4
commit 9052313245
4 changed files with 109 additions and 46 deletions

View File

@ -10,6 +10,8 @@
* Fix a bug where `ExoPlayer.isLoading()` remains `true` while it has
transitioned to `STATE_IDLE` or `STATE_ENDED`
([#2133](https://github.com/androidx/media/issues/2133)).
* Add `lastRebufferRealtimeMs` to `LoadControl.Parameter`
([#2113](https://github.com/androidx/media/pull/2113))
* Transformer:
* Track Selection:
* Extractors:

View File

@ -2169,7 +2169,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
mediaClock.getPlaybackParameters().speed,
playbackInfo.playWhenReady,
isRebuffering,
targetLiveOffsetUs));
targetLiveOffsetUs,
lastRebufferRealtimeMs));
}
private boolean isTimelineReady() {
@ -2889,7 +2890,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
@ -3147,7 +3149,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
mediaClock.getPlaybackParameters().speed,
playbackInfo.playWhenReady,
isRebuffering,
targetLiveOffsetUs),
targetLiveOffsetUs,
lastRebufferRealtimeMs),
trackGroups,
trackSelectorResult.selections);
}

View File

@ -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.
*
* <p>The time base used is the same as that measured by {@link SystemClock#elapsedRealtime}.
*
* <p><b>Note:</b> 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;
}
}

View File

@ -86,7 +86,8 @@ public class DefaultLoadControlTest {
SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
/* targetLiveOffsetUs= */ C.TIME_UNSET,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ C.TIME_UNSET)))
.isFalse();
}
@ -142,7 +145,8 @@ public class DefaultLoadControlTest {
SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET));
/* targetLiveOffsetUs= */ C.TIME_UNSET,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ C.TIME_UNSET)))
.isTrue();
}
@ -230,7 +239,8 @@ public class DefaultLoadControlTest {
SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
/* targetLiveOffsetUs= */ C.TIME_UNSET,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ C.TIME_UNSET)))
.isTrue();
}
@ -293,7 +306,8 @@ public class DefaultLoadControlTest {
SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
/* targetLiveOffsetUs= */ C.TIME_UNSET,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ C.TIME_UNSET)))
.isTrue();
}
@ -345,7 +361,8 @@ public class DefaultLoadControlTest {
SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
/* targetLiveOffsetUs= */ C.TIME_UNSET,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ C.TIME_UNSET)))
.isFalse();
}
@ -406,7 +426,8 @@ public class DefaultLoadControlTest {
SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
/* targetLiveOffsetUs= */ C.TIME_UNSET,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ C.TIME_UNSET)))
.isFalse();
}
@ -485,7 +510,8 @@ public class DefaultLoadControlTest {
SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
/* targetLiveOffsetUs= */ C.TIME_UNSET,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ C.TIME_UNSET)))
.isFalse();
}
@ -570,7 +600,8 @@ public class DefaultLoadControlTest {
SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
/* targetLiveOffsetUs= */ C.TIME_UNSET,
/* lastRebufferRealtimeMs= */ C.TIME_UNSET)))
.isTrue();
}
@ -595,7 +626,8 @@ public class DefaultLoadControlTest {
SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
/* targetLiveOffsetUs= */ C.TIME_UNSET,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ C.TIME_UNSET)))
.isTrue();
}
@ -632,7 +665,8 @@ public class DefaultLoadControlTest {
SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ true,
/* targetLiveOffsetUs= */ 1_000_000L)))
/* targetLiveOffsetUs= */ 1_000_000L,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ C.TIME_UNSET)))
.isTrue();
}
@ -670,7 +705,8 @@ public class DefaultLoadControlTest {
SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ true,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
/* targetLiveOffsetUs= */ C.TIME_UNSET,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ C.TIME_UNSET)))
.isTrue();
}
@ -707,7 +744,8 @@ public class DefaultLoadControlTest {
SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ true,
/* targetLiveOffsetUs= */ 1_000_000L)))
/* targetLiveOffsetUs= */ 1_000_000L,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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,
/* lastRebufferRealtimeMs= */ 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);
}