MediaPeriodQueue { public boolean updateQueuedPeriods(long rendererPositionUs, long maxRendererReadPositionUs) { MediaPeriodHolder previousPeriodHolder = null; MediaPeriodHolder periodHolder = playing; while (periodHolder != null) { MediaPeriodInfo oldPeriodInfo = periodHolder.info; MediaPeriodInfo newPeriodInfo; if (previousPeriodHolder == null) { newPeriodInfo = getUpdatedMediaPeriodInfo(oldPeriodInfo); } else { newPeriodInfo = getFollowingMediaPeriodInfo(previousPeriodHolder, rendererPositionUs); if (newPeriodInfo == null) { return !removeAfter(previousPeriodHolder); } if (!canKeepMediaPeriodHolder(oldPeriodInfo, newPeriodInfo)) { return !removeAfter(previousPeriodHolder); } } periodHolder.info = newPeriodInfo.copyWithContentPositionUs(oldPeriodInfo.contentPositionUs); if (!areDurationsCompatible(oldPeriodInfo.durationUs, newPeriodInfo.durationUs)) { long newDurationInRendererTime = newPeriodInfo.durationUs == C.TIME_UNSET ? Long.MAX_VALUE : periodHolder.toRendererTime(newPeriodInfo.durationUs); boolean isReadingAndReadBeyondNewDuration = periodHolder == reading && (maxRendererReadPositionUs == C.TIME_END_OF_SOURCE || maxRendererReadPositionUs >= newDurationInRendererTime); boolean readingPeriodRemoved = removeAfter(periodHolder); return !readingPeriodRemoved && !isReadingAndReadBeyondNewDuration; } previousPeriodHolder = periodHolder; periodHolder = periodHolder.getNext(); } return true; } MediaPeriodQueue(); void setTimeline(Timeline timeline); boolean updateRepeatMode(@RepeatMode int repeatMode); boolean updateShuffleModeEnabled(boolean shuffleModeEnabled); boolean isLoading(MediaPeriod mediaPeriod); void reevaluateBuffer(long rendererPositionUs); boolean shouldLoadNextMediaPeriod(); @Nullable MediaPeriodInfo getNextMediaPeriodInfo(
      long rendererPositionUs, PlaybackInfo playbackInfo); MediaPeriodHolder enqueueNextMediaPeriodHolder(
      RendererCapabilities[] rendererCapabilities,
      TrackSelector trackSelector,
      Allocator allocator,
      MediaSource mediaSource,
      MediaPeriodInfo info,
      TrackSelectorResult emptyTrackSelectorResult); @Nullable MediaPeriodHolder getLoadingPeriod(); @Nullable MediaPeriodHolder getPlayingPeriod(); @Nullable MediaPeriodHolder getReadingPeriod(); MediaPeriodHolder advanceReadingPeriod(); @Nullable MediaPeriodHolder advancePlayingPeriod(); boolean removeAfter(MediaPeriodHolder mediaPeriodHolder); void clear(boolean keepFrontPeriodUid); boolean updateQueuedPeriods(long rendererPositionUs, long maxRendererReadPositionUs); MediaPeriodInfo getUpdatedMediaPeriodInfo(MediaPeriodInfo info); MediaPeriodId resolveMediaPeriodIdForAds(Object periodUid, long positionUs);  }
@Test public void updateQueuedPeriods_withDurationChangeAfterReadingPeriod_handlesChangeAndRemovesPeriodsAfterChangedPeriod() { setupTimeline( 0, FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US); setAdGroupLoaded( 0); setAdGroupLoaded( 1); enqueueNext(); advancePlaying(); enqueueNext(); enqueueNext(); enqueueNext(); setupTimeline( 0, FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US + 1); setAdGroupLoaded( 0); setAdGroupLoaded( 1); boolean changeHandled = mediaPeriodQueue.updateQueuedPeriods( 0, 0); assertThat(changeHandled).isTrue(); assertThat(getQueueLength()).isEqualTo(3); }
@Test public void updateQueuedPeriods_withDurationChangeBeforeReadingPeriod_doesntHandleChangeAndRemovesPeriodsAfterChangedPeriod() { setupTimeline( 0, FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US); setAdGroupLoaded( 0); setAdGroupLoaded( 1); enqueueNext(); advancePlaying(); enqueueNext(); enqueueNext(); enqueueNext(); advanceReading(); setupTimeline( 0, FIRST_AD_START_TIME_US + 1, SECOND_AD_START_TIME_US); setAdGroupLoaded( 0); setAdGroupLoaded( 1); boolean changeHandled = mediaPeriodQueue.updateQueuedPeriods( 0, FIRST_AD_START_TIME_US); assertThat(changeHandled).isFalse(); assertThat(getQueueLength()).isEqualTo(1); }
@Test public void updateQueuedPeriods_withDurationChangeInReadingPeriodAfterReadingPosition_handlesChangeAndRemovesPeriodsAfterChangedPeriod() { setupTimeline( 0, FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US); setAdGroupLoaded( 0); setAdGroupLoaded( 1); enqueueNext(); advancePlaying(); enqueueNext(); enqueueNext(); enqueueNext(); advanceReading(); advanceReading(); setupTimeline( 0, FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000); setAdGroupLoaded( 0); setAdGroupLoaded( 1); long readingPositionAtStartOfContentBetweenAds = FIRST_AD_START_TIME_US + AD_DURATION_US; boolean changeHandled = mediaPeriodQueue.updateQueuedPeriods( 0, readingPositionAtStartOfContentBetweenAds); assertThat(changeHandled).isTrue(); assertThat(getQueueLength()).isEqualTo(3); }
@Test public void updateQueuedPeriods_withDurationChangeInReadingPeriodBeforeReadingPosition_doesntHandleChangeAndRemovesPeriodsAfterChangedPeriod() { setupTimeline( 0, FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US); setAdGroupLoaded( 0); setAdGroupLoaded( 1); enqueueNext(); advancePlaying(); enqueueNext(); enqueueNext(); enqueueNext(); advanceReading(); advanceReading(); setupTimeline( 0, FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000); setAdGroupLoaded( 0); setAdGroupLoaded( 1); long readingPositionAtEndOfContentBetweenAds = SECOND_AD_START_TIME_US + AD_DURATION_US; boolean changeHandled = mediaPeriodQueue.updateQueuedPeriods( 0, readingPositionAtEndOfContentBetweenAds); assertThat(changeHandled).isFalse(); assertThat(getQueueLength()).isEqualTo(3); }
@Test public void updateQueuedPeriods_withDurationChangeInReadingPeriodReadToEnd_doesntHandleChangeAndRemovesPeriodsAfterChangedPeriod() { setupTimeline( 0, FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US); setAdGroupLoaded( 0); setAdGroupLoaded( 1); enqueueNext(); advancePlaying(); enqueueNext(); enqueueNext(); enqueueNext(); advanceReading(); advanceReading(); setupTimeline( 0, FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000); setAdGroupLoaded( 0); setAdGroupLoaded( 1); boolean changeHandled = mediaPeriodQueue.updateQueuedPeriods( 0, C.TIME_END_OF_SOURCE); assertThat(changeHandled).isFalse(); assertThat(getQueueLength()).isEqualTo(3); }