diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java index 9c2be39576..07813ff046 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java @@ -26,9 +26,17 @@ import com.google.android.exoplayer2.Timeline; /* package */ abstract class AbstractConcatenatedTimeline extends Timeline { private final int childCount; + private final ShuffleOrder shuffleOrder; - public AbstractConcatenatedTimeline(int childCount) { - this.childCount = childCount; + /** + * Sets up a concatenated timeline with a shuffle order of child timelines. + * + * @param shuffleOrder A shuffle order of child timelines. The number of child timelines must + * match the number of elements in the shuffle order. + */ + public AbstractConcatenatedTimeline(ShuffleOrder shuffleOrder) { + this.shuffleOrder = shuffleOrder; + this.childCount = shuffleOrder.getLength(); } @Override @@ -42,16 +50,17 @@ import com.google.android.exoplayer2.Timeline; shuffleModeEnabled); if (nextWindowIndexInChild != C.INDEX_UNSET) { return firstWindowIndexInChild + nextWindowIndexInChild; - } else { - int nextChildIndex = childIndex + 1; - if (nextChildIndex < childCount) { - return getFirstWindowIndexByChildIndex(nextChildIndex); - } else if (repeatMode == Player.REPEAT_MODE_ALL) { - return 0; - } else { - return C.INDEX_UNSET; - } } + int nextChildIndex = shuffleModeEnabled ? shuffleOrder.getNextIndex(childIndex) + : childIndex + 1; + if (nextChildIndex != C.INDEX_UNSET && nextChildIndex < childCount) { + return getFirstWindowIndexByChildIndex(nextChildIndex) + + getTimelineByChildIndex(nextChildIndex).getFirstWindowIndex(shuffleModeEnabled); + } + if (repeatMode == Player.REPEAT_MODE_ALL) { + return getFirstWindowIndex(shuffleModeEnabled); + } + return C.INDEX_UNSET; } @Override @@ -65,15 +74,31 @@ import com.google.android.exoplayer2.Timeline; shuffleModeEnabled); if (previousWindowIndexInChild != C.INDEX_UNSET) { return firstWindowIndexInChild + previousWindowIndexInChild; - } else { - if (firstWindowIndexInChild > 0) { - return firstWindowIndexInChild - 1; - } else if (repeatMode == Player.REPEAT_MODE_ALL) { - return getWindowCount() - 1; - } else { - return C.INDEX_UNSET; - } } + int previousChildIndex = shuffleModeEnabled ? shuffleOrder.getPreviousIndex(childIndex) + : childIndex - 1; + if (previousChildIndex != C.INDEX_UNSET && previousChildIndex >= 0) { + return getFirstWindowIndexByChildIndex(previousChildIndex) + + getTimelineByChildIndex(previousChildIndex).getLastWindowIndex(shuffleModeEnabled); + } + if (repeatMode == Player.REPEAT_MODE_ALL) { + return getLastWindowIndex(shuffleModeEnabled); + } + return C.INDEX_UNSET; + } + + @Override + public int getLastWindowIndex(boolean shuffleModeEnabled) { + int lastChildIndex = shuffleModeEnabled ? shuffleOrder.getLastIndex() : childCount - 1; + return getFirstWindowIndexByChildIndex(lastChildIndex) + + getTimelineByChildIndex(lastChildIndex).getLastWindowIndex(shuffleModeEnabled); + } + + @Override + public int getFirstWindowIndex(boolean shuffleModeEnabled) { + int firstChildIndex = shuffleModeEnabled ? shuffleOrder.getFirstIndex() : 0; + return getFirstWindowIndexByChildIndex(firstChildIndex) + + getTimelineByChildIndex(firstChildIndex).getFirstWindowIndex(shuffleModeEnabled); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index 0f6f1b345d..f12e1c006f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -19,6 +19,7 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.ShuffleOrder.UnshuffledShuffleOrder; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; @@ -167,7 +168,7 @@ public final class ConcatenatingMediaSource implements MediaSource { private final boolean isRepeatOneAtomic; public ConcatenatedTimeline(Timeline[] timelines, boolean isRepeatOneAtomic) { - super(timelines.length); + super(new UnshuffledShuffleOrder(timelines.length)); int[] sourcePeriodOffsets = new int[timelines.length]; int[] sourceWindowOffsets = new int[timelines.length]; long periodCount = 0; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java index c2d2e5f11e..02d4bad2bf 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java @@ -23,6 +23,7 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer.ExoPlayerComponent; import com.google.android.exoplayer2.ExoPlayer.ExoPlayerMessage; import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.ShuffleOrder.UnshuffledShuffleOrder; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.util.Assertions; @@ -397,7 +398,7 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl public ConcatenatedTimeline(Collection mediaSourceHolders, int windowCount, int periodCount) { - super(mediaSourceHolders.size()); + super(new UnshuffledShuffleOrder(mediaSourceHolders.size())); this.windowCount = windowCount; this.periodCount = periodCount; int childCount = mediaSourceHolders.size(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index 28380e50b2..00e3c50506 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -19,6 +19,7 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.ShuffleOrder.UnshuffledShuffleOrder; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; @@ -101,7 +102,7 @@ public final class LoopingMediaSource implements MediaSource { private final int loopCount; public LoopingTimeline(Timeline childTimeline, int loopCount) { - super(loopCount); + super(new UnshuffledShuffleOrder(loopCount)); this.childTimeline = childTimeline; childPeriodCount = childTimeline.getPeriodCount(); childWindowCount = childTimeline.getWindowCount();