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; ...@@ -20,6 +20,7 @@ import static java.lang.Math.max;
import static java.lang.Math.min; import static java.lang.Math.min;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.source.MediaPeriodId;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.ExoTrackSelection; import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
...@@ -327,7 +328,11 @@ public class DefaultLoadControl implements LoadControl { ...@@ -327,7 +328,11 @@ public class DefaultLoadControl implements LoadControl {
@Override @Override
public void onTracksSelected( public void onTracksSelected(
Renderer[] renderers, TrackGroupArray trackGroups, ExoTrackSelection[] trackSelections) { Timeline timeline,
MediaPeriodId mediaPeriodId,
Renderer[] renderers,
TrackGroupArray trackGroups,
ExoTrackSelection[] trackSelections) {
targetBufferBytes = targetBufferBytes =
targetBufferBytesOverwrite == C.LENGTH_UNSET targetBufferBytesOverwrite == C.LENGTH_UNSET
? calculateTargetBufferBytes(renderers, trackSelections) ? calculateTargetBufferBytes(renderers, trackSelections)
...@@ -389,7 +394,12 @@ public class DefaultLoadControl implements LoadControl { ...@@ -389,7 +394,12 @@ public class DefaultLoadControl implements LoadControl {
@Override @Override
public boolean shouldStartPlayback( 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); bufferedDurationUs = Util.getPlayoutDurationForMediaDuration(bufferedDurationUs, playbackSpeed);
long minBufferDurationUs = rebuffering ? bufferForPlaybackAfterRebufferUs : bufferForPlaybackUs; long minBufferDurationUs = rebuffering ? bufferForPlaybackAfterRebufferUs : bufferForPlaybackUs;
if (targetLiveOffsetUs != C.TIME_UNSET) { if (targetLiveOffsetUs != C.TIME_UNSET) {
......
...@@ -1815,8 +1815,9 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -1815,8 +1815,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
return true; return true;
} }
// Renderers are ready and we're loading. Ask the LoadControl whether to transition. // Renderers are ready and we're loading. Ask the LoadControl whether to transition.
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
long targetLiveOffsetUs = long targetLiveOffsetUs =
shouldUseLivePlaybackSpeedControl(playbackInfo.timeline, queue.getPlayingPeriod().info.id) shouldUseLivePlaybackSpeedControl(playbackInfo.timeline, playingPeriodHolder.info.id)
? livePlaybackSpeedControl.getTargetLiveOffsetUs() ? livePlaybackSpeedControl.getTargetLiveOffsetUs()
: C.TIME_UNSET; : C.TIME_UNSET;
MediaPeriodHolder loadingHolder = queue.getLoadingPeriod(); MediaPeriodHolder loadingHolder = queue.getLoadingPeriod();
...@@ -1828,6 +1829,8 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -1828,6 +1829,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
return isBufferedToEnd return isBufferedToEnd
|| isAdPendingPreparation || isAdPendingPreparation
|| loadControl.shouldStartPlayback( || loadControl.shouldStartPlayback(
playbackInfo.timeline,
playingPeriodHolder.info.id,
getTotalBufferedDurationUs(), getTotalBufferedDurationUs(),
mediaClock.getPlaybackParameters().speed, mediaClock.getPlaybackParameters().speed,
isRebuffering, isRebuffering,
...@@ -2283,7 +2286,9 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -2283,7 +2286,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
loadingPeriodHolder.handlePrepared( loadingPeriodHolder.handlePrepared(
mediaClock.getPlaybackParameters().speed, playbackInfo.timeline); mediaClock.getPlaybackParameters().speed, playbackInfo.timeline);
updateLoadControlTrackSelection( updateLoadControlTrackSelection(
loadingPeriodHolder.getTrackGroups(), loadingPeriodHolder.getTrackSelectorResult()); loadingPeriodHolder.info.id,
loadingPeriodHolder.getTrackGroups(),
loadingPeriodHolder.getTrackSelectorResult());
if (loadingPeriodHolder == queue.getPlayingPeriod()) { if (loadingPeriodHolder == queue.getPlayingPeriod()) {
// This is the first prepared period, so update the position and the renderers. // This is the first prepared period, so update the position and the renderers.
resetRendererPosition(loadingPeriodHolder.info.startPositionUs); resetRendererPosition(loadingPeriodHolder.info.startPositionUs);
...@@ -2568,6 +2573,7 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -2568,6 +2573,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
&& loadingMediaPeriodHolder != null && loadingMediaPeriodHolder != null
&& loadingMediaPeriodHolder.prepared) { && loadingMediaPeriodHolder.prepared) {
updateLoadControlTrackSelection( updateLoadControlTrackSelection(
loadingMediaPeriodHolder.info.id,
loadingMediaPeriodHolder.getTrackGroups(), loadingMediaPeriodHolder.getTrackGroups(),
loadingMediaPeriodHolder.getTrackSelectorResult()); loadingMediaPeriodHolder.getTrackSelectorResult());
} }
...@@ -2588,8 +2594,15 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -2588,8 +2594,15 @@ import java.util.concurrent.atomic.AtomicBoolean;
} }
private void updateLoadControlTrackSelection( private void updateLoadControlTrackSelection(
TrackGroupArray trackGroups, TrackSelectorResult trackSelectorResult) { MediaPeriodId mediaPeriodId,
loadControl.onTracksSelected(renderers, trackGroups, trackSelectorResult.selections); TrackGroupArray trackGroups,
TrackSelectorResult trackSelectorResult) {
loadControl.onTracksSelected(
playbackInfo.timeline,
mediaPeriodId,
renderers,
trackGroups,
trackSelectorResult.selections);
} }
private boolean shouldPlayWhenReady() { private boolean shouldPlayWhenReady() {
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2; 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.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.ExoTrackSelection; import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
...@@ -23,18 +25,49 @@ import com.google.android.exoplayer2.upstream.Allocator; ...@@ -23,18 +25,49 @@ import com.google.android.exoplayer2.upstream.Allocator;
/** Controls buffering of media. */ /** Controls buffering of media. */
public interface LoadControl { 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. */ /** Called by the player when prepared with a new source. */
void onPrepared(); void onPrepared();
/** /**
* Called by the player when a track selection occurs. * 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 renderers The renderers.
* @param trackGroups The {@link TrackGroup}s from which the selection was made. * @param trackGroups The {@link TrackGroup}s from which the selection was made.
* @param trackSelections The track selections that were made. * @param trackSelections The track selections that were made.
*/ */
void onTracksSelected( @SuppressWarnings("deprecation") // Calling deprecated version of this method.
Renderer[] renderers, TrackGroupArray trackGroups, ExoTrackSelection[] trackSelections); 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. */ /** Called by the player when stopped. */
void onStopped(); void onStopped();
...@@ -80,7 +113,9 @@ public interface LoadControl { ...@@ -80,7 +113,9 @@ public interface LoadControl {
boolean retainBackBufferFromKeyframe(); 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 * @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 * of the {@link Timeline.Period period} that will continue to be loaded if this method
...@@ -100,6 +135,10 @@ public interface LoadControl { ...@@ -100,6 +135,10 @@ 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 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 bufferedDurationUs The duration of media that's currently buffered.
* @param playbackSpeed The current factor by which playback is sped up. * @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 * @param rebuffering Whether the player is rebuffering. A rebuffer is defined to be caused by
...@@ -110,6 +149,30 @@ public interface LoadControl { ...@@ -110,6 +149,30 @@ public interface LoadControl {
* configured. * configured.
* @return Whether playback should be allowed to start or resume. * @return Whether playback should be allowed to start or resume.
*/ */
boolean shouldStartPlayback( @SuppressWarnings("deprecation") // Calling deprecated version of this method.
long bufferedDurationUs, float playbackSpeed, boolean rebuffering, long targetLiveOffsetUs); 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 { ...@@ -178,7 +178,12 @@ public class DefaultLoadControlTest {
@Test @Test
public void shouldContinueLoading_withNoSelectedTracks_returnsTrue() { public void shouldContinueLoading_withNoSelectedTracks_returnsTrue() {
loadControl = builder.build(); 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( assertThat(
loadControl.shouldContinueLoading( loadControl.shouldContinueLoading(
...@@ -202,6 +207,8 @@ public class DefaultLoadControlTest { ...@@ -202,6 +207,8 @@ public class DefaultLoadControlTest {
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
MIN_BUFFER_US, MIN_BUFFER_US,
SPEED, SPEED,
/* rebuffering= */ false, /* rebuffering= */ false,
...@@ -221,6 +228,8 @@ public class DefaultLoadControlTest { ...@@ -221,6 +228,8 @@ public class DefaultLoadControlTest {
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 2_999_999, /* bufferedDurationUs= */ 2_999_999,
SPEED, SPEED,
/* rebuffering= */ false, /* rebuffering= */ false,
...@@ -228,6 +237,8 @@ public class DefaultLoadControlTest { ...@@ -228,6 +237,8 @@ public class DefaultLoadControlTest {
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 3_000_000, /* bufferedDurationUs= */ 3_000_000,
SPEED, SPEED,
/* rebuffering= */ false, /* rebuffering= */ false,
...@@ -246,6 +257,8 @@ public class DefaultLoadControlTest { ...@@ -246,6 +257,8 @@ public class DefaultLoadControlTest {
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 499_999, /* bufferedDurationUs= */ 499_999,
SPEED, SPEED,
/* rebuffering= */ true, /* rebuffering= */ true,
...@@ -253,6 +266,8 @@ public class DefaultLoadControlTest { ...@@ -253,6 +266,8 @@ public class DefaultLoadControlTest {
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 500_000, /* bufferedDurationUs= */ 500_000,
SPEED, SPEED,
/* rebuffering= */ true, /* rebuffering= */ true,
...@@ -272,6 +287,8 @@ public class DefaultLoadControlTest { ...@@ -272,6 +287,8 @@ public class DefaultLoadControlTest {
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 3_999_999, /* bufferedDurationUs= */ 3_999_999,
SPEED, SPEED,
/* rebuffering= */ true, /* rebuffering= */ true,
...@@ -279,6 +296,8 @@ public class DefaultLoadControlTest { ...@@ -279,6 +296,8 @@ public class DefaultLoadControlTest {
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 4_000_000, /* bufferedDurationUs= */ 4_000_000,
SPEED, SPEED,
/* rebuffering= */ true, /* rebuffering= */ true,
...@@ -297,6 +316,8 @@ public class DefaultLoadControlTest { ...@@ -297,6 +316,8 @@ public class DefaultLoadControlTest {
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 499_999, /* bufferedDurationUs= */ 499_999,
SPEED, SPEED,
/* rebuffering= */ true, /* rebuffering= */ true,
...@@ -304,6 +325,8 @@ public class DefaultLoadControlTest { ...@@ -304,6 +325,8 @@ public class DefaultLoadControlTest {
.isFalse(); .isFalse();
assertThat( assertThat(
loadControl.shouldStartPlayback( loadControl.shouldStartPlayback(
Timeline.EMPTY,
LoadControl.EMPTY_MEDIA_PERIOD_ID,
/* bufferedDurationUs= */ 500_000, /* bufferedDurationUs= */ 500_000,
SPEED, SPEED,
/* rebuffering= */ true, /* rebuffering= */ true,
...@@ -314,7 +337,8 @@ public class DefaultLoadControlTest { ...@@ -314,7 +337,8 @@ public class DefaultLoadControlTest {
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();
loadControl.onTracksSelected(new Renderer[0], null, null); loadControl.onTracksSelected(
Timeline.EMPTY, LoadControl.EMPTY_MEDIA_PERIOD_ID, new Renderer[0], null, null);
} }
private void makeSureTargetBufferBytesReached() { 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