diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java index 208a235777..3efff58f5d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java @@ -44,6 +44,7 @@ import com.google.android.exoplayer2.util.Assertions; private final Timeline.Period period; private final Timeline.Window window; + private long nextWindowSequenceNumber; private Timeline timeline; private @RepeatMode int repeatMode; private boolean shuffleModeEnabled; @@ -368,18 +369,70 @@ import com.google.android.exoplayer2.util.Assertions; * @return The identifier for the first media period to play, taking into account unplayed ads. */ public MediaPeriodId resolveMediaPeriodIdForAds(int periodIndex, long positionUs) { - timeline.getPeriod(periodIndex, period); - int adGroupIndex = period.getAdGroupIndexForPositionUs(positionUs); - if (adGroupIndex == C.INDEX_UNSET) { - return new MediaPeriodId(periodIndex); - } else { - int adIndexInAdGroup = period.getFirstAdIndexToPlay(adGroupIndex); - return new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup); - } + long windowSequenceNumber = resolvePeriodIndexToWindowSequenceNumber(periodIndex); + return resolveMediaPeriodIdForAds(periodIndex, positionUs, windowSequenceNumber); } // Internal methods. + /** + * Resolves the specified timeline period and position to a {@link MediaPeriodId} that should be + * played, returning an identifier for an ad group if one needs to be played before the specified + * position, or an identifier for a content media period if not. + * + * @param periodIndex The index of the timeline period to play. + * @param positionUs The next content position in the period to play. + * @param windowSequenceNumber The sequence number of the window in the buffered sequence of + * windows this period is part of. + * @return The identifier for the first media period to play, taking into account unplayed ads. + */ + private MediaPeriodId resolveMediaPeriodIdForAds( + int periodIndex, long positionUs, long windowSequenceNumber) { + timeline.getPeriod(periodIndex, period); + int adGroupIndex = period.getAdGroupIndexForPositionUs(positionUs); + if (adGroupIndex == C.INDEX_UNSET) { + return new MediaPeriodId(periodIndex, windowSequenceNumber); + } else { + int adIndexInAdGroup = period.getFirstAdIndexToPlay(adGroupIndex); + return new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber); + } + } + + /** + * Resolves the specified period index to a corresponding window sequence number. Either by + * reusing the window sequence number of an existing matching media period or by creating a new + * window sequence number. + * + * @param periodIndex The index of the timeline period. + * @return A window sequence number for a media period created for this timeline period. + */ + private long resolvePeriodIndexToWindowSequenceNumber(int periodIndex) { + Object periodUid = timeline.getPeriod(periodIndex, period, /* setIds= */ true).uid; + MediaPeriodHolder mediaPeriodHolder = getFrontPeriod(); + while (mediaPeriodHolder != null) { + if (mediaPeriodHolder.uid.equals(periodUid)) { + // Reuse window sequence number of first exact period match. + return mediaPeriodHolder.info.id.windowSequenceNumber; + } + mediaPeriodHolder = mediaPeriodHolder.next; + } + int windowIndex = period.windowIndex; + mediaPeriodHolder = getFrontPeriod(); + while (mediaPeriodHolder != null) { + int indexOfHolderInTimeline = timeline.getIndexOfPeriod(mediaPeriodHolder.uid); + if (indexOfHolderInTimeline != C.INDEX_UNSET) { + int holderWindowIndex = timeline.getPeriod(indexOfHolderInTimeline, period).windowIndex; + if (holderWindowIndex == windowIndex) { + // As an alternative, try to match other periods of the same window. + return mediaPeriodHolder.info.id.windowSequenceNumber; + } + } + mediaPeriodHolder = mediaPeriodHolder.next; + } + // If no match is found, create new sequence number. + return nextWindowSequenceNumber++; + } + /** * Returns whether {@code periodHolder} can be kept for playing the media period described by * {@code info}. @@ -466,7 +519,10 @@ import com.google.android.exoplayer2.util.Assertions; } long startPositionUs; - int nextWindowIndex = timeline.getPeriod(nextPeriodIndex, period).windowIndex; + int nextWindowIndex = + timeline.getPeriod(nextPeriodIndex, period, /* setIds= */ true).windowIndex; + Object nextPeriodUid = period.uid; + long windowSequenceNumber = mediaPeriodInfo.id.windowSequenceNumber; if (timeline.getWindow(nextWindowIndex, window).firstPeriodIndex == nextPeriodIndex) { // We're starting to buffer a new window. When playback transitions to this window we'll // want it to be from its default start position. The expected delay until playback @@ -487,10 +543,16 @@ import com.google.android.exoplayer2.util.Assertions; } nextPeriodIndex = defaultPosition.first; startPositionUs = defaultPosition.second; + if (mediaPeriodHolder.next != null && mediaPeriodHolder.next.uid.equals(nextPeriodUid)) { + windowSequenceNumber = mediaPeriodHolder.next.info.id.windowSequenceNumber; + } else { + windowSequenceNumber = nextWindowSequenceNumber++; + } } else { startPositionUs = 0; } - MediaPeriodId periodId = resolveMediaPeriodIdForAds(nextPeriodIndex, startPositionUs); + MediaPeriodId periodId = + resolveMediaPeriodIdForAds(nextPeriodIndex, startPositionUs, windowSequenceNumber); return getMediaPeriodInfo(periodId, startPositionUs, startPositionUs); } @@ -512,11 +574,14 @@ import com.google.android.exoplayer2.util.Assertions; currentPeriodId.periodIndex, adGroupIndex, nextAdIndexInAdGroup, - mediaPeriodInfo.contentPositionUs); + mediaPeriodInfo.contentPositionUs, + currentPeriodId.windowSequenceNumber); } else { // Play content from the ad group position. return getMediaPeriodInfoForContent( - currentPeriodId.periodIndex, mediaPeriodInfo.contentPositionUs); + currentPeriodId.periodIndex, + mediaPeriodInfo.contentPositionUs, + currentPeriodId.windowSequenceNumber); } } else if (mediaPeriodInfo.endPositionUs != C.TIME_END_OF_SOURCE) { // Play the next ad group if it's available. @@ -524,7 +589,9 @@ import com.google.android.exoplayer2.util.Assertions; if (nextAdGroupIndex == C.INDEX_UNSET) { // The next ad group can't be played. Play content from the ad group position instead. return getMediaPeriodInfoForContent( - currentPeriodId.periodIndex, mediaPeriodInfo.endPositionUs); + currentPeriodId.periodIndex, + mediaPeriodInfo.endPositionUs, + currentPeriodId.windowSequenceNumber); } int adIndexInAdGroup = period.getFirstAdIndexToPlay(nextAdGroupIndex); return !period.isAdAvailable(nextAdGroupIndex, adIndexInAdGroup) @@ -533,7 +600,8 @@ import com.google.android.exoplayer2.util.Assertions; currentPeriodId.periodIndex, nextAdGroupIndex, adIndexInAdGroup, - mediaPeriodInfo.endPositionUs); + mediaPeriodInfo.endPositionUs, + currentPeriodId.windowSequenceNumber); } else { // Check if the postroll ad should be played. int adGroupCount = period.getAdGroupCount(); @@ -551,7 +619,11 @@ import com.google.android.exoplayer2.util.Assertions; } long contentDurationUs = period.getDurationUs(); return getMediaPeriodInfoForAd( - currentPeriodId.periodIndex, adGroupIndex, adIndexInAdGroup, contentDurationUs); + currentPeriodId.periodIndex, + adGroupIndex, + adIndexInAdGroup, + contentDurationUs, + currentPeriodId.windowSequenceNumber); } } @@ -583,15 +655,24 @@ import com.google.android.exoplayer2.util.Assertions; return null; } return getMediaPeriodInfoForAd( - id.periodIndex, id.adGroupIndex, id.adIndexInAdGroup, contentPositionUs); + id.periodIndex, + id.adGroupIndex, + id.adIndexInAdGroup, + contentPositionUs, + id.windowSequenceNumber); } else { - return getMediaPeriodInfoForContent(id.periodIndex, startPositionUs); + return getMediaPeriodInfoForContent(id.periodIndex, startPositionUs, id.windowSequenceNumber); } } private MediaPeriodInfo getMediaPeriodInfoForAd( - int periodIndex, int adGroupIndex, int adIndexInAdGroup, long contentPositionUs) { - MediaPeriodId id = new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup); + int periodIndex, + int adGroupIndex, + int adIndexInAdGroup, + long contentPositionUs, + long windowSequenceNumber) { + MediaPeriodId id = + new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber); boolean isLastInPeriod = isLastInPeriod(id, C.TIME_END_OF_SOURCE); boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod); long durationUs = @@ -612,8 +693,9 @@ import com.google.android.exoplayer2.util.Assertions; isLastInTimeline); } - private MediaPeriodInfo getMediaPeriodInfoForContent(int periodIndex, long startPositionUs) { - MediaPeriodId id = new MediaPeriodId(periodIndex); + private MediaPeriodInfo getMediaPeriodInfoForContent( + int periodIndex, long startPositionUs, long windowSequenceNumber) { + MediaPeriodId id = new MediaPeriodId(periodIndex, windowSequenceNumber); timeline.getPeriod(id.periodIndex, period); int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(startPositionUs); long endUs = diff --git a/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java index bb39bf3d0b..3ff2ec9461 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java @@ -41,7 +41,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; this( timeline, /* manifest= */ null, - new MediaPeriodId(0), + new MediaPeriodId(/* periodIndex= */ 0), startPositionUs, /* contentPositionUs =*/ C.TIME_UNSET, Player.STATE_IDLE, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java index 25da60cb74..02bd0cdbc7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java @@ -63,12 +63,6 @@ public interface MediaSource { */ final class MediaPeriodId { - /** - * Value for unset media period identifiers. - */ - public static final MediaPeriodId UNSET = - new MediaPeriodId(C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET); - /** * The timeline period index. */ @@ -86,13 +80,32 @@ public interface MediaSource { */ public final int adIndexInAdGroup; + /** + * The sequence number of the window in the buffered sequence of windows this media period is + * part of. {@link C#INDEX_UNSET} if the media period id is not part of a buffered sequence of + * windows. + */ + public final long windowSequenceNumber; + + /** + * Creates a media period identifier for a dummy period which is not part of a buffered sequence + * of windows. + * + * @param periodIndex The period index. + */ + public MediaPeriodId(int periodIndex) { + this(periodIndex, C.INDEX_UNSET); + } + /** * Creates a media period identifier for the specified period in the timeline. * * @param periodIndex The timeline period index. + * @param windowSequenceNumber The sequence number of the window in the buffered sequence of + * windows this media period is part of. */ - public MediaPeriodId(int periodIndex) { - this(periodIndex, C.INDEX_UNSET, C.INDEX_UNSET); + public MediaPeriodId(int periodIndex, long windowSequenceNumber) { + this(periodIndex, C.INDEX_UNSET, C.INDEX_UNSET, windowSequenceNumber); } /** @@ -102,19 +115,24 @@ public interface MediaSource { * @param periodIndex The index of the timeline period that contains the ad group. * @param adGroupIndex The index of the ad group. * @param adIndexInAdGroup The index of the ad in the ad group. + * @param windowSequenceNumber The sequence number of the window in the buffered sequence of + * windows this media period is part of. */ - public MediaPeriodId(int periodIndex, int adGroupIndex, int adIndexInAdGroup) { + public MediaPeriodId( + int periodIndex, int adGroupIndex, int adIndexInAdGroup, long windowSequenceNumber) { this.periodIndex = periodIndex; this.adGroupIndex = adGroupIndex; this.adIndexInAdGroup = adIndexInAdGroup; + this.windowSequenceNumber = windowSequenceNumber; } /** * Returns a copy of this period identifier but with {@code newPeriodIndex} as its period index. */ public MediaPeriodId copyWithPeriodIndex(int newPeriodIndex) { - return periodIndex == newPeriodIndex ? this - : new MediaPeriodId(newPeriodIndex, adGroupIndex, adIndexInAdGroup); + return periodIndex == newPeriodIndex + ? this + : new MediaPeriodId(newPeriodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber); } /** @@ -134,8 +152,10 @@ public interface MediaSource { } MediaPeriodId periodId = (MediaPeriodId) obj; - return periodIndex == periodId.periodIndex && adGroupIndex == periodId.adGroupIndex - && adIndexInAdGroup == periodId.adIndexInAdGroup; + return periodIndex == periodId.periodIndex + && adGroupIndex == periodId.adGroupIndex + && adIndexInAdGroup == periodId.adIndexInAdGroup + && windowSequenceNumber == periodId.windowSequenceNumber; } @Override @@ -144,6 +164,7 @@ public interface MediaSource { result = 31 * result + periodIndex; result = 31 * result + adGroupIndex; result = 31 * result + adIndexInAdGroup; + result = 31 * result + (int) windowSequenceNumber; return result; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java index 8c4d85ff4c..854be90d1c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java @@ -235,7 +235,10 @@ public final class AdsMediaSource extends CompositeMediaSource { } MediaSource mediaSource = adGroupMediaSources[adGroupIndex][adIndexInAdGroup]; DeferredMediaPeriod deferredMediaPeriod = - new DeferredMediaPeriod(mediaSource, new MediaPeriodId(0), allocator); + new DeferredMediaPeriod( + mediaSource, + new MediaPeriodId(/* periodIndex= */ 0, id.windowSequenceNumber), + allocator); deferredMediaPeriod.setPrepareErrorListener( new AdPrepareErrorListener(adGroupIndex, adIndexInAdGroup)); List mediaPeriods = deferredMediaPeriodByAdMediaSource.get(mediaSource); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java index 7faa349705..3d0cde5df8 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -1802,7 +1802,10 @@ public final class ExoPlayerTest { testRunner.assertPlayedPeriodIndices(0, 1); // Assert that the second period was re-created from the new timeline. assertThat(mediaSource.getCreatedMediaPeriods()) - .containsExactly(new MediaPeriodId(0), new MediaPeriodId(1), new MediaPeriodId(1)) + .containsExactly( + new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0), + new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 1), + new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 2)) .inOrder(); } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java index d7cf8db4bc..ccc3ddea46 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java @@ -245,12 +245,26 @@ public final class ConcatenatingMediaSourceTest { // Create all periods and assert period creation of child media sources has been called. testRunner.assertPrepareAndReleaseAllPeriods(); - mediaSourceContentOnly.assertMediaPeriodCreated(new MediaPeriodId(0)); - mediaSourceContentOnly.assertMediaPeriodCreated(new MediaPeriodId(1)); - mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(0)); - mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(1)); - mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(0, 0, 0)); - mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(1, 0, 0)); + mediaSourceContentOnly.assertMediaPeriodCreated( + new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0)); + mediaSourceContentOnly.assertMediaPeriodCreated( + new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 0)); + mediaSourceWithAds.assertMediaPeriodCreated( + new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 1)); + mediaSourceWithAds.assertMediaPeriodCreated( + new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 1)); + mediaSourceWithAds.assertMediaPeriodCreated( + new MediaPeriodId( + /* periodIndex= */ 0, + /* adGroupIndex= */ 0, + /* adIndexInAdGroup= */ 0, + /* windowSequenceNumber= */ 1)); + mediaSourceWithAds.assertMediaPeriodCreated( + new MediaPeriodId( + /* periodIndex= */ 1, + /* adGroupIndex= */ 0, + /* adIndexInAdGroup= */ 0, + /* windowSequenceNumber= */ 1)); } finally { testRunner.release(); } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java index a58a427b67..d71b02d39a 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java @@ -267,12 +267,16 @@ public final class DynamicConcatenatingMediaSourceTest { // Create a period from an unprepared lazy media source and assert Callback.onPrepared is not // called yet. - MediaPeriod lazyPeriod = testRunner.createPeriod(new MediaPeriodId(0)); + MediaPeriod lazyPeriod = + testRunner.createPeriod( + new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0)); CountDownLatch preparedCondition = testRunner.preparePeriod(lazyPeriod, 0); assertThat(preparedCondition.getCount()).isEqualTo(1); // Assert that a second period can also be created and released without problems. - MediaPeriod secondLazyPeriod = testRunner.createPeriod(new MediaPeriodId(0)); + MediaPeriod secondLazyPeriod = + testRunner.createPeriod( + new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0)); testRunner.releasePeriod(secondLazyPeriod); // Trigger source info refresh for lazy media source. Assert that now all information is @@ -653,12 +657,26 @@ public final class DynamicConcatenatingMediaSourceTest { // Create all periods and assert period creation of child media sources has been called. testRunner.assertPrepareAndReleaseAllPeriods(); - mediaSourceContentOnly.assertMediaPeriodCreated(new MediaPeriodId(0)); - mediaSourceContentOnly.assertMediaPeriodCreated(new MediaPeriodId(1)); - mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(0)); - mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(1)); - mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(0, 0, 0)); - mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(1, 0, 0)); + mediaSourceContentOnly.assertMediaPeriodCreated( + new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0)); + mediaSourceContentOnly.assertMediaPeriodCreated( + new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 0)); + mediaSourceWithAds.assertMediaPeriodCreated( + new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 1)); + mediaSourceWithAds.assertMediaPeriodCreated( + new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 1)); + mediaSourceWithAds.assertMediaPeriodCreated( + new MediaPeriodId( + /* periodIndex= */ 0, + /* adGroupIndex= */ 0, + /* adIndexInAdGroup= */ 0, + /* windowSequenceNumber= */ 1)); + mediaSourceWithAds.assertMediaPeriodCreated( + new MediaPeriodId( + /* periodIndex= */ 1, + /* adGroupIndex= */ 0, + /* adIndexInAdGroup= */ 0, + /* windowSequenceNumber= */ 1)); } @Test @@ -754,7 +772,9 @@ public final class DynamicConcatenatingMediaSourceTest { FakeMediaSource childSource = createFakeMediaSource(); mediaSource.addMediaSource(childSource); testRunner.prepareSource(); - MediaPeriod mediaPeriod = testRunner.createPeriod(new MediaPeriodId(/* periodIndex= */ 0)); + MediaPeriod mediaPeriod = + testRunner.createPeriod( + new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0)); mediaSource.removeMediaSource(/* index= */ 0); testRunner.assertTimelineChangeBlocking(); testRunner.releasePeriod(mediaPeriod); diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/MediaSourceTestRunner.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/MediaSourceTestRunner.java index cf0cc342f8..16389112ca 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/MediaSourceTestRunner.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/MediaSourceTestRunner.java @@ -244,16 +244,18 @@ public class MediaSourceTestRunner { /** * Creates and releases all periods (including ad periods) defined in the last timeline to be * returned from {@link #prepareSource()}, {@link #assertTimelineChange()} or {@link - * #assertTimelineChangeBlocking()}. + * #assertTimelineChangeBlocking()}. The {@link MediaPeriodId#windowSequenceNumber} is set to the + * index of the window. */ public void assertPrepareAndReleaseAllPeriods() throws InterruptedException { Timeline.Period period = new Timeline.Period(); for (int i = 0; i < timeline.getPeriodCount(); i++) { - assertPrepareAndReleasePeriod(new MediaPeriodId(i)); timeline.getPeriod(i, period); + assertPrepareAndReleasePeriod(new MediaPeriodId(i, period.windowIndex)); for (int adGroupIndex = 0; adGroupIndex < period.getAdGroupCount(); adGroupIndex++) { for (int adIndex = 0; adIndex < period.getAdCountInAdGroup(adGroupIndex); adIndex++) { - assertPrepareAndReleasePeriod(new MediaPeriodId(i, adGroupIndex, adIndex)); + assertPrepareAndReleasePeriod( + new MediaPeriodId(i, adGroupIndex, adIndex, period.windowIndex)); } } }