Move parameters inside LoadControl and use it for shouldStartPlayback

+additional formatting and Javadoc changes
This commit is contained in:
tonihei 2024-05-14 16:26:06 +01:00
parent be5cf6b5fd
commit c46bb24264
7 changed files with 561 additions and 510 deletions

View File

@ -192,6 +192,7 @@ This release includes the following changes since the
`DefaultPreloadManager` which uses `PreloadMediaSource` to preload media `DefaultPreloadManager` which uses `PreloadMediaSource` to preload media
samples of the sources into memory, and uses an integer `rankingData` samples of the sources into memory, and uses an integer `rankingData`
that indicates the index of an item on the UI. 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` * Add `PlayerId` to most methods of `LoadControl` to enable `LoadControl`
implementations to support multiple players. implementations to support multiple players.
* Remove `Buffer.isDecodeOnly()` and `C.BUFFER_FLAG_DECODE_ONLY`. There is * Remove `Buffer.isDecodeOnly()` and `C.BUFFER_FLAG_DECODE_ONLY`. There is

View File

@ -379,47 +379,42 @@ public class DefaultLoadControl implements LoadControl {
} }
@Override @Override
public boolean shouldContinueLoading(LoadParameters loadParameters) { public boolean shouldContinueLoading(Parameters parameters) {
PlayerLoadingState playerLoadingState = PlayerLoadingState playerLoadingState = checkNotNull(loadingStates.get(parameters.playerId));
checkNotNull(loadingStates.get(loadParameters.playerId));
boolean targetBufferSizeReached = boolean targetBufferSizeReached =
allocator.getTotalBytesAllocated() >= calculateTotalTargetBufferBytes(); allocator.getTotalBytesAllocated() >= calculateTotalTargetBufferBytes();
long minBufferUs = this.minBufferUs; 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 // 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. // duration to keep enough media buffered for a playout duration of minBufferUs.
long mediaDurationMinBufferUs = long mediaDurationMinBufferUs =
Util.getMediaDurationForPlayoutDuration(minBufferUs, loadParameters.playbackSpeed); Util.getMediaDurationForPlayoutDuration(minBufferUs, parameters.playbackSpeed);
minBufferUs = min(mediaDurationMinBufferUs, maxBufferUs); minBufferUs = min(mediaDurationMinBufferUs, maxBufferUs);
} }
// Prevent playback from getting stuck if minBufferUs is too small. // Prevent playback from getting stuck if minBufferUs is too small.
minBufferUs = max(minBufferUs, 500_000); minBufferUs = max(minBufferUs, 500_000);
if (loadParameters.bufferedDurationUs < minBufferUs) { if (parameters.bufferedDurationUs < minBufferUs) {
playerLoadingState.isLoading = prioritizeTimeOverSizeThresholds || !targetBufferSizeReached; playerLoadingState.isLoading = prioritizeTimeOverSizeThresholds || !targetBufferSizeReached;
if (!playerLoadingState.isLoading && loadParameters.bufferedDurationUs < 500_000) { if (!playerLoadingState.isLoading && parameters.bufferedDurationUs < 500_000) {
Log.w( Log.w(
"DefaultLoadControl", "DefaultLoadControl",
"Target buffer size reached with less than 500ms of buffered media data."); "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; playerLoadingState.isLoading = false;
} // Else don't change the loading state. } // Else don't change the loading state.
return playerLoadingState.isLoading; return playerLoadingState.isLoading;
} }
@Override @Override
public boolean shouldStartPlayback( public boolean shouldStartPlayback(Parameters parameters) {
PlayerId playerId, long bufferedDurationUs =
Timeline timeline, Util.getPlayoutDurationForMediaDuration(
MediaPeriodId mediaPeriodId, parameters.bufferedDurationUs, parameters.playbackSpeed);
long bufferedDurationUs, long minBufferDurationUs =
float playbackSpeed, parameters.rebuffering ? bufferForPlaybackAfterRebufferUs : bufferForPlaybackUs;
boolean rebuffering, if (parameters.targetLiveOffsetUs != C.TIME_UNSET) {
long targetLiveOffsetUs) { minBufferDurationUs = min(parameters.targetLiveOffsetUs / 2, minBufferDurationUs);
bufferedDurationUs = Util.getPlayoutDurationForMediaDuration(bufferedDurationUs, playbackSpeed);
long minBufferDurationUs = rebuffering ? bufferForPlaybackAfterRebufferUs : bufferForPlaybackUs;
if (targetLiveOffsetUs != C.TIME_UNSET) {
minBufferDurationUs = min(targetLiveOffsetUs / 2, minBufferDurationUs);
} }
return minBufferDurationUs <= 0 return minBufferDurationUs <= 0
|| bufferedDurationUs >= minBufferDurationUs || bufferedDurationUs >= minBufferDurationUs

View File

@ -1975,13 +1975,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
return isBufferedToEnd return isBufferedToEnd
|| isAdPendingPreparation || isAdPendingPreparation
|| loadControl.shouldStartPlayback( || loadControl.shouldStartPlayback(
playerId, new LoadControl.Parameters(
playbackInfo.timeline, playerId,
playingPeriodHolder.info.id, playbackInfo.timeline,
getTotalBufferedDurationUs(), playingPeriodHolder.info.id,
mediaClock.getPlaybackParameters().speed, playingPeriodHolder.toPeriodTime(rendererPositionUs),
isRebuffering, getTotalBufferedDurationUs(),
targetLiveOffsetUs); mediaClock.getPlaybackParameters().speed,
playbackInfo.playWhenReady,
isRebuffering,
targetLiveOffsetUs));
} }
private boolean isTimelineReady() { private boolean isTimelineReady() {
@ -2577,14 +2580,21 @@ import java.util.concurrent.atomic.AtomicBoolean;
? loadingPeriodHolder.toPeriodTime(rendererPositionUs) ? loadingPeriodHolder.toPeriodTime(rendererPositionUs)
: loadingPeriodHolder.toPeriodTime(rendererPositionUs) : loadingPeriodHolder.toPeriodTime(rendererPositionUs)
- loadingPeriodHolder.info.startPositionUs; - loadingPeriodHolder.info.startPositionUs;
LoadParameters loadParameters = new LoadParameters( long targetLiveOffsetUs =
playerId, shouldUseLivePlaybackSpeedControl(playbackInfo.timeline, loadingPeriodHolder.info.id)
playbackInfo.timeline, ? livePlaybackSpeedControl.getTargetLiveOffsetUs()
loadingPeriodHolder.info.id, : C.TIME_UNSET;
playbackPositionUs, LoadControl.Parameters loadParameters =
bufferedDurationUs, new LoadControl.Parameters(
mediaClock.getPlaybackParameters().speed, playerId,
playbackInfo.playWhenReady); playbackInfo.timeline,
loadingPeriodHolder.info.id,
playbackPositionUs,
bufferedDurationUs,
mediaClock.getPlaybackParameters().speed,
playbackInfo.playWhenReady,
isRebuffering,
targetLiveOffsetUs);
boolean shouldContinueLoading = loadControl.shouldContinueLoading(loadParameters); boolean shouldContinueLoading = loadControl.shouldContinueLoading(loadParameters);
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod(); MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
if (!shouldContinueLoading 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. // and try again in case it's blocked on memory usage of the back buffer.
playingPeriodHolder.mediaPeriod.discardBuffer( playingPeriodHolder.mediaPeriod.discardBuffer(
playbackInfo.positionUs, /* toKeyframe= */ false); playbackInfo.positionUs, /* toKeyframe= */ false);
shouldContinueLoading = shouldContinueLoading = loadControl.shouldContinueLoading(loadParameters);
loadControl.shouldContinueLoading(loadParameters);
} }
return shouldContinueLoading; return shouldContinueLoading;
} }

View File

@ -16,6 +16,7 @@
package androidx.media3.exoplayer; package androidx.media3.exoplayer;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Player;
import androidx.media3.common.Timeline; import androidx.media3.common.Timeline;
import androidx.media3.common.TrackGroup; import androidx.media3.common.TrackGroup;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
@ -30,6 +31,88 @@ import androidx.media3.exoplayer.upstream.Allocator;
@UnstableApi @UnstableApi
public interface LoadControl { 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 * @deprecated Used as a placeholder when MediaPeriodId is unknown. Only used when the deprecated
* methods {@link #onTracksSelected(Renderer[], TrackGroupArray, ExoTrackSelection[])} or * 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} * returns true, the {@link MediaPeriod} identified in the most recent {@link #onTracksSelected}
* call will continue being loaded. * call will continue being loaded.
* *
* @param loadParameters Parameters for Load Control. Refer to {@link LoadParameters} for more * @param parameters Information about the playback context and the {@link MediaPeriod} that will
* information on the individual parameters * continue to load if this method returns {@code true}.
* @return Whether the loading should continue. * @return Whether the loading should continue.
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
default boolean shouldContinueLoading(final LoadParameters loadParameters) { default boolean shouldContinueLoading(Parameters parameters) {
return shouldContinueLoading( return shouldContinueLoading(
loadParameters.playerId, parameters.playbackPositionUs, parameters.bufferedDurationUs, parameters.playbackSpeed);
loadParameters.timeline,
loadParameters.mediaPeriodId,
loadParameters.playbackPositionUs,
loadParameters.bufferedDurationUs,
loadParameters.playbackSpeed);
} }
/** /**
* @deprecated Implement {@link #shouldContinueLoading(LoadParameters)} instead. * @deprecated Implement {@link #shouldContinueLoading(Parameters)} 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 @Deprecated
default boolean shouldContinueLoading( default boolean shouldContinueLoading(
@ -267,43 +330,25 @@ public interface LoadControl {
* determines whether playback is actually started. The load control may opt to return {@code * 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). * 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 parameters Information about the playback context and the {@link MediaPeriod} that will
* @param timeline The current {@link Timeline} in ExoPlayer. Can be {@link Timeline#EMPTY} only * start playing if this method returns {@code true}.
* 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.
* @return Whether playback should be allowed to start or resume. * @return Whether playback should be allowed to start or resume.
*/ */
@SuppressWarnings("deprecation") // Calling deprecated version of this method. @SuppressWarnings("deprecation") // Calling deprecated version of this method.
default boolean shouldStartPlayback( default boolean shouldStartPlayback(Parameters parameters) {
PlayerId playerId,
Timeline timeline,
MediaPeriodId mediaPeriodId,
long bufferedDurationUs,
float playbackSpeed,
boolean rebuffering,
long targetLiveOffsetUs) {
return shouldStartPlayback( return shouldStartPlayback(
timeline, parameters.timeline,
mediaPeriodId, parameters.mediaPeriodId,
bufferedDurationUs, parameters.bufferedDurationUs,
playbackSpeed, parameters.playbackSpeed,
rebuffering, parameters.rebuffering,
targetLiveOffsetUs); parameters.targetLiveOffsetUs);
} }
/** /**
* @deprecated Implement {@link #shouldStartPlayback(PlayerId, Timeline, MediaPeriodId, long, * @deprecated Implement {@link #shouldStartPlayback(Parameters)} instead.
* float, boolean, long)} instead.
*/ */
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
@Deprecated @Deprecated
default boolean shouldStartPlayback( default boolean shouldStartPlayback(
Timeline timeline, Timeline timeline,
@ -312,14 +357,13 @@ public interface LoadControl {
float playbackSpeed, float playbackSpeed,
boolean rebuffering, boolean rebuffering,
long targetLiveOffsetUs) { long targetLiveOffsetUs) {
// Media3 ExoPlayer will never call this method. This default implementation provides an // Media3 ExoPlayer will never call this method. The default implementation is only used to
// implementation to please the compiler only. // forward to the deprecated version below.
throw new IllegalStateException("shouldStartPlayback not implemented"); return shouldStartPlayback(bufferedDurationUs, playbackSpeed, rebuffering, targetLiveOffsetUs);
} }
/** /**
* @deprecated Implement {@link #shouldStartPlayback(PlayerId, Timeline, MediaPeriodId, long, * @deprecated Implement {@link #shouldStartPlayback(Parameters)} instead.
* float, boolean, long)} instead.
*/ */
@Deprecated @Deprecated
default boolean shouldStartPlayback( default boolean shouldStartPlayback(

View File

@ -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;
}
}

View File

@ -80,34 +80,43 @@ public class DefaultLoadControlTest {
public void shouldContinueLoading_untilMaxBufferExceeded() { public void shouldContinueLoading_untilMaxBufferExceeded() {
build(); build();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
/* bufferedDurationUs= */ 0L, /* playbackPositionUs= */ 0L,
SPEED, /* bufferedDurationUs= */ 0L,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MAX_BUFFER_US - 1, /* playbackPositionUs= */ 0L,
SPEED, MAX_BUFFER_US - 1,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MAX_BUFFER_US, /* playbackPositionUs= */ 0L,
SPEED, MAX_BUFFER_US,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
} }
@ -128,59 +137,80 @@ public class DefaultLoadControlTest {
loadControl.onPrepared(playerId2); loadControl.onPrepared(playerId2);
// First player is fully buffered. Buffer starts depleting until it falls under min size. // First player is fully buffered. Buffer starts depleting until it falls under min size.
loadControl.shouldContinueLoading( loadControl.shouldContinueLoading(
new LoadParameters( new LoadControl.Parameters(
playerId, timeline, mediaPeriodId, playerId,
/* playbackPositionUs= */ 0L, MAX_BUFFER_US, SPEED, timeline,
false)); 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. // Second player fell below min size and starts loading until max size is reached.
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId2, new LoadControl.Parameters(
timeline2, playerId2,
mediaPeriodId2, timeline2,
/* playbackPositionUs= */ 0L, mediaPeriodId2,
MIN_BUFFER_US - 1, /* playbackPositionUs= */ 0L,
SPEED, MIN_BUFFER_US - 1,
false)); SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET));
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MAX_BUFFER_US - 1, /* playbackPositionUs= */ 0L,
SPEED, MAX_BUFFER_US - 1,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId2, new LoadControl.Parameters(
timeline2, playerId2,
mediaPeriodId2, timeline2,
/* playbackPositionUs= */ 0L, mediaPeriodId2,
MIN_BUFFER_US, /* playbackPositionUs= */ 0L,
SPEED, MIN_BUFFER_US,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MIN_BUFFER_US, /* playbackPositionUs= */ 0L,
SPEED, MIN_BUFFER_US,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId2, new LoadControl.Parameters(
timeline2, playerId2,
mediaPeriodId2, timeline2,
/* playbackPositionUs= */ 0L, mediaPeriodId2,
MAX_BUFFER_US - 1, /* playbackPositionUs= */ 0L,
SPEED, MAX_BUFFER_US - 1,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
} }
@ -194,44 +224,56 @@ public class DefaultLoadControlTest {
build(); build();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MAX_BUFFER_US, /* playbackPositionUs= */ 0L,
SPEED, MAX_BUFFER_US,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MAX_BUFFER_US - 1, /* playbackPositionUs= */ 0L,
SPEED, MAX_BUFFER_US - 1,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MIN_BUFFER_US, /* playbackPositionUs= */ 0L,
SPEED, MIN_BUFFER_US,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MIN_BUFFER_US - 1, /* playbackPositionUs= */ 0L,
SPEED, MIN_BUFFER_US - 1,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
} }
@ -245,30 +287,43 @@ public class DefaultLoadControlTest {
build(); build();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MAX_BUFFER_US, /* playbackPositionUs= */ 0L,
SPEED, MAX_BUFFER_US,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
5 * C.MICROS_PER_SECOND, /* playbackPositionUs= */ 0L,
SPEED, 5 * C.MICROS_PER_SECOND,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, timeline, mediaPeriodId, new LoadControl.Parameters(
/* playbackPositionUs= */ 0L, 500L, SPEED, playerId,
false))) timeline,
mediaPeriodId,
/* playbackPositionUs= */ 0L,
500L,
SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
} }
@ -284,44 +339,56 @@ public class DefaultLoadControlTest {
makeSureTargetBufferBytesReached(); makeSureTargetBufferBytesReached();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
/* bufferedDurationUs= */ 0L, /* playbackPositionUs= */ 0L,
SPEED, /* bufferedDurationUs= */ 0L,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MIN_BUFFER_US - 1, /* playbackPositionUs= */ 0L,
SPEED, MIN_BUFFER_US - 1,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MIN_BUFFER_US, /* playbackPositionUs= */ 0L,
SPEED, MIN_BUFFER_US,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MAX_BUFFER_US, /* playbackPositionUs= */ 0L,
SPEED, MAX_BUFFER_US,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
} }
@ -333,56 +400,71 @@ public class DefaultLoadControlTest {
// Put loadControl in buffering state. // Put loadControl in buffering state.
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
/* bufferedDurationUs= */ 0L, /* playbackPositionUs= */ 0L,
SPEED, /* bufferedDurationUs= */ 0L,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
makeSureTargetBufferBytesReached(); makeSureTargetBufferBytesReached();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
/* bufferedDurationUs= */ 0L, /* playbackPositionUs= */ 0L,
SPEED, /* bufferedDurationUs= */ 0L,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MIN_BUFFER_US - 1, /* playbackPositionUs= */ 0L,
SPEED, MIN_BUFFER_US - 1,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MIN_BUFFER_US, /* playbackPositionUs= */ 0L,
SPEED, MIN_BUFFER_US,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MAX_BUFFER_US, /* playbackPositionUs= */ 0L,
SPEED, MAX_BUFFER_US,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
} }
@ -397,25 +479,31 @@ public class DefaultLoadControlTest {
// At normal playback speed, we stop buffering when the buffer reaches the minimum. // At normal playback speed, we stop buffering when the buffer reaches the minimum.
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MIN_BUFFER_US, /* playbackPositionUs= */ 0L,
SPEED, MIN_BUFFER_US,
false))) SPEED,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
// At double playback speed, we continue loading. // At double playback speed, we continue loading.
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MIN_BUFFER_US, /* playbackPositionUs= */ 0L,
/* playbackSpeed= */ 2f, MIN_BUFFER_US,
false))) /* playbackSpeed= */ 2f,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
} }
@ -432,30 +520,36 @@ public class DefaultLoadControlTest {
new ExoTrackSelection[0]); new ExoTrackSelection[0]);
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
/* bufferedDurationUs= */ 0L, /* playbackPositionUs= */ 0L,
/* playbackSpeed= */ 1f, /* bufferedDurationUs= */ 0L,
false))) /* playbackSpeed= */ 1f,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
} }
@Test @Test
public void shouldNotContinueLoadingWithMaxBufferReached_inFastPlayback() { public void shouldContinueLoading_withMaxBufferReachedInFastPlayback_returnsFalse() {
build(); build();
assertThat( assertThat(
loadControl.shouldContinueLoading(new LoadParameters( loadControl.shouldContinueLoading(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* playbackPositionUs= */ 0L, mediaPeriodId,
MAX_BUFFER_US, /* playbackPositionUs= */ 0L,
/* playbackSpeed= */ 100f, MAX_BUFFER_US,
false))) /* playbackSpeed= */ 100f,
/* playWhenReady= */ false,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
} }
@ -465,13 +559,16 @@ public class DefaultLoadControlTest {
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
MIN_BUFFER_US, mediaPeriodId,
SPEED, /* playbackPositionUs= */ 0,
/* rebuffering= */ false, MIN_BUFFER_US,
/* targetLiveOffsetUs= */ C.TIME_UNSET)) SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
} }
@ -487,23 +584,29 @@ public class DefaultLoadControlTest {
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* bufferedDurationUs= */ 2_999_999L, mediaPeriodId,
SPEED, /* playbackPositionUs= */ 0,
/* rebuffering= */ false, /* bufferedDurationUs= */ 2_999_999L,
/* targetLiveOffsetUs= */ C.TIME_UNSET)) SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* bufferedDurationUs= */ 3_000_000L, mediaPeriodId,
SPEED, /* playbackPositionUs= */ 0,
/* rebuffering= */ false, /* bufferedDurationUs= */ 3_000_000L,
/* targetLiveOffsetUs= */ C.TIME_UNSET)) SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ false,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
} }
@ -518,23 +621,29 @@ public class DefaultLoadControlTest {
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* bufferedDurationUs= */ 499_999L, mediaPeriodId,
SPEED, /* playbackPositionUs= */ 0,
/* rebuffering= */ true, /* bufferedDurationUs= */ 499_999L,
/* targetLiveOffsetUs= */ 1_000_000L)) SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ true,
/* targetLiveOffsetUs= */ 1_000_000L)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* bufferedDurationUs= */ 500_000L, mediaPeriodId,
SPEED, /* playbackPositionUs= */ 0,
/* rebuffering= */ true, /* bufferedDurationUs= */ 500_000L,
/* targetLiveOffsetUs= */ 1_000_000L)) SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ true,
/* targetLiveOffsetUs= */ 1_000_000L)))
.isTrue(); .isTrue();
} }
@ -550,23 +659,29 @@ public class DefaultLoadControlTest {
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* bufferedDurationUs= */ 3_999_999L, mediaPeriodId,
SPEED, /* playbackPositionUs= */ 0,
/* rebuffering= */ true, /* bufferedDurationUs= */ 3_999_999L,
/* targetLiveOffsetUs= */ C.TIME_UNSET)) SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ true,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* bufferedDurationUs= */ 4_000_000L, mediaPeriodId,
SPEED, /* playbackPositionUs= */ 0,
/* rebuffering= */ true, /* bufferedDurationUs= */ 4_000_000L,
/* targetLiveOffsetUs= */ C.TIME_UNSET)) SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ true,
/* targetLiveOffsetUs= */ C.TIME_UNSET)))
.isTrue(); .isTrue();
} }
@ -581,23 +696,29 @@ public class DefaultLoadControlTest {
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* bufferedDurationUs= */ 499_999L, mediaPeriodId,
SPEED, /* playbackPositionUs= */ 0,
/* rebuffering= */ true, /* bufferedDurationUs= */ 499_999L,
/* targetLiveOffsetUs= */ 1_000_000L)) SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ true,
/* targetLiveOffsetUs= */ 1_000_000L)))
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
playerId, new LoadControl.Parameters(
timeline, playerId,
mediaPeriodId, timeline,
/* bufferedDurationUs= */ 500_000L, mediaPeriodId,
SPEED, /* playbackPositionUs= */ 0,
/* rebuffering= */ true, /* bufferedDurationUs= */ 500_000L,
/* targetLiveOffsetUs= */ 1_000_000L)) SPEED,
/* playWhenReady= */ true,
/* rebuffering= */ true,
/* targetLiveOffsetUs= */ 1_000_000L)))
.isTrue(); .isTrue();
} }
@ -670,32 +791,6 @@ public class DefaultLoadControlTest {
assertThat(loadControl.calculateTotalTargetBufferBytes()).isEqualTo(0); 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() { private void build() {
builder.setAllocator(allocator).setTargetBufferBytes(TARGET_BUFFER_BYTES); builder.setAllocator(allocator).setTargetBufferBytes(TARGET_BUFFER_BYTES);
loadControl = builder.build(); loadControl = builder.build();

View File

@ -6046,19 +6046,12 @@ public class ExoPlayerTest {
LoadControl neverLoadingLoadControl = LoadControl neverLoadingLoadControl =
new DefaultLoadControl() { new DefaultLoadControl() {
@Override @Override
public boolean shouldContinueLoading(LoadParameters loadParameters) { public boolean shouldContinueLoading(LoadControl.Parameters parameters) {
return false; return false;
} }
@Override @Override
public boolean shouldStartPlayback( public boolean shouldStartPlayback(LoadControl.Parameters parameters) {
PlayerId playerId,
Timeline timeline,
MediaPeriodId mediaPeriodid,
long bufferedDurationUs,
float playbackSpeed,
boolean rebuffering,
long targetLiveOffsetUs) {
return true; return true;
} }
}; };
@ -6095,25 +6088,12 @@ public class ExoPlayerTest {
LoadControl loadControlWithMaxBufferUs = LoadControl loadControlWithMaxBufferUs =
new DefaultLoadControl() { new DefaultLoadControl() {
@Override @Override
public boolean shouldContinueLoading( public boolean shouldContinueLoading(LoadControl.Parameters parameters) {
PlayerId playerId, return parameters.bufferedDurationUs < maxBufferUs;
Timeline timeline,
MediaPeriodId mediaPeriodid,
long playbackPositionUs,
long bufferedDurationUs,
float playbackSpeed) {
return bufferedDurationUs < maxBufferUs;
} }
@Override @Override
public boolean shouldStartPlayback( public boolean shouldStartPlayback(LoadControl.Parameters parameters) {
PlayerId playerId,
Timeline timeline,
MediaPeriodId mediaPeriodid,
long bufferedDurationUs,
float playbackSpeed,
boolean rebuffering,
long targetLiveOffsetUs) {
return true; return true;
} }
}; };
@ -6184,25 +6164,12 @@ public class ExoPlayerTest {
LoadControl neverLoadingOrPlayingLoadControl = LoadControl neverLoadingOrPlayingLoadControl =
new DefaultLoadControl() { new DefaultLoadControl() {
@Override @Override
public boolean shouldContinueLoading( public boolean shouldContinueLoading(LoadControl.Parameters parameters) {
PlayerId playerId,
Timeline timeline,
MediaPeriodId mediaPeriodid,
long playbackPositionUs,
long bufferedDurationUs,
float playbackSpeed) {
return true; return true;
} }
@Override @Override
public boolean shouldStartPlayback( public boolean shouldStartPlayback(LoadControl.Parameters parameters) {
PlayerId playerId,
Timeline timeline,
MediaPeriodId mediaPeriodid,
long bufferedDurationUs,
float playbackSpeed,
boolean rebuffering,
long targetLiveOffsetUs) {
return false; return false;
} }
}; };