mirror of
https://github.com/samsonjs/media.git
synced 2026-03-31 10:25:48 +00:00
Add support to change shuffle order after playlist creation.
This allows to update the shuffle order after the ConcatenatingMediaSource has been created. ShuffleOrder objects should be immutable to ensure thread safety and thus there is no way to do this currently. Issue:#4791 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=212443146
This commit is contained in:
parent
b31438b670
commit
b1d48179e8
4 changed files with 101 additions and 2 deletions
|
|
@ -98,6 +98,8 @@
|
|||
([#3972](https://github.com/google/ExoPlayer/issues/3972)).
|
||||
* Support range removal with `removeMediaSourceRange` methods
|
||||
([#4542](https://github.com/google/ExoPlayer/issues/4542)).
|
||||
* Support setting a new shuffle order with `setShuffleOrder`
|
||||
([#4791](https://github.com/google/ExoPlayer/issues/4791)).
|
||||
* MPEG-TS: Support CEA-608/708 in H262
|
||||
([#2565](https://github.com/google/ExoPlayer/issues/2565)).
|
||||
* Allow apps to pass a `CacheKeyFactory` for setting custom cache keys when
|
||||
|
|
|
|||
|
|
@ -53,8 +53,9 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
|
|||
private static final int MSG_REMOVE_RANGE = 3;
|
||||
private static final int MSG_MOVE = 4;
|
||||
private static final int MSG_CLEAR = 5;
|
||||
private static final int MSG_NOTIFY_LISTENER = 6;
|
||||
private static final int MSG_ON_COMPLETION = 7;
|
||||
private static final int MSG_SET_SHUFFLE_ORDER = 6;
|
||||
private static final int MSG_NOTIFY_LISTENER = 7;
|
||||
private static final int MSG_ON_COMPLETION = 8;
|
||||
|
||||
// Accessed on the app thread.
|
||||
private final List<MediaSourceHolder> mediaSourcesPublic;
|
||||
|
|
@ -433,6 +434,47 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
|
|||
return mediaSourcesPublic.get(index).mediaSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new shuffle order to use when shuffling the child media sources.
|
||||
*
|
||||
* @param shuffleOrder A {@link ShuffleOrder}.
|
||||
*/
|
||||
public final synchronized void setShuffleOrder(ShuffleOrder shuffleOrder) {
|
||||
setShuffleOrder(shuffleOrder, /* actionOnCompletion= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new shuffle order to use when shuffling the child media sources.
|
||||
*
|
||||
* @param shuffleOrder A {@link ShuffleOrder}.
|
||||
* @param actionOnCompletion A {@link Runnable} which is executed immediately after the shuffle
|
||||
* order has been changed.
|
||||
*/
|
||||
public final synchronized void setShuffleOrder(
|
||||
ShuffleOrder shuffleOrder, @Nullable Runnable actionOnCompletion) {
|
||||
ExoPlayer player = this.player;
|
||||
if (player != null) {
|
||||
int size = getSize();
|
||||
if (shuffleOrder.getLength() != size) {
|
||||
shuffleOrder =
|
||||
shuffleOrder
|
||||
.cloneAndClear()
|
||||
.cloneAndInsert(/* insertionIndex= */ 0, /* insertionCount= */ size);
|
||||
}
|
||||
player
|
||||
.createMessage(this)
|
||||
.setType(MSG_SET_SHUFFLE_ORDER)
|
||||
.setPayload(new MessageData<>(/* index= */ 0, shuffleOrder, actionOnCompletion))
|
||||
.send();
|
||||
} else {
|
||||
this.shuffleOrder =
|
||||
shuffleOrder.getLength() > 0 ? shuffleOrder.cloneAndClear() : shuffleOrder;
|
||||
if (actionOnCompletion != null) {
|
||||
actionOnCompletion.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized void prepareSourceInternal(
|
||||
ExoPlayer player,
|
||||
|
|
@ -579,6 +621,11 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
|
|||
clearInternal();
|
||||
scheduleListenerNotification((Runnable) message);
|
||||
break;
|
||||
case MSG_SET_SHUFFLE_ORDER:
|
||||
MessageData<ShuffleOrder> shuffleOrderMessage = (MessageData<ShuffleOrder>) message;
|
||||
shuffleOrder = shuffleOrderMessage.customData;
|
||||
scheduleListenerNotification(shuffleOrderMessage.actionOnCompletion);
|
||||
break;
|
||||
case MSG_NOTIFY_LISTENER:
|
||||
notifyListener();
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import java.util.Random;
|
|||
|
||||
/**
|
||||
* Shuffled order of indices.
|
||||
*
|
||||
* <p>The shuffle order must be immutable to ensure thread safety.
|
||||
*/
|
||||
public interface ShuffleOrder {
|
||||
|
||||
|
|
|
|||
|
|
@ -925,6 +925,54 @@ public final class ConcatenatingMediaSourceTest {
|
|||
testRunner.createPeriod(mediaPeriodId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetShuffleOrderBeforePreparation() throws Exception {
|
||||
mediaSource.setShuffleOrder(new ShuffleOrder.UnshuffledShuffleOrder(/* length= */ 0));
|
||||
mediaSource.addMediaSources(
|
||||
Arrays.asList(createFakeMediaSource(), createFakeMediaSource(), createFakeMediaSource()));
|
||||
Timeline timeline = testRunner.prepareSource();
|
||||
|
||||
assertThat(timeline.getFirstWindowIndex(/* shuffleModeEnabled= */ true)).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetShuffleOrderAfterPreparation() throws Exception {
|
||||
mediaSource.addMediaSources(
|
||||
Arrays.asList(createFakeMediaSource(), createFakeMediaSource(), createFakeMediaSource()));
|
||||
testRunner.prepareSource();
|
||||
mediaSource.setShuffleOrder(new ShuffleOrder.UnshuffledShuffleOrder(/* length= */ 3));
|
||||
Timeline timeline = testRunner.assertTimelineChangeBlocking();
|
||||
|
||||
assertThat(timeline.getFirstWindowIndex(/* shuffleModeEnabled= */ true)).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomCallbackBeforePreparationSetShuffleOrder() throws Exception {
|
||||
Runnable runnable = Mockito.mock(Runnable.class);
|
||||
mediaSource.setShuffleOrder(new ShuffleOrder.UnshuffledShuffleOrder(/* length= */ 0), runnable);
|
||||
|
||||
verify(runnable).run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomCallbackAfterPreparationSetShuffleOrder() throws Exception {
|
||||
DummyMainThread dummyMainThread = new DummyMainThread();
|
||||
try {
|
||||
mediaSource.addMediaSources(
|
||||
Arrays.asList(createFakeMediaSource(), createFakeMediaSource(), createFakeMediaSource()));
|
||||
testRunner.prepareSource();
|
||||
TimelineGrabber timelineGrabber = new TimelineGrabber(testRunner);
|
||||
dummyMainThread.runOnMainThread(
|
||||
() ->
|
||||
mediaSource.setShuffleOrder(
|
||||
new ShuffleOrder.UnshuffledShuffleOrder(/* length= */ 3), timelineGrabber));
|
||||
Timeline timeline = timelineGrabber.assertTimelineChangeBlocking();
|
||||
assertThat(timeline.getFirstWindowIndex(/* shuffleModeEnabled= */ true)).isEqualTo(0);
|
||||
} finally {
|
||||
dummyMainThread.release();
|
||||
}
|
||||
}
|
||||
|
||||
private void assertCompletedAllMediaPeriodLoads(Timeline timeline) {
|
||||
Timeline.Period period = new Timeline.Period();
|
||||
Timeline.Window window = new Timeline.Window();
|
||||
|
|
|
|||
Loading…
Reference in a new issue