Do not manipulate the duration of SSAI periods in FakeTimeline

#minor-release

PiperOrigin-RevId: 428727560
This commit is contained in:
bachinger 2022-02-15 10:33:30 +00:00 committed by Ian Baker
parent 76c87462e2
commit 190aa84d01
3 changed files with 84 additions and 55 deletions

View file

@ -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<Timeline> 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();
}
}

View file

@ -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<AdPlaybackState> 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;
}
}

View file

@ -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);
}
}