mirror of
https://github.com/samsonjs/media.git
synced 2026-04-20 13:45:47 +00:00
Preserve window indices of Timeline when bundling
PiperOrigin-RevId: 364324490
This commit is contained in:
parent
10a8c603f7
commit
7b4b5cbf5a
6 changed files with 282 additions and 80 deletions
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
||||
|
||||
import android.net.Uri;
|
||||
|
|
@ -1255,11 +1256,16 @@ public abstract class Timeline implements Bundleable {
|
|||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({FIELD_WINDOWS, FIELD_PERIODS})
|
||||
@IntDef({
|
||||
FIELD_WINDOWS,
|
||||
FIELD_PERIODS,
|
||||
FIELD_SHUFFLED_WINDOW_INDICES,
|
||||
})
|
||||
private @interface FieldNumber {}
|
||||
|
||||
private static final int FIELD_WINDOWS = 0;
|
||||
private static final int FIELD_PERIODS = 1;
|
||||
private static final int FIELD_SHUFFLED_WINDOW_INDICES = 2;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
|
@ -1272,18 +1278,24 @@ public abstract class Timeline implements Bundleable {
|
|||
public final Bundle toBundle() {
|
||||
List<Bundle> windowBundles = new ArrayList<>();
|
||||
int windowCount = getWindowCount();
|
||||
Window window = new Window();
|
||||
for (int i = 0; i < windowCount; i++) {
|
||||
Window window = new Window();
|
||||
getWindow(i, window, /* defaultPositionProjectionUs= */ 0);
|
||||
windowBundles.add(window.toBundle());
|
||||
windowBundles.add(getWindow(i, window, /* defaultPositionProjectionUs= */ 0).toBundle());
|
||||
}
|
||||
|
||||
List<Bundle> periodBundles = new ArrayList<>();
|
||||
int periodCount = getPeriodCount();
|
||||
Period period = new Period();
|
||||
for (int i = 0; i < periodCount; i++) {
|
||||
Period period = new Period();
|
||||
getPeriod(i, period, /* setIds= */ false);
|
||||
periodBundles.add(period.toBundle());
|
||||
periodBundles.add(getPeriod(i, period, /* setIds= */ false).toBundle());
|
||||
}
|
||||
|
||||
int[] shuffledWindowIndices = new int[windowCount];
|
||||
shuffledWindowIndices[0] = getFirstWindowIndex(/* shuffleModeEnabled= */ true);
|
||||
for (int i = 1; i < windowCount; i++) {
|
||||
shuffledWindowIndices[i] =
|
||||
getNextWindowIndex(
|
||||
shuffledWindowIndices[i - 1], Player.REPEAT_MODE_OFF, /* shuffleModeEnabled= */ true);
|
||||
}
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
|
|
@ -1291,6 +1303,7 @@ public abstract class Timeline implements Bundleable {
|
|||
bundle, keyForField(FIELD_WINDOWS), new BundleListRetriever(windowBundles));
|
||||
BundleCompat.putBinder(
|
||||
bundle, keyForField(FIELD_PERIODS), new BundleListRetriever(periodBundles));
|
||||
bundle.putIntArray(keyForField(FIELD_SHUFFLED_WINDOW_INDICES), shuffledWindowIndices);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
|
|
@ -1310,7 +1323,14 @@ public abstract class Timeline implements Bundleable {
|
|||
ImmutableList<Period> periods =
|
||||
fromBundleListRetriever(
|
||||
Period.CREATOR, BundleCompat.getBinder(bundle, keyForField(FIELD_PERIODS)));
|
||||
return new RemotableTimeline(windows, periods);
|
||||
@Nullable
|
||||
int[] shuffledWindowIndices = bundle.getIntArray(keyForField(FIELD_SHUFFLED_WINDOW_INDICES));
|
||||
return new RemotableTimeline(
|
||||
windows,
|
||||
periods,
|
||||
shuffledWindowIndices == null
|
||||
? generateUnshuffledIndices(windows.size())
|
||||
: shuffledWindowIndices);
|
||||
}
|
||||
|
||||
private static <T extends Bundleable> ImmutableList<T> fromBundleListRetriever(
|
||||
|
|
@ -1330,6 +1350,14 @@ public abstract class Timeline implements Bundleable {
|
|||
return Integer.toString(field, Character.MAX_RADIX);
|
||||
}
|
||||
|
||||
private static int[] generateUnshuffledIndices(int n) {
|
||||
int[] indices = new int[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
indices[i] = i;
|
||||
}
|
||||
return indices;
|
||||
}
|
||||
|
||||
/**
|
||||
* A concrete class of {@link Timeline} to restore a {@link Timeline} instance from a {@link
|
||||
* Bundle} sent by another process via {@link IBinder}.
|
||||
|
|
@ -1338,10 +1366,19 @@ public abstract class Timeline implements Bundleable {
|
|||
|
||||
private final ImmutableList<Window> windows;
|
||||
private final ImmutableList<Period> periods;
|
||||
private final int[] shuffledWindowIndices;
|
||||
private final int[] windowIndicesInShuffled;
|
||||
|
||||
public RemotableTimeline(ImmutableList<Window> windows, ImmutableList<Period> periods) {
|
||||
public RemotableTimeline(
|
||||
ImmutableList<Window> windows, ImmutableList<Period> periods, int[] shuffledWindowIndices) {
|
||||
checkArgument(windows.size() == shuffledWindowIndices.length);
|
||||
this.windows = windows;
|
||||
this.periods = periods;
|
||||
this.shuffledWindowIndices = shuffledWindowIndices;
|
||||
windowIndicesInShuffled = new int[shuffledWindowIndices.length];
|
||||
for (int i = 0; i < shuffledWindowIndices.length; i++) {
|
||||
windowIndicesInShuffled[shuffledWindowIndices[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1372,6 +1409,56 @@ public abstract class Timeline implements Bundleable {
|
|||
return window;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextWindowIndex(
|
||||
int windowIndex, @Player.RepeatMode int repeatMode, boolean shuffleModeEnabled) {
|
||||
if (repeatMode == Player.REPEAT_MODE_ONE) {
|
||||
return windowIndex;
|
||||
}
|
||||
if (windowIndex == getLastWindowIndex(shuffleModeEnabled)) {
|
||||
return repeatMode == Player.REPEAT_MODE_ALL
|
||||
? getFirstWindowIndex(shuffleModeEnabled)
|
||||
: C.INDEX_UNSET;
|
||||
}
|
||||
return shuffleModeEnabled
|
||||
? shuffledWindowIndices[windowIndicesInShuffled[windowIndex] + 1]
|
||||
: windowIndex + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousWindowIndex(
|
||||
int windowIndex, @Player.RepeatMode int repeatMode, boolean shuffleModeEnabled) {
|
||||
if (repeatMode == Player.REPEAT_MODE_ONE) {
|
||||
return windowIndex;
|
||||
}
|
||||
if (windowIndex == getFirstWindowIndex(shuffleModeEnabled)) {
|
||||
return repeatMode == Player.REPEAT_MODE_ALL
|
||||
? getLastWindowIndex(shuffleModeEnabled)
|
||||
: C.INDEX_UNSET;
|
||||
}
|
||||
return shuffleModeEnabled
|
||||
? shuffledWindowIndices[windowIndicesInShuffled[windowIndex] - 1]
|
||||
: windowIndex - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLastWindowIndex(boolean shuffleModeEnabled) {
|
||||
if (isEmpty()) {
|
||||
return C.INDEX_UNSET;
|
||||
}
|
||||
return shuffleModeEnabled
|
||||
? shuffledWindowIndices[getWindowCount() - 1]
|
||||
: getWindowCount() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstWindowIndex(boolean shuffleModeEnabled) {
|
||||
if (isEmpty()) {
|
||||
return C.INDEX_UNSET;
|
||||
}
|
||||
return shuffleModeEnabled ? shuffledWindowIndices[0] : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPeriodCount() {
|
||||
return periods.size();
|
||||
|
|
|
|||
|
|
@ -237,6 +237,47 @@ public class TimelineTest {
|
|||
/* expectedTimeline= */ timeline, /* actualTimeline= */ restoredTimeline);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void roundtripViaBundle_ofTimeline_preservesWindowIndices() {
|
||||
int windowCount = 10;
|
||||
FakeTimeline timeline = new FakeTimeline(windowCount);
|
||||
|
||||
Timeline restoredTimeline = Timeline.CREATOR.fromBundle(timeline.toBundle());
|
||||
|
||||
assertThat(restoredTimeline.getLastWindowIndex(/* shuffleModeEnabled= */ false))
|
||||
.isEqualTo(timeline.getLastWindowIndex(/* shuffleModeEnabled= */ false));
|
||||
assertThat(restoredTimeline.getLastWindowIndex(/* shuffleModeEnabled= */ true))
|
||||
.isEqualTo(timeline.getLastWindowIndex(/* shuffleModeEnabled= */ true));
|
||||
assertThat(restoredTimeline.getFirstWindowIndex(/* shuffleModeEnabled= */ false))
|
||||
.isEqualTo(timeline.getFirstWindowIndex(/* shuffleModeEnabled= */ false));
|
||||
assertThat(restoredTimeline.getFirstWindowIndex(/* shuffleModeEnabled= */ true))
|
||||
.isEqualTo(timeline.getFirstWindowIndex(/* shuffleModeEnabled= */ true));
|
||||
TimelineAsserts.assertEqualNextWindowIndices(
|
||||
timeline, restoredTimeline, Player.REPEAT_MODE_OFF, /* shuffleModeEnabled= */ false);
|
||||
TimelineAsserts.assertEqualNextWindowIndices(
|
||||
timeline, restoredTimeline, Player.REPEAT_MODE_OFF, /* shuffleModeEnabled= */ true);
|
||||
TimelineAsserts.assertEqualNextWindowIndices(
|
||||
timeline, restoredTimeline, Player.REPEAT_MODE_ONE, /* shuffleModeEnabled= */ false);
|
||||
TimelineAsserts.assertEqualNextWindowIndices(
|
||||
timeline, restoredTimeline, Player.REPEAT_MODE_ONE, /* shuffleModeEnabled= */ true);
|
||||
TimelineAsserts.assertEqualNextWindowIndices(
|
||||
timeline, restoredTimeline, Player.REPEAT_MODE_ALL, /* shuffleModeEnabled= */ false);
|
||||
TimelineAsserts.assertEqualNextWindowIndices(
|
||||
timeline, restoredTimeline, Player.REPEAT_MODE_ALL, /* shuffleModeEnabled= */ true);
|
||||
TimelineAsserts.assertEqualPreviousWindowIndices(
|
||||
timeline, restoredTimeline, Player.REPEAT_MODE_OFF, /* shuffleModeEnabled= */ false);
|
||||
TimelineAsserts.assertEqualPreviousWindowIndices(
|
||||
timeline, restoredTimeline, Player.REPEAT_MODE_OFF, /* shuffleModeEnabled= */ true);
|
||||
TimelineAsserts.assertEqualPreviousWindowIndices(
|
||||
timeline, restoredTimeline, Player.REPEAT_MODE_ONE, /* shuffleModeEnabled= */ false);
|
||||
TimelineAsserts.assertEqualPreviousWindowIndices(
|
||||
timeline, restoredTimeline, Player.REPEAT_MODE_ONE, /* shuffleModeEnabled= */ true);
|
||||
TimelineAsserts.assertEqualPreviousWindowIndices(
|
||||
timeline, restoredTimeline, Player.REPEAT_MODE_ALL, /* shuffleModeEnabled= */ false);
|
||||
TimelineAsserts.assertEqualPreviousWindowIndices(
|
||||
timeline, restoredTimeline, Player.REPEAT_MODE_ALL, /* shuffleModeEnabled= */ true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void roundtripViaBundle_ofWindow_yieldsEqualInstanceExceptUidAndManifest() {
|
||||
Timeline.Window window = new Timeline.Window();
|
||||
|
|
|
|||
|
|
@ -1706,40 +1706,6 @@ public final class ExoPlayerTest {
|
|||
assertThat(positionWhenFullyReadyAfterReprepare).isEqualTo(50);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
testInvalidSeekPositionAfterSourceInfoRefreshWithShuffleModeEnabledUsesCorrectFirstPeriod()
|
||||
throws Exception {
|
||||
FakeMediaSource mediaSource = new FakeMediaSource(new FakeTimeline(/* windowCount= */ 2));
|
||||
AtomicInteger windowIndexAfterUpdate = new AtomicInteger();
|
||||
ActionSchedule actionSchedule =
|
||||
new ActionSchedule.Builder(TAG)
|
||||
.setShuffleOrder(new FakeShuffleOrder(/* length= */ 0))
|
||||
.setShuffleModeEnabled(true)
|
||||
.waitForPlaybackState(Player.STATE_BUFFERING)
|
||||
// Seeking to an invalid position will end playback.
|
||||
.seek(
|
||||
/* windowIndex= */ 100, /* positionMs= */ 0, /* catchIllegalSeekException= */ true)
|
||||
.waitForPlaybackState(Player.STATE_ENDED)
|
||||
.executeRunnable(
|
||||
new PlayerRunnable() {
|
||||
@Override
|
||||
public void run(SimpleExoPlayer player) {
|
||||
windowIndexAfterUpdate.set(player.getCurrentWindowIndex());
|
||||
}
|
||||
})
|
||||
.build();
|
||||
new ExoPlayerTestRunner.Builder(context)
|
||||
.setMediaSources(mediaSource)
|
||||
.setActionSchedule(actionSchedule)
|
||||
.build()
|
||||
.start()
|
||||
.blockUntilActionScheduleFinished(TIMEOUT_MS)
|
||||
.blockUntilEnded(TIMEOUT_MS);
|
||||
|
||||
assertThat(windowIndexAfterUpdate.get()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restartAfterEmptyTimelineWithShuffleModeEnabledUsesCorrectFirstPeriod()
|
||||
throws Exception {
|
||||
|
|
|
|||
|
|
@ -49,18 +49,28 @@ public class LoopingMediaSourceTest {
|
|||
Timeline timeline = getLoopingTimeline(multiWindowTimeline, 1);
|
||||
TimelineAsserts.assertWindowTags(timeline, 111, 222, 333);
|
||||
TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1);
|
||||
for (boolean shuffled : new boolean[] {false, true}) {
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, C.INDEX_UNSET, 0, 1);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, shuffled, 2, 0, 1);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, 1, 2, C.INDEX_UNSET);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, shuffled, 1, 2, 0);
|
||||
}
|
||||
boolean shuffled = false;
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, C.INDEX_UNSET, 0, 1);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, shuffled, 2, 0, 1);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, 1, 2, C.INDEX_UNSET);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, shuffled, 1, 2, 0);
|
||||
shuffled = true; // FakeTimeline has FakeShuffleOrder which returns a reverse order.
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, 1, 2, C.INDEX_UNSET);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, shuffled, 1, 2, 0);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, C.INDEX_UNSET, 0, 1);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, shuffled, 2, 0, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -68,20 +78,32 @@ public class LoopingMediaSourceTest {
|
|||
Timeline timeline = getLoopingTimeline(multiWindowTimeline, 3);
|
||||
TimelineAsserts.assertWindowTags(timeline, 111, 222, 333, 111, 222, 333, 111, 222, 333);
|
||||
TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1, 1, 1, 1, 1, 1, 1);
|
||||
for (boolean shuffled : new boolean[] {false, true}) {
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, C.INDEX_UNSET, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, shuffled, 8, 0, 1, 2, 3, 4, 5, 6, 7);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, 1, 2, 3, 4, 5, 6, 7, 8, C.INDEX_UNSET);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, shuffled, 1, 2, 3, 4, 5, 6, 7, 8, 0);
|
||||
}
|
||||
boolean shuffled = false;
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, C.INDEX_UNSET, 0, 1, 2, 3, 4, 5, 6, 7);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, shuffled, 8, 0, 1, 2, 3, 4, 5, 6, 7);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, 1, 2, 3, 4, 5, 6, 7, 8, C.INDEX_UNSET);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, shuffled, 1, 2, 3, 4, 5, 6, 7, 8, 0);
|
||||
shuffled = true; // FakeTimeline has FakeShuffleOrder which returns a reverse order.
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, 1, 2, C.INDEX_UNSET, 4, 5, 0, 7, 8, 3);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, shuffled, 1, 2, 6, 4, 5, 0, 7, 8, 3);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, 5, 0, 1, 8, 3, 4, C.INDEX_UNSET, 6, 7);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, shuffled, 5, 0, 1, 8, 3, 4, 2, 6, 7);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -89,17 +111,26 @@ public class LoopingMediaSourceTest {
|
|||
Timeline timeline = getLoopingTimeline(multiWindowTimeline, Integer.MAX_VALUE);
|
||||
TimelineAsserts.assertWindowTags(timeline, 111, 222, 333);
|
||||
TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1);
|
||||
for (boolean shuffled : new boolean[] {false, true}) {
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, 2, 0, 1);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, shuffled, 2, 0, 1);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, shuffled, 1, 2, 0);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, shuffled, 1, 2, 0);
|
||||
}
|
||||
boolean shuffled = false;
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, 2, 0, 1);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, shuffled, 2, 0, 1);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, shuffled, 1, 2, 0);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, shuffled, 1, 2, 0);
|
||||
shuffled = true; // FakeTimeline has FakeShuffleOrder which returns a reverse order.
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, shuffled, 1, 2, 0);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, shuffled, 1, 2, 0);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, shuffled, 2, 0, 1);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, shuffled, 0, 1, 2);
|
||||
TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, shuffled, 2, 0, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import android.net.Uri;
|
|||
import android.util.Pair;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
|
|
@ -235,6 +236,7 @@ public final class FakeTimeline extends Timeline {
|
|||
private final TimelineWindowDefinition[] windowDefinitions;
|
||||
private final Object[] manifests;
|
||||
private final int[] periodOffsets;
|
||||
private final FakeShuffleOrder fakeShuffleOrder;
|
||||
|
||||
/**
|
||||
* Returns an ad playback state with the specified number of ads in each of the specified ad
|
||||
|
|
@ -308,6 +310,7 @@ public final class FakeTimeline extends Timeline {
|
|||
for (int i = 0; i < windowDefinitions.length; i++) {
|
||||
periodOffsets[i + 1] = periodOffsets[i] + windowDefinitions[i].periodCount;
|
||||
}
|
||||
fakeShuffleOrder = new FakeShuffleOrder(windowDefinitions.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -315,6 +318,48 @@ public final class FakeTimeline extends Timeline {
|
|||
return windowDefinitions.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextWindowIndex(
|
||||
int windowIndex, @Player.RepeatMode int repeatMode, boolean shuffleModeEnabled) {
|
||||
if (repeatMode == Player.REPEAT_MODE_ONE) {
|
||||
return windowIndex;
|
||||
}
|
||||
if (windowIndex == getLastWindowIndex(shuffleModeEnabled)) {
|
||||
return repeatMode == Player.REPEAT_MODE_ALL
|
||||
? getFirstWindowIndex(shuffleModeEnabled)
|
||||
: C.INDEX_UNSET;
|
||||
}
|
||||
return shuffleModeEnabled ? fakeShuffleOrder.getNextIndex(windowIndex) : windowIndex + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousWindowIndex(
|
||||
int windowIndex, @Player.RepeatMode int repeatMode, boolean shuffleModeEnabled) {
|
||||
if (repeatMode == Player.REPEAT_MODE_ONE) {
|
||||
return windowIndex;
|
||||
}
|
||||
if (windowIndex == getFirstWindowIndex(shuffleModeEnabled)) {
|
||||
return repeatMode == Player.REPEAT_MODE_ALL
|
||||
? getLastWindowIndex(shuffleModeEnabled)
|
||||
: C.INDEX_UNSET;
|
||||
}
|
||||
return shuffleModeEnabled ? fakeShuffleOrder.getPreviousIndex(windowIndex) : windowIndex - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLastWindowIndex(boolean shuffleModeEnabled) {
|
||||
return shuffleModeEnabled
|
||||
? fakeShuffleOrder.getLastIndex()
|
||||
: super.getLastWindowIndex(/* shuffleModeEnabled= */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstWindowIndex(boolean shuffleModeEnabled) {
|
||||
return shuffleModeEnabled
|
||||
? fakeShuffleOrder.getFirstIndex()
|
||||
: super.getFirstWindowIndex(/* shuffleModeEnabled= */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Window getWindow(int windowIndex, Window window, long defaultPositionProjectionUs) {
|
||||
TimelineWindowDefinition windowDefinition = windowDefinitions[windowIndex];
|
||||
|
|
|
|||
|
|
@ -104,6 +104,38 @@ public final class TimelineAsserts {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that previous window indices for each window of the actual timeline are equal to the
|
||||
* indices of the expected timeline depending on the repeat mode and the shuffle mode.
|
||||
*/
|
||||
public static void assertEqualPreviousWindowIndices(
|
||||
Timeline expectedTimeline,
|
||||
Timeline actualTimeline,
|
||||
@Player.RepeatMode int repeatMode,
|
||||
boolean shuffleModeEnabled) {
|
||||
for (int windowIndex = 0; windowIndex < actualTimeline.getWindowCount(); windowIndex++) {
|
||||
assertThat(actualTimeline.getPreviousWindowIndex(windowIndex, repeatMode, shuffleModeEnabled))
|
||||
.isEqualTo(
|
||||
expectedTimeline.getPreviousWindowIndex(windowIndex, repeatMode, shuffleModeEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that next window indices for each window of the actual timeline are equal to the
|
||||
* indices of the expected timeline depending on the repeat mode and the shuffle mode.
|
||||
*/
|
||||
public static void assertEqualNextWindowIndices(
|
||||
Timeline expectedTimeline,
|
||||
Timeline actualTimeline,
|
||||
@Player.RepeatMode int repeatMode,
|
||||
boolean shuffleModeEnabled) {
|
||||
for (int windowIndex = 0; windowIndex < actualTimeline.getWindowCount(); windowIndex++) {
|
||||
assertThat(actualTimeline.getNextWindowIndex(windowIndex, repeatMode, shuffleModeEnabled))
|
||||
.isEqualTo(
|
||||
expectedTimeline.getNextWindowIndex(windowIndex, repeatMode, shuffleModeEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the durations of the periods in the {@link Timeline} and the durations in the
|
||||
* given sequence are equal.
|
||||
|
|
|
|||
Loading…
Reference in a new issue