mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Implement shuffle mode logic in ExoPlayerImplInternal.
This is mostly connecting the already stored shuffleMode with the timeline queries for the playback order. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=166199330
This commit is contained in:
parent
1305b1155b
commit
eeebb3968b
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
@ -24,6 +25,7 @@ import com.google.android.exoplayer2.testutil.ExoPlayerTestRunner.Builder;
|
||||
import com.google.android.exoplayer2.testutil.FakeMediaClockRenderer;
|
||||
import com.google.android.exoplayer2.testutil.FakeMediaSource;
|
||||
import com.google.android.exoplayer2.testutil.FakeRenderer;
|
||||
import com.google.android.exoplayer2.testutil.FakeShuffleOrder;
|
||||
import com.google.android.exoplayer2.testutil.FakeTimeline;
|
||||
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@ -234,4 +236,27 @@ public final class ExoPlayerTest extends TestCase {
|
||||
assertTrue(renderer.isEnded);
|
||||
}
|
||||
|
||||
public void testShuffleModeEnabledChanges() throws Exception {
|
||||
Timeline fakeTimeline = new FakeTimeline(new TimelineWindowDefinition(true, false, 100000));
|
||||
MediaSource[] fakeMediaSources = {
|
||||
new FakeMediaSource(fakeTimeline, null, Builder.VIDEO_FORMAT),
|
||||
new FakeMediaSource(fakeTimeline, null, Builder.VIDEO_FORMAT),
|
||||
new FakeMediaSource(fakeTimeline, null, Builder.VIDEO_FORMAT)
|
||||
};
|
||||
ConcatenatingMediaSource mediaSource = new ConcatenatingMediaSource(false,
|
||||
new FakeShuffleOrder(3), fakeMediaSources);
|
||||
FakeRenderer renderer = new FakeRenderer(Builder.VIDEO_FORMAT);
|
||||
ActionSchedule actionSchedule = new ActionSchedule.Builder("testShuffleModeEnabled")
|
||||
.setRepeatMode(Player.REPEAT_MODE_ALL).waitForPositionDiscontinuity() // 0 -> 1
|
||||
.setShuffleModeEnabled(true).waitForPositionDiscontinuity() // 1 -> 0
|
||||
.waitForPositionDiscontinuity().waitForPositionDiscontinuity() // 0 -> 2 -> 1
|
||||
.setShuffleModeEnabled(false).setRepeatMode(Player.REPEAT_MODE_OFF) // 1 -> 2 -> end
|
||||
.build();
|
||||
ExoPlayerTestRunner testRunner = new ExoPlayerTestRunner.Builder()
|
||||
.setMediaSource(mediaSource).setRenderers(renderer).setActionSchedule(actionSchedule)
|
||||
.build().start().blockUntilEnded(TIMEOUT_MS);
|
||||
testRunner.assertPlayedPeriodIndices(0, 1, 0, 2, 1, 2);
|
||||
assertTrue(renderer.isEnded);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -488,7 +488,7 @@ import java.io.IOException;
|
||||
}
|
||||
while (true) {
|
||||
int nextPeriodIndex = timeline.getNextPeriodIndex(lastValidPeriodHolder.info.id.periodIndex,
|
||||
period, window, repeatMode, false);
|
||||
period, window, repeatMode, shuffleModeEnabled);
|
||||
while (lastValidPeriodHolder.next != null
|
||||
&& !lastValidPeriodHolder.info.isLastInTimelinePeriod) {
|
||||
lastValidPeriodHolder = lastValidPeriodHolder.next;
|
||||
@ -686,13 +686,15 @@ import java.io.IOException;
|
||||
|
||||
Pair<Integer, Long> periodPosition = resolveSeekPosition(seekPosition);
|
||||
if (periodPosition == null) {
|
||||
int firstPeriodIndex = timeline.isEmpty() ? 0 : timeline.getWindow(
|
||||
timeline.getFirstWindowIndex(shuffleModeEnabled), window).firstPeriodIndex;
|
||||
// The seek position was valid for the timeline that it was performed into, but the
|
||||
// timeline has changed and a suitable seek position could not be resolved in the new one.
|
||||
playbackInfo = new PlaybackInfo(0, 0);
|
||||
playbackInfo = new PlaybackInfo(firstPeriodIndex, 0);
|
||||
eventHandler.obtainMessage(MSG_SEEK_ACK, 1, 0, playbackInfo).sendToTarget();
|
||||
// Set the internal position to (0,TIME_UNSET) so that a subsequent seek to (0,0) isn't
|
||||
// ignored.
|
||||
playbackInfo = new PlaybackInfo(0, C.TIME_UNSET);
|
||||
// Set the internal position to (firstPeriodIndex,TIME_UNSET) so that a subsequent seek to
|
||||
// (firstPeriodIndex,0) isn't ignored.
|
||||
playbackInfo = new PlaybackInfo(firstPeriodIndex, C.TIME_UNSET);
|
||||
setState(Player.STATE_ENDED);
|
||||
// Reset, but retain the source so that it can still be used should a seek occur.
|
||||
resetInternal(false);
|
||||
@ -1029,7 +1031,8 @@ import java.io.IOException;
|
||||
if (timeline.isEmpty()) {
|
||||
handleSourceInfoRefreshEndedPlayback(manifest);
|
||||
} else {
|
||||
Pair<Integer, Long> defaultPosition = getPeriodPosition(0, C.TIME_UNSET);
|
||||
Pair<Integer, Long> defaultPosition = getPeriodPosition(
|
||||
timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET);
|
||||
int periodIndex = defaultPosition.first;
|
||||
long startPositionUs = defaultPosition.second;
|
||||
MediaPeriodId periodId = mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex,
|
||||
@ -1122,7 +1125,8 @@ import java.io.IOException;
|
||||
while (periodHolder.next != null) {
|
||||
MediaPeriodHolder previousPeriodHolder = periodHolder;
|
||||
periodHolder = periodHolder.next;
|
||||
periodIndex = timeline.getNextPeriodIndex(periodIndex, period, window, repeatMode, false);
|
||||
periodIndex = timeline.getNextPeriodIndex(periodIndex, period, window, repeatMode,
|
||||
shuffleModeEnabled);
|
||||
if (periodIndex != C.INDEX_UNSET
|
||||
&& periodHolder.uid.equals(timeline.getPeriod(periodIndex, period, true).uid)) {
|
||||
// The holder is consistent with the new timeline. Update its index and continue.
|
||||
@ -1170,11 +1174,14 @@ import java.io.IOException;
|
||||
|
||||
private void handleSourceInfoRefreshEndedPlayback(Object manifest,
|
||||
int processedInitialSeekCount) {
|
||||
// Set the playback position to (0,0) for notifying the eventHandler.
|
||||
playbackInfo = new PlaybackInfo(0, 0);
|
||||
int firstPeriodIndex = timeline.isEmpty() ? 0 : timeline.getWindow(
|
||||
timeline.getFirstWindowIndex(shuffleModeEnabled), window).firstPeriodIndex;
|
||||
// Set the playback position to (firstPeriodIndex,0) for notifying the eventHandler.
|
||||
playbackInfo = new PlaybackInfo(firstPeriodIndex, 0);
|
||||
notifySourceInfoRefresh(manifest, processedInitialSeekCount);
|
||||
// Set the internal position to (0,TIME_UNSET) so that a subsequent seek to (0,0) isn't ignored.
|
||||
playbackInfo = new PlaybackInfo(0, C.TIME_UNSET);
|
||||
// Set the internal position to (firstPeriodIndex,TIME_UNSET) so that a subsequent seek to
|
||||
// (firstPeriodIndex,0) isn't ignored.
|
||||
playbackInfo = new PlaybackInfo(firstPeriodIndex, C.TIME_UNSET);
|
||||
setState(Player.STATE_ENDED);
|
||||
// Reset, but retain the source so that it can still be used should a seek occur.
|
||||
resetInternal(false);
|
||||
@ -1205,7 +1212,7 @@ import java.io.IOException;
|
||||
int maxIterations = oldTimeline.getPeriodCount();
|
||||
for (int i = 0; i < maxIterations && newPeriodIndex == C.INDEX_UNSET; i++) {
|
||||
oldPeriodIndex = oldTimeline.getNextPeriodIndex(oldPeriodIndex, period, window, repeatMode,
|
||||
false);
|
||||
shuffleModeEnabled);
|
||||
if (oldPeriodIndex == C.INDEX_UNSET) {
|
||||
// We've reached the end of the old timeline.
|
||||
break;
|
||||
|
@ -162,7 +162,7 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
// timeline is updated, to avoid repeatedly checking the same timeline.
|
||||
if (currentMediaPeriodInfo.isLastInTimelinePeriod) {
|
||||
int nextPeriodIndex = timeline.getNextPeriodIndex(currentMediaPeriodInfo.id.periodIndex,
|
||||
period, window, repeatMode, false);
|
||||
period, window, repeatMode, shuffleModeEnabled);
|
||||
if (nextPeriodIndex == C.INDEX_UNSET) {
|
||||
// We can't create a next period yet.
|
||||
return null;
|
||||
@ -353,7 +353,7 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
private boolean isLastInTimeline(MediaPeriodId id, boolean isLastMediaPeriodInPeriod) {
|
||||
int windowIndex = timeline.getPeriod(id.periodIndex, period).windowIndex;
|
||||
return !timeline.getWindow(windowIndex, window).isDynamic
|
||||
&& timeline.isLastPeriod(id.periodIndex, period, window, repeatMode, false)
|
||||
&& timeline.isLastPeriod(id.periodIndex, period, window, repeatMode, shuffleModeEnabled)
|
||||
&& isLastMediaPeriodInPeriod;
|
||||
}
|
||||
|
||||
|
@ -284,6 +284,29 @@ public abstract class Action {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link Player#setShuffleModeEnabled(boolean)}.
|
||||
*/
|
||||
public static final class SetShuffleModeEnabled extends Action {
|
||||
|
||||
private final boolean shuffleModeEnabled;
|
||||
|
||||
/**
|
||||
* @param tag A tag to use for logging.
|
||||
*/
|
||||
public SetShuffleModeEnabled(String tag, boolean shuffleModeEnabled) {
|
||||
super(tag, "SetShuffleModeEnabled:" + shuffleModeEnabled);
|
||||
this.shuffleModeEnabled = shuffleModeEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doActionImpl(SimpleExoPlayer player, MappingTrackSelector trackSelector,
|
||||
Surface surface) {
|
||||
player.setShuffleModeEnabled(shuffleModeEnabled);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for {@link Player.EventListener#onTimelineChanged(Timeline, Object)}.
|
||||
*/
|
||||
|
@ -30,6 +30,7 @@ import com.google.android.exoplayer2.testutil.Action.Seek;
|
||||
import com.google.android.exoplayer2.testutil.Action.SetPlayWhenReady;
|
||||
import com.google.android.exoplayer2.testutil.Action.SetRendererDisabled;
|
||||
import com.google.android.exoplayer2.testutil.Action.SetRepeatMode;
|
||||
import com.google.android.exoplayer2.testutil.Action.SetShuffleModeEnabled;
|
||||
import com.google.android.exoplayer2.testutil.Action.SetVideoSurface;
|
||||
import com.google.android.exoplayer2.testutil.Action.Stop;
|
||||
import com.google.android.exoplayer2.testutil.Action.WaitForPositionDiscontinuity;
|
||||
@ -217,6 +218,15 @@ public final class ActionSchedule {
|
||||
return apply(new SetRepeatMode(tag, repeatMode));
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a shuffle setting action to be executed.
|
||||
*
|
||||
* @return The builder, for convenience.
|
||||
*/
|
||||
public Builder setShuffleModeEnabled(boolean shuffleModeEnabled) {
|
||||
return apply(new SetShuffleModeEnabled(tag, shuffleModeEnabled));
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a delay until the timeline changed to a specified expected timeline.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user