diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e8f9a2670e0..81a1518b0b8 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -4,6 +4,8 @@ * Common Library: * ExoPlayer: + * Add `cloneAndSet(int, int)` to `ShuffleOrder` with a default + implementation ([#2834](https://github.com/androidx/media/pull/2834)). * CompositionPlayer: * Transformer: * Track Selection: diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java index 5e7ed708563..6f96427b15e 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java @@ -2513,12 +2513,8 @@ private void setMediaSourcesInternal( int currentWindowIndex = getCurrentWindowIndexInternal(playbackInfo); long currentPositionMs = getCurrentPosition(); pendingOperationAcks++; - if (!mediaSourceHolderSnapshots.isEmpty()) { - removeMediaSourceHolders( - /* fromIndex= */ 0, /* toIndexExclusive= */ mediaSourceHolderSnapshots.size()); - } List holders = - addMediaSourceHolders(/* index= */ 0, mediaSources); + setMediaSourceHolders(mediaSources, startWindowIndex); Timeline timeline = createMaskingTimeline(); if (!timeline.isEmpty() && startWindowIndex >= timeline.getWindowCount()) { throw new IllegalSeekPositionException(timeline, startWindowIndex, startPositionMs); @@ -2564,6 +2560,21 @@ private void setMediaSourcesInternal( /* repeatCurrentMediaItem= */ false); } + private List setMediaSourceHolders( + List mediaSources, int startIndex) { + mediaSourceHolderSnapshots.clear(); + List holders = new ArrayList<>(); + for (int i = 0; i < mediaSources.size(); i++) { + MediaSourceList.MediaSourceHolder holder = + new MediaSourceList.MediaSourceHolder(mediaSources.get(i), useLazyPreparation); + holders.add(holder); + mediaSourceHolderSnapshots.add( + i, new MediaSourceHolderSnapshot(holder.uid, holder.mediaSource)); + } + shuffleOrder = shuffleOrder.cloneAndSet(/* insertionCount= */ holders.size(), startIndex); + return holders; + } + private List addMediaSourceHolders( int index, List mediaSources) { List holders = new ArrayList<>(); diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ShuffleOrder.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ShuffleOrder.java index dbdf2f272f8..fc909b653e5 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ShuffleOrder.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ShuffleOrder.java @@ -284,6 +284,25 @@ default ShuffleOrder cloneAndMove(int indexFrom, int indexToExclusive, int newIn return this; } + /** + * Returns a copy of the shuffle order with all elements replaced. + * + *

The default implementation uses {@link #cloneAndClear} and {@link #cloneAndInsert(int, int)} + * to replace all elements in the shuffle order. Custom implementations can override this method + * if the first element in the shuffled order should be set to the one whose index in the + * unshuffled order is {@code startIndex}. + * + * @param insertionCount The number of elements. + * @param startIndex The index of the new element in the unshuffled order that should be the first + * in the shuffled order or {@link C#INDEX_UNSET} if the the first element in the shuffled + * order is not specified. It should be ignored if the new list is empty, or if it is larger + * than the last index (inclusive) of the new list. + * @return A copy of this {@link ShuffleOrder} with the elements replaced. + */ + default ShuffleOrder cloneAndSet(int insertionCount, int startIndex) { + return cloneAndClear().cloneAndInsert(0, insertionCount); + } + /** * Returns a copy of the shuffle order with a range of elements removed. *