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 985c43fa55..b9ce48d3c8 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 @@ -50,6 +50,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSourceNote: If you want to move the instance, it's preferable to use {@link #moveMediaSource(int, * int)} instead. * + *

Note: If you want to remove a set of contiguous sources, it's preferable to use + * {@link #removeMediaSourceRange(int, int)} instead. + * * @param index The index at which the media source will be removed. This index must be in the * range of 0 <= index < {@link #getSize()}. */ @@ -278,6 +282,9 @@ public class ConcatenatingMediaSource extends CompositeMediaSourceNote: If you want to move the instance, it's preferable to use {@link #moveMediaSource(int, * int)} instead. * + *

Note: If you want to remove a set of contiguous sources, it's preferable to use + * {@link #removeMediaSourceRange(int, int)} instead. + * * @param index The index at which the media source will be removed. This index must be in the * range of 0 <= index < {@link #getSize()}. * @param actionOnCompletion A {@link Runnable} which is executed immediately after the media @@ -297,6 +304,79 @@ public class ConcatenatingMediaSource extends CompositeMediaSourceNote: when specified range is empty, no actual media source is removed and no exception + * is thrown. + * + * @param fromIndex The initial range index, pointing to the first media source that will be + * removed. This index must be in the range of 0 <= index < {@link #getSize()}. + * @param toIndex The final range index, pointing to the first media source that will be left + * untouched. The last media source to be removed is at index {@code toIndex} - 1. + * This index must be in the range of 0 <= index < {@link #getSize()}. + * + * @throws IndexOutOfBoundsException when either index is out of playlist bounds, i.e. {@code + * fromIndex} < 0 or >= {@link #getSize()}, {@code toIndex} < 0 or > {@link + * #getSize()} + * @throws IndexOutOfBoundsException when range is malformed, i.e. {@code fromIndex} > + * {@code toIndex} + */ + public final synchronized void removeMediaSourceRange(int fromIndex, int toIndex) { + removeMediaSourceRange(fromIndex, toIndex, null); + } + + /** + * Removes a range of {@link MediaSource}s from the playlist, by specifying an initial index + * (included) and a final index (excluded), and executes a custom action on completion.. + * + *

Note: when specified range is empty, no actual media source is removed and no exception + * is thrown. + * + * @param fromIndex The initial range index, pointing to the first media source that will be + * removed. This index must be in the range of 0 <= index < {@link #getSize()}. + * @param toIndex The final range index, pointing to the first media source that will be left + * untouched. The last media source to be removed is at index {@code toIndex} - 1. + * This index must be in the range of 0 <= index < {@link #getSize()}. + * + * @throws IndexOutOfBoundsException when either index is out of playlist bounds, i.e. {@code + * fromIndex} < 0 or >= {@link #getSize()}, {@code toIndex} < 0 or > {@link + * #getSize()} + * @throws IndexOutOfBoundsException when range is malformed, i.e. {@code fromIndex} > + * {@code toIndex} + * @param actionOnCompletion A {@link Runnable} which is executed immediately after the media + * source has been removed from the playlist. + */ + public final synchronized void removeMediaSourceRange( + int fromIndex, int toIndex, @Nullable Runnable actionOnCompletion) { + if (fromIndex < 0 || fromIndex >= mediaSourcesPublic.size()) { + throw new IndexOutOfBoundsException(String.format("Cannot remove source range: initial index (%d) out of bounds", fromIndex)); + } + if (toIndex < 0 || toIndex > mediaSourcesPublic.size()) { + throw new IndexOutOfBoundsException(String.format("Cannot remove source range: final index (%d) out of bounds", toIndex)); + } + if (fromIndex > toIndex) { + throw new IndexOutOfBoundsException(String.format("Cannot remove source range: range malformed (%d, %d)", fromIndex, toIndex)); + } + if (fromIndex == toIndex) { + if (actionOnCompletion != null) { + actionOnCompletion.run(); + } + return; + } + mediaSourcesPublic.subList(fromIndex, toIndex).clear(); + if (player != null) { + player + .createMessage(this) + .setType(MSG_REMOVE_RANGE) + .setPayload(new MessageData<>(fromIndex, toIndex, actionOnCompletion)) + .send(); + } else if (actionOnCompletion != null) { + actionOnCompletion.run(); + } + } + /** * Moves an existing {@link MediaSource} within the playlist. * @@ -489,6 +569,18 @@ public class ConcatenatingMediaSource extends CompositeMediaSource removeRangeMessage = (MessageData) message; + int fromIndex = removeRangeMessage.index; + int toIndex = removeRangeMessage.customData; + for (int index = toIndex - 1; index >= fromIndex; index--) { + shuffleOrder = shuffleOrder.cloneAndRemove(index); + } + for (int index = toIndex - 1; index >= fromIndex; index--) { + removeMediaSourceInternal(index); + } + scheduleListenerNotification(removeRangeMessage.actionOnCompletion); + break; case MSG_MOVE: MessageData moveMessage = (MessageData) message; shuffleOrder = shuffleOrder.cloneAndRemove(moveMessage.index);