Merge pull request #1742 from colinkho:trackselection-playwhenready

PiperOrigin-RevId: 688050467
This commit is contained in:
Copybara-Service 2024-10-21 02:27:20 -07:00
commit f2ecca3b6a
6 changed files with 120 additions and 12 deletions

View File

@ -1879,7 +1879,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
// The reselection did not change any prepared periods.
return;
}
newTrackSelectorResult = periodHolder.selectTracks(playbackSpeed, playbackInfo.timeline);
newTrackSelectorResult =
periodHolder.selectTracks(
playbackSpeed, playbackInfo.timeline, playbackInfo.playWhenReady);
if (periodHolder == queue.getPlayingPeriod()) {
newPlayingPeriodTrackSelectorResult = newTrackSelectorResult;
}
@ -2563,7 +2565,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
if (preloadHolder != null) {
checkState(!preloadHolder.prepared);
preloadHolder.handlePrepared(
mediaClock.getPlaybackParameters().speed, playbackInfo.timeline);
mediaClock.getPlaybackParameters().speed,
playbackInfo.timeline,
playbackInfo.playWhenReady);
if (queue.isPreloading(mediaPeriod)) {
maybeContinuePreloading();
}
@ -2575,7 +2579,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
throws ExoPlaybackException {
if (!loadingPeriodHolder.prepared) {
loadingPeriodHolder.handlePrepared(
mediaClock.getPlaybackParameters().speed, playbackInfo.timeline);
mediaClock.getPlaybackParameters().speed,
playbackInfo.timeline,
playbackInfo.playWhenReady);
}
updateLoadControlTrackSelection(
loadingPeriodHolder.info.id,

View File

@ -203,12 +203,14 @@ import java.io.IOException;
*
* @param playbackSpeed The current factor by which playback is sped up.
* @param timeline The current {@link Timeline}.
* @param playWhenReady The current value of whether playback should proceed when ready.
* @throws ExoPlaybackException If an error occurs during track selection.
*/
public void handlePrepared(float playbackSpeed, Timeline timeline) throws ExoPlaybackException {
public void handlePrepared(float playbackSpeed, Timeline timeline, boolean playWhenReady)
throws ExoPlaybackException {
prepared = true;
trackGroups = mediaPeriod.getTrackGroups();
TrackSelectorResult selectorResult = selectTracks(playbackSpeed, timeline);
TrackSelectorResult selectorResult = selectTracks(playbackSpeed, timeline, playWhenReady);
long requestedStartPositionUs = info.startPositionUs;
if (info.durationUs != C.TIME_UNSET && requestedStartPositionUs >= info.durationUs) {
// Make sure start position doesn't exceed period duration.
@ -254,11 +256,12 @@ import java.io.IOException;
*
* @param playbackSpeed The current factor by which playback is sped up.
* @param timeline The current {@link Timeline}.
* @param playWhenReady The current value of whether playback should proceed when ready.
* @return The {@link TrackSelectorResult}.
* @throws ExoPlaybackException If an error occurs during track selection.
*/
public TrackSelectorResult selectTracks(float playbackSpeed, Timeline timeline)
throws ExoPlaybackException {
public TrackSelectorResult selectTracks(
float playbackSpeed, Timeline timeline, boolean playWhenReady) throws ExoPlaybackException {
TrackSelectorResult selectorResult =
trackSelector.selectTracks(rendererCapabilities, getTrackGroups(), info.id, timeline);
for (int i = 0; i < selectorResult.length; i++) {
@ -273,6 +276,7 @@ import java.io.IOException;
for (ExoTrackSelection trackSelection : selectorResult.selections) {
if (trackSelection != null) {
trackSelection.onPlaybackSpeed(playbackSpeed);
trackSelection.onPlayWhenReadyChanged(playWhenReady);
}
}
return selectorResult;

View File

@ -18,6 +18,7 @@ package androidx.media3.exoplayer.trackselection;
import static java.lang.Math.max;
import android.os.SystemClock;
import androidx.annotation.CallSuper;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.Format;
@ -54,6 +55,9 @@ public abstract class BaseTrackSelection implements ExoTrackSelection {
// Lazily initialized hashcode.
private int hashCode;
/** The current value of whether playback will proceed when ready. */
private boolean playWhenReady;
/**
* @param group The {@link TrackGroup}. Must not be null.
* @param tracks The indices of the selected tracks within the {@link TrackGroup}. Must not be
@ -87,6 +91,7 @@ public abstract class BaseTrackSelection implements ExoTrackSelection {
this.tracks[i] = group.indexOf(formats[i]);
}
excludeUntilTimes = new long[length];
playWhenReady = false;
}
// TrackSelection implementation.
@ -191,6 +196,17 @@ public abstract class BaseTrackSelection implements ExoTrackSelection {
return excludeUntilTimes[index] > nowMs;
}
@CallSuper
@Override
public void onPlayWhenReadyChanged(boolean playWhenReady) {
this.playWhenReady = playWhenReady;
}
/** Returns whether the playback using this track selection will proceed when ready. */
protected final boolean getPlayWhenReady() {
return playWhenReady;
}
// Object overrides.
@Override

View File

@ -16174,6 +16174,79 @@ public class ExoPlayerTest {
assertThat(deviceVolumeChanged.get()).isFalse();
}
@Test
public void playWhenReadyChanges_areForwardedToTrackSelection() throws Exception {
ArrayList<Boolean> reportedPlayWhenReadyChanges = new ArrayList<>();
ArrayList<Boolean> playWhenReadyStatesInTrackSelector = new ArrayList<>();
ExoPlayer player =
new TestExoPlayerBuilder(context)
.setTrackSelector(
new FakeTrackSelector(
new FakeTrackSelector.FakeTrackSelectionFactory(
/* mayReuseTrackSelection= */ false) {
@Override
protected ExoTrackSelection createTrackSelection(TrackGroup trackGroup) {
return new FakeTrackSelection(trackGroup) {
@Override
public void onPlayWhenReadyChanged(boolean playWhenReady) {
super.onPlayWhenReadyChanged(playWhenReady);
reportedPlayWhenReadyChanges.add(playWhenReady);
playWhenReadyStatesInTrackSelector.add(getPlayWhenReady());
}
};
}
}))
.build();
player.setMediaSource(
new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.VIDEO_FORMAT));
player.setPlayWhenReady(true);
player.prepare();
run(player).untilState(Player.STATE_READY);
player.setPlayWhenReady(false);
player.setPlayWhenReady(true);
run(player).untilPendingCommandsAreFullyHandled();
player.release();
assertThat(reportedPlayWhenReadyChanges).containsExactly(true, false, true).inOrder();
assertThat(playWhenReadyStatesInTrackSelector).containsExactly(true, false, true).inOrder();
}
@Test
public void playbackSpeedChanges_areForwardedToTrackSelection() throws Exception {
ArrayList<Float> reportedSpeedChanges = new ArrayList<>();
ExoPlayer player =
new TestExoPlayerBuilder(context)
.setTrackSelector(
new FakeTrackSelector(
new FakeTrackSelector.FakeTrackSelectionFactory(
/* mayReuseTrackSelection= */ false) {
@Override
protected ExoTrackSelection createTrackSelection(TrackGroup trackGroup) {
return new FakeTrackSelection(trackGroup) {
@Override
public void onPlaybackSpeed(float playbackSpeed) {
super.onPlaybackSpeed(playbackSpeed);
reportedSpeedChanges.add(playbackSpeed);
}
};
}
}))
.build();
player.setMediaSource(
new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.VIDEO_FORMAT));
player.setPlaybackSpeed(2f);
player.prepare();
run(player).untilState(Player.STATE_READY);
player.setPlaybackSpeed(1.5f);
player.setPlaybackSpeed(1f);
run(player).untilPendingCommandsAreFullyHandled();
player.release();
assertThat(reportedSpeedChanges).containsExactly(2f, 1.5f, 1f).inOrder();
}
// Internal methods.
private void addWatchAsSystemFeature() {

View File

@ -33,7 +33,7 @@ import java.util.List;
* of calls to its methods.
*/
@UnstableApi
public final class FakeTrackSelection extends BaseTrackSelection {
public class FakeTrackSelection extends BaseTrackSelection {
private final TrackGroup rendererTrackGroup;
private final int selectedIndex;

View File

@ -50,7 +50,11 @@ public class FakeTrackSelector extends DefaultTrackSelector {
this(new FakeTrackSelectionFactory(mayReuseTrackSelection));
}
private FakeTrackSelector(FakeTrackSelectionFactory fakeTrackSelectionFactory) {
/**
* @param fakeTrackSelectionFactory The {@link FakeTrackSelectionFactory} used to create the
* {@link FakeTrackSelection} instances.
*/
public FakeTrackSelector(FakeTrackSelectionFactory fakeTrackSelectionFactory) {
super(ApplicationProvider.getApplicationContext(), fakeTrackSelectionFactory);
this.fakeTrackSelectionFactory = fakeTrackSelectionFactory;
}
@ -80,7 +84,11 @@ public class FakeTrackSelector extends DefaultTrackSelector {
return fakeTrackSelectionFactory.trackSelections;
}
private static class FakeTrackSelectionFactory implements ExoTrackSelection.Factory {
/**
* A factory for the {@link androidx.media3.test.utils.FakeTrackSelection} instances requested by
* the {@link FakeTrackSelector}.
*/
public static class FakeTrackSelectionFactory implements ExoTrackSelection.Factory {
private final List<FakeTrackSelection> trackSelections;
private final boolean mayReuseTrackSelection;
@ -91,7 +99,7 @@ public class FakeTrackSelector extends DefaultTrackSelector {
}
@Override
public ExoTrackSelection[] createTrackSelections(
public final ExoTrackSelection[] createTrackSelections(
ExoTrackSelection.@NullableType Definition[] definitions,
BandwidthMeter bandwidthMeter,
MediaPeriodId mediaPeriodId,
@ -106,7 +114,8 @@ public class FakeTrackSelector extends DefaultTrackSelector {
return selections;
}
private ExoTrackSelection createTrackSelection(TrackGroup trackGroup) {
/** Creates the {@link FakeTrackSelection} from a {@link TrackGroup}. */
protected ExoTrackSelection createTrackSelection(TrackGroup trackGroup) {
if (mayReuseTrackSelection) {
for (FakeTrackSelection trackSelection : trackSelections) {
if (trackSelection.getTrackGroup().equals(trackGroup)) {