@Override public Object getUidOfPeriod(int periodIndex) { return timeline.getUidOfPeriod(periodIndex); } }
@Override public Object getUidOfPeriod(int periodIndex) { Object uid = timeline.getUidOfPeriod(periodIndex); return Util.areEqual(uid, replacedId) ? DUMMY_ID : uid; } }
/** * Given a period index into an old timeline, finds the first subsequent period that also exists * in a new timeline. The uid of this period in the new timeline is returned. * * @param oldPeriodUid The index of the period in the old timeline. * @param oldTimeline The old timeline. * @param newTimeline The new timeline. * @return The uid in the new timeline of the first subsequent period, or null if no such period * was found. */ private @Nullable Object resolveSubsequentPeriod( Object oldPeriodUid, Timeline oldTimeline, Timeline newTimeline) { int oldPeriodIndex = oldTimeline.getIndexOfPeriod(oldPeriodUid); int newPeriodIndex = C.INDEX_UNSET; int maxIterations = oldTimeline.getPeriodCount(); for (int i = 0; i < maxIterations && newPeriodIndex == C.INDEX_UNSET; i++) { oldPeriodIndex = oldTimeline.getNextPeriodIndex(oldPeriodIndex, period, window, repeatMode, shuffleModeEnabled); if (oldPeriodIndex == C.INDEX_UNSET) { // We've reached the end of the old timeline. break; } newPeriodIndex = newTimeline.getIndexOfPeriod(oldTimeline.getUidOfPeriod(oldPeriodIndex)); } return newPeriodIndex == C.INDEX_UNSET ? null : newTimeline.getUidOfPeriod(newPeriodIndex); }
private void onAdSourceInfoRefreshed(MediaSource mediaSource, int adGroupIndex, int adIndexInAdGroup, Timeline timeline) { Assertions.checkArgument(timeline.getPeriodCount() == 1); adGroupTimelines[adGroupIndex][adIndexInAdGroup] = timeline; List<DeferredMediaPeriod> mediaPeriods = deferredMediaPeriodByAdMediaSource.remove(mediaSource); if (mediaPeriods != null) { Object periodUid = timeline.getUidOfPeriod(/* periodIndex= */ 0); for (int i = 0; i < mediaPeriods.size(); i++) { DeferredMediaPeriod mediaPeriod = mediaPeriods.get(i); MediaPeriodId adSourceMediaPeriodId = new MediaPeriodId(periodUid, mediaPeriod.id.windowSequenceNumber); mediaPeriod.createPeriod(adSourceMediaPeriodId); } } maybeUpdateSourceInfo(); }
@Override public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { MediaPeriod[] periods = new MediaPeriod[mediaSources.length]; int periodIndex = timelines[0].getIndexOfPeriod(id.periodUid); for (int i = 0; i < periods.length; i++) { MediaPeriodId childMediaPeriodId = id.copyWithPeriodUid(timelines[i].getUidOfPeriod(periodIndex)); periods[i] = mediaSources[i].createPeriod(childMediaPeriodId, allocator, startPositionUs); } return new MergingMediaPeriod(compositeSequenceableLoaderFactory, periods); }
/** * Returns dummy media period id for the first-to-be-played period of the current timeline. * * @param shuffleModeEnabled Whether shuffle mode is enabled. * @param window A writable {@link Timeline.Window}. * @return A dummy media period id for the first-to-be-played period of the current timeline. */ public MediaPeriodId getDummyFirstMediaPeriodId( boolean shuffleModeEnabled, Timeline.Window window) { if (timeline.isEmpty()) { return DUMMY_MEDIA_PERIOD_ID; } int firstPeriodIndex = timeline.getWindow(timeline.getFirstWindowIndex(shuffleModeEnabled), window) .firstPeriodIndex; return new MediaPeriodId(timeline.getUidOfPeriod(firstPeriodIndex)); }
@Override public final Object getUidOfPeriod(int periodIndex) { int childIndex = getChildIndexByPeriodIndex(periodIndex); int firstPeriodIndexInChild = getFirstPeriodIndexByChildIndex(childIndex); Object periodUidInChild = getTimelineByChildIndex(childIndex).getUidOfPeriod(periodIndex - firstPeriodIndexInChild); return getConcatenatedUid(getChildUidByChildIndex(childIndex), periodUidInChild); }
@Test public void testReleaseAndReprepareSource() throws IOException { 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.getUidOfPeriod(/* periodIndex= */ 0); Object periodId1 = timeline.getUidOfPeriod(/* periodIndex= */ 1); Object periodId2 = timeline.getUidOfPeriod(/* periodIndex= */ 2); testRunner.releaseSource(); mediaSource.moveMediaSource(/* currentIndex= */ 1, /* newIndex= */ 0); timeline = testRunner.prepareSource(); Object newPeriodId0 = timeline.getUidOfPeriod(/* periodIndex= */ 0); Object newPeriodId1 = timeline.getUidOfPeriod(/* periodIndex= */ 1); Object newPeriodId2 = timeline.getUidOfPeriod(/* periodIndex= */ 2); assertThat(newPeriodId0).isEqualTo(periodId1); assertThat(newPeriodId1).isEqualTo(periodId2); assertThat(newPeriodId2).isEqualTo(periodId0); }
assertThat(timeline.getUidOfPeriod(i)).isEqualTo(period.uid); for (int repeatMode : REPEAT_MODES) { if (i < accumulatedPeriodCounts[expectedWindowIndex + 1] - 1) {
/* windowIndex= */ 0, new MediaPeriodId( timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0)); period0Seq0 = period0; period0Seq1 = /* windowIndex= */ 0, new MediaPeriodId( timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 1)); window1Period0Seq1 = new EventWindowAndPeriodId( /* windowIndex= */ 1, new MediaPeriodId( timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 1)); if (timeline.getPeriodCount() > 1) { period1 = /* windowIndex= */ 1, new MediaPeriodId( timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1)); period1Seq1 = period1; period1Seq0 = /* windowIndex= */ 1, new MediaPeriodId( timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 0)); period1Seq2 = new EventWindowAndPeriodId( /* windowIndex= */ 1,
private void assertCompletedAllMediaPeriodLoads(Timeline timeline) { Timeline.Period period = new Timeline.Period(); Timeline.Window window = new Timeline.Window(); ArrayList<MediaPeriodId> expectedMediaPeriodIds = new ArrayList<>(); for (int windowIndex = 0; windowIndex < timeline.getWindowCount(); windowIndex++) { timeline.getWindow(windowIndex, window); for (int periodIndex = window.firstPeriodIndex; periodIndex <= window.lastPeriodIndex; periodIndex++) { timeline.getPeriod(periodIndex, period); Object periodUid = timeline.getUidOfPeriod(periodIndex); expectedMediaPeriodIds.add(new MediaPeriodId(periodUid, windowIndex)); for (int adGroupIndex = 0; adGroupIndex < period.getAdGroupCount(); adGroupIndex++) { for (int adIndex = 0; adIndex < period.getAdCountInAdGroup(adGroupIndex); adIndex++) { expectedMediaPeriodIds.add( new MediaPeriodId(periodUid, adGroupIndex, adIndex, windowIndex)); } } } } testRunner.assertCompletedMediaPeriodLoads( expectedMediaPeriodIds.toArray(new MediaPeriodId[0])); }
@Test public void testChildTimelineChangeWithActiveMediaPeriod() throws IOException { FakeMediaSource[] nestedChildSources = createMediaSources(/* count= */ 2); ConcatenatingMediaSource childSource = new ConcatenatingMediaSource(nestedChildSources); mediaSource.addMediaSource(childSource); Timeline timeline = testRunner.prepareSource(); MediaPeriod mediaPeriod = testRunner.createPeriod( new MediaPeriodId( timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 0)); childSource.moveMediaSource(/* currentIndex= */ 0, /* newIndex= */ 1); timeline = testRunner.assertTimelineChangeBlocking(); testRunner.preparePeriod(mediaPeriod, /* positionUs= */ 0); testRunner.assertCompletedMediaPeriodLoads( new MediaPeriodId( timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0)); }
@Test public void testChildSourceIsPreparedWithLazyPreparationAfterPeriodCreation() throws IOException { FakeMediaSource[] childSources = createMediaSources(/* count= */ 2); mediaSource = new ConcatenatingMediaSource( /* isAtomic= */ false, /* useLazyPreparation= */ true, new DefaultShuffleOrder(0), childSources); testRunner = new MediaSourceTestRunner(mediaSource, /* allocator= */ null); Timeline timeline = testRunner.prepareSource(); testRunner.createPeriod( new MediaPeriodId( timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0)); assertThat(childSources[0].isPrepared()).isTrue(); assertThat(childSources[1].isPrepared()).isFalse(); }
.containsAllOf( new MediaPeriodId( timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0), new MediaPeriodId( timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 0)); assertThat(mediaSource.getCreatedMediaPeriods()) .doesNotContain( new MediaPeriodId( timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1));
@Test public void testRemoveChildSourceWithActiveMediaPeriod() throws IOException { FakeMediaSource childSource = createFakeMediaSource(); mediaSource.addMediaSource(childSource); Timeline timeline = testRunner.prepareSource(); MediaPeriod mediaPeriod = testRunner.createPeriod( new MediaPeriodId( timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0)); mediaSource.removeMediaSource(/* index= */ 0); testRunner.assertTimelineChangeBlocking(); testRunner.releasePeriod(mediaPeriod); childSource.assertReleased(); testRunner.releaseSource(); }
@Test public void testDuplicateMediaSources() throws IOException, InterruptedException { Timeline childTimeline = new FakeTimeline(/* windowCount= */ 2); FakeMediaSource childSource = new FakeMediaSource(childTimeline, /* manifest= */ null); mediaSource.addMediaSource(childSource); mediaSource.addMediaSource(childSource); testRunner.prepareSource(); mediaSource.addMediaSources(Arrays.asList(childSource, childSource)); Timeline timeline = testRunner.assertTimelineChangeBlocking(); TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1, 1, 1, 1, 1, 1); testRunner.assertPrepareAndReleaseAllPeriods(); Object childPeriodUid0 = childTimeline.getUidOfPeriod(/* periodIndex= */ 0); Object childPeriodUid1 = childTimeline.getUidOfPeriod(/* periodIndex= */ 1); assertThat(childSource.getCreatedMediaPeriods()) .containsAllOf( new MediaPeriodId(childPeriodUid0, /* windowSequenceNumber= */ 0), new MediaPeriodId(childPeriodUid0, /* windowSequenceNumber= */ 2), new MediaPeriodId(childPeriodUid0, /* windowSequenceNumber= */ 4), new MediaPeriodId(childPeriodUid0, /* windowSequenceNumber= */ 6), new MediaPeriodId(childPeriodUid1, /* windowSequenceNumber= */ 1), new MediaPeriodId(childPeriodUid1, /* windowSequenceNumber= */ 3), new MediaPeriodId(childPeriodUid1, /* windowSequenceNumber= */ 5), new MediaPeriodId(childPeriodUid1, /* windowSequenceNumber= */ 7)); // Assert that only one manifest load is reported because the source is reused. testRunner.assertCompletedManifestLoads(/* windowIndices= */ 0); assertCompletedAllMediaPeriodLoads(timeline); testRunner.releaseSource(); childSource.assertReleased(); }
@Test public void testChildSourceWithLazyPreparationOnlyPreparesSourceOnce() throws IOException { FakeMediaSource[] childSources = createMediaSources(/* count= */ 2); mediaSource = new ConcatenatingMediaSource( /* isAtomic= */ false, /* useLazyPreparation= */ true, new DefaultShuffleOrder(0), childSources); testRunner = new MediaSourceTestRunner(mediaSource, /* allocator= */ null); Timeline timeline = testRunner.prepareSource(); // The lazy preparation must only be triggered once, even if we create multiple periods from // the media source. FakeMediaSource.prepareSource asserts that it's not called twice, so // creating two periods shouldn't throw. MediaPeriodId mediaPeriodId = new MediaPeriodId( timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0); testRunner.createPeriod(mediaPeriodId); testRunner.createPeriod(mediaPeriodId); }
private static Timeline[] getClippedTimelines( FakeMediaSource fakeMediaSource, ClippingMediaSource clippingMediaSource, Timeline... additionalTimelines) throws IOException { MediaSourceTestRunner testRunner = new MediaSourceTestRunner(clippingMediaSource, /* allocator= */ null); Timeline[] clippedTimelines = new Timeline[additionalTimelines.length + 1]; try { clippedTimelines[0] = testRunner.prepareSource(); MediaPeriod mediaPeriod = testRunner.createPeriod( new MediaPeriodId( clippedTimelines[0].getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0)); for (int i = 0; i < additionalTimelines.length; i++) { fakeMediaSource.setNewSourceInfo(additionalTimelines[i], /* newManifest= */ null); clippedTimelines[i + 1] = testRunner.assertTimelineChangeBlocking(); } testRunner.releasePeriod(mediaPeriod); testRunner.releaseSource(); fakeMediaSource.assertReleased(); return clippedTimelines; } finally { testRunner.release(); } } }
.containsExactly( new MediaPeriodId( timeline1.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0), new MediaPeriodId( timeline1.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1), new MediaPeriodId( timeline2.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 2)) .inOrder();
@Test public void testDuplicateNestedMediaSources() throws IOException, InterruptedException { Timeline childTimeline = new FakeTimeline(/* windowCount= */ 1); FakeMediaSource childSource = new FakeMediaSource(childTimeline, /* manifest= */ null); ConcatenatingMediaSource nestedConcatenation = new ConcatenatingMediaSource(); testRunner.prepareSource(); mediaSource.addMediaSources( Arrays.asList(childSource, nestedConcatenation, nestedConcatenation)); testRunner.assertTimelineChangeBlocking(); nestedConcatenation.addMediaSource(childSource); testRunner.assertTimelineChangeBlocking(); nestedConcatenation.addMediaSource(childSource); Timeline timeline = testRunner.assertTimelineChangeBlocking(); TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1, 1, 1); testRunner.assertPrepareAndReleaseAllPeriods(); Object childPeriodUid = childTimeline.getUidOfPeriod(/* periodIndex= */ 0); assertThat(childSource.getCreatedMediaPeriods()) .containsAllOf( new MediaPeriodId(childPeriodUid, /* windowSequenceNumber= */ 0), new MediaPeriodId(childPeriodUid, /* windowSequenceNumber= */ 1), new MediaPeriodId(childPeriodUid, /* windowSequenceNumber= */ 2), new MediaPeriodId(childPeriodUid, /* windowSequenceNumber= */ 3), new MediaPeriodId(childPeriodUid, /* windowSequenceNumber= */ 4)); // Assert that only one manifest load is needed because the source is reused. testRunner.assertCompletedManifestLoads(/* windowIndices= */ 0); assertCompletedAllMediaPeriodLoads(timeline); testRunner.releaseSource(); childSource.assertReleased(); }