Make period durations of FakeMultiPeriodLiveTimeline configurable
PiperOrigin-RevId: 522046876
This commit is contained in:
parent
5442c33ac7
commit
e4194fc862
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package androidx.media3.common;
|
||||
|
||||
import static androidx.media3.test.utils.FakeMultiPeriodLiveTimeline.AD_PERIOD_DURATION_MS;
|
||||
import static androidx.media3.test.utils.FakeMultiPeriodLiveTimeline.PERIOD_DURATION_MS;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.os.Bundle;
|
||||
@ -436,10 +438,13 @@ public class TimelineTest {
|
||||
public void periodIsLivePostrollPlaceholder_recognizesLivePostrollPlaceholder() {
|
||||
FakeMultiPeriodLiveTimeline timeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 60_000_000,
|
||||
/* nowUs= */ 60_000_000,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ false,
|
||||
/* populateAds= */ true,
|
||||
/* playedAds= */ false);
|
||||
|
@ -15,8 +15,11 @@
|
||||
*/
|
||||
package androidx.media3.exoplayer;
|
||||
|
||||
import static androidx.media3.common.util.Util.msToUs;
|
||||
import static androidx.media3.test.utils.ExoPlayerTestRunner.AUDIO_FORMAT;
|
||||
import static androidx.media3.test.utils.ExoPlayerTestRunner.VIDEO_FORMAT;
|
||||
import static androidx.media3.test.utils.FakeMultiPeriodLiveTimeline.AD_PERIOD_DURATION_MS;
|
||||
import static androidx.media3.test.utils.FakeMultiPeriodLiveTimeline.PERIOD_DURATION_MS;
|
||||
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 com.google.common.truth.Truth.assertThat;
|
||||
@ -430,15 +433,18 @@ public final class MediaPeriodQueueTest {
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getNextMediaPeriodInfo_multiPeriodTimelineWithNoAdsAndNoPostrollPlaceholder() {
|
||||
long contentPeriodDurationUs = FakeMultiPeriodLiveTimeline.PERIOD_DURATION_US;
|
||||
long adPeriodDurationUs = FakeMultiPeriodLiveTimeline.AD_PERIOD_DURATION_US;
|
||||
long contentPeriodDurationUs = msToUs(PERIOD_DURATION_MS);
|
||||
long adPeriodDurationUs = msToUs(AD_PERIOD_DURATION_MS);
|
||||
// Multi period timeline without ad playback state.
|
||||
FakeMultiPeriodLiveTimeline multiPeriodLiveTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 60_000_000,
|
||||
/* nowUs= */ 110_000_000,
|
||||
new boolean[] {false, true, true},
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -497,15 +503,18 @@ public final class MediaPeriodQueueTest {
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getNextMediaPeriodInfo_multiPeriodTimelineWithPostrollPlaceHolder() {
|
||||
long contentPeriodDurationUs = FakeMultiPeriodLiveTimeline.PERIOD_DURATION_US;
|
||||
long adPeriodDurationUs = FakeMultiPeriodLiveTimeline.AD_PERIOD_DURATION_US;
|
||||
long contentPeriodDurationUs = msToUs(PERIOD_DURATION_MS);
|
||||
long adPeriodDurationUs = msToUs(AD_PERIOD_DURATION_MS);
|
||||
// Multi period timeline without ad playback state.
|
||||
FakeMultiPeriodLiveTimeline multiPeriodLiveTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 60_000_000,
|
||||
/* nowUs= */ 110_000_000,
|
||||
new boolean[] {false, true, true},
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ false,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -564,14 +573,17 @@ public final class MediaPeriodQueueTest {
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getNextMediaPeriodInfo_multiPeriodTimelineWithAdsAndWithPostRollPlaceHolder() {
|
||||
long contentPeriodDurationUs = FakeMultiPeriodLiveTimeline.PERIOD_DURATION_US;
|
||||
long adPeriodDurationUs = FakeMultiPeriodLiveTimeline.AD_PERIOD_DURATION_US;
|
||||
long contentPeriodDurationUs = msToUs(PERIOD_DURATION_MS);
|
||||
long adPeriodDurationUs = msToUs(AD_PERIOD_DURATION_MS);
|
||||
FakeMultiPeriodLiveTimeline multiPeriodLiveTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 60_000_000,
|
||||
/* nowUs= */ 110_000_000,
|
||||
new boolean[] {false, true, true},
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ false,
|
||||
/* populateAds= */ true,
|
||||
/* playedAds= */ false);
|
||||
@ -646,13 +658,16 @@ public final class MediaPeriodQueueTest {
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getNextMediaPeriodInfo_multiPeriodTimelineWithPlayedAdsAndWithPostRollPlaceHolder() {
|
||||
long contentPeriodDurationUs = FakeMultiPeriodLiveTimeline.PERIOD_DURATION_US;
|
||||
long contentPeriodDurationUs = msToUs(PERIOD_DURATION_MS);
|
||||
FakeMultiPeriodLiveTimeline multiPeriodLiveTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 60_000_000,
|
||||
/* nowUs= */ 110_000_000,
|
||||
new boolean[] {false, true, true},
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ false,
|
||||
/* populateAds= */ true,
|
||||
/* playedAds= */ true);
|
||||
|
@ -20,6 +20,7 @@ import static androidx.media3.common.AdPlaybackState.AD_STATE_ERROR;
|
||||
import static androidx.media3.common.AdPlaybackState.AD_STATE_PLAYED;
|
||||
import static androidx.media3.common.AdPlaybackState.AD_STATE_SKIPPED;
|
||||
import static androidx.media3.common.AdPlaybackState.AD_STATE_UNAVAILABLE;
|
||||
import static androidx.media3.common.util.Util.msToUs;
|
||||
import static androidx.media3.exoplayer.ima.ImaUtil.addLiveAdBreak;
|
||||
import static androidx.media3.exoplayer.ima.ImaUtil.getAdGroupAndIndexInLiveMultiPeriodTimeline;
|
||||
import static androidx.media3.exoplayer.ima.ImaUtil.getAdGroupAndIndexInVodMultiPeriodTimeline;
|
||||
@ -28,7 +29,8 @@ import static androidx.media3.exoplayer.ima.ImaUtil.maybeCorrectPreviouslyUnknow
|
||||
import static androidx.media3.exoplayer.ima.ImaUtil.secToUsRounded;
|
||||
import static androidx.media3.exoplayer.ima.ImaUtil.splitAdGroup;
|
||||
import static androidx.media3.exoplayer.source.ads.ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState;
|
||||
import static androidx.media3.test.utils.FakeMultiPeriodLiveTimeline.AD_PERIOD_DURATION_US;
|
||||
import static androidx.media3.test.utils.FakeMultiPeriodLiveTimeline.AD_PERIOD_DURATION_MS;
|
||||
import static androidx.media3.test.utils.FakeMultiPeriodLiveTimeline.PERIOD_DURATION_MS;
|
||||
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 com.google.common.truth.Truth.assertThat;
|
||||
@ -560,7 +562,7 @@ public class ImaUtilTest {
|
||||
@Test
|
||||
public void
|
||||
splitAdPlaybackStateForPeriods_liveAdGroupStartedAndMovedOutOfWindow_splitCorrectly() {
|
||||
long adPeriodDurationUs = AD_PERIOD_DURATION_US;
|
||||
long adPeriodDurationUs = msToUs(AD_PERIOD_DURATION_MS);
|
||||
AdPlaybackState adPlaybackState =
|
||||
new AdPlaybackState(/* adsId= */ "adsId", C.TIME_END_OF_SOURCE)
|
||||
.withIsServerSideInserted(/* adGroupIndex= */ 0, true);
|
||||
@ -568,10 +570,13 @@ public class ImaUtilTest {
|
||||
// Period durations: content=30_000_000, ad=10_000_000
|
||||
FakeMultiPeriodLiveTimeline liveTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 100_000_000,
|
||||
/* nowUs= */ 150_000_000,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -851,6 +856,7 @@ public class ImaUtilTest {
|
||||
@Test
|
||||
public void
|
||||
splitAdPlaybackStateForPeriods_fullAdGroupAtBeginOfWindow_adPeriodsCorrectlyDetected() {
|
||||
long adPeriodDurationUs = msToUs(AD_PERIOD_DURATION_MS);
|
||||
AdPlaybackState adPlaybackState =
|
||||
new AdPlaybackState(/* adsId= */ "adsId", C.TIME_END_OF_SOURCE)
|
||||
.withIsServerSideInserted(/* adGroupIndex= */ 0, true);
|
||||
@ -858,10 +864,13 @@ public class ImaUtilTest {
|
||||
// Period durations: content=30_000_000, ad=10_000_000
|
||||
FakeMultiPeriodLiveTimeline liveTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 30_000_000,
|
||||
/* nowUs= */ 59_999_999,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -869,9 +878,9 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 30_000_000,
|
||||
AD_PERIOD_DURATION_US,
|
||||
adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 1,
|
||||
/* totalAdDurationUs= */ 2 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 2 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 2,
|
||||
adPlaybackState);
|
||||
|
||||
@ -968,9 +977,9 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 80_000_000,
|
||||
AD_PERIOD_DURATION_US - 1000L, // SDK fallback duration.
|
||||
adPeriodDurationUs - 1000L, // SDK fallback duration.
|
||||
/* adPositionInAdPod= */ 1,
|
||||
/* totalAdDurationUs= */ 2 * AD_PERIOD_DURATION_US - 1001L,
|
||||
/* totalAdDurationUs= */ 2 * adPeriodDurationUs - 1001L,
|
||||
/* totalAdsInAdPod= */ 2,
|
||||
adPlaybackState);
|
||||
splitAdPlaybackStates = ImaUtil.splitAdPlaybackStateForPeriods(adPlaybackState, liveTimeline);
|
||||
@ -984,7 +993,7 @@ public class ImaUtilTest {
|
||||
AdPlaybackState.AdGroup actualAdGroup =
|
||||
splitAdPlaybackStates.get("uid-4[a]").getAdGroup(/* adGroupIndex= */ 0);
|
||||
assertThat(actualAdGroup.count).isEqualTo(1);
|
||||
assertThat(actualAdGroup.durationsUs[0]).isEqualTo(AD_PERIOD_DURATION_US - 1000L);
|
||||
assertThat(actualAdGroup.durationsUs[0]).isEqualTo(adPeriodDurationUs - 1000L);
|
||||
|
||||
// Advance to make the window overlap 1 microsecond into the second ad period. Assert whether
|
||||
// both ad periods, including the last with unknown duration, are correctly marked as ad.
|
||||
@ -999,11 +1008,11 @@ public class ImaUtilTest {
|
||||
assertThat(splitAdPlaybackStates.get("uid-4[a]").adGroupCount).isEqualTo(2);
|
||||
actualAdGroup = splitAdPlaybackStates.get("uid-4[a]").getAdGroup(/* adGroupIndex= */ 0);
|
||||
assertThat(actualAdGroup.count).isEqualTo(1);
|
||||
assertThat(actualAdGroup.durationsUs[0]).isEqualTo(AD_PERIOD_DURATION_US);
|
||||
assertThat(actualAdGroup.durationsUs[0]).isEqualTo(adPeriodDurationUs);
|
||||
assertThat(splitAdPlaybackStates.get("uid-5[a]").adGroupCount).isEqualTo(2);
|
||||
actualAdGroup = splitAdPlaybackStates.get("uid-5[a]").getAdGroup(/* adGroupIndex= */ 0);
|
||||
assertThat(actualAdGroup.count).isEqualTo(1);
|
||||
assertThat(actualAdGroup.durationsUs[0]).isEqualTo(AD_PERIOD_DURATION_US - 1L); // SDK fallback.
|
||||
assertThat(actualAdGroup.durationsUs[0]).isEqualTo(adPeriodDurationUs - 1L); // SDK fallback.
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1033,6 +1042,7 @@ public class ImaUtilTest {
|
||||
|
||||
@Test
|
||||
public void maybeCorrectPreviouslyUnknownAdDuration_singleAdInAdGroup_adDurationCorrected() {
|
||||
long adPeriodDurationUs = msToUs(AD_PERIOD_DURATION_MS);
|
||||
long liveWindowDurationUs = 60_000_000L;
|
||||
long nowUs = 110_234_567L;
|
||||
AdPlaybackState adPlaybackState =
|
||||
@ -1053,10 +1063,13 @@ public class ImaUtilTest {
|
||||
/* adDurationsUs...= */ 123);
|
||||
FakeMultiPeriodLiveTimeline contentTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
liveWindowDurationUs,
|
||||
nowUs,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -1070,13 +1083,14 @@ public class ImaUtilTest {
|
||||
assertThat(adPlaybackState.getAdGroup(/* adGroupIndex= */ 1).timeUs).isEqualTo(90_000_000L);
|
||||
assertThat(adPlaybackState.getAdGroup(/* adGroupIndex= */ 1).durationsUs)
|
||||
.asList()
|
||||
.containsExactly(AD_PERIOD_DURATION_US);
|
||||
.containsExactly(adPeriodDurationUs);
|
||||
assertThat(adPlaybackState.getAdGroup(/* adGroupIndex= */ 1).contentResumeOffsetUs)
|
||||
.isEqualTo(AD_PERIOD_DURATION_US);
|
||||
.isEqualTo(adPeriodDurationUs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void maybeCorrectPreviouslyUnknownAdDuration_multipleAdsInAdGroup_adDurationCorrected() {
|
||||
long adPeriodDurationUs = msToUs(AD_PERIOD_DURATION_MS);
|
||||
long liveWindowDurationUs = 60_000_000L;
|
||||
long nowUs = 110_234_567L;
|
||||
AdPlaybackState adPlaybackState =
|
||||
@ -1086,15 +1100,18 @@ public class ImaUtilTest {
|
||||
adPlaybackState,
|
||||
/* fromPositionUs= */ 80_000_000L,
|
||||
/* contentResumeOffsetUs= */ 10_000_123L,
|
||||
/* adDurationsUs...= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationsUs...= */ adPeriodDurationUs,
|
||||
123L);
|
||||
// Content timeline: [content, ad, ad, content]
|
||||
FakeMultiPeriodLiveTimeline contentTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
liveWindowDurationUs,
|
||||
nowUs,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -1104,9 +1121,9 @@ public class ImaUtilTest {
|
||||
assertThat(adPlaybackState.getAdGroup(/* adGroupIndex= */ 0).timeUs).isEqualTo(80_000_000L);
|
||||
assertThat(adPlaybackState.getAdGroup(/* adGroupIndex= */ 0).durationsUs)
|
||||
.asList()
|
||||
.containsExactly(AD_PERIOD_DURATION_US, AD_PERIOD_DURATION_US);
|
||||
.containsExactly(adPeriodDurationUs, adPeriodDurationUs);
|
||||
assertThat(adPlaybackState.getAdGroup(/* adGroupIndex= */ 0).contentResumeOffsetUs)
|
||||
.isEqualTo(2 * AD_PERIOD_DURATION_US);
|
||||
.isEqualTo(2 * adPeriodDurationUs);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1128,10 +1145,13 @@ public class ImaUtilTest {
|
||||
/* adDurationsUs...= */ 123);
|
||||
FakeMultiPeriodLiveTimeline contentTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 60_000_000L,
|
||||
/* nowUs= */ 160_000_000L,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -1150,10 +1170,17 @@ public class ImaUtilTest {
|
||||
// Content and ad period in window at the beginning: [c, a, a]
|
||||
FakeMultiPeriodLiveTimeline contentTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 50_000_000L,
|
||||
/* nowUs= */ 50_000_000L,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -1271,14 +1298,16 @@ public class ImaUtilTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
maybeCorrectPreviouslyUnknownAdDuration_singleContentPeriodTimeline_adPlaybackStateNotChanged() {
|
||||
public void maybeCorrectPreviouslyUnknownAdDuration_singleContentPeriodTimeline_doNothing() {
|
||||
FakeMultiPeriodLiveTimeline contentTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 30_000_000L,
|
||||
/* nowUs= */ 80_000_000L,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -1308,10 +1337,13 @@ public class ImaUtilTest {
|
||||
maybeCorrectPreviouslyUnknownAdDuration_singleAdPeriodTimeline_doesNotOverrideWithTimeUnset() {
|
||||
FakeMultiPeriodLiveTimeline contentTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 10_000_000L,
|
||||
/* nowUs= */ 90_000_000L,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -1608,13 +1640,20 @@ public class ImaUtilTest {
|
||||
@Test
|
||||
public void
|
||||
getAdGroupAndIndexInLiveMultiPeriodTimeline_calledForPeriodsAfterUnplayedAdGroup_correctAdGroupIndexAndAdIndexInAdGroup() {
|
||||
long adPeriodDurationUs = msToUs(AD_PERIOD_DURATION_MS);
|
||||
// Content live window with content and ad periods: c, [a, c, a, a, a, c, a], a, a
|
||||
FakeMultiPeriodLiveTimeline contentTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 100_000_000,
|
||||
/* nowUs= */ 159_000_123,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -1623,9 +1662,9 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 50_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 1,
|
||||
/* totalAdDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 1,
|
||||
adPlaybackState);
|
||||
|
||||
@ -1642,25 +1681,25 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 90_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 1,
|
||||
/* totalAdDurationUs= */ 3 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 3 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 3,
|
||||
adPlaybackState);
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 100_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 2,
|
||||
/* totalAdDurationUs= */ 3 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 3 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 3,
|
||||
adPlaybackState);
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 110_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 3,
|
||||
/* totalAdDurationUs= */ 3 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 3 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 3,
|
||||
adPlaybackState);
|
||||
|
||||
@ -1699,9 +1738,9 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 150_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 2,
|
||||
/* totalAdDurationUs= */ 3 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 3 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 3,
|
||||
adPlaybackState);
|
||||
|
||||
@ -1717,13 +1756,20 @@ public class ImaUtilTest {
|
||||
@Test
|
||||
public void
|
||||
getAdGroupAndIndexInLiveMultiPeriodTimeline_calledForPeriodsBeforeUnplayedAdGroup_throwsWhenCalledForNonAdPeriods() {
|
||||
long adPeriodDurationUs = msToUs(AD_PERIOD_DURATION_MS);
|
||||
// Content live window with content and ad periods: c, [a, c, a, a, a, c, a], a, a
|
||||
FakeMultiPeriodLiveTimeline contentTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 100_000_000,
|
||||
/* nowUs= */ 159_000_123,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -1732,9 +1778,9 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 50_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 1,
|
||||
/* totalAdDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 1,
|
||||
adPlaybackState);
|
||||
adPlaybackState =
|
||||
@ -1742,25 +1788,25 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 90_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 1,
|
||||
/* totalAdDurationUs= */ 3 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 3 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 3,
|
||||
adPlaybackState);
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 100_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 2,
|
||||
/* totalAdDurationUs= */ 3 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 3 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 3,
|
||||
adPlaybackState);
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 110_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 3,
|
||||
/* totalAdDurationUs= */ 3 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 3 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 3,
|
||||
adPlaybackState);
|
||||
AdPlaybackState finalAdPlaybackState = adPlaybackState;
|
||||
@ -1783,9 +1829,9 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 150_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 2,
|
||||
/* totalAdDurationUs= */ 3 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 3 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 3,
|
||||
adPlaybackState);
|
||||
AdPlaybackState anotherFinalAdPlaybackState = adPlaybackState;
|
||||
@ -1803,13 +1849,20 @@ public class ImaUtilTest {
|
||||
@Test
|
||||
public void
|
||||
getAdGroupAndIndexInLiveMultiPeriodTimeline_partialAdGroupAtTimelineStart_correctAdGroupIndexAndAdIndexInAdGroup() {
|
||||
long adPeriodDurationUs = msToUs(AD_PERIOD_DURATION_MS);
|
||||
// Content timeline with content and ad periods: c, a, a, [a, c, a, a, a, c]
|
||||
FakeMultiPeriodLiveTimeline contentTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 100_000_000,
|
||||
/* nowUs= */ 151_000_123,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -1818,25 +1871,25 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 30_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 1,
|
||||
/* totalAdDurationUs= */ 3 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 3 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 3,
|
||||
adPlaybackState);
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 40_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 2,
|
||||
/* totalAdDurationUs= */ 3 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 3 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 3,
|
||||
adPlaybackState);
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 50_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 3,
|
||||
/* totalAdDurationUs= */ 3 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 3 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 3,
|
||||
adPlaybackState);
|
||||
adPlaybackState =
|
||||
@ -1856,14 +1909,24 @@ public class ImaUtilTest {
|
||||
@Test
|
||||
public void
|
||||
getAdGroupAndIndexInLiveMultiPeriodTimeline_onlyPartialAdGroupInWindow_correctAdGroupIndexAndAdIndexInAdGroup() {
|
||||
long adPeriodDurationUs = msToUs(AD_PERIOD_DURATION_MS);
|
||||
// Content timeline with content and ad periods: c, a, [a, a, a, a], a, c
|
||||
// First three ad periods of the ad group already outside of the live window.
|
||||
FakeMultiPeriodLiveTimeline contentTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 30_000_000,
|
||||
/* nowUs= */ 71_000_123,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true, true, true, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -1873,9 +1936,9 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 30_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 1,
|
||||
/* totalAdDurationUs= */ 6 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 6 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 6,
|
||||
adPlaybackState);
|
||||
adPlaybackState =
|
||||
@ -1883,9 +1946,9 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 40_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 2,
|
||||
/* totalAdDurationUs= */ 6 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 6 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 6,
|
||||
adPlaybackState);
|
||||
|
||||
@ -1903,9 +1966,9 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 50_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 3,
|
||||
/* totalAdDurationUs= */ 6 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 6 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 6,
|
||||
adPlaybackState);
|
||||
|
||||
@ -1941,13 +2004,23 @@ public class ImaUtilTest {
|
||||
|
||||
@Test
|
||||
public void handleAdPeriodRemovedFromTimeline_removalCorrectlyHandled() {
|
||||
long adPeriodDurationUs = msToUs(AD_PERIOD_DURATION_MS);
|
||||
// Content timeline with content and ad periods: a,[c, a, a, a, a, a, a, c], a
|
||||
FakeMultiPeriodLiveTimeline contentTimeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 70_000_123,
|
||||
/* nowUs= */ 189_453_123,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true, true, true, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ false,
|
||||
/* populateAds= */ true,
|
||||
/* playedAds= */ false);
|
||||
@ -1957,9 +2030,9 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 120_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 1,
|
||||
/* totalAdDurationUs= */ 6 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 6 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 6,
|
||||
adPlaybackState);
|
||||
adPlaybackState =
|
||||
@ -1967,9 +2040,9 @@ public class ImaUtilTest {
|
||||
adPlaybackState =
|
||||
addLiveAdBreak(
|
||||
/* currentContentPeriodPositionUs= */ 130_000_000,
|
||||
/* adDurationUs= */ AD_PERIOD_DURATION_US,
|
||||
/* adDurationUs= */ adPeriodDurationUs,
|
||||
/* adPositionInAdPod= */ 2,
|
||||
/* totalAdDurationUs= */ 6 * AD_PERIOD_DURATION_US,
|
||||
/* totalAdDurationUs= */ 6 * adPeriodDurationUs,
|
||||
/* totalAdsInAdPod= */ 6,
|
||||
adPlaybackState);
|
||||
|
||||
@ -2099,13 +2172,17 @@ public class ImaUtilTest {
|
||||
@Test
|
||||
public void getAdGroupDurationUsForLiveAdPeriodIndex_allAdsInTimeline_correctAdGroupDuration() {
|
||||
int adPodTotalAdCount = 2;
|
||||
long adPeriodDurationUs = msToUs(AD_PERIOD_DURATION_MS);
|
||||
// Content and ad periods in timeline: [c, a, a, c, a, a].
|
||||
FakeMultiPeriodLiveTimeline timeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 75_007_123,
|
||||
/* nowUs= */ 99_321_457,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ false,
|
||||
/* populateAds= */ true,
|
||||
/* playedAds= */ false);
|
||||
@ -2121,11 +2198,11 @@ public class ImaUtilTest {
|
||||
assertThat(
|
||||
ImaUtil.getAdGroupDurationUsForLiveAdPeriodIndex(
|
||||
timeline, firstAdPodInfo, /* adPeriodIndex= */ 1, new Window(), new Period()))
|
||||
.isEqualTo(2 * AD_PERIOD_DURATION_US);
|
||||
.isEqualTo(2 * adPeriodDurationUs);
|
||||
assertThat(
|
||||
ImaUtil.getAdGroupDurationUsForLiveAdPeriodIndex(
|
||||
timeline, secondAdPodInfo, /* adPeriodIndex= */ 2, new Window(), new Period()))
|
||||
.isEqualTo(2 * AD_PERIOD_DURATION_US);
|
||||
.isEqualTo(2 * adPeriodDurationUs);
|
||||
// The second ad group has the last ad with an unknown duration.
|
||||
assertThat(
|
||||
ImaUtil.getAdGroupDurationUsForLiveAdPeriodIndex(
|
||||
@ -2144,10 +2221,13 @@ public class ImaUtilTest {
|
||||
// Content and ad periods in timeline: [a, a, c]. First two ads not in window.
|
||||
FakeMultiPeriodLiveTimeline timeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0,
|
||||
/* availabilityStartTimeMs= */ 0,
|
||||
/* liveWindowDurationUs= */ 49_321_753,
|
||||
/* nowUs= */ 85_007_123,
|
||||
/* adSequencePattern= */ new boolean[] {false, true, true},
|
||||
/* periodDurationMsPattern= */ new long[] {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ false,
|
||||
/* populateAds= */ true,
|
||||
/* playedAds= */ false);
|
||||
|
@ -17,6 +17,7 @@ package androidx.media3.test.utils;
|
||||
|
||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
||||
import static androidx.media3.common.util.Util.msToUs;
|
||||
import static androidx.media3.common.util.Util.sum;
|
||||
import static androidx.media3.common.util.Util.usToMs;
|
||||
|
||||
import androidx.media3.common.AdPlaybackState;
|
||||
@ -42,14 +43,14 @@ import java.util.Arrays;
|
||||
*
|
||||
* <p>Periods are either of type content or ad as defined by the ad sequence pattern. A period is an
|
||||
* ad if {@code adSequencePattern[id % adSequencePattern.length]} evaluates to true. Ad periods have
|
||||
* a duration of {@link #AD_PERIOD_DURATION_US} and content periods have a duration of {@link
|
||||
* #PERIOD_DURATION_US}.
|
||||
* a duration of {@link #AD_PERIOD_DURATION_MS} and content periods have a duration of {@link
|
||||
* #PERIOD_DURATION_MS}.
|
||||
*/
|
||||
@UnstableApi
|
||||
public class FakeMultiPeriodLiveTimeline extends Timeline {
|
||||
|
||||
public static final long AD_PERIOD_DURATION_US = 10_000_000L;
|
||||
public static final long PERIOD_DURATION_US = 30_000_000L;
|
||||
public static final long AD_PERIOD_DURATION_MS = 10_000L;
|
||||
public static final long PERIOD_DURATION_MS = 30_000L;
|
||||
|
||||
private final boolean[] adSequencePattern;
|
||||
private final MediaItem mediaItem;
|
||||
@ -58,6 +59,7 @@ public class FakeMultiPeriodLiveTimeline extends Timeline {
|
||||
private final boolean isContentTimeline;
|
||||
private final boolean populateAds;
|
||||
private final boolean playedAds;
|
||||
private final long[] periodDurationUsPattern;
|
||||
|
||||
private long nowUs;
|
||||
private ImmutableList<PeriodData> periods;
|
||||
@ -65,53 +67,55 @@ public class FakeMultiPeriodLiveTimeline extends Timeline {
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param availabilityStartTimeUs The start time of the available time range, in UNIX epoch.
|
||||
* @param availabilityStartTimeMs The start time of the available time range, UNIX epoch in
|
||||
* milliseconds.
|
||||
* @param liveWindowDurationUs The duration of the live window.
|
||||
* @param nowUs The current time that determines the end of the live window.
|
||||
* @param adSequencePattern The repeating pattern of periods starting at {@code
|
||||
* availabilityStartTimeUs}. True is an ad period, and false a content period.
|
||||
* availabilityStartTimeMs}. True is an ad period, and false a content period.
|
||||
* @param periodDurationMsPattern The repeating pattern of periods durations starting at {@code
|
||||
* availabilityStartTimeMs}, in milliseconds. Must have the same length as {@code
|
||||
* adSequencePattern}.
|
||||
* @param isContentTimeline Whether the timeline is a content timeline without {@link
|
||||
* AdPlaybackState}s.
|
||||
* @param populateAds Whether to populate ads in the same way if an ad event has been received.
|
||||
* @param playedAds Whether ads should be marked as played if populated.
|
||||
*/
|
||||
public FakeMultiPeriodLiveTimeline(
|
||||
long availabilityStartTimeUs,
|
||||
long availabilityStartTimeMs,
|
||||
long liveWindowDurationUs,
|
||||
long nowUs,
|
||||
boolean[] adSequencePattern,
|
||||
long[] periodDurationMsPattern,
|
||||
boolean isContentTimeline,
|
||||
boolean populateAds,
|
||||
boolean playedAds) {
|
||||
checkArgument(nowUs - liveWindowDurationUs >= availabilityStartTimeUs);
|
||||
this.availabilityStartTimeUs = availabilityStartTimeUs;
|
||||
checkArgument(nowUs - liveWindowDurationUs >= msToUs(availabilityStartTimeMs));
|
||||
checkArgument(adSequencePattern.length == periodDurationMsPattern.length);
|
||||
this.availabilityStartTimeUs = msToUs(availabilityStartTimeMs);
|
||||
this.liveWindowDurationUs = liveWindowDurationUs;
|
||||
this.nowUs = nowUs;
|
||||
this.adSequencePattern = Arrays.copyOf(adSequencePattern, adSequencePattern.length);
|
||||
periodDurationUsPattern = new long[periodDurationMsPattern.length];
|
||||
for (int i = 0; i < periodDurationMsPattern.length; i++) {
|
||||
periodDurationUsPattern[i] = msToUs(periodDurationMsPattern[i]);
|
||||
}
|
||||
this.isContentTimeline = isContentTimeline;
|
||||
this.populateAds = populateAds;
|
||||
this.playedAds = playedAds;
|
||||
mediaItem = new MediaItem.Builder().build();
|
||||
periods =
|
||||
invalidate(
|
||||
availabilityStartTimeUs,
|
||||
msToUs(availabilityStartTimeMs),
|
||||
liveWindowDurationUs,
|
||||
nowUs,
|
||||
adSequencePattern,
|
||||
periodDurationUsPattern,
|
||||
isContentTimeline,
|
||||
populateAds,
|
||||
playedAds);
|
||||
}
|
||||
|
||||
/** Calculates the total duration of the given ad period sequence. */
|
||||
public static long calculateAdSequencePatternDurationUs(boolean[] adSequencePattern) {
|
||||
long durationUs = 0;
|
||||
for (boolean isAd : adSequencePattern) {
|
||||
durationUs += (isAd ? AD_PERIOD_DURATION_US : PERIOD_DURATION_US);
|
||||
}
|
||||
return durationUs;
|
||||
}
|
||||
|
||||
/** Advances the live window by the given duration, in microseconds. */
|
||||
public void advanceNowUs(long durationUs) {
|
||||
nowUs += durationUs;
|
||||
@ -121,11 +125,35 @@ public class FakeMultiPeriodLiveTimeline extends Timeline {
|
||||
liveWindowDurationUs,
|
||||
nowUs,
|
||||
adSequencePattern,
|
||||
periodDurationUsPattern,
|
||||
isContentTimeline,
|
||||
populateAds,
|
||||
playedAds);
|
||||
}
|
||||
|
||||
/**
|
||||
* The window's start time in microseconds since the Unix epoch, or {@link C#TIME_UNSET} if
|
||||
* unknown or not applicable.
|
||||
*/
|
||||
public long getWindowStartTimeUs() {
|
||||
Window window = getWindow(/* windowIndex= */ 0, new Window());
|
||||
// Revert us/ms truncation introduced in `getWindow()`. This is identical to the truncation
|
||||
// applied in the Media3 `DashMediaSource.DashTimeline` and can be reverted in the same way.
|
||||
return window.windowStartTimeMs != C.TIME_UNSET
|
||||
? msToUs(window.windowStartTimeMs) + (window.positionInFirstPeriodUs % 1000)
|
||||
: C.TIME_UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the period start time since Unix epoch, in microseconds.
|
||||
*
|
||||
* <p>Note: The returned value has millisecond precision only, so the trailing 3 digits are always
|
||||
* zeros.
|
||||
*/
|
||||
public long getPeriodStartTimeUs(int periodIndex) {
|
||||
return msToUs(periods.get(periodIndex).periodStartTimeMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWindowCount() {
|
||||
return 1;
|
||||
@ -136,12 +164,13 @@ public class FakeMultiPeriodLiveTimeline extends Timeline {
|
||||
checkArgument(windowIndex == 0);
|
||||
MediaItem.LiveConfiguration liveConfiguration =
|
||||
new MediaItem.LiveConfiguration.Builder().build();
|
||||
long positionInFirstPeriodUs = -periods.get(0).positionInWindowUs;
|
||||
window.set(
|
||||
/* uid= */ "live-window",
|
||||
mediaItem,
|
||||
/* manifest= */ null,
|
||||
/* presentationStartTimeMs= */ C.TIME_UNSET,
|
||||
/* windowStartTimeMs= */ usToMs(nowUs - liveWindowDurationUs),
|
||||
/* windowStartTimeMs= */ periods.get(0).periodStartTimeMs + usToMs(positionInFirstPeriodUs),
|
||||
/* elapsedRealtimeEpochOffsetMs= */ 0,
|
||||
/* isSeekable= */ true,
|
||||
/* isDynamic= */ true,
|
||||
@ -150,7 +179,7 @@ public class FakeMultiPeriodLiveTimeline extends Timeline {
|
||||
/* durationUs= */ liveWindowDurationUs,
|
||||
/* firstPeriodIndex= */ 0,
|
||||
/* lastPeriodIndex= */ getPeriodCount() - 1,
|
||||
/* positionInFirstPeriodUs= */ -periods.get(0).positionInWindowUs);
|
||||
positionInFirstPeriodUs);
|
||||
return window;
|
||||
}
|
||||
|
||||
@ -193,24 +222,23 @@ public class FakeMultiPeriodLiveTimeline extends Timeline {
|
||||
long liveWindowDurationUs,
|
||||
long now,
|
||||
boolean[] adSequencePattern,
|
||||
long[] periodDurationUsPattern,
|
||||
boolean isContentTimeline,
|
||||
boolean populateAds,
|
||||
boolean playedAds) {
|
||||
long windowStartTimeUs = now - liveWindowDurationUs;
|
||||
int sequencePeriodCount = adSequencePattern.length;
|
||||
long sequenceDurationUs = calculateAdSequencePatternDurationUs(adSequencePattern);
|
||||
long sequenceDurationUs = sum(periodDurationUsPattern);
|
||||
long skippedSequenceCount = (windowStartTimeUs - availabilityStartTimeUs) / sequenceDurationUs;
|
||||
// Search the first period of the live window.
|
||||
int firstPeriodIndex = (int) (skippedSequenceCount * sequencePeriodCount);
|
||||
boolean isAd = adSequencePattern[firstPeriodIndex % sequencePeriodCount];
|
||||
long firstPeriodDurationUs = isAd ? AD_PERIOD_DURATION_US : PERIOD_DURATION_US;
|
||||
long firstPeriodDurationUs = periodDurationUsPattern[firstPeriodIndex % sequencePeriodCount];
|
||||
long firstPeriodEndTimeUs =
|
||||
availabilityStartTimeUs
|
||||
+ (sequenceDurationUs * skippedSequenceCount)
|
||||
+ firstPeriodDurationUs;
|
||||
while (firstPeriodEndTimeUs <= windowStartTimeUs) {
|
||||
isAd = adSequencePattern[++firstPeriodIndex % sequencePeriodCount];
|
||||
firstPeriodDurationUs = isAd ? AD_PERIOD_DURATION_US : PERIOD_DURATION_US;
|
||||
firstPeriodDurationUs = periodDurationUsPattern[++firstPeriodIndex % sequencePeriodCount];
|
||||
firstPeriodEndTimeUs += firstPeriodDurationUs;
|
||||
}
|
||||
ImmutableList.Builder<PeriodData> liveWindow = new ImmutableList.Builder<>();
|
||||
@ -218,8 +246,8 @@ public class FakeMultiPeriodLiveTimeline extends Timeline {
|
||||
int lastPeriodIndex = firstPeriodIndex;
|
||||
// Add periods to the window from the first period until we find a period start after `now`.
|
||||
while (lastPeriodStartTimeUs < now) {
|
||||
isAd = adSequencePattern[lastPeriodIndex % sequencePeriodCount];
|
||||
long periodDurationUs = isAd ? AD_PERIOD_DURATION_US : PERIOD_DURATION_US;
|
||||
long periodDurationUs = periodDurationUsPattern[lastPeriodIndex % sequencePeriodCount];
|
||||
boolean isAd = adSequencePattern[lastPeriodIndex % sequencePeriodCount];
|
||||
AdPlaybackState adPlaybackState = AdPlaybackState.NONE;
|
||||
if (!isContentTimeline) {
|
||||
adPlaybackState = new AdPlaybackState("adsId").withLivePostrollPlaceholderAppended();
|
||||
@ -244,6 +272,7 @@ public class FakeMultiPeriodLiveTimeline extends Timeline {
|
||||
/* id= */ lastPeriodIndex++,
|
||||
periodDurationUs,
|
||||
/* positionInWindowUs= */ lastPeriodStartTimeUs - windowStartTimeUs,
|
||||
/* periodStartTimeMs= */ usToMs(lastPeriodStartTimeUs),
|
||||
isAd,
|
||||
adPlaybackState));
|
||||
lastPeriodStartTimeUs += periodDurationUs;
|
||||
@ -257,6 +286,7 @@ public class FakeMultiPeriodLiveTimeline extends Timeline {
|
||||
private final Object uid;
|
||||
private final long durationUs;
|
||||
private final long positionInWindowUs;
|
||||
private final long periodStartTimeMs;
|
||||
private final AdPlaybackState adPlaybackState;
|
||||
|
||||
/** Creates an instance. */
|
||||
@ -264,9 +294,11 @@ public class FakeMultiPeriodLiveTimeline extends Timeline {
|
||||
int id,
|
||||
long durationUs,
|
||||
long positionInWindowUs,
|
||||
long periodStartTimeMs,
|
||||
boolean isAd,
|
||||
AdPlaybackState adPlaybackState) {
|
||||
this.id = id;
|
||||
this.periodStartTimeMs = periodStartTimeMs;
|
||||
this.uid = "uid-" + id + "[" + (isAd ? "a" : "c") + "]";
|
||||
this.durationUs = durationUs;
|
||||
this.positionInWindowUs = positionInWindowUs;
|
||||
|
@ -15,14 +15,15 @@
|
||||
*/
|
||||
package androidx.media3.test.utils;
|
||||
|
||||
import static androidx.media3.test.utils.FakeMultiPeriodLiveTimeline.AD_PERIOD_DURATION_US;
|
||||
import static androidx.media3.test.utils.FakeMultiPeriodLiveTimeline.PERIOD_DURATION_US;
|
||||
import static androidx.media3.test.utils.FakeMultiPeriodLiveTimeline.calculateAdSequencePatternDurationUs;
|
||||
import static androidx.media3.common.util.Util.msToUs;
|
||||
import static androidx.media3.common.util.Util.sum;
|
||||
import static androidx.media3.common.util.Util.usToMs;
|
||||
import static androidx.media3.test.utils.FakeMultiPeriodLiveTimeline.AD_PERIOD_DURATION_MS;
|
||||
import static androidx.media3.test.utils.FakeMultiPeriodLiveTimeline.PERIOD_DURATION_MS;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Timeline;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -36,12 +37,16 @@ public class FakeMultiPeriodLiveTimelineTest {
|
||||
@Test
|
||||
public void newInstance_availabilitySinceStartOfUnixEpoch_correctLiveWindow() {
|
||||
boolean[] adSequencePattern = {false, true, true};
|
||||
long[] periodDurationMsPattern = {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
};
|
||||
FakeMultiPeriodLiveTimeline timeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0L,
|
||||
/* availabilityStartTimeMs= */ 0L,
|
||||
/* liveWindowDurationUs= */ 60_000_000L,
|
||||
/* nowUs= */ 60_000_000L,
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern,
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -63,22 +68,28 @@ public class FakeMultiPeriodLiveTimelineTest {
|
||||
assertExpectedWindow(
|
||||
timeline,
|
||||
calculateExpectedWindow(
|
||||
/* availabilityStartTimeUs= */ 0L,
|
||||
/* availabilityStartTimeMs= */ 0L,
|
||||
/* liveWindowDurationUs= */ 60_000_000L,
|
||||
/* nowUs= */ 60_000_000L,
|
||||
adSequencePattern),
|
||||
adSequencePattern);
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern),
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newInstance_timelineWithAdsPopulated_correctPlaybackStates() {
|
||||
boolean[] adSequencePattern = {false, true, true};
|
||||
long[] periodDurationMsPattern = {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
};
|
||||
FakeMultiPeriodLiveTimeline timeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0L,
|
||||
/* availabilityStartTimeMs= */ 0L,
|
||||
/* liveWindowDurationUs= */ 50_000_000L,
|
||||
/* nowUs= */ 100_000_000L,
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern,
|
||||
/* isContentTimeline= */ false,
|
||||
/* populateAds= */ true,
|
||||
/* playedAds= */ false);
|
||||
@ -123,22 +134,28 @@ public class FakeMultiPeriodLiveTimelineTest {
|
||||
assertExpectedWindow(
|
||||
timeline,
|
||||
calculateExpectedWindow(
|
||||
/* availabilityStartTimeUs= */ 0L,
|
||||
/* availabilityStartTimeMs= */ 0L,
|
||||
/* liveWindowDurationUs= */ 50_000_000L,
|
||||
/* nowUs= */ 100_000_000L,
|
||||
adSequencePattern),
|
||||
adSequencePattern);
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern),
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newInstance_timelineWithAdsNotPopulated_correctPlaybackStates() {
|
||||
boolean[] adSequencePattern = {false, true, true};
|
||||
long[] periodDurationMsPattern = {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
};
|
||||
FakeMultiPeriodLiveTimeline timeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0L,
|
||||
/* availabilityStartTimeMs= */ 0L,
|
||||
/* liveWindowDurationUs= */ 50_000_000L,
|
||||
/* nowUs= */ 100_000_000L,
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern,
|
||||
/* isContentTimeline= */ false,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -175,22 +192,28 @@ public class FakeMultiPeriodLiveTimelineTest {
|
||||
assertExpectedWindow(
|
||||
timeline,
|
||||
calculateExpectedWindow(
|
||||
/* availabilityStartTimeUs= */ 0L,
|
||||
/* availabilityStartTimeMs= */ 0L,
|
||||
/* liveWindowDurationUs= */ 50_000_000L,
|
||||
/* nowUs= */ 100_000_000L,
|
||||
adSequencePattern),
|
||||
adSequencePattern);
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern),
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void advanceTimeUs_availabilitySinceStartOfUnixEpoch_correctPeriodsInLiveWindow() {
|
||||
boolean[] adSequencePattern = {false, true, true};
|
||||
long[] periodDurationMsPattern = {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
};
|
||||
FakeMultiPeriodLiveTimeline timeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0L,
|
||||
/* availabilityStartTimeMs= */ 0L,
|
||||
/* liveWindowDurationUs= */ 60_000_000L,
|
||||
/* nowUs= */ 60_000_123L,
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern,
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -209,11 +232,13 @@ public class FakeMultiPeriodLiveTimelineTest {
|
||||
assertExpectedWindow(
|
||||
timeline,
|
||||
calculateExpectedWindow(
|
||||
/* availabilityStartTimeUs= */ 0L,
|
||||
/* availabilityStartTimeMs= */ 0L,
|
||||
/* liveWindowDurationUs= */ 60_000_000L,
|
||||
/* nowUs= */ 60_000_123L,
|
||||
adSequencePattern),
|
||||
adSequencePattern);
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern),
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern);
|
||||
|
||||
// Advance nowUs so that the window ends just 1us before the next period moves into the window.
|
||||
timeline.advanceNowUs(19999877L);
|
||||
@ -231,11 +256,13 @@ public class FakeMultiPeriodLiveTimelineTest {
|
||||
assertExpectedWindow(
|
||||
timeline,
|
||||
calculateExpectedWindow(
|
||||
/* availabilityStartTimeUs= */ 0L,
|
||||
/* availabilityStartTimeMs= */ 0L,
|
||||
/* liveWindowDurationUs= */ 60_000_000L,
|
||||
/* nowUs= */ 60_000_123L + 19999877L,
|
||||
adSequencePattern),
|
||||
adSequencePattern);
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern),
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern);
|
||||
|
||||
// Advance the window by 1us to add the next period at the end of the window.
|
||||
timeline.advanceNowUs(1L);
|
||||
@ -254,110 +281,159 @@ public class FakeMultiPeriodLiveTimelineTest {
|
||||
assertExpectedWindow(
|
||||
timeline,
|
||||
calculateExpectedWindow(
|
||||
/* availabilityStartTimeUs= */ 0L,
|
||||
/* availabilityStartTimeMs= */ 0L,
|
||||
/* liveWindowDurationUs= */ 60_000_000L,
|
||||
/* nowUs= */ 60_000_123L + 19999878L,
|
||||
adSequencePattern),
|
||||
adSequencePattern);
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern),
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newInstance_advancedAvailabilityStartTime_correctlyInterpolatedPeriodIds() {
|
||||
Timeline.Period period = new Timeline.Period();
|
||||
long availabilityStartTimeUs = 0;
|
||||
long availabilityStartTimeMs = 0;
|
||||
long nowUs = 120_000_123;
|
||||
long liveWindowDurationUs = 60_000_987L;
|
||||
boolean[] adSequencePattern = {false, true, true};
|
||||
long sequenceDurationUs = calculateAdSequencePatternDurationUs(adSequencePattern);
|
||||
long[] periodDurationMsPattern = {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
};
|
||||
long sequenceDurationUs = 50_000_000L;
|
||||
|
||||
FakeMultiPeriodLiveTimeline timeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
availabilityStartTimeUs,
|
||||
availabilityStartTimeMs,
|
||||
liveWindowDurationUs,
|
||||
nowUs,
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern,
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ true);
|
||||
|
||||
assertThat(timeline.getWindow(0, new Timeline.Window()).windowStartTimeMs)
|
||||
.isEqualTo(Util.usToMs(nowUs - liveWindowDurationUs));
|
||||
assertThat(timeline.getPeriodCount()).isEqualTo(4);
|
||||
long windowStartTimeUs = timeline.getWindowStartTimeUs();
|
||||
assertThat(
|
||||
windowStartTimeUs + timeline.getPeriod(/* periodIndex= */ 0, period).positionInWindowUs)
|
||||
.isEqualTo(timeline.getPeriodStartTimeUs(/* periodIndex= */ 0));
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 0, period).id).isEqualTo(3);
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 0, period).uid).isEqualTo("uid-3[c]");
|
||||
assertThat(
|
||||
windowStartTimeUs + timeline.getPeriod(/* periodIndex= */ 1, period).positionInWindowUs)
|
||||
.isEqualTo(timeline.getPeriodStartTimeUs(/* periodIndex= */ 1));
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 1, period).id).isEqualTo(4);
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 1, period).uid).isEqualTo("uid-4[a]");
|
||||
assertThat(
|
||||
windowStartTimeUs + timeline.getPeriod(/* periodIndex= */ 2, period).positionInWindowUs)
|
||||
.isEqualTo(timeline.getPeriodStartTimeUs(/* periodIndex= */ 2));
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 2, period).id).isEqualTo(5);
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 2, period).uid).isEqualTo("uid-5[a]");
|
||||
assertThat(
|
||||
windowStartTimeUs + timeline.getPeriod(/* periodIndex= */ 3, period).positionInWindowUs)
|
||||
.isEqualTo(timeline.getPeriodStartTimeUs(/* periodIndex= */ 3));
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 3, period).id).isEqualTo(6);
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 3, period).uid).isEqualTo("uid-6[c]");
|
||||
assertExpectedWindow(
|
||||
timeline,
|
||||
calculateExpectedWindow(
|
||||
availabilityStartTimeUs, liveWindowDurationUs, nowUs, adSequencePattern),
|
||||
adSequencePattern);
|
||||
availabilityStartTimeMs,
|
||||
liveWindowDurationUs,
|
||||
nowUs,
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern),
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern);
|
||||
|
||||
timeline.advanceNowUs(sequenceDurationUs * 13);
|
||||
|
||||
assertThat(timeline.getWindow(0, new Timeline.Window()).windowStartTimeMs)
|
||||
.isEqualTo(Util.usToMs((nowUs + sequenceDurationUs * 13) - liveWindowDurationUs));
|
||||
windowStartTimeUs = timeline.getWindowStartTimeUs();
|
||||
assertThat(
|
||||
windowStartTimeUs + timeline.getPeriod(/* periodIndex= */ 0, period).positionInWindowUs)
|
||||
.isEqualTo(timeline.getPeriodStartTimeUs(/* periodIndex= */ 0));
|
||||
assertThat(timeline.getPeriodCount()).isEqualTo(4);
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 0, period).id).isEqualTo((13 * 3) + 3);
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 0, period).uid)
|
||||
.isEqualTo("uid-" + ((13 * 3) + 3) + "[c]");
|
||||
assertThat(
|
||||
windowStartTimeUs + timeline.getPeriod(/* periodIndex= */ 1, period).positionInWindowUs)
|
||||
.isEqualTo(timeline.getPeriodStartTimeUs(/* periodIndex= */ 1));
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 1, period).id).isEqualTo((13 * 3) + 4);
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 1, period).uid)
|
||||
.isEqualTo("uid-" + ((13 * 3) + 4) + "[a]");
|
||||
assertThat(
|
||||
windowStartTimeUs + timeline.getPeriod(/* periodIndex= */ 2, period).positionInWindowUs)
|
||||
.isEqualTo(timeline.getPeriodStartTimeUs(/* periodIndex= */ 2));
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 2, period).id).isEqualTo((13 * 3) + 5);
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 2, period).uid)
|
||||
.isEqualTo("uid-" + ((13 * 3) + 5) + "[a]");
|
||||
assertThat(
|
||||
windowStartTimeUs + timeline.getPeriod(/* periodIndex= */ 3, period).positionInWindowUs)
|
||||
.isEqualTo(timeline.getPeriodStartTimeUs(/* periodIndex= */ 3));
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 3, period).id).isEqualTo((13 * 3) + 6);
|
||||
assertThat(timeline.getPeriod(/* periodIndex= */ 3, period).uid)
|
||||
.isEqualTo("uid-" + ((13 * 3) + 6) + "[c]");
|
||||
assertExpectedWindow(
|
||||
timeline,
|
||||
calculateExpectedWindow(
|
||||
availabilityStartTimeUs,
|
||||
availabilityStartTimeMs,
|
||||
liveWindowDurationUs,
|
||||
(nowUs + sequenceDurationUs * 13),
|
||||
adSequencePattern),
|
||||
adSequencePattern);
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern),
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newInstance_availabilitySinceAWeekAfterStartOfUnixEpoch_correctLiveWindow() {
|
||||
long availabilityStartTimeUs = 7 * A_DAY_US;
|
||||
long availabilityStartTimeMs = usToMs(7 * A_DAY_US);
|
||||
long nowUs = 18 * A_DAY_US + 135_000_000;
|
||||
long liveWindowDurationUs = 60_000_000L;
|
||||
boolean[] adSequencePattern = {false, true, true};
|
||||
long[] periodDurationMsPattern = {
|
||||
PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS, AD_PERIOD_DURATION_MS
|
||||
};
|
||||
|
||||
FakeMultiPeriodLiveTimeline timeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
availabilityStartTimeUs,
|
||||
availabilityStartTimeMs,
|
||||
liveWindowDurationUs,
|
||||
nowUs,
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern,
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
|
||||
assertThat(timeline.getWindow(0, new Timeline.Window()).windowStartTimeMs)
|
||||
.isEqualTo(Util.usToMs(nowUs - liveWindowDurationUs));
|
||||
.isEqualTo(usToMs(nowUs - liveWindowDurationUs));
|
||||
assertExpectedWindow(
|
||||
timeline,
|
||||
calculateExpectedWindow(
|
||||
availabilityStartTimeUs, liveWindowDurationUs, nowUs, adSequencePattern),
|
||||
adSequencePattern);
|
||||
availabilityStartTimeMs,
|
||||
liveWindowDurationUs,
|
||||
nowUs,
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern),
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newInstance_adSequencePattern_correctPeriodTypesFromStartOfAvailability() {
|
||||
FakeMultiPeriodLiveTimeline timeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0L,
|
||||
/* availabilityStartTimeMs= */ 0L,
|
||||
/* liveWindowDurationUs= */ 120_000_000L,
|
||||
/* nowUs= */ 120_000_000L,
|
||||
new boolean[] {false, true, true, true},
|
||||
new long[] {
|
||||
PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -392,10 +468,17 @@ public class FakeMultiPeriodLiveTimelineTest {
|
||||
|
||||
timeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
/* availabilityStartTimeUs= */ 0L,
|
||||
/* availabilityStartTimeMs= */ 0L,
|
||||
/* liveWindowDurationUs= */ 220_000_000L,
|
||||
/* nowUs= */ 250_000_000L,
|
||||
new boolean[] {false, true, false, true, false},
|
||||
new long[] {
|
||||
PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
PERIOD_DURATION_MS,
|
||||
AD_PERIOD_DURATION_MS,
|
||||
PERIOD_DURATION_MS
|
||||
},
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
@ -415,22 +498,62 @@ public class FakeMultiPeriodLiveTimelineTest {
|
||||
assertThat(timeline.getPeriod(9, period).uid).isEqualTo("uid-10[c]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void advanceNowUs_calculatePeriodStartTimeUsFromWindowStartMs_correctPeriodStartTimeUs() {
|
||||
long[] periodDurationMsPattern = {1, 7, 5, 3};
|
||||
boolean[] adSequencePattern = {false, true, true, true};
|
||||
long liveWindowDurationUs = 15_243L;
|
||||
long nowUs = 29_000_123L;
|
||||
long availabilityStartTimeMs = 1L;
|
||||
FakeMultiPeriodLiveTimeline timeline =
|
||||
new FakeMultiPeriodLiveTimeline(
|
||||
availabilityStartTimeMs,
|
||||
liveWindowDurationUs,
|
||||
nowUs,
|
||||
adSequencePattern,
|
||||
periodDurationMsPattern,
|
||||
/* isContentTimeline= */ true,
|
||||
/* populateAds= */ false,
|
||||
/* playedAds= */ false);
|
||||
Timeline.Window window = new Timeline.Window();
|
||||
Timeline.Period period = new Timeline.Period();
|
||||
|
||||
for (long i = 0; i < 50_000L; i++) {
|
||||
timeline.getWindow(/* windowIndex= */ 0, window);
|
||||
// Assert the DashMediaSource specific truncation can be reverted to calculate the period
|
||||
// start time (See `FakeMultiPeriodLiveTimeline.getWindowStartImeUs()` also).
|
||||
long windowStartTimeUs =
|
||||
msToUs(window.windowStartTimeMs) + (window.positionInFirstPeriodUs % 1000);
|
||||
for (int j = window.firstPeriodIndex; j <= window.lastPeriodIndex; j++) {
|
||||
timeline.getPeriod(/* periodIndex= */ j, period);
|
||||
assertThat(windowStartTimeUs + period.positionInWindowUs)
|
||||
.isEqualTo(timeline.getPeriodStartTimeUs(/* periodIndex= */ j));
|
||||
}
|
||||
timeline.advanceNowUs(1);
|
||||
}
|
||||
}
|
||||
|
||||
private ExpectedWindow calculateExpectedWindow(
|
||||
long availabilityStartTimeUs,
|
||||
long availabilityStartTimeMs,
|
||||
long liveWindowDurationUs,
|
||||
long nowUs,
|
||||
boolean[] adSequencePattern) {
|
||||
boolean[] adSequencePattern,
|
||||
long[] periodDurationMsPattern) {
|
||||
long[] periodDurationUsPattern = new long[periodDurationMsPattern.length];
|
||||
for (int i = 0; i < periodDurationMsPattern.length; i++) {
|
||||
periodDurationUsPattern[i] = msToUs(periodDurationMsPattern[i]);
|
||||
}
|
||||
long windowStartTimeUs = nowUs - liveWindowDurationUs;
|
||||
long sequenceDurationUs = calculateAdSequencePatternDurationUs(adSequencePattern);
|
||||
long durationBeforeWindowStartUs = windowStartTimeUs - availabilityStartTimeUs;
|
||||
long sequenceDurationUs = sum(periodDurationUsPattern);
|
||||
long durationBeforeWindowStartUs = windowStartTimeUs - msToUs(availabilityStartTimeMs);
|
||||
long skippedSequenceCount = durationBeforeWindowStartUs / sequenceDurationUs;
|
||||
long remainingDurationBeforeWindowUs = durationBeforeWindowStartUs % sequenceDurationUs;
|
||||
int idOfFirstPeriodInWindow = (int) (skippedSequenceCount * adSequencePattern.length);
|
||||
long lastSkippedPeriodDurationUs = 0L;
|
||||
// Skip period by period until we reach the window start.
|
||||
while (remainingDurationBeforeWindowUs > 0) {
|
||||
boolean isAd = adSequencePattern[idOfFirstPeriodInWindow++ % adSequencePattern.length];
|
||||
lastSkippedPeriodDurationUs = isAd ? AD_PERIOD_DURATION_US : PERIOD_DURATION_US;
|
||||
lastSkippedPeriodDurationUs =
|
||||
periodDurationUsPattern[idOfFirstPeriodInWindow++ % adSequencePattern.length];
|
||||
remainingDurationBeforeWindowUs -= lastSkippedPeriodDurationUs;
|
||||
}
|
||||
long positionOfFirstPeriodInWindowUs = 0;
|
||||
@ -442,24 +565,29 @@ public class FakeMultiPeriodLiveTimelineTest {
|
||||
-(lastSkippedPeriodDurationUs + remainingDurationBeforeWindowUs);
|
||||
}
|
||||
long durationOfFirstPeriodInWindowUs =
|
||||
adSequencePattern[idOfFirstPeriodInWindow % adSequencePattern.length]
|
||||
? AD_PERIOD_DURATION_US
|
||||
: PERIOD_DURATION_US;
|
||||
periodDurationUsPattern[idOfFirstPeriodInWindow % adSequencePattern.length];
|
||||
long durationInWindowUs =
|
||||
remainingDurationBeforeWindowUs == 0
|
||||
? durationOfFirstPeriodInWindowUs
|
||||
: -remainingDurationBeforeWindowUs;
|
||||
int idOfLastPeriodInWindow = idOfFirstPeriodInWindow;
|
||||
while (durationInWindowUs < liveWindowDurationUs) {
|
||||
boolean isAd = adSequencePattern[++idOfLastPeriodInWindow % adSequencePattern.length];
|
||||
durationInWindowUs += isAd ? AD_PERIOD_DURATION_US : PERIOD_DURATION_US;
|
||||
durationInWindowUs +=
|
||||
periodDurationUsPattern[++idOfLastPeriodInWindow % adSequencePattern.length];
|
||||
}
|
||||
return new ExpectedWindow(
|
||||
idOfFirstPeriodInWindow, idOfLastPeriodInWindow, positionOfFirstPeriodInWindowUs);
|
||||
}
|
||||
|
||||
private void assertExpectedWindow(
|
||||
Timeline timeline, ExpectedWindow expectedWindow, boolean[] adSequencePattern) {
|
||||
Timeline timeline,
|
||||
ExpectedWindow expectedWindow,
|
||||
boolean[] adSequencePattern,
|
||||
long[] periodDurationMsPattern) {
|
||||
long[] periodDurationUsPattern = new long[periodDurationMsPattern.length];
|
||||
for (int i = 0; i < periodDurationMsPattern.length; i++) {
|
||||
periodDurationUsPattern[i] = msToUs(periodDurationMsPattern[i]);
|
||||
}
|
||||
Timeline.Period period = new Timeline.Period();
|
||||
assertThat(timeline.getPeriodCount())
|
||||
.isEqualTo(expectedWindow.idOfLastPeriod - expectedWindow.idOfFirstPeriod + 1);
|
||||
@ -467,11 +595,12 @@ public class FakeMultiPeriodLiveTimelineTest {
|
||||
for (int i = 0; i < timeline.getPeriodCount(); i++) {
|
||||
int id = expectedWindow.idOfFirstPeriod + i;
|
||||
boolean isAd = adSequencePattern[id % adSequencePattern.length];
|
||||
long durationUs = periodDurationUsPattern[id % periodDurationUsPattern.length];
|
||||
assertThat(timeline.getPeriod(i, period).id).isEqualTo(id);
|
||||
assertThat(timeline.getPeriod(i, period).uid)
|
||||
.isEqualTo("uid-" + id + "[" + (isAd ? "a" : "c") + "]");
|
||||
assertThat(timeline.getPeriod(i, period).positionInWindowUs).isEqualTo(positionInWindowUs);
|
||||
positionInWindowUs += isAd ? AD_PERIOD_DURATION_US : PERIOD_DURATION_US;
|
||||
positionInWindowUs += durationUs;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user