Commit f3cc5327 by bachinger Committed by Ian Baker

Do not manipulate the duration of SSAI periods in FakeTimeline

#minor-release

PiperOrigin-RevId: 428727560
parent 1a31faae
...@@ -15,8 +15,12 @@ ...@@ -15,8 +15,12 @@
*/ */
package androidx.media3.exoplayer; package androidx.media3.exoplayer;
import static androidx.media3.test.utils.ExoPlayerTestRunner.AUDIO_FORMAT;
import static androidx.media3.test.utils.ExoPlayerTestRunner.VIDEO_FORMAT;
import static androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; import static androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
import static com.google.common.truth.Truth.assertThat; 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.mockito.Mockito.mock;
import static org.robolectric.Shadows.shadowOf; import static org.robolectric.Shadows.shadowOf;
...@@ -38,6 +42,7 @@ import androidx.media3.exoplayer.analytics.PlayerId; ...@@ -38,6 +42,7 @@ import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId; import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId;
import androidx.media3.exoplayer.source.MediaSource.MediaSourceCaller; import androidx.media3.exoplayer.source.MediaSource.MediaSourceCaller;
import androidx.media3.exoplayer.source.SinglePeriodTimeline; import androidx.media3.exoplayer.source.SinglePeriodTimeline;
import androidx.media3.exoplayer.source.ads.ServerSideAdInsertionMediaSource;
import androidx.media3.exoplayer.source.ads.SinglePeriodAdTimeline; import androidx.media3.exoplayer.source.ads.SinglePeriodAdTimeline;
import androidx.media3.exoplayer.trackselection.ExoTrackSelection; import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
import androidx.media3.exoplayer.trackselection.TrackSelector; import androidx.media3.exoplayer.trackselection.TrackSelector;
...@@ -50,6 +55,8 @@ import androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition; ...@@ -50,6 +55,8 @@ import androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
...@@ -824,10 +831,11 @@ public final class MediaPeriodQueueTest { ...@@ -824,10 +831,11 @@ public final class MediaPeriodQueueTest {
@Test @Test
public void public void
resolveMediaPeriodIdForAdsAfterPeriodPositionChange_behindAdInMultiPeriodTimeline_rollForward() { resolveMediaPeriodIdForAdsAfterPeriodPositionChange_behindAdInMultiPeriodTimeline_rollForward()
throws InterruptedException {
Object windowId = new Object(); Object windowId = new Object();
FakeTimeline timeline = Timeline timeline =
FakeTimeline.createMultiPeriodAdTimeline( createMultiPeriodServerSideInsertedTimeline(
windowId, windowId,
/* numberOfPlayedAds= */ 0, /* numberOfPlayedAds= */ 0,
/* isAdPeriodFlags...= */ true, /* isAdPeriodFlags...= */ true,
...@@ -858,10 +866,11 @@ public final class MediaPeriodQueueTest { ...@@ -858,10 +866,11 @@ public final class MediaPeriodQueueTest {
@Test @Test
public void public void
resolveMediaPeriodIdForAdsAfterPeriodPositionChange_behindAdInMultiPeriodAllAdsPlayed_seekNotAdjusted() { resolveMediaPeriodIdForAdsAfterPeriodPositionChange_behindAdInMultiPeriodAllAdsPlayed_seekNotAdjusted()
throws InterruptedException {
Object windowId = new Object(); Object windowId = new Object();
FakeTimeline timeline = Timeline timeline =
FakeTimeline.createMultiPeriodAdTimeline( createMultiPeriodServerSideInsertedTimeline(
windowId, windowId,
/* numberOfPlayedAds= */ 4, /* numberOfPlayedAds= */ 4,
/* isAdPeriodFlags...= */ true, /* isAdPeriodFlags...= */ true,
...@@ -892,10 +901,11 @@ public final class MediaPeriodQueueTest { ...@@ -892,10 +901,11 @@ public final class MediaPeriodQueueTest {
@Test @Test
public void public void
resolveMediaPeriodIdForAdsAfterPeriodPositionChange_behindAdInMultiPeriodFirstTwoAdsPlayed_rollForward() { resolveMediaPeriodIdForAdsAfterPeriodPositionChange_behindAdInMultiPeriodFirstTwoAdsPlayed_rollForward()
throws InterruptedException {
Object windowId = new Object(); Object windowId = new Object();
FakeTimeline timeline = Timeline timeline =
FakeTimeline.createMultiPeriodAdTimeline( createMultiPeriodServerSideInsertedTimeline(
windowId, windowId,
/* numberOfPlayedAds= */ 2, /* numberOfPlayedAds= */ 2,
/* isAdPeriodFlags...= */ true, /* isAdPeriodFlags...= */ true,
...@@ -917,10 +927,11 @@ public final class MediaPeriodQueueTest { ...@@ -917,10 +927,11 @@ public final class MediaPeriodQueueTest {
@Test @Test
public void public void
resolveMediaPeriodIdForAdsAfterPeriodPositionChange_beforeAdInMultiPeriodTimeline_seekNotAdjusted() { resolveMediaPeriodIdForAdsAfterPeriodPositionChange_beforeAdInMultiPeriodTimeline_seekNotAdjusted()
throws InterruptedException {
Object windowId = new Object(); Object windowId = new Object();
FakeTimeline timeline = Timeline timeline =
FakeTimeline.createMultiPeriodAdTimeline( createMultiPeriodServerSideInsertedTimeline(
windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags...= */ false, true); windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags...= */ false, true);
MediaPeriodId mediaPeriodId = MediaPeriodId mediaPeriodId =
...@@ -935,10 +946,11 @@ public final class MediaPeriodQueueTest { ...@@ -935,10 +946,11 @@ public final class MediaPeriodQueueTest {
@Test @Test
public void public void
resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toUnplayedAdInMultiPeriodTimeline_resolvedAsAd() { resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toUnplayedAdInMultiPeriodTimeline_resolvedAsAd()
throws InterruptedException {
Object windowId = new Object(); Object windowId = new Object();
FakeTimeline timeline = Timeline timeline =
FakeTimeline.createMultiPeriodAdTimeline( createMultiPeriodServerSideInsertedTimeline(
windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags...= */ false, true, false); windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags...= */ false, true, false);
MediaPeriodId mediaPeriodId = MediaPeriodId mediaPeriodId =
...@@ -953,10 +965,11 @@ public final class MediaPeriodQueueTest { ...@@ -953,10 +965,11 @@ public final class MediaPeriodQueueTest {
@Test @Test
public void public void
resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toPlayedAdInMultiPeriodTimeline_skipPlayedAd() { resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toPlayedAdInMultiPeriodTimeline_skipPlayedAd()
throws InterruptedException {
Object windowId = new Object(); Object windowId = new Object();
FakeTimeline timeline = Timeline timeline =
FakeTimeline.createMultiPeriodAdTimeline( createMultiPeriodServerSideInsertedTimeline(
windowId, /* numberOfPlayedAds= */ 1, /* isAdPeriodFlags...= */ false, true, false); windowId, /* numberOfPlayedAds= */ 1, /* isAdPeriodFlags...= */ false, true, false);
MediaPeriodId mediaPeriodId = MediaPeriodId mediaPeriodId =
...@@ -971,12 +984,12 @@ public final class MediaPeriodQueueTest { ...@@ -971,12 +984,12 @@ public final class MediaPeriodQueueTest {
@Test @Test
public void public void
resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toStartOfWindowPlayedAdPreroll_skipsPlayedPrerolls() { resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toStartOfWindowPlayedAdPreroll_skipsPlayedPrerolls()
throws InterruptedException {
Object windowId = new Object(); Object windowId = new Object();
FakeTimeline timeline = Timeline timeline =
FakeTimeline.createMultiPeriodAdTimeline( createMultiPeriodServerSideInsertedTimeline(
windowId, /* numberOfPlayedAds= */ 2, /* isAdPeriodFlags...= */ true, true, false); windowId, /* numberOfPlayedAds= */ 2, /* isAdPeriodFlags...= */ true, true, false);
MediaPeriodId mediaPeriodId = MediaPeriodId mediaPeriodId =
mediaPeriodQueue.resolveMediaPeriodIdForAdsAfterPeriodPositionChange( mediaPeriodQueue.resolveMediaPeriodIdForAdsAfterPeriodPositionChange(
timeline, new Pair<>(windowId, 0), /* positionUs= */ 0); timeline, new Pair<>(windowId, 0), /* positionUs= */ 0);
...@@ -989,10 +1002,11 @@ public final class MediaPeriodQueueTest { ...@@ -989,10 +1002,11 @@ public final class MediaPeriodQueueTest {
@Test @Test
public void public void
resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toPlayedPostrolls_skipsAllButLastPostroll() { resolveMediaPeriodIdForAdsAfterPeriodPositionChange_toPlayedPostrolls_skipsAllButLastPostroll()
throws InterruptedException {
Object windowId = new Object(); Object windowId = new Object();
FakeTimeline timeline = Timeline timeline =
FakeTimeline.createMultiPeriodAdTimeline( createMultiPeriodServerSideInsertedTimeline(
windowId, windowId,
/* numberOfPlayedAds= */ 4, /* numberOfPlayedAds= */ 4,
/* isAdPeriodFlags...= */ false, /* isAdPeriodFlags...= */ false,
...@@ -1013,10 +1027,11 @@ public final class MediaPeriodQueueTest { ...@@ -1013,10 +1027,11 @@ public final class MediaPeriodQueueTest {
@Test @Test
public void public void
resolveMediaPeriodIdForAdsAfterPeriodPositionChange_consecutiveContentPeriods_rollForward() { resolveMediaPeriodIdForAdsAfterPeriodPositionChange_consecutiveContentPeriods_rollForward()
throws InterruptedException {
Object windowId = new Object(); Object windowId = new Object();
FakeTimeline timeline = Timeline timeline =
FakeTimeline.createMultiPeriodAdTimeline( createMultiPeriodServerSideInsertedTimeline(
windowId, windowId,
/* numberOfPlayedAds= */ 0, /* numberOfPlayedAds= */ 0,
/* isAdPeriodFlags...= */ true, /* isAdPeriodFlags...= */ true,
...@@ -1036,10 +1051,11 @@ public final class MediaPeriodQueueTest { ...@@ -1036,10 +1051,11 @@ public final class MediaPeriodQueueTest {
@Test @Test
public void public void
resolveMediaPeriodIdForAdsAfterPeriodPositionChange_onlyConsecutiveContentPeriods_seekNotAdjusted() { resolveMediaPeriodIdForAdsAfterPeriodPositionChange_onlyConsecutiveContentPeriods_seekNotAdjusted()
throws InterruptedException {
Object windowId = new Object(); Object windowId = new Object();
FakeTimeline timeline = Timeline timeline =
FakeTimeline.createMultiPeriodAdTimeline( createMultiPeriodServerSideInsertedTimeline(
windowId, windowId,
/* numberOfPlayedAds= */ 0, /* numberOfPlayedAds= */ 0,
/* isAdPeriodFlags...= */ false, /* isAdPeriodFlags...= */ false,
...@@ -1251,4 +1267,29 @@ public final class MediaPeriodQueueTest { ...@@ -1251,4 +1267,29 @@ public final class MediaPeriodQueueTest {
} }
return length; 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();
}
} }
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
*/ */
package androidx.media3.test.utils; package androidx.media3.test.utils;
import static androidx.media3.common.util.Util.sum;
import static androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_DURATION_US; import static androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_DURATION_US;
import static androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; import static androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
import static java.lang.Math.min; import static java.lang.Math.min;
...@@ -323,14 +322,15 @@ public final class FakeTimeline extends Timeline { ...@@ -323,14 +322,15 @@ public final class FakeTimeline extends Timeline {
public static FakeTimeline createMultiPeriodAdTimeline( public static FakeTimeline createMultiPeriodAdTimeline(
Object windowId, int numberOfPlayedAds, boolean... isAdPeriodFlags) { Object windowId, int numberOfPlayedAds, boolean... isAdPeriodFlags) {
long periodDurationUs = DEFAULT_WINDOW_DURATION_US / isAdPeriodFlags.length; long periodDurationUs = DEFAULT_WINDOW_DURATION_US / isAdPeriodFlags.length;
AdPlaybackState contentPeriodState = new AdPlaybackState(/* adsId= */ "adsId");
AdPlaybackState firstAdPeriodState = AdPlaybackState firstAdPeriodState =
new AdPlaybackState(/* adsId= */ "adsId", /* adGroupTimesUs... */ 0) contentPeriodState
.withNewAdGroup(/* adGroupIndex= */ 0, /* adGroupTimesUs */ 0)
.withAdCount(/* adGroupIndex= */ 0, 1) .withAdCount(/* adGroupIndex= */ 0, 1)
.withAdDurationsUs( .withAdDurationsUs(
/* adGroupIndex= */ 0, DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US + periodDurationUs) /* adGroupIndex= */ 0, DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US + periodDurationUs)
.withIsServerSideInserted(/* adGroupIndex= */ 0, true); .withIsServerSideInserted(/* adGroupIndex= */ 0, true);
AdPlaybackState commonAdPeriodState = firstAdPeriodState.withAdDurationsUs(0, periodDurationUs); AdPlaybackState commonAdPeriodState = firstAdPeriodState.withAdDurationsUs(0, periodDurationUs);
AdPlaybackState contentPeriodState = new AdPlaybackState(/* adsId= */ "adsId");
List<AdPlaybackState> adPlaybackStates = new ArrayList<>(); List<AdPlaybackState> adPlaybackStates = new ArrayList<>();
int playedAdsCounter = 0; int playedAdsCounter = 0;
...@@ -524,9 +524,7 @@ public final class FakeTimeline extends Timeline { ...@@ -524,9 +524,7 @@ public final class FakeTimeline extends Timeline {
id, id,
uid, uid,
windowIndex, windowIndex,
periodDurationUs == C.TIME_UNSET periodDurationUs,
? C.TIME_UNSET
: periodDurationUs - getServerSideAdInsertionAdDurationUs(adPlaybackState),
positionInWindowUs, positionInWindowUs,
adPlaybackState, adPlaybackState,
windowDefinition.isPlaceholder); windowDefinition.isPlaceholder);
...@@ -577,15 +575,4 @@ public final class FakeTimeline extends Timeline { ...@@ -577,15 +575,4 @@ public final class FakeTimeline extends Timeline {
} }
return windowDefinitions; 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;
}
} }
...@@ -45,20 +45,21 @@ public class FakeTimelineTest { ...@@ -45,20 +45,21 @@ public class FakeTimelineTest {
true, true,
true, true,
false, false,
true,
true); true);
assertThat(timeline.getWindowCount()).isEqualTo(1); assertThat(timeline.getWindowCount()).isEqualTo(1);
assertThat(timeline.getPeriodCount()).isEqualTo(7); assertThat(timeline.getPeriodCount()).isEqualTo(8);
// Assert content periods and window duration. // Assert content periods and window duration.
Timeline.Period contentPeriod1 = timeline.getPeriod(/* periodIndex= */ 1, period); Timeline.Period contentPeriod1 = timeline.getPeriod(/* periodIndex= */ 1, period);
Timeline.Period contentPeriod5 = timeline.getPeriod(/* periodIndex= */ 5, period); Timeline.Period contentPeriod5 = timeline.getPeriod(/* periodIndex= */ 5, period);
assertThat(contentPeriod1.durationUs).isEqualTo(DEFAULT_WINDOW_DURATION_US / 7); assertThat(contentPeriod1.durationUs).isEqualTo(DEFAULT_WINDOW_DURATION_US / 8);
assertThat(contentPeriod5.durationUs).isEqualTo(DEFAULT_WINDOW_DURATION_US / 7); assertThat(contentPeriod5.durationUs).isEqualTo(DEFAULT_WINDOW_DURATION_US / 8);
assertThat(contentPeriod1.getAdGroupCount()).isEqualTo(0); assertThat(contentPeriod1.getAdGroupCount()).isEqualTo(0);
assertThat(contentPeriod5.getAdGroupCount()).isEqualTo(0); assertThat(contentPeriod5.getAdGroupCount()).isEqualTo(0);
timeline.getWindow(/* windowIndex= */ 0, window); timeline.getWindow(/* windowIndex= */ 0, window);
assertThat(window.uid).isEqualTo(windowId); 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); assertThat(window.positionInFirstPeriodUs).isEqualTo(DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US);
// Assert ad periods. // Assert ad periods.
int[] adIndices = {0, 2, 3, 4, 6}; int[] adIndices = {0, 2, 3, 4, 6};
...@@ -67,7 +68,6 @@ public class FakeTimelineTest { ...@@ -67,7 +68,6 @@ public class FakeTimelineTest {
Timeline.Period adPeriod = timeline.getPeriod(periodIndex, period); Timeline.Period adPeriod = timeline.getPeriod(periodIndex, period);
assertThat(adPeriod.isServerSideInsertedAdGroup(0)).isTrue(); assertThat(adPeriod.isServerSideInsertedAdGroup(0)).isTrue();
assertThat(adPeriod.getAdGroupCount()).isEqualTo(1); assertThat(adPeriod.getAdGroupCount()).isEqualTo(1);
assertThat(adPeriod.durationUs).isEqualTo(0);
if (adPeriod.getAdGroupCount() > 0) { if (adPeriod.getAdGroupCount() > 0) {
if (adCounter < numberOfPlayedAds) { if (adCounter < numberOfPlayedAds) {
assertThat(adPeriod.getAdState(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)) assertThat(adPeriod.getAdState(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0))
...@@ -79,8 +79,9 @@ public class FakeTimelineTest { ...@@ -79,8 +79,9 @@ public class FakeTimelineTest {
adCounter++; adCounter++;
} }
long expectedDurationUs = long expectedDurationUs =
(DEFAULT_WINDOW_DURATION_US / 7) (DEFAULT_WINDOW_DURATION_US / 8)
+ (periodIndex == 0 ? DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US : 0); + (periodIndex == 0 ? DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US : 0);
assertThat(adPeriod.durationUs).isEqualTo(expectedDurationUs);
assertThat(adPeriod.getAdDurationUs(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)) assertThat(adPeriod.getAdDurationUs(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0))
.isEqualTo(expectedDurationUs); .isEqualTo(expectedDurationUs);
} }
...@@ -100,7 +101,7 @@ public class FakeTimelineTest { ...@@ -100,7 +101,7 @@ public class FakeTimelineTest {
timeline.getWindow(/* windowIndex= */ 0, window); timeline.getWindow(/* windowIndex= */ 0, window);
// Assert content periods and window duration. // 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); assertThat(window.positionInFirstPeriodUs).isEqualTo(DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US);
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment