Commit 6a3e2a64 by Googler Committed by Tianyi Feng

Allow associating LoadControl methods with the relevant MediaPeriod.

PiperOrigin-RevId: 520037412
parent e44e3377
......@@ -20,6 +20,7 @@ import static java.lang.Math.max;
import static java.lang.Math.min;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.source.MediaPeriodId;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
import com.google.android.exoplayer2.upstream.Allocator;
......@@ -327,7 +328,11 @@ public class DefaultLoadControl implements LoadControl {
@Override
public void onTracksSelected(
Renderer[] renderers, TrackGroupArray trackGroups, ExoTrackSelection[] trackSelections) {
Timeline timeline,
MediaPeriodId mediaPeriodId,
Renderer[] renderers,
TrackGroupArray trackGroups,
ExoTrackSelection[] trackSelections) {
targetBufferBytes =
targetBufferBytesOverwrite == C.LENGTH_UNSET
? calculateTargetBufferBytes(renderers, trackSelections)
......@@ -389,7 +394,12 @@ public class DefaultLoadControl implements LoadControl {
@Override
public boolean shouldStartPlayback(
long bufferedDurationUs, float playbackSpeed, boolean rebuffering, long targetLiveOffsetUs) {
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) {
......
......@@ -1815,8 +1815,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
return true;
}
// Renderers are ready and we're loading. Ask the LoadControl whether to transition.
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
long targetLiveOffsetUs =
shouldUseLivePlaybackSpeedControl(playbackInfo.timeline, queue.getPlayingPeriod().info.id)
shouldUseLivePlaybackSpeedControl(playbackInfo.timeline, playingPeriodHolder.info.id)
? livePlaybackSpeedControl.getTargetLiveOffsetUs()
: C.TIME_UNSET;
MediaPeriodHolder loadingHolder = queue.getLoadingPeriod();
......@@ -1828,6 +1829,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
return isBufferedToEnd
|| isAdPendingPreparation
|| loadControl.shouldStartPlayback(
playbackInfo.timeline,
playingPeriodHolder.info.id,
getTotalBufferedDurationUs(),
mediaClock.getPlaybackParameters().speed,
isRebuffering,
......@@ -2283,7 +2286,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
loadingPeriodHolder.handlePrepared(
mediaClock.getPlaybackParameters().speed, playbackInfo.timeline);
updateLoadControlTrackSelection(
loadingPeriodHolder.getTrackGroups(), loadingPeriodHolder.getTrackSelectorResult());
loadingPeriodHolder.info.id,
loadingPeriodHolder.getTrackGroups(),
loadingPeriodHolder.getTrackSelectorResult());
if (loadingPeriodHolder == queue.getPlayingPeriod()) {
// This is the first prepared period, so update the position and the renderers.
resetRendererPosition(loadingPeriodHolder.info.startPositionUs);
......@@ -2568,6 +2573,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
&& loadingMediaPeriodHolder != null
&& loadingMediaPeriodHolder.prepared) {
updateLoadControlTrackSelection(
loadingMediaPeriodHolder.info.id,
loadingMediaPeriodHolder.getTrackGroups(),
loadingMediaPeriodHolder.getTrackSelectorResult());
}
......@@ -2588,8 +2594,15 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
private void updateLoadControlTrackSelection(
TrackGroupArray trackGroups, TrackSelectorResult trackSelectorResult) {
loadControl.onTracksSelected(renderers, trackGroups, trackSelectorResult.selections);
MediaPeriodId mediaPeriodId,
TrackGroupArray trackGroups,
TrackSelectorResult trackSelectorResult) {
loadControl.onTracksSelected(
playbackInfo.timeline,
mediaPeriodId,
renderers,
trackGroups,
trackSelectorResult.selections);
}
private boolean shouldPlayWhenReady() {
......
......@@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaPeriodId;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
......@@ -23,18 +25,49 @@ import com.google.android.exoplayer2.upstream.Allocator;
/** Controls buffering of media. */
public interface LoadControl {
/**
* @deprecated Used as a placeholder when MediaPeriodId is unknown. Only used when the deprecated
* methods {@link #onTracksSelected(Renderer[], TrackGroupArray, ExoTrackSelection[])} or
* {@link #shouldStartPlayback(long, float, boolean, long)} are called.
*/
@Deprecated
MediaPeriodId EMPTY_MEDIA_PERIOD_ID = new MediaPeriodId(/* periodUid= */ new Object());
/** Called by the player when prepared with a new source. */
void onPrepared();
/**
* Called by the player when a track selection occurs.
*
* @param timeline The current {@link Timeline} in ExoPlayer. Can be {@link Timeline#EMPTY} only
* when the deprecated {@link #onTracksSelected(Renderer[], TrackGroupArray,
* ExoTrackSelection[])} was called.
* @param mediaPeriodId Identifies (in the current timeline) the {@link MediaPeriod} for which the
* selection was made. Will be {@link #EMPTY_MEDIA_PERIOD_ID} when {@code timeline} is empty.
* @param renderers The renderers.
* @param trackGroups The {@link TrackGroup}s from which the selection was made.
* @param trackSelections The track selections that were made.
*/
void onTracksSelected(
Renderer[] renderers, TrackGroupArray trackGroups, ExoTrackSelection[] trackSelections);
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
default void onTracksSelected(
Timeline timeline,
MediaPeriodId mediaPeriodId,
Renderer[] renderers,
TrackGroupArray trackGroups,
ExoTrackSelection[] trackSelections) {
onTracksSelected(renderers, trackGroups, trackSelections);
}
/**
* @deprecated Implement {@link #onTracksSelected(Timeline, MediaPeriodId, Renderer[],
* TrackGroupArray, ExoTrackSelection[])} instead.
*/
@Deprecated
default void onTracksSelected(
Renderer[] renderers, TrackGroupArray trackGroups, ExoTrackSelection[] trackSelections) {
onTracksSelected(
Timeline.EMPTY, EMPTY_MEDIA_PERIOD_ID, renderers, trackGroups, trackSelections);
}
/** Called by the player when stopped. */
void onStopped();
......@@ -80,7 +113,9 @@ public interface LoadControl {
boolean retainBackBufferFromKeyframe();
/**
* Called by the player to determine whether it should continue to load the source.
* Called by the player to determine whether it should continue to load the source. If this method
* returns true, the {@link MediaPeriod} identified in the most recent {@link #onTracksSelected}
* call will continue being loaded.
*
* @param playbackPositionUs 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
......@@ -100,6 +135,10 @@ 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 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
......@@ -110,6 +149,30 @@ public interface LoadControl {
* configured.
* @return Whether playback should be allowed to start or resume.
*/
boolean shouldStartPlayback(
long bufferedDurationUs, float playbackSpeed, boolean rebuffering, long targetLiveOffsetUs);
@SuppressWarnings("deprecation") // Calling deprecated version of this method.
default boolean shouldStartPlayback(
Timeline timeline,
MediaPeriodId mediaPeriodId,
long bufferedDurationUs,
float playbackSpeed,
boolean rebuffering,
long targetLiveOffsetUs) {
return shouldStartPlayback(bufferedDurationUs, playbackSpeed, rebuffering, targetLiveOffsetUs);
}
/**
* @deprecated Implement {@link #shouldStartPlayback(Timeline, MediaPeriodId, long, float,
* boolean, long)} instead.
*/
@Deprecated
default boolean shouldStartPlayback(
long bufferedDurationUs, float playbackSpeed, boolean rebuffering, long targetLiveOffsetUs) {
return shouldStartPlayback(
Timeline.EMPTY,
EMPTY_MEDIA_PERIOD_ID,
bufferedDurationUs,
playbackSpeed,
rebuffering,
targetLiveOffsetUs);
}
}
......@@ -178,7 +178,12 @@ public class DefaultLoadControlTest {
@Test
public void shouldContinueLoading_withNoSelectedTracks_returnsTrue() {
loadControl = builder.build();
loadControl.onTracksSelected(new Renderer[0], TrackGroupArray.EMPTY, new ExoTrackSelection[0]);
loadControl.onTracksSelected(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
new Renderer[0],
TrackGroupArray.EMPTY,
new ExoTrackSelection[0]);
assertThat(
loadControl.shouldContinueLoading(
......@@ -202,6 +207,8 @@ public class DefaultLoadControlTest {
assertThat(
loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
MIN_BUFFER_US,
SPEED,
/* rebuffering= */ false,
......@@ -221,6 +228,8 @@ public class DefaultLoadControlTest {
assertThat(
loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 2_999_999,
SPEED,
/* rebuffering= */ false,
......@@ -228,6 +237,8 @@ public class DefaultLoadControlTest {
.isFalse();
assertThat(
loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 3_000_000,
SPEED,
/* rebuffering= */ false,
......@@ -246,6 +257,8 @@ public class DefaultLoadControlTest {
assertThat(
loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 499_999,
SPEED,
/* rebuffering= */ true,
......@@ -253,6 +266,8 @@ public class DefaultLoadControlTest {
.isFalse();
assertThat(
loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 500_000,
SPEED,
/* rebuffering= */ true,
......@@ -272,6 +287,8 @@ public class DefaultLoadControlTest {
assertThat(
loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 3_999_999,
SPEED,
/* rebuffering= */ true,
......@@ -279,6 +296,8 @@ public class DefaultLoadControlTest {
.isFalse();
assertThat(
loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 4_000_000,
SPEED,
/* rebuffering= */ true,
......@@ -297,6 +316,8 @@ public class DefaultLoadControlTest {
assertThat(
loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 499_999,
SPEED,
/* rebuffering= */ true,
......@@ -304,6 +325,8 @@ public class DefaultLoadControlTest {
.isFalse();
assertThat(
loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 500_000,
SPEED,
/* rebuffering= */ true,
......@@ -314,7 +337,8 @@ public class DefaultLoadControlTest {
private void build() {
builder.setAllocator(allocator).setTargetBufferBytes(TARGET_BUFFER_BYTES);
loadControl = builder.build();
loadControl.onTracksSelected(new Renderer[0], null, null);
loadControl.onTracksSelected(
Timeline.EMPTY, LoadControl.EMPTY_MEDIA_PERIOD_ID, new Renderer[0], null, null);
}
private void makeSureTargetBufferBytesReached() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment