diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 9befa059e0..a316e536f9 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -192,6 +192,7 @@ This release includes the following changes since the `DefaultPreloadManager` which uses `PreloadMediaSource` to preload media samples of the sources into memory, and uses an integer `rankingData` that indicates the index of an item on the UI. + * Use data class for `LoadControl` methods instead of individual parameters. * Add `PlayerId` to most methods of `LoadControl` to enable `LoadControl` implementations to support multiple players. * Remove `Buffer.isDecodeOnly()` and `C.BUFFER_FLAG_DECODE_ONLY`. There is diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultLoadControl.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultLoadControl.java index 682267355d..9066566b7a 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultLoadControl.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultLoadControl.java @@ -379,47 +379,42 @@ public class DefaultLoadControl implements LoadControl { } @Override - public boolean shouldContinueLoading(LoadParameters loadParameters) { - PlayerLoadingState playerLoadingState = - checkNotNull(loadingStates.get(loadParameters.playerId)); + public boolean shouldContinueLoading(Parameters parameters) { + PlayerLoadingState playerLoadingState = checkNotNull(loadingStates.get(parameters.playerId)); boolean targetBufferSizeReached = allocator.getTotalBytesAllocated() >= calculateTotalTargetBufferBytes(); long minBufferUs = this.minBufferUs; - if (loadParameters.playbackSpeed > 1) { + if (parameters.playbackSpeed > 1) { // The playback speed is faster than real time, so scale up the minimum required media // duration to keep enough media buffered for a playout duration of minBufferUs. long mediaDurationMinBufferUs = - Util.getMediaDurationForPlayoutDuration(minBufferUs, loadParameters.playbackSpeed); + Util.getMediaDurationForPlayoutDuration(minBufferUs, parameters.playbackSpeed); minBufferUs = min(mediaDurationMinBufferUs, maxBufferUs); } // Prevent playback from getting stuck if minBufferUs is too small. minBufferUs = max(minBufferUs, 500_000); - if (loadParameters.bufferedDurationUs < minBufferUs) { + if (parameters.bufferedDurationUs < minBufferUs) { playerLoadingState.isLoading = prioritizeTimeOverSizeThresholds || !targetBufferSizeReached; - if (!playerLoadingState.isLoading && loadParameters.bufferedDurationUs < 500_000) { + if (!playerLoadingState.isLoading && parameters.bufferedDurationUs < 500_000) { Log.w( "DefaultLoadControl", "Target buffer size reached with less than 500ms of buffered media data."); } - } else if (loadParameters.bufferedDurationUs >= maxBufferUs || targetBufferSizeReached) { + } else if (parameters.bufferedDurationUs >= maxBufferUs || targetBufferSizeReached) { playerLoadingState.isLoading = false; } // Else don't change the loading state. return playerLoadingState.isLoading; } @Override - public boolean shouldStartPlayback( - PlayerId playerId, - Timeline timeline, - MediaPeriodId mediaPeriodId, - long bufferedDurationUs, - float playbackSpeed, - boolean rebuffering, - long targetLiveOffsetUs) { - bufferedDurationUs = Util.getPlayoutDurationForMediaDuration(bufferedDurationUs, playbackSpeed); - long minBufferDurationUs = rebuffering ? bufferForPlaybackAfterRebufferUs : bufferForPlaybackUs; - if (targetLiveOffsetUs != C.TIME_UNSET) { - minBufferDurationUs = min(targetLiveOffsetUs / 2, minBufferDurationUs); + public boolean shouldStartPlayback(Parameters parameters) { + long bufferedDurationUs = + Util.getPlayoutDurationForMediaDuration( + parameters.bufferedDurationUs, parameters.playbackSpeed); + long minBufferDurationUs = + parameters.rebuffering ? bufferForPlaybackAfterRebufferUs : bufferForPlaybackUs; + if (parameters.targetLiveOffsetUs != C.TIME_UNSET) { + minBufferDurationUs = min(parameters.targetLiveOffsetUs / 2, minBufferDurationUs); } return minBufferDurationUs <= 0 || bufferedDurationUs >= minBufferDurationUs 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 3bb94e5508..872fbeec82 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java @@ -1975,13 +1975,16 @@ import java.util.concurrent.atomic.AtomicBoolean; return isBufferedToEnd || isAdPendingPreparation || loadControl.shouldStartPlayback( - playerId, - playbackInfo.timeline, - playingPeriodHolder.info.id, - getTotalBufferedDurationUs(), - mediaClock.getPlaybackParameters().speed, - isRebuffering, - targetLiveOffsetUs); + new LoadControl.Parameters( + playerId, + playbackInfo.timeline, + playingPeriodHolder.info.id, + playingPeriodHolder.toPeriodTime(rendererPositionUs), + getTotalBufferedDurationUs(), + mediaClock.getPlaybackParameters().speed, + playbackInfo.playWhenReady, + isRebuffering, + targetLiveOffsetUs)); } private boolean isTimelineReady() { @@ -2577,14 +2580,21 @@ import java.util.concurrent.atomic.AtomicBoolean; ? loadingPeriodHolder.toPeriodTime(rendererPositionUs) : loadingPeriodHolder.toPeriodTime(rendererPositionUs) - loadingPeriodHolder.info.startPositionUs; - LoadParameters loadParameters = new LoadParameters( - playerId, - playbackInfo.timeline, - loadingPeriodHolder.info.id, - playbackPositionUs, - bufferedDurationUs, - mediaClock.getPlaybackParameters().speed, - playbackInfo.playWhenReady); + long targetLiveOffsetUs = + shouldUseLivePlaybackSpeedControl(playbackInfo.timeline, loadingPeriodHolder.info.id) + ? livePlaybackSpeedControl.getTargetLiveOffsetUs() + : C.TIME_UNSET; + LoadControl.Parameters loadParameters = + new LoadControl.Parameters( + playerId, + playbackInfo.timeline, + loadingPeriodHolder.info.id, + playbackPositionUs, + bufferedDurationUs, + mediaClock.getPlaybackParameters().speed, + playbackInfo.playWhenReady, + isRebuffering, + targetLiveOffsetUs); boolean shouldContinueLoading = loadControl.shouldContinueLoading(loadParameters); MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod(); if (!shouldContinueLoading @@ -2595,8 +2605,7 @@ import java.util.concurrent.atomic.AtomicBoolean; // and try again in case it's blocked on memory usage of the back buffer. playingPeriodHolder.mediaPeriod.discardBuffer( playbackInfo.positionUs, /* toKeyframe= */ false); - shouldContinueLoading = - loadControl.shouldContinueLoading(loadParameters); + shouldContinueLoading = loadControl.shouldContinueLoading(loadParameters); } return shouldContinueLoading; } 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 378fef914b..3602250be6 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/LoadControl.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/LoadControl.java @@ -16,6 +16,7 @@ package androidx.media3.exoplayer; import androidx.media3.common.C; +import androidx.media3.common.Player; import androidx.media3.common.Timeline; import androidx.media3.common.TrackGroup; import androidx.media3.common.util.UnstableApi; @@ -30,6 +31,88 @@ import androidx.media3.exoplayer.upstream.Allocator; @UnstableApi public interface LoadControl { + /** + * Information about the current playback context and the {@link MediaPeriod} for which {@link + * LoadControl} methods are called. + */ + final class Parameters { + /** The {@linkplain PlayerId ID of the player}. */ + public final PlayerId playerId; + + /** The current {@link Timeline} of the player. */ + public final Timeline timeline; + + /** + * The {@link MediaPeriodId} of the affected {@link MediaPeriod} in the current {@link + * #timeline}. + */ + public final MediaPeriodId mediaPeriodId; + + /** + * The current playback position in microseconds, relative to the start of the affected {@link + * MediaPeriod} identified by {@link #mediaPeriodId}. If playback of this period has not yet + * started, the value will be negative and equal in magnitude to the duration of any media in + * previous periods still to be played. + */ + public final long playbackPositionUs; + + /** The total duration of media that's currently buffered. */ + public final long bufferedDurationUs; + + /** The current factor by which playback is sped up. */ + public final float playbackSpeed; + + /** Whether playback should proceed when {@link Player#STATE_READY}. */ + public final boolean playWhenReady; + + /** + * Whether the player is rebuffering. A rebuffer is defined to be caused by buffer depletion + * rather than a user action. Hence this parameter is false during initial buffering and when + * buffering as a result of a seek operation. + */ + public final boolean rebuffering; + + /** + * The desired playback position offset to the live edge in microseconds, or {@link + * C#TIME_UNSET} if the media is not a live stream or no offset is configured. + */ + public final long targetLiveOffsetUs; + + /** + * Creates parameters for {@link LoadControl} methods. + * + * @param playerId See {@link #playerId}. + * @param timeline See {@link #timeline}. + * @param mediaPeriodId See {@link #mediaPeriodId}. + * @param playbackPositionUs See {@link #playbackPositionUs}. + * @param bufferedDurationUs See {@link #bufferedDurationUs}. + * @param playbackSpeed See {@link #playbackSpeed}. + * @param playWhenReady See {@link #playWhenReady}. + * @param rebuffering See {@link #rebuffering}. + * @param targetLiveOffsetUs See {@link #targetLiveOffsetUs}. + */ + public Parameters( + PlayerId playerId, + Timeline timeline, + MediaPeriodId mediaPeriodId, + long playbackPositionUs, + long bufferedDurationUs, + float playbackSpeed, + boolean playWhenReady, + boolean rebuffering, + long targetLiveOffsetUs) { + this.playerId = playerId; + this.timeline = timeline; + this.mediaPeriodId = mediaPeriodId; + this.playbackPositionUs = playbackPositionUs; + this.bufferedDurationUs = bufferedDurationUs; + this.playbackSpeed = playbackSpeed; + this.playWhenReady = playWhenReady; + this.rebuffering = rebuffering; + this.targetLiveOffsetUs = targetLiveOffsetUs; + } + } + /** * @deprecated Used as a placeholder when MediaPeriodId is unknown. Only used when the deprecated * methods {@link #onTracksSelected(Renderer[], TrackGroupArray, ExoTrackSelection[])} or @@ -220,38 +303,18 @@ public interface LoadControl { * returns true, the {@link MediaPeriod} identified in the most recent {@link #onTracksSelected} * call will continue being loaded. * - * @param loadParameters Parameters for Load Control. Refer to {@link LoadParameters} for more - * information on the individual parameters + * @param parameters Information about the playback context and the {@link MediaPeriod} that will + * continue to load if this method returns {@code true}. * @return Whether the loading should continue. */ @SuppressWarnings("deprecation") - default boolean shouldContinueLoading(final LoadParameters loadParameters) { + default boolean shouldContinueLoading(Parameters parameters) { return shouldContinueLoading( - loadParameters.playerId, - loadParameters.timeline, - loadParameters.mediaPeriodId, - loadParameters.playbackPositionUs, - loadParameters.bufferedDurationUs, - loadParameters.playbackSpeed); + parameters.playbackPositionUs, parameters.bufferedDurationUs, parameters.playbackSpeed); } /** - * @deprecated Implement {@link #shouldContinueLoading(LoadParameters)} instead. - */ - @SuppressWarnings("deprecation") // Calling deprecated version of this method. - @Deprecated - default boolean shouldContinueLoading( - PlayerId playerId, - Timeline timeline, - MediaPeriodId mediaPeriodId, - long playbackPositionUs, - long bufferedDurationUs, - float playbackSpeed) { - return shouldContinueLoading(playbackPositionUs, bufferedDurationUs, playbackSpeed); - } - - /** - * @deprecated Implement {@link #shouldContinueLoading(LoadParameters)} instead. + * @deprecated Implement {@link #shouldContinueLoading(Parameters)} instead. */ @Deprecated default boolean shouldContinueLoading( @@ -267,43 +330,25 @@ public interface LoadControl { * determines whether playback is actually started. The load control may opt to return {@code * false} until some condition has been met (e.g. a certain amount of media is buffered). * - * @param playerId The {@linkplain PlayerId ID of the player} that wants to start playback. - * @param timeline The current {@link Timeline} in ExoPlayer. Can be {@link Timeline#EMPTY} only - * when the deprecated {@link #shouldStartPlayback(long, float, boolean, long)} was called. - * @param mediaPeriodId Identifies (in the current timeline) the {@link MediaPeriod} for which - * playback will start. Will be {@link #EMPTY_MEDIA_PERIOD_ID} when {@code timeline} is empty. - * @param bufferedDurationUs The duration of media that's currently buffered. - * @param playbackSpeed The current factor by which playback is sped up. - * @param rebuffering Whether the player is rebuffering. A rebuffer is defined to be caused by - * buffer depletion rather than a user action. Hence this parameter is false during initial - * buffering and when buffering as a result of a seek operation. - * @param targetLiveOffsetUs The desired playback position offset to the live edge in - * microseconds, or {@link C#TIME_UNSET} if the media is not a live stream or no offset is - * configured. + * @param parameters Information about the playback context and the {@link MediaPeriod} that will + * start playing if this method returns {@code true}. * @return Whether playback should be allowed to start or resume. */ @SuppressWarnings("deprecation") // Calling deprecated version of this method. - default boolean shouldStartPlayback( - PlayerId playerId, - Timeline timeline, - MediaPeriodId mediaPeriodId, - long bufferedDurationUs, - float playbackSpeed, - boolean rebuffering, - long targetLiveOffsetUs) { + default boolean shouldStartPlayback(Parameters parameters) { return shouldStartPlayback( - timeline, - mediaPeriodId, - bufferedDurationUs, - playbackSpeed, - rebuffering, - targetLiveOffsetUs); + parameters.timeline, + parameters.mediaPeriodId, + parameters.bufferedDurationUs, + parameters.playbackSpeed, + parameters.rebuffering, + parameters.targetLiveOffsetUs); } /** - * @deprecated Implement {@link #shouldStartPlayback(PlayerId, Timeline, MediaPeriodId, long, - * float, boolean, long)} instead. + * @deprecated Implement {@link #shouldStartPlayback(Parameters)} instead. */ + @SuppressWarnings("deprecation") // Calling deprecated version of this method. @Deprecated default boolean shouldStartPlayback( Timeline timeline, @@ -312,14 +357,13 @@ public interface LoadControl { float playbackSpeed, boolean rebuffering, long targetLiveOffsetUs) { - // Media3 ExoPlayer will never call this method. This default implementation provides an - // implementation to please the compiler only. - throw new IllegalStateException("shouldStartPlayback not implemented"); + // Media3 ExoPlayer will never call this method. The default implementation is only used to + // forward to the deprecated version below. + return shouldStartPlayback(bufferedDurationUs, playbackSpeed, rebuffering, targetLiveOffsetUs); } /** - * @deprecated Implement {@link #shouldStartPlayback(PlayerId, Timeline, MediaPeriodId, long, - * float, boolean, long)} instead. + * @deprecated Implement {@link #shouldStartPlayback(Parameters)} instead. */ @Deprecated default boolean shouldStartPlayback( diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/LoadParameters.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/LoadParameters.java deleted file mode 100644 index 1c7070a6de..0000000000 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/LoadParameters.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package androidx.media3.exoplayer; - -import androidx.media3.common.Player; -import androidx.media3.common.Timeline; -import androidx.media3.exoplayer.analytics.PlayerId; -import androidx.media3.exoplayer.source.MediaPeriod; -import androidx.media3.exoplayer.source.MediaSource; - -public class LoadParameters { - /* Identifier for a player instance. */ - public final PlayerId playerId; - /* A flexible representation of the structure of media. */ - public final Timeline timeline; - /* Identifier for a {@link MediaPeriod}. */ - public final MediaSource.MediaPeriodId mediaPeriodId; - /* The current playback position in microseconds, relative to the start - * of the {@link Timeline.Period period} that will continue to be loaded if this method - * returns {@code true}. If playback of this period has not yet started, the value will be - * negative and equal in magnitude to the duration of any media in previous periods still to - * be played. - */ - public final long playbackPositionUs; - /* The duration of media that's currently buffered. */ - public final long bufferedDurationUs; - /* The current factor by which playback is sped up. */ - public final float playbackSpeed; - /** Whether playback should proceed when {@link Player#STATE_READY}. */ - public final boolean playWhenReady; - - public LoadParameters(final PlayerId playerId, - final Timeline timeline, - final MediaSource.MediaPeriodId mediaPeriodId, - final long playbackPositionUs, - final long bufferedDurationUs, - final float playbackSpeed, - final boolean playWhenReady) { - this.playerId = playerId; - this.timeline = timeline; - this.mediaPeriodId = mediaPeriodId; - this.playbackPositionUs = playbackPositionUs; - this.bufferedDurationUs = bufferedDurationUs; - this.playbackSpeed = playbackSpeed; - this.playWhenReady = playWhenReady; - } -} 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 afe07beae0..5795d4d811 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/DefaultLoadControlTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/DefaultLoadControlTest.java @@ -80,34 +80,43 @@ public class DefaultLoadControlTest { public void shouldContinueLoading_untilMaxBufferExceeded() { build(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - /* bufferedDurationUs= */ 0L, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + /* bufferedDurationUs= */ 0L, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MAX_BUFFER_US - 1, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MAX_BUFFER_US - 1, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MAX_BUFFER_US, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MAX_BUFFER_US, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); } @@ -128,59 +137,80 @@ public class DefaultLoadControlTest { loadControl.onPrepared(playerId2); // First player is fully buffered. Buffer starts depleting until it falls under min size. loadControl.shouldContinueLoading( - new LoadParameters( - playerId, timeline, mediaPeriodId, - /* playbackPositionUs= */ 0L, MAX_BUFFER_US, SPEED, - false)); + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MAX_BUFFER_US, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET)); // Second player fell below min size and starts loading until max size is reached. - loadControl.shouldContinueLoading(new LoadParameters( - playerId2, - timeline2, - mediaPeriodId2, - /* playbackPositionUs= */ 0L, - MIN_BUFFER_US - 1, - SPEED, - false)); + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId2, + timeline2, + mediaPeriodId2, + /* playbackPositionUs= */ 0L, + MIN_BUFFER_US - 1, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET)); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MAX_BUFFER_US - 1, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MAX_BUFFER_US - 1, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId2, - timeline2, - mediaPeriodId2, - /* playbackPositionUs= */ 0L, - MIN_BUFFER_US, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId2, + timeline2, + mediaPeriodId2, + /* playbackPositionUs= */ 0L, + MIN_BUFFER_US, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MIN_BUFFER_US, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MIN_BUFFER_US, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId2, - timeline2, - mediaPeriodId2, - /* playbackPositionUs= */ 0L, - MAX_BUFFER_US - 1, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId2, + timeline2, + mediaPeriodId2, + /* playbackPositionUs= */ 0L, + MAX_BUFFER_US - 1, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); } @@ -194,44 +224,56 @@ public class DefaultLoadControlTest { build(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MAX_BUFFER_US, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MAX_BUFFER_US, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MAX_BUFFER_US - 1, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MAX_BUFFER_US - 1, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MIN_BUFFER_US, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MIN_BUFFER_US, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MIN_BUFFER_US - 1, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MIN_BUFFER_US - 1, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); } @@ -245,30 +287,43 @@ public class DefaultLoadControlTest { build(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MAX_BUFFER_US, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MAX_BUFFER_US, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - 5 * C.MICROS_PER_SECOND, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + 5 * C.MICROS_PER_SECOND, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, timeline, mediaPeriodId, - /* playbackPositionUs= */ 0L, 500L, SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + 500L, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); } @@ -284,44 +339,56 @@ public class DefaultLoadControlTest { makeSureTargetBufferBytesReached(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - /* bufferedDurationUs= */ 0L, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + /* bufferedDurationUs= */ 0L, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MIN_BUFFER_US - 1, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MIN_BUFFER_US - 1, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MIN_BUFFER_US, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MIN_BUFFER_US, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MAX_BUFFER_US, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MAX_BUFFER_US, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); } @@ -333,56 +400,71 @@ public class DefaultLoadControlTest { // Put loadControl in buffering state. assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - /* bufferedDurationUs= */ 0L, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + /* bufferedDurationUs= */ 0L, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); makeSureTargetBufferBytesReached(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - /* bufferedDurationUs= */ 0L, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + /* bufferedDurationUs= */ 0L, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MIN_BUFFER_US - 1, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MIN_BUFFER_US - 1, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MIN_BUFFER_US, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MIN_BUFFER_US, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MAX_BUFFER_US, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MAX_BUFFER_US, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); } @@ -397,25 +479,31 @@ public class DefaultLoadControlTest { // At normal playback speed, we stop buffering when the buffer reaches the minimum. assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MIN_BUFFER_US, - SPEED, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MIN_BUFFER_US, + SPEED, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); // At double playback speed, we continue loading. assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MIN_BUFFER_US, - /* playbackSpeed= */ 2f, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MIN_BUFFER_US, + /* playbackSpeed= */ 2f, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); } @@ -432,30 +520,36 @@ public class DefaultLoadControlTest { new ExoTrackSelection[0]); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - /* bufferedDurationUs= */ 0L, - /* playbackSpeed= */ 1f, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + /* bufferedDurationUs= */ 0L, + /* playbackSpeed= */ 1f, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); } @Test - public void shouldNotContinueLoadingWithMaxBufferReached_inFastPlayback() { + public void shouldContinueLoading_withMaxBufferReachedInFastPlayback_returnsFalse() { build(); assertThat( - loadControl.shouldContinueLoading(new LoadParameters( - playerId, - timeline, - mediaPeriodId, - /* playbackPositionUs= */ 0L, - MAX_BUFFER_US, - /* playbackSpeed= */ 100f, - false))) + loadControl.shouldContinueLoading( + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0L, + MAX_BUFFER_US, + /* playbackSpeed= */ 100f, + /* playWhenReady= */ false, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); } @@ -465,13 +559,16 @@ public class DefaultLoadControlTest { assertThat( loadControl.shouldStartPlayback( - playerId, - timeline, - mediaPeriodId, - MIN_BUFFER_US, - SPEED, - /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET)) + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0, + MIN_BUFFER_US, + SPEED, + /* playWhenReady= */ true, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); } @@ -487,23 +584,29 @@ public class DefaultLoadControlTest { assertThat( loadControl.shouldStartPlayback( - playerId, - timeline, - mediaPeriodId, - /* bufferedDurationUs= */ 2_999_999L, - SPEED, - /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET)) + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0, + /* bufferedDurationUs= */ 2_999_999L, + SPEED, + /* playWhenReady= */ true, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldStartPlayback( - playerId, - timeline, - mediaPeriodId, - /* bufferedDurationUs= */ 3_000_000L, - SPEED, - /* rebuffering= */ false, - /* targetLiveOffsetUs= */ C.TIME_UNSET)) + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0, + /* bufferedDurationUs= */ 3_000_000L, + SPEED, + /* playWhenReady= */ true, + /* rebuffering= */ false, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); } @@ -518,23 +621,29 @@ public class DefaultLoadControlTest { assertThat( loadControl.shouldStartPlayback( - playerId, - timeline, - mediaPeriodId, - /* bufferedDurationUs= */ 499_999L, - SPEED, - /* rebuffering= */ true, - /* targetLiveOffsetUs= */ 1_000_000L)) + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0, + /* bufferedDurationUs= */ 499_999L, + SPEED, + /* playWhenReady= */ true, + /* rebuffering= */ true, + /* targetLiveOffsetUs= */ 1_000_000L))) .isFalse(); assertThat( loadControl.shouldStartPlayback( - playerId, - timeline, - mediaPeriodId, - /* bufferedDurationUs= */ 500_000L, - SPEED, - /* rebuffering= */ true, - /* targetLiveOffsetUs= */ 1_000_000L)) + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0, + /* bufferedDurationUs= */ 500_000L, + SPEED, + /* playWhenReady= */ true, + /* rebuffering= */ true, + /* targetLiveOffsetUs= */ 1_000_000L))) .isTrue(); } @@ -550,23 +659,29 @@ public class DefaultLoadControlTest { assertThat( loadControl.shouldStartPlayback( - playerId, - timeline, - mediaPeriodId, - /* bufferedDurationUs= */ 3_999_999L, - SPEED, - /* rebuffering= */ true, - /* targetLiveOffsetUs= */ C.TIME_UNSET)) + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0, + /* bufferedDurationUs= */ 3_999_999L, + SPEED, + /* playWhenReady= */ true, + /* rebuffering= */ true, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isFalse(); assertThat( loadControl.shouldStartPlayback( - playerId, - timeline, - mediaPeriodId, - /* bufferedDurationUs= */ 4_000_000L, - SPEED, - /* rebuffering= */ true, - /* targetLiveOffsetUs= */ C.TIME_UNSET)) + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0, + /* bufferedDurationUs= */ 4_000_000L, + SPEED, + /* playWhenReady= */ true, + /* rebuffering= */ true, + /* targetLiveOffsetUs= */ C.TIME_UNSET))) .isTrue(); } @@ -581,23 +696,29 @@ public class DefaultLoadControlTest { assertThat( loadControl.shouldStartPlayback( - playerId, - timeline, - mediaPeriodId, - /* bufferedDurationUs= */ 499_999L, - SPEED, - /* rebuffering= */ true, - /* targetLiveOffsetUs= */ 1_000_000L)) + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0, + /* bufferedDurationUs= */ 499_999L, + SPEED, + /* playWhenReady= */ true, + /* rebuffering= */ true, + /* targetLiveOffsetUs= */ 1_000_000L))) .isFalse(); assertThat( loadControl.shouldStartPlayback( - playerId, - timeline, - mediaPeriodId, - /* bufferedDurationUs= */ 500_000L, - SPEED, - /* rebuffering= */ true, - /* targetLiveOffsetUs= */ 1_000_000L)) + new LoadControl.Parameters( + playerId, + timeline, + mediaPeriodId, + /* playbackPositionUs= */ 0, + /* bufferedDurationUs= */ 500_000L, + SPEED, + /* playWhenReady= */ true, + /* rebuffering= */ true, + /* targetLiveOffsetUs= */ 1_000_000L))) .isTrue(); } @@ -670,32 +791,6 @@ public class DefaultLoadControlTest { assertThat(loadControl.calculateTotalTargetBufferBytes()).isEqualTo(0); } - @Test - public void shouldContinueLoading_backwardCompatible() { - final LoadControl oldLoadControl = - new DefaultLoadControl() { - @Override - public boolean shouldContinueLoading(LoadParameters loadParameters) { - return super.shouldContinueLoading(loadParameters); - } - - @Override - public boolean shouldContinueLoading( - long playbackPositionUs, long bufferedDurationUs, float playbackSpeed) { - return true; - } - }; - - oldLoadControl.onPrepared(playerId); - - final LoadParameters loadParameters = - new LoadParameters(playerId, timeline, mediaPeriodId, - 0, 0, SPEED, false); - assertThat( - oldLoadControl.shouldContinueLoading(loadParameters)) - .isTrue(); - } - private void build() { builder.setAllocator(allocator).setTargetBufferBytes(TARGET_BUFFER_BYTES); loadControl = builder.build(); diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java index fc04d953c1..fc2db401d2 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java @@ -6046,19 +6046,12 @@ public class ExoPlayerTest { LoadControl neverLoadingLoadControl = new DefaultLoadControl() { @Override - public boolean shouldContinueLoading(LoadParameters loadParameters) { + public boolean shouldContinueLoading(LoadControl.Parameters parameters) { return false; } @Override - public boolean shouldStartPlayback( - PlayerId playerId, - Timeline timeline, - MediaPeriodId mediaPeriodid, - long bufferedDurationUs, - float playbackSpeed, - boolean rebuffering, - long targetLiveOffsetUs) { + public boolean shouldStartPlayback(LoadControl.Parameters parameters) { return true; } }; @@ -6095,25 +6088,12 @@ public class ExoPlayerTest { LoadControl loadControlWithMaxBufferUs = new DefaultLoadControl() { @Override - public boolean shouldContinueLoading( - PlayerId playerId, - Timeline timeline, - MediaPeriodId mediaPeriodid, - long playbackPositionUs, - long bufferedDurationUs, - float playbackSpeed) { - return bufferedDurationUs < maxBufferUs; + public boolean shouldContinueLoading(LoadControl.Parameters parameters) { + return parameters.bufferedDurationUs < maxBufferUs; } @Override - public boolean shouldStartPlayback( - PlayerId playerId, - Timeline timeline, - MediaPeriodId mediaPeriodid, - long bufferedDurationUs, - float playbackSpeed, - boolean rebuffering, - long targetLiveOffsetUs) { + public boolean shouldStartPlayback(LoadControl.Parameters parameters) { return true; } }; @@ -6184,25 +6164,12 @@ public class ExoPlayerTest { LoadControl neverLoadingOrPlayingLoadControl = new DefaultLoadControl() { @Override - public boolean shouldContinueLoading( - PlayerId playerId, - Timeline timeline, - MediaPeriodId mediaPeriodid, - long playbackPositionUs, - long bufferedDurationUs, - float playbackSpeed) { + public boolean shouldContinueLoading(LoadControl.Parameters parameters) { return true; } @Override - public boolean shouldStartPlayback( - PlayerId playerId, - Timeline timeline, - MediaPeriodId mediaPeriodid, - long bufferedDurationUs, - float playbackSpeed, - boolean rebuffering, - long targetLiveOffsetUs) { + public boolean shouldStartPlayback(LoadControl.Parameters parameters) { return false; } };