Commit 2c671711 by tonihei Committed by Oliver Woodman

Ensure child source ids are kept in ConcatenatingMediaSource.

Previously, child source ids were reassigned when the media source is reused.
Now the creation of the ids moved to outer level to stay in sync with the list
of child media sources.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=188014739
parent cc48b556
...@@ -55,7 +55,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo ...@@ -55,7 +55,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
private static final int MSG_ON_COMPLETION = 6; private static final int MSG_ON_COMPLETION = 6;
// Accessed on the app thread. // Accessed on the app thread.
private final List<MediaSource> mediaSourcesPublic; private final List<MediaSourceHolder> mediaSourcesPublic;
// Accessed on the playback thread. // Accessed on the playback thread.
private final List<MediaSourceHolder> mediaSourceHolders; private final List<MediaSourceHolder> mediaSourceHolders;
...@@ -129,12 +129,13 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo ...@@ -129,12 +129,13 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
} }
this.shuffleOrder = shuffleOrder.getLength() > 0 ? shuffleOrder.cloneAndClear() : shuffleOrder; this.shuffleOrder = shuffleOrder.getLength() > 0 ? shuffleOrder.cloneAndClear() : shuffleOrder;
this.mediaSourceByMediaPeriod = new IdentityHashMap<>(); this.mediaSourceByMediaPeriod = new IdentityHashMap<>();
this.mediaSourcesPublic = new ArrayList<>(Arrays.asList(mediaSources)); this.mediaSourcesPublic = new ArrayList<>();
this.mediaSourceHolders = new ArrayList<>(); this.mediaSourceHolders = new ArrayList<>();
this.deferredMediaPeriods = new ArrayList<>(1); this.deferredMediaPeriods = new ArrayList<>(1);
this.pendingOnCompletionActions = new ArrayList<>(); this.pendingOnCompletionActions = new ArrayList<>();
this.query = new MediaSourceHolder(null, null, -1, -1, -1); this.query = new MediaSourceHolder(/* mediaSource= */ null);
this.isAtomic = isAtomic; this.isAtomic = isAtomic;
addMediaSources(Arrays.asList(mediaSources));
} }
/** /**
...@@ -181,12 +182,13 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo ...@@ -181,12 +182,13 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
public final synchronized void addMediaSource( public final synchronized void addMediaSource(
int index, MediaSource mediaSource, @Nullable Runnable actionOnCompletion) { int index, MediaSource mediaSource, @Nullable Runnable actionOnCompletion) {
Assertions.checkNotNull(mediaSource); Assertions.checkNotNull(mediaSource);
mediaSourcesPublic.add(index, mediaSource); MediaSourceHolder mediaSourceHolder = new MediaSourceHolder(mediaSource);
mediaSourcesPublic.add(index, mediaSourceHolder);
if (player != null) { if (player != null) {
player player
.createMessage(this) .createMessage(this)
.setType(MSG_ADD) .setType(MSG_ADD)
.setPayload(new MessageData<>(index, mediaSource, actionOnCompletion)) .setPayload(new MessageData<>(index, mediaSourceHolder, actionOnCompletion))
.send(); .send();
} else if (actionOnCompletion != null) { } else if (actionOnCompletion != null) {
actionOnCompletion.run(); actionOnCompletion.run();
...@@ -244,12 +246,16 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo ...@@ -244,12 +246,16 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
for (MediaSource mediaSource : mediaSources) { for (MediaSource mediaSource : mediaSources) {
Assertions.checkNotNull(mediaSource); Assertions.checkNotNull(mediaSource);
} }
mediaSourcesPublic.addAll(index, mediaSources); List<MediaSourceHolder> mediaSourceHolders = new ArrayList<>(mediaSources.size());
for (MediaSource mediaSource : mediaSources) {
mediaSourceHolders.add(new MediaSourceHolder(mediaSource));
}
mediaSourcesPublic.addAll(index, mediaSourceHolders);
if (player != null && !mediaSources.isEmpty()) { if (player != null && !mediaSources.isEmpty()) {
player player
.createMessage(this) .createMessage(this)
.setType(MSG_ADD_MULTIPLE) .setType(MSG_ADD_MULTIPLE)
.setPayload(new MessageData<>(index, mediaSources, actionOnCompletion)) .setPayload(new MessageData<>(index, mediaSourceHolders, actionOnCompletion))
.send(); .send();
} else if (actionOnCompletion != null) { } else if (actionOnCompletion != null) {
actionOnCompletion.run(); actionOnCompletion.run();
...@@ -370,7 +376,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo ...@@ -370,7 +376,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
* @return The {@link MediaSource} at this index. * @return The {@link MediaSource} at this index.
*/ */
public final synchronized MediaSource getMediaSource(int index) { public final synchronized MediaSource getMediaSource(int index) {
return mediaSourcesPublic.get(index); return mediaSourcesPublic.get(index).mediaSource;
} }
@Override @Override
...@@ -443,14 +449,14 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo ...@@ -443,14 +449,14 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
public final void handleMessage(int messageType, Object message) throws ExoPlaybackException { public final void handleMessage(int messageType, Object message) throws ExoPlaybackException {
switch (messageType) { switch (messageType) {
case MSG_ADD: case MSG_ADD:
MessageData<MediaSource> addMessage = (MessageData<MediaSource>) message; MessageData<MediaSourceHolder> addMessage = (MessageData<MediaSourceHolder>) message;
shuffleOrder = shuffleOrder.cloneAndInsert(addMessage.index, 1); shuffleOrder = shuffleOrder.cloneAndInsert(addMessage.index, 1);
addMediaSourceInternal(addMessage.index, addMessage.customData); addMediaSourceInternal(addMessage.index, addMessage.customData);
scheduleListenerNotification(addMessage.actionOnCompletion); scheduleListenerNotification(addMessage.actionOnCompletion);
break; break;
case MSG_ADD_MULTIPLE: case MSG_ADD_MULTIPLE:
MessageData<Collection<MediaSource>> addMultipleMessage = MessageData<Collection<MediaSourceHolder>> addMultipleMessage =
(MessageData<Collection<MediaSource>>) message; (MessageData<Collection<MediaSourceHolder>>) message;
shuffleOrder = shuffleOrder =
shuffleOrder.cloneAndInsert( shuffleOrder.cloneAndInsert(
addMultipleMessage.index, addMultipleMessage.customData.size()); addMultipleMessage.index, addMultipleMessage.customData.size());
...@@ -514,33 +520,30 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo ...@@ -514,33 +520,30 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
} }
} }
private void addMediaSourceInternal(int newIndex, MediaSource newMediaSource) { private void addMediaSourceInternal(int newIndex, MediaSourceHolder newMediaSourceHolder) {
final MediaSourceHolder newMediaSourceHolder;
DeferredTimeline newTimeline = new DeferredTimeline();
if (newIndex > 0) { if (newIndex > 0) {
MediaSourceHolder previousHolder = mediaSourceHolders.get(newIndex - 1); MediaSourceHolder previousHolder = mediaSourceHolders.get(newIndex - 1);
newMediaSourceHolder = newMediaSourceHolder.reset(
new MediaSourceHolder( newIndex,
newMediaSource, previousHolder.firstWindowIndexInChild + previousHolder.timeline.getWindowCount(),
newTimeline, previousHolder.firstPeriodIndexInChild + previousHolder.timeline.getPeriodCount());
newIndex,
previousHolder.firstWindowIndexInChild + previousHolder.timeline.getWindowCount(),
previousHolder.firstPeriodIndexInChild + previousHolder.timeline.getPeriodCount());
} else { } else {
newMediaSourceHolder = new MediaSourceHolder(newMediaSource, newTimeline, 0, 0, 0); newMediaSourceHolder.reset(
newIndex, /* firstWindowIndexInChild= */ 0, /* firstPeriodIndexInChild= */ 0);
} }
correctOffsets( correctOffsets(
newIndex, newIndex,
/* childIndexUpdate= */ 1, /* childIndexUpdate= */ 1,
newTimeline.getWindowCount(), newMediaSourceHolder.timeline.getWindowCount(),
newTimeline.getPeriodCount()); newMediaSourceHolder.timeline.getPeriodCount());
mediaSourceHolders.add(newIndex, newMediaSourceHolder); mediaSourceHolders.add(newIndex, newMediaSourceHolder);
prepareChildSource(newMediaSourceHolder, newMediaSourceHolder.mediaSource); prepareChildSource(newMediaSourceHolder, newMediaSourceHolder.mediaSource);
} }
private void addMediaSourcesInternal(int index, Collection<MediaSource> mediaSources) { private void addMediaSourcesInternal(
for (MediaSource mediaSource : mediaSources) { int index, Collection<MediaSourceHolder> mediaSourceHolders) {
addMediaSourceInternal(index++, mediaSource); for (MediaSourceHolder mediaSourceHolder : mediaSourceHolders) {
addMediaSourceInternal(index++, mediaSourceHolder);
} }
} }
...@@ -647,18 +650,19 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo ...@@ -647,18 +650,19 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
public boolean isRemoved; public boolean isRemoved;
public int activeMediaPeriods; public int activeMediaPeriods;
public MediaSourceHolder( public MediaSourceHolder(MediaSource mediaSource) {
MediaSource mediaSource,
DeferredTimeline timeline,
int childIndex,
int window,
int period) {
this.mediaSource = mediaSource; this.mediaSource = mediaSource;
this.timeline = timeline;
this.childIndex = childIndex;
this.firstWindowIndexInChild = window;
this.firstPeriodIndexInChild = period;
this.uid = System.identityHashCode(this); this.uid = System.identityHashCode(this);
this.timeline = new DeferredTimeline();
}
public void reset(int childIndex, int firstWindowIndexInChild, int firstPeriodIndexInChild) {
this.childIndex = childIndex;
this.firstWindowIndexInChild = firstWindowIndexInChild;
this.firstPeriodIndexInChild = firstPeriodIndexInChild;
this.isPrepared = false;
this.isRemoved = false;
this.activeMediaPeriods = 0;
} }
@Override @Override
......
...@@ -23,6 +23,7 @@ import android.os.ConditionVariable; ...@@ -23,6 +23,7 @@ import android.os.ConditionVariable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.DummyMainThread;
import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeMediaSource;
...@@ -851,6 +852,28 @@ public final class ConcatenatingMediaSourceTest { ...@@ -851,6 +852,28 @@ public final class ConcatenatingMediaSourceTest {
unpreparedChildSource.assertReleased(); unpreparedChildSource.assertReleased();
} }
@Test
public void testReleaseAndReprepareSource() throws IOException {
Period period = new Period();
FakeMediaSource[] fakeMediaSources = createMediaSources(/* count= */ 2);
mediaSource.addMediaSource(fakeMediaSources[0]); // Child source with 1 period.
mediaSource.addMediaSource(fakeMediaSources[1]); // Child source with 2 periods.
Timeline timeline = testRunner.prepareSource();
Object periodId0 = timeline.getPeriod(/* periodIndex= */ 0, period, /* setIds= */ true).uid;
Object periodId1 = timeline.getPeriod(/* periodIndex= */ 1, period, /* setIds= */ true).uid;
Object periodId2 = timeline.getPeriod(/* periodIndex= */ 2, period, /* setIds= */ true).uid;
testRunner.releaseSource();
mediaSource.moveMediaSource(/* currentIndex= */ 1, /* newIndex= */ 0);
timeline = testRunner.prepareSource();
Object newPeriodId0 = timeline.getPeriod(/* periodIndex= */ 0, period, /* setIds= */ true).uid;
Object newPeriodId1 = timeline.getPeriod(/* periodIndex= */ 1, period, /* setIds= */ true).uid;
Object newPeriodId2 = timeline.getPeriod(/* periodIndex= */ 2, period, /* setIds= */ true).uid;
assertThat(newPeriodId0).isEqualTo(periodId1);
assertThat(newPeriodId1).isEqualTo(periodId2);
assertThat(newPeriodId2).isEqualTo(periodId0);
}
private static FakeMediaSource[] createMediaSources(int count) { private static FakeMediaSource[] createMediaSources(int count) {
FakeMediaSource[] sources = new FakeMediaSource[count]; FakeMediaSource[] sources = new FakeMediaSource[count];
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment