diff --git a/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java b/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java index 0c538e105d..9c73ec3e59 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java @@ -15,8 +15,12 @@ */ package com.google.android.exoplayer2; +import static com.google.android.exoplayer2.testutil.ExoPlayerTestRunner.AUDIO_FORMAT; +import static com.google.android.exoplayer2.testutil.ExoPlayerTestRunner.VIDEO_FORMAT; import static com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.robolectric.Shadows.shadowOf; @@ -33,6 +37,7 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaSourceCaller; import com.google.android.exoplayer2.source.SinglePeriodTimeline; import com.google.android.exoplayer2.source.ads.AdPlaybackState; +import com.google.android.exoplayer2.source.ads.ServerSideAdInsertionMediaSource; import com.google.android.exoplayer2.source.ads.SinglePeriodAdTimeline; import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeShuffleOrder; @@ -44,6 +49,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.util.Clock; import com.google.common.collect.ImmutableList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -818,10 +825,11 @@ public final class MediaPeriodQueueTest { @Test public void - resolveMediaPeriodIdForAdsAfterPeriodPositionChange_behindAdInMultiPeriodTimeline_rollForward() { + resolveMediaPeriodIdForAdsAfterPeriodPositionChange_behindAdInMultiPeriodTimeline_rollForward() + throws InterruptedException { Object windowId = new Object(); - FakeTimeline timeline = - FakeTimeline.createMultiPeriodAdTimeline( + Timeline timeline = + createMultiPeriodServerSideInsertedTimeline( windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags...= */ true, @@ -852,10 +860,11 @@ public final class MediaPeriodQueueTest { @Test public void - resolveMediaPeriodIdForAdsAfterPeriodPositionChange_behindAdInMultiPeriodAllAdsPlayed_seekNotAdjusted() { + resolveMediaPeriodIdForAdsAfterPeriodPositionChange_behindAdInMultiPeriodAllAdsPlayed_seekNotAdjusted() + throws InterruptedException { Object windowId = new Object(); - FakeTimeline timeline = - FakeTimeline.createMultiPeriodAdTimeline( + Timeline timeline = + createMultiPeriodServerSideInsertedTimeline( windowId, /* numberOfPlayedAds= */ 4, /* isAdPeriodFlags...= */ true, @@ -886,10 +895,11 @@ public final class MediaPeriodQueueTest { @Test public void - resolveMediaPeriodIdForAdsAfterPeriodPositionChange_behindAdInMultiPeriodFirstTwoAdsPlayed_rollForward() { + resolveMediaPeriodIdForAdsAfterPeriodPositionChange_behindAdInMultiPeriodFirstTwoAdsPlayed_rollForward() + throws InterruptedException { Object windowId = new Object(); - FakeTimeline timeline = - FakeTimeline.createMultiPeriodAdTimeline( + Timeline timeline = + createMultiPeriodServerSideInsertedTimeline( windowId, /* numberOfPlayedAds= */ 2, /* isAdPeriodFlags...= */ true, @@ -911,10 +921,11 @@ public final class MediaPeriodQueueTest { @Test public void - resolveMediaPeriodIdForAdsAfterPeriodPositionChange_beforeAdInMultiPeriodTimeline_seekNotAdjusted() { + resolveMediaPeriodIdForAdsAfterPeriodPositionChange_beforeAdInMultiPeriodTimeline_seekNotAdjusted() + throws InterruptedException { Object windowId = new Object(); - FakeTimeline timeline = - FakeTimeline.createMultiPeriodAdTimeline( + Timeline timeline = + createMultiPeriodServerSideInsertedTimeline( windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags...= */ false, true); MediaPeriodId mediaPeriodId = @@ -929,10 +940,11 @@ public final class MediaPeriodQueueTest { @Test public void - resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toUnplayedAdInMultiPeriodTimeline_resolvedAsAd() { + resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toUnplayedAdInMultiPeriodTimeline_resolvedAsAd() + throws InterruptedException { Object windowId = new Object(); - FakeTimeline timeline = - FakeTimeline.createMultiPeriodAdTimeline( + Timeline timeline = + createMultiPeriodServerSideInsertedTimeline( windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags...= */ false, true, false); MediaPeriodId mediaPeriodId = @@ -947,10 +959,11 @@ public final class MediaPeriodQueueTest { @Test public void - resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toPlayedAdInMultiPeriodTimeline_skipPlayedAd() { + resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toPlayedAdInMultiPeriodTimeline_skipPlayedAd() + throws InterruptedException { Object windowId = new Object(); - FakeTimeline timeline = - FakeTimeline.createMultiPeriodAdTimeline( + Timeline timeline = + createMultiPeriodServerSideInsertedTimeline( windowId, /* numberOfPlayedAds= */ 1, /* isAdPeriodFlags...= */ false, true, false); MediaPeriodId mediaPeriodId = @@ -965,12 +978,12 @@ public final class MediaPeriodQueueTest { @Test public void - resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toStartOfWindowPlayedAdPreroll_skipsPlayedPrerolls() { + resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toStartOfWindowPlayedAdPreroll_skipsPlayedPrerolls() + throws InterruptedException { Object windowId = new Object(); - FakeTimeline timeline = - FakeTimeline.createMultiPeriodAdTimeline( + Timeline timeline = + createMultiPeriodServerSideInsertedTimeline( windowId, /* numberOfPlayedAds= */ 2, /* isAdPeriodFlags...= */ true, true, false); - MediaPeriodId mediaPeriodId = mediaPeriodQueue.resolveMediaPeriodIdForAdsAfterPeriodPositionChange( timeline, new Pair<>(windowId, 0), /* positionUs= */ 0); @@ -983,10 +996,11 @@ public final class MediaPeriodQueueTest { @Test public void - resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toPlayedPostrolls_skipsAllButLastPostroll() { + resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toPlayedPostrolls_skipsAllButLastPostroll() + throws InterruptedException { Object windowId = new Object(); - FakeTimeline timeline = - FakeTimeline.createMultiPeriodAdTimeline( + Timeline timeline = + createMultiPeriodServerSideInsertedTimeline( windowId, /* numberOfPlayedAds= */ 4, /* isAdPeriodFlags...= */ false, @@ -1007,10 +1021,11 @@ public final class MediaPeriodQueueTest { @Test public void - resolveMediaPeriodIdForAdsAfterPeriodPositionChange_consecutiveContentPeriods_rollForward() { + resolveMediaPeriodIdForAdsAfterPeriodPositionChange_consecutiveContentPeriods_rollForward() + throws InterruptedException { Object windowId = new Object(); - FakeTimeline timeline = - FakeTimeline.createMultiPeriodAdTimeline( + Timeline timeline = + createMultiPeriodServerSideInsertedTimeline( windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags...= */ true, @@ -1030,10 +1045,11 @@ public final class MediaPeriodQueueTest { @Test public void - resolveMediaPeriodIdForAdsAfterPeriodPositionChange_onlyConsecutiveContentPeriods_seekNotAdjusted() { + resolveMediaPeriodIdForAdsAfterPeriodPositionChange_onlyConsecutiveContentPeriods_seekNotAdjusted() + throws InterruptedException { Object windowId = new Object(); - FakeTimeline timeline = - FakeTimeline.createMultiPeriodAdTimeline( + Timeline timeline = + createMultiPeriodServerSideInsertedTimeline( windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags...= */ false, @@ -1245,4 +1261,29 @@ public final class MediaPeriodQueueTest { } return length; } + + private static Timeline createMultiPeriodServerSideInsertedTimeline( + Object windowId, int numberOfPlayedAds, boolean... isAdPeriodFlags) + throws InterruptedException { + FakeTimeline timeline = + FakeTimeline.createMultiPeriodAdTimeline(windowId, numberOfPlayedAds, isAdPeriodFlags); + ServerSideAdInsertionMediaSource serverSideAdInsertionMediaSource = + new ServerSideAdInsertionMediaSource( + new FakeMediaSource(timeline, VIDEO_FORMAT, AUDIO_FORMAT), contentTimeline -> false); + serverSideAdInsertionMediaSource.setAdPlaybackStates( + timeline.getAdPlaybackStates(/* windowIndex= */ 0)); + AtomicReference serverSideAdInsertionTimelineRef = new AtomicReference<>(); + CountDownLatch countDownLatch = new CountDownLatch(/* count= */ 1); + serverSideAdInsertionMediaSource.prepareSource( + (source, serverSideInsertedAdTimeline) -> { + serverSideAdInsertionTimelineRef.set(serverSideInsertedAdTimeline); + countDownLatch.countDown(); + }, + /* mediaTransferListener= */ null, + new PlayerId()); + if (!countDownLatch.await(/* timeout= */ 2, SECONDS)) { + fail(); + } + return serverSideAdInsertionTimelineRef.get(); + } } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java index 41bb273662..6e14864da1 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java @@ -17,7 +17,6 @@ package com.google.android.exoplayer2.testutil; import static com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_DURATION_US; import static com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; -import static com.google.android.exoplayer2.util.Util.sum; import static java.lang.Math.min; import android.net.Uri; @@ -321,14 +320,15 @@ public final class FakeTimeline extends Timeline { public static FakeTimeline createMultiPeriodAdTimeline( Object windowId, int numberOfPlayedAds, boolean... isAdPeriodFlags) { long periodDurationUs = DEFAULT_WINDOW_DURATION_US / isAdPeriodFlags.length; + AdPlaybackState contentPeriodState = new AdPlaybackState(/* adsId= */ "adsId"); AdPlaybackState firstAdPeriodState = - new AdPlaybackState(/* adsId= */ "adsId", /* adGroupTimesUs... */ 0) + contentPeriodState + .withNewAdGroup(/* adGroupIndex= */ 0, /* adGroupTimesUs */ 0) .withAdCount(/* adGroupIndex= */ 0, 1) .withAdDurationsUs( /* adGroupIndex= */ 0, DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US + periodDurationUs) .withIsServerSideInserted(/* adGroupIndex= */ 0, true); AdPlaybackState commonAdPeriodState = firstAdPeriodState.withAdDurationsUs(0, periodDurationUs); - AdPlaybackState contentPeriodState = new AdPlaybackState(/* adsId= */ "adsId"); List adPlaybackStates = new ArrayList<>(); int playedAdsCounter = 0; @@ -522,9 +522,7 @@ public final class FakeTimeline extends Timeline { id, uid, windowIndex, - periodDurationUs == C.TIME_UNSET - ? C.TIME_UNSET - : periodDurationUs - getServerSideAdInsertionAdDurationUs(adPlaybackState), + periodDurationUs, positionInWindowUs, adPlaybackState, windowDefinition.isPlaceholder); @@ -575,15 +573,4 @@ public final class FakeTimeline extends Timeline { } return windowDefinitions; } - - private static long getServerSideAdInsertionAdDurationUs(AdPlaybackState adPlaybackState) { - long adDurationUs = 0; - for (int i = 0; i < adPlaybackState.adGroupCount; i++) { - AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(i); - if (adGroup.isServerSideInserted) { - adDurationUs += sum(adGroup.durationsUs); - } - } - return adDurationUs; - } } diff --git a/testutils/src/test/java/com/google/android/exoplayer2/testutil/FakeTimelineTest.java b/testutils/src/test/java/com/google/android/exoplayer2/testutil/FakeTimelineTest.java index c513200dff..ac5ad1bbc8 100644 --- a/testutils/src/test/java/com/google/android/exoplayer2/testutil/FakeTimelineTest.java +++ b/testutils/src/test/java/com/google/android/exoplayer2/testutil/FakeTimelineTest.java @@ -45,20 +45,21 @@ public class FakeTimelineTest { true, true, false, + true, true); assertThat(timeline.getWindowCount()).isEqualTo(1); - assertThat(timeline.getPeriodCount()).isEqualTo(7); + assertThat(timeline.getPeriodCount()).isEqualTo(8); // Assert content periods and window duration. Timeline.Period contentPeriod1 = timeline.getPeriod(/* periodIndex= */ 1, period); Timeline.Period contentPeriod5 = timeline.getPeriod(/* periodIndex= */ 5, period); - assertThat(contentPeriod1.durationUs).isEqualTo(DEFAULT_WINDOW_DURATION_US / 7); - assertThat(contentPeriod5.durationUs).isEqualTo(DEFAULT_WINDOW_DURATION_US / 7); + assertThat(contentPeriod1.durationUs).isEqualTo(DEFAULT_WINDOW_DURATION_US / 8); + assertThat(contentPeriod5.durationUs).isEqualTo(DEFAULT_WINDOW_DURATION_US / 8); assertThat(contentPeriod1.getAdGroupCount()).isEqualTo(0); assertThat(contentPeriod5.getAdGroupCount()).isEqualTo(0); timeline.getWindow(/* windowIndex= */ 0, window); assertThat(window.uid).isEqualTo(windowId); - assertThat(window.durationUs).isEqualTo(contentPeriod1.durationUs + contentPeriod5.durationUs); + assertThat(window.durationUs).isEqualTo(DEFAULT_WINDOW_DURATION_US); assertThat(window.positionInFirstPeriodUs).isEqualTo(DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US); // Assert ad periods. int[] adIndices = {0, 2, 3, 4, 6}; @@ -67,7 +68,6 @@ public class FakeTimelineTest { Timeline.Period adPeriod = timeline.getPeriod(periodIndex, period); assertThat(adPeriod.isServerSideInsertedAdGroup(0)).isTrue(); assertThat(adPeriod.getAdGroupCount()).isEqualTo(1); - assertThat(adPeriod.durationUs).isEqualTo(0); if (adPeriod.getAdGroupCount() > 0) { if (adCounter < numberOfPlayedAds) { assertThat(adPeriod.getAdState(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)) @@ -79,8 +79,9 @@ public class FakeTimelineTest { adCounter++; } long expectedDurationUs = - (DEFAULT_WINDOW_DURATION_US / 7) + (DEFAULT_WINDOW_DURATION_US / 8) + (periodIndex == 0 ? DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US : 0); + assertThat(adPeriod.durationUs).isEqualTo(expectedDurationUs); assertThat(adPeriod.getAdDurationUs(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)) .isEqualTo(expectedDurationUs); } @@ -100,7 +101,7 @@ public class FakeTimelineTest { timeline.getWindow(/* windowIndex= */ 0, window); // Assert content periods and window duration. - assertThat(window.durationUs).isEqualTo(DEFAULT_WINDOW_DURATION_US / 2); + assertThat(window.durationUs).isEqualTo(DEFAULT_WINDOW_DURATION_US); assertThat(window.positionInFirstPeriodUs).isEqualTo(DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US); } }