diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 04e35d6cec8..f9d225cf863 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -101,6 +101,8 @@ a `playerName` of `PlayerId.Preload.name` ("preload"), and inject the created `DefaultLoadControl` via `DefaultPreloadManager.Builder.setLoadControl(LoadControl)`. + * Add `cloneAndSet(int, int)` to `ShuffleOrder` with a default + implementation ([#2834](https://github.com/androidx/media/pull/2834)). * Transformer: * Add support for `COMMAND_SET_AUDIO_ATTRIBUTES` and audio focus handling in `CompositionPlayer`. 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 8e29727c69c..68b329c94b2 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java @@ -2505,12 +2505,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); @@ -2556,6 +2552,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. *