Pull IMA cuePoints -> adGroupTimesUs logic into a helper class

We're then able to use this same helper class from tests, to avoid
running into spurious failures caused by long microseconds being
round-tripped through float seconds.

PiperOrigin-RevId: 316435084
This commit is contained in:
ibaker 2020-06-15 11:54:43 +01:00 committed by Oliver Woodman
parent 1ce040003a
commit a0e90ce1ff
3 changed files with 134 additions and 116 deletions

View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.ext.ima;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
import java.util.Arrays;
import java.util.List;
/**
* Static utility class for constructing {@link AdPlaybackState} instances from IMA-specific data.
*/
/* package */ final class AdPlaybackStateFactory {
private AdPlaybackStateFactory() {}
/**
* Construct an {@link AdPlaybackState} from the provided {@code cuePoints}.
*
* @param cuePoints The cue points of the ads in seconds.
* @return The {@link AdPlaybackState}.
*/
public static AdPlaybackState fromCuePoints(List<Float> cuePoints) {
if (cuePoints.isEmpty()) {
// If no cue points are specified, there is a preroll ad.
return new AdPlaybackState(/* adGroupTimesUs...= */ 0);
}
int count = cuePoints.size();
long[] adGroupTimesUs = new long[count];
int adGroupIndex = 0;
for (int i = 0; i < count; i++) {
double cuePoint = cuePoints.get(i);
if (cuePoint == -1.0) {
adGroupTimesUs[count - 1] = C.TIME_END_OF_SOURCE;
} else {
adGroupTimesUs[adGroupIndex++] = (long) (C.MICROS_PER_SECOND * cuePoint);
}
}
// Cue points may be out of order, so sort them.
Arrays.sort(adGroupTimesUs, 0, adGroupIndex);
return new AdPlaybackState(adGroupTimesUs);
}
}

View File

@ -662,7 +662,7 @@ public final class ImaAdsLoader
adsManager.resume(); adsManager.resume();
} }
} else if (adsManager != null) { } else if (adsManager != null) {
adPlaybackState = new AdPlaybackState(getAdGroupTimesUs(adsManager.getAdCuePoints())); adPlaybackState = AdPlaybackStateFactory.fromCuePoints(adsManager.getAdCuePoints());
updateAdPlaybackState(); updateAdPlaybackState();
} else { } else {
// Ads haven't loaded yet, so request them. // Ads haven't loaded yet, so request them.
@ -739,7 +739,7 @@ public final class ImaAdsLoader
if (player != null) { if (player != null) {
// If a player is attached already, start playback immediately. // If a player is attached already, start playback immediately.
try { try {
adPlaybackState = new AdPlaybackState(getAdGroupTimesUs(adsManager.getAdCuePoints())); adPlaybackState = AdPlaybackStateFactory.fromCuePoints(adsManager.getAdCuePoints());
hasAdPlaybackState = true; hasAdPlaybackState = true;
updateAdPlaybackState(); updateAdPlaybackState();
} catch (RuntimeException e) { } catch (RuntimeException e) {
@ -1545,28 +1545,6 @@ public final class ImaAdsLoader
: timeline.getPeriod(/* periodIndex= */ 0, period).getPositionInWindowMs()); : timeline.getPeriod(/* periodIndex= */ 0, period).getPositionInWindowMs());
} }
private static long[] getAdGroupTimesUs(List<Float> cuePoints) {
if (cuePoints.isEmpty()) {
// If no cue points are specified, there is a preroll ad.
return new long[] {0};
}
int count = cuePoints.size();
long[] adGroupTimesUs = new long[count];
int adGroupIndex = 0;
for (int i = 0; i < count; i++) {
double cuePoint = cuePoints.get(i);
if (cuePoint == -1.0) {
adGroupTimesUs[count - 1] = C.TIME_END_OF_SOURCE;
} else {
adGroupTimesUs[adGroupIndex++] = (long) (C.MICROS_PER_SECOND * cuePoint);
}
}
// Cue points may be out of order, so sort them.
Arrays.sort(adGroupTimesUs, 0, adGroupIndex);
return adGroupTimesUs;
}
private static boolean isAdGroupLoadError(AdError adError) { private static boolean isAdGroupLoadError(AdError adError) {
// TODO: Find out what other errors need to be handled (if any), and whether each one relates to // TODO: Find out what other errors need to be handled (if any), and whether each one relates to
// a single ad, ad group or the whole timeline. // a single ad, ad group or the whole timeline.

View File

@ -58,6 +58,7 @@ import com.google.android.exoplayer2.source.ads.SinglePeriodAdTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.io.IOException; import java.io.IOException;
import java.time.Duration; import java.time.Duration;
@ -93,7 +94,7 @@ public final class ImaAdsLoaderTest {
private static final Uri TEST_URI = Uri.EMPTY; private static final Uri TEST_URI = Uri.EMPTY;
private static final AdMediaInfo TEST_AD_MEDIA_INFO = new AdMediaInfo(TEST_URI.toString()); private static final AdMediaInfo TEST_AD_MEDIA_INFO = new AdMediaInfo(TEST_URI.toString());
private static final long TEST_AD_DURATION_US = 5 * C.MICROS_PER_SECOND; private static final long TEST_AD_DURATION_US = 5 * C.MICROS_PER_SECOND;
private static final Float[] PREROLL_CUE_POINTS_SECONDS = new Float[] {0f}; private static final ImmutableList<Float> PREROLL_CUE_POINTS_SECONDS = ImmutableList.of(0f);
@Rule public final MockitoRule mockito = MockitoJUnit.rule(); @Rule public final MockitoRule mockito = MockitoJUnit.rule();
@ -256,7 +257,7 @@ public final class ImaAdsLoaderTest {
@Test @Test
public void playback_withPostrollFetchError_marksAdAsInErrorState() { public void playback_withPostrollFetchError_marksAdAsInErrorState() {
setupPlayback(CONTENT_TIMELINE, new Float[] {-1f}); setupPlayback(CONTENT_TIMELINE, ImmutableList.of(-1f));
// Simulate loading an empty postroll ad. // Simulate loading an empty postroll ad.
imaAdsLoader.start(adsLoaderListener, adViewProvider); imaAdsLoader.start(adsLoaderListener, adViewProvider);
@ -275,9 +276,9 @@ public final class ImaAdsLoaderTest {
public void playback_withAdNotPreloadingBeforeTimeout_hasNoError() { public void playback_withAdNotPreloadingBeforeTimeout_hasNoError() {
// Simulate an ad at 2 seconds. // Simulate an ad at 2 seconds.
long adGroupPositionInWindowUs = 2 * C.MICROS_PER_SECOND; long adGroupPositionInWindowUs = 2 * C.MICROS_PER_SECOND;
setupPlayback( long adGroupTimeUs = adGroupPositionInWindowUs;
CONTENT_TIMELINE, ImmutableList<Float> cuePoints = ImmutableList.of((float) adGroupTimeUs / C.MICROS_PER_SECOND);
new Float[] {(float) adGroupPositionInWindowUs / C.MICROS_PER_SECOND}); setupPlayback(CONTENT_TIMELINE, cuePoints);
// Advance playback to just before the midroll and simulate buffering. // Advance playback to just before the midroll and simulate buffering.
imaAdsLoader.start(adsLoaderListener, adViewProvider); imaAdsLoader.start(adsLoaderListener, adViewProvider);
@ -289,7 +290,7 @@ public final class ImaAdsLoaderTest {
assertThat(adsLoaderListener.adPlaybackState) assertThat(adsLoaderListener.adPlaybackState)
.isEqualTo( .isEqualTo(
new AdPlaybackState(/* adGroupTimesUs...= */ adGroupPositionInWindowUs) AdPlaybackStateFactory.fromCuePoints(cuePoints)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)); .withContentDurationUs(CONTENT_PERIOD_DURATION_US));
} }
@ -297,9 +298,9 @@ public final class ImaAdsLoaderTest {
public void playback_withAdNotPreloadingAfterTimeout_hasErrorAdGroup() { public void playback_withAdNotPreloadingAfterTimeout_hasErrorAdGroup() {
// Simulate an ad at 2 seconds. // Simulate an ad at 2 seconds.
long adGroupPositionInWindowUs = 2 * C.MICROS_PER_SECOND; long adGroupPositionInWindowUs = 2 * C.MICROS_PER_SECOND;
setupPlayback( long adGroupTimeUs = adGroupPositionInWindowUs;
CONTENT_TIMELINE, ImmutableList<Float> cuePoints = ImmutableList.of((float) adGroupTimeUs / C.MICROS_PER_SECOND);
new Float[] {(float) adGroupPositionInWindowUs / C.MICROS_PER_SECOND}); setupPlayback(CONTENT_TIMELINE, cuePoints);
// Advance playback to just before the midroll and simulate buffering. // Advance playback to just before the midroll and simulate buffering.
imaAdsLoader.start(adsLoaderListener, adViewProvider); imaAdsLoader.start(adsLoaderListener, adViewProvider);
@ -311,7 +312,7 @@ public final class ImaAdsLoaderTest {
assertThat(adsLoaderListener.adPlaybackState) assertThat(adsLoaderListener.adPlaybackState)
.isEqualTo( .isEqualTo(
new AdPlaybackState(/* adGroupTimesUs...= */ adGroupPositionInWindowUs) AdPlaybackStateFactory.fromCuePoints(cuePoints)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US) .withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}}) .withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}})
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1) .withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
@ -321,10 +322,10 @@ public final class ImaAdsLoaderTest {
@Test @Test
public void resumePlaybackBeforeMidroll_playsPreroll() { public void resumePlaybackBeforeMidroll_playsPreroll() {
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND; long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
long midrollPeriodTimeUs = long midrollPeriodTimeUs = midrollWindowTimeUs;
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; ImmutableList<Float> cuePoints =
setupPlayback( ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
CONTENT_TIMELINE, new Float[] {0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND}); setupPlayback(CONTENT_TIMELINE, cuePoints);
fakeExoPlayer.setPlayingContentPosition(C.usToMs(midrollWindowTimeUs) - 1_000); fakeExoPlayer.setPlayingContentPosition(C.usToMs(midrollWindowTimeUs) - 1_000);
imaAdsLoader.start(adsLoaderListener, adViewProvider); imaAdsLoader.start(adsLoaderListener, adViewProvider);
@ -332,17 +333,17 @@ public final class ImaAdsLoaderTest {
verify(mockAdsRenderingSettings, never()).setPlayAdsAfterTime(anyDouble()); verify(mockAdsRenderingSettings, never()).setPlayAdsAfterTime(anyDouble());
assertThat(adsLoaderListener.adPlaybackState) assertThat(adsLoaderListener.adPlaybackState)
.isEqualTo( .isEqualTo(
new AdPlaybackState(/* adGroupTimesUs...= */ 0, midrollPeriodTimeUs) AdPlaybackStateFactory.fromCuePoints(cuePoints)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)); .withContentDurationUs(CONTENT_PERIOD_DURATION_US));
} }
@Test @Test
public void resumePlaybackAtMidroll_skipsPreroll() { public void resumePlaybackAtMidroll_skipsPreroll() {
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND; long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
long midrollPeriodTimeUs = long midrollPeriodTimeUs = midrollWindowTimeUs;
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; ImmutableList<Float> cuePoints =
setupPlayback( ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
CONTENT_TIMELINE, new Float[] {0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND}); setupPlayback(CONTENT_TIMELINE, cuePoints);
fakeExoPlayer.setPlayingContentPosition(C.usToMs(midrollWindowTimeUs)); fakeExoPlayer.setPlayingContentPosition(C.usToMs(midrollWindowTimeUs));
imaAdsLoader.start(adsLoaderListener, adViewProvider); imaAdsLoader.start(adsLoaderListener, adViewProvider);
@ -355,7 +356,7 @@ public final class ImaAdsLoaderTest {
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND); .of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
assertThat(adsLoaderListener.adPlaybackState) assertThat(adsLoaderListener.adPlaybackState)
.isEqualTo( .isEqualTo(
new AdPlaybackState(/* adGroupTimesUs...= */ 0, midrollPeriodTimeUs) AdPlaybackStateFactory.fromCuePoints(cuePoints)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US) .withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withSkippedAdGroup(/* adGroupIndex= */ 0)); .withSkippedAdGroup(/* adGroupIndex= */ 0));
} }
@ -363,10 +364,10 @@ public final class ImaAdsLoaderTest {
@Test @Test
public void resumePlaybackAfterMidroll_skipsPreroll() { public void resumePlaybackAfterMidroll_skipsPreroll() {
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND; long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
long midrollPeriodTimeUs = long midrollPeriodTimeUs = midrollWindowTimeUs;
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; ImmutableList<Float> cuePoints =
setupPlayback( ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
CONTENT_TIMELINE, new Float[] {0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND}); setupPlayback(CONTENT_TIMELINE, cuePoints);
fakeExoPlayer.setPlayingContentPosition(C.usToMs(midrollWindowTimeUs) + 1_000); fakeExoPlayer.setPlayingContentPosition(C.usToMs(midrollWindowTimeUs) + 1_000);
imaAdsLoader.start(adsLoaderListener, adViewProvider); imaAdsLoader.start(adsLoaderListener, adViewProvider);
@ -379,7 +380,7 @@ public final class ImaAdsLoaderTest {
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND); .of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
assertThat(adsLoaderListener.adPlaybackState) assertThat(adsLoaderListener.adPlaybackState)
.isEqualTo( .isEqualTo(
new AdPlaybackState(/* adGroupTimesUs...= */ 0, midrollPeriodTimeUs) AdPlaybackStateFactory.fromCuePoints(cuePoints)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US) .withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withSkippedAdGroup(/* adGroupIndex= */ 0)); .withSkippedAdGroup(/* adGroupIndex= */ 0));
} }
@ -387,19 +388,14 @@ public final class ImaAdsLoaderTest {
@Test @Test
public void resumePlaybackBeforeSecondMidroll_playsFirstMidroll() { public void resumePlaybackBeforeSecondMidroll_playsFirstMidroll() {
long firstMidrollWindowTimeUs = 2 * C.MICROS_PER_SECOND; long firstMidrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
long firstMidrollPeriodTimeUs = long firstMidrollPeriodTimeUs = firstMidrollWindowTimeUs;
firstMidrollWindowTimeUs
+ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
long secondMidrollWindowTimeUs = 4 * C.MICROS_PER_SECOND; long secondMidrollWindowTimeUs = 4 * C.MICROS_PER_SECOND;
long secondMidrollPeriodTimeUs = long secondMidrollPeriodTimeUs = secondMidrollWindowTimeUs;
secondMidrollWindowTimeUs ImmutableList<Float> cuePoints =
+ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; ImmutableList.of(
setupPlayback( (float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
CONTENT_TIMELINE, (float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND);
new Float[] { setupPlayback(CONTENT_TIMELINE, cuePoints);
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND
});
fakeExoPlayer.setPlayingContentPosition(C.usToMs(secondMidrollWindowTimeUs) - 1_000); fakeExoPlayer.setPlayingContentPosition(C.usToMs(secondMidrollWindowTimeUs) - 1_000);
imaAdsLoader.start(adsLoaderListener, adViewProvider); imaAdsLoader.start(adsLoaderListener, adViewProvider);
@ -407,27 +403,21 @@ public final class ImaAdsLoaderTest {
verify(mockAdsRenderingSettings, never()).setPlayAdsAfterTime(anyDouble()); verify(mockAdsRenderingSettings, never()).setPlayAdsAfterTime(anyDouble());
assertThat(adsLoaderListener.adPlaybackState) assertThat(adsLoaderListener.adPlaybackState)
.isEqualTo( .isEqualTo(
new AdPlaybackState( AdPlaybackStateFactory.fromCuePoints(cuePoints)
/* adGroupTimesUs...= */ firstMidrollPeriodTimeUs, secondMidrollPeriodTimeUs)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)); .withContentDurationUs(CONTENT_PERIOD_DURATION_US));
} }
@Test @Test
public void resumePlaybackAtSecondMidroll_skipsFirstMidroll() { public void resumePlaybackAtSecondMidroll_skipsFirstMidroll() {
long firstMidrollWindowTimeUs = 2 * C.MICROS_PER_SECOND; long firstMidrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
long firstMidrollPeriodTimeUs = long firstMidrollPeriodTimeUs = firstMidrollWindowTimeUs;
firstMidrollWindowTimeUs
+ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
long secondMidrollWindowTimeUs = 4 * C.MICROS_PER_SECOND; long secondMidrollWindowTimeUs = 4 * C.MICROS_PER_SECOND;
long secondMidrollPeriodTimeUs = long secondMidrollPeriodTimeUs = secondMidrollWindowTimeUs;
secondMidrollWindowTimeUs ImmutableList<Float> cuePoints =
+ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; ImmutableList.of(
setupPlayback( (float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
CONTENT_TIMELINE, (float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND);
new Float[] { setupPlayback(CONTENT_TIMELINE, cuePoints);
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND
});
fakeExoPlayer.setPlayingContentPosition(C.usToMs(secondMidrollWindowTimeUs)); fakeExoPlayer.setPlayingContentPosition(C.usToMs(secondMidrollWindowTimeUs));
imaAdsLoader.start(adsLoaderListener, adViewProvider); imaAdsLoader.start(adsLoaderListener, adViewProvider);
@ -440,8 +430,7 @@ public final class ImaAdsLoaderTest {
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND); .of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
assertThat(adsLoaderListener.adPlaybackState) assertThat(adsLoaderListener.adPlaybackState)
.isEqualTo( .isEqualTo(
new AdPlaybackState( AdPlaybackStateFactory.fromCuePoints(cuePoints)
/* adGroupTimesUs...= */ firstMidrollPeriodTimeUs, secondMidrollPeriodTimeUs)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US) .withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withSkippedAdGroup(/* adGroupIndex= */ 0)); .withSkippedAdGroup(/* adGroupIndex= */ 0));
} }
@ -449,11 +438,12 @@ public final class ImaAdsLoaderTest {
@Test @Test
public void resumePlaybackBeforeMidroll_withoutPlayAdBeforeStartPosition_skipsPreroll() { public void resumePlaybackBeforeMidroll_withoutPlayAdBeforeStartPosition_skipsPreroll() {
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND; long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
long midrollPeriodTimeUs = long midrollPeriodTimeUs = midrollWindowTimeUs;
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; ImmutableList<Float> cuePoints =
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
setupPlayback( setupPlayback(
CONTENT_TIMELINE, CONTENT_TIMELINE,
new Float[] {0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND}, cuePoints,
new ImaAdsLoader.Builder(ApplicationProvider.getApplicationContext()) new ImaAdsLoader.Builder(ApplicationProvider.getApplicationContext())
.setPlayAdBeforeStartPosition(false) .setPlayAdBeforeStartPosition(false)
.setImaFactory(mockImaFactory) .setImaFactory(mockImaFactory)
@ -471,7 +461,7 @@ public final class ImaAdsLoaderTest {
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND); .of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
assertThat(adsLoaderListener.adPlaybackState) assertThat(adsLoaderListener.adPlaybackState)
.isEqualTo( .isEqualTo(
new AdPlaybackState(/* adGroupTimesUs...= */ 0, midrollPeriodTimeUs) AdPlaybackStateFactory.fromCuePoints(cuePoints)
.withSkippedAdGroup(/* adGroupIndex= */ 0) .withSkippedAdGroup(/* adGroupIndex= */ 0)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)); .withContentDurationUs(CONTENT_PERIOD_DURATION_US));
} }
@ -479,11 +469,12 @@ public final class ImaAdsLoaderTest {
@Test @Test
public void resumePlaybackAtMidroll_withoutPlayAdBeforeStartPosition_skipsPreroll() { public void resumePlaybackAtMidroll_withoutPlayAdBeforeStartPosition_skipsPreroll() {
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND; long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
long midrollPeriodTimeUs = long midrollPeriodTimeUs = midrollWindowTimeUs;
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; ImmutableList<Float> cuePoints =
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
setupPlayback( setupPlayback(
CONTENT_TIMELINE, CONTENT_TIMELINE,
new Float[] {0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND}, cuePoints,
new ImaAdsLoader.Builder(ApplicationProvider.getApplicationContext()) new ImaAdsLoader.Builder(ApplicationProvider.getApplicationContext())
.setPlayAdBeforeStartPosition(false) .setPlayAdBeforeStartPosition(false)
.setImaFactory(mockImaFactory) .setImaFactory(mockImaFactory)
@ -501,7 +492,7 @@ public final class ImaAdsLoaderTest {
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND); .of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
assertThat(adsLoaderListener.adPlaybackState) assertThat(adsLoaderListener.adPlaybackState)
.isEqualTo( .isEqualTo(
new AdPlaybackState(/* adGroupTimesUs...= */ 0, midrollPeriodTimeUs) AdPlaybackStateFactory.fromCuePoints(cuePoints)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US) .withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withSkippedAdGroup(/* adGroupIndex= */ 0)); .withSkippedAdGroup(/* adGroupIndex= */ 0));
} }
@ -509,11 +500,12 @@ public final class ImaAdsLoaderTest {
@Test @Test
public void resumePlaybackAfterMidroll_withoutPlayAdBeforeStartPosition_skipsMidroll() { public void resumePlaybackAfterMidroll_withoutPlayAdBeforeStartPosition_skipsMidroll() {
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND; long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
long midrollPeriodTimeUs = long midrollPeriodTimeUs = midrollWindowTimeUs;
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; ImmutableList<Float> cuePoints =
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
setupPlayback( setupPlayback(
CONTENT_TIMELINE, CONTENT_TIMELINE,
new Float[] {0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND}, cuePoints,
new ImaAdsLoader.Builder(ApplicationProvider.getApplicationContext()) new ImaAdsLoader.Builder(ApplicationProvider.getApplicationContext())
.setPlayAdBeforeStartPosition(false) .setPlayAdBeforeStartPosition(false)
.setImaFactory(mockImaFactory) .setImaFactory(mockImaFactory)
@ -526,7 +518,7 @@ public final class ImaAdsLoaderTest {
verify(mockAdsManager).destroy(); verify(mockAdsManager).destroy();
assertThat(adsLoaderListener.adPlaybackState) assertThat(adsLoaderListener.adPlaybackState)
.isEqualTo( .isEqualTo(
new AdPlaybackState(/* adGroupTimesUs...= */ 0, midrollPeriodTimeUs) AdPlaybackStateFactory.fromCuePoints(cuePoints)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US) .withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withSkippedAdGroup(/* adGroupIndex= */ 0) .withSkippedAdGroup(/* adGroupIndex= */ 0)
.withSkippedAdGroup(/* adGroupIndex= */ 1)); .withSkippedAdGroup(/* adGroupIndex= */ 1));
@ -536,19 +528,16 @@ public final class ImaAdsLoaderTest {
public void public void
resumePlaybackBeforeSecondMidroll_withoutPlayAdBeforeStartPosition_skipsFirstMidroll() { resumePlaybackBeforeSecondMidroll_withoutPlayAdBeforeStartPosition_skipsFirstMidroll() {
long firstMidrollWindowTimeUs = 2 * C.MICROS_PER_SECOND; long firstMidrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
long firstMidrollPeriodTimeUs = long firstMidrollPeriodTimeUs = firstMidrollWindowTimeUs;
firstMidrollWindowTimeUs
+ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
long secondMidrollWindowTimeUs = 4 * C.MICROS_PER_SECOND; long secondMidrollWindowTimeUs = 4 * C.MICROS_PER_SECOND;
long secondMidrollPeriodTimeUs = long secondMidrollPeriodTimeUs = secondMidrollWindowTimeUs;
secondMidrollWindowTimeUs ImmutableList<Float> cuePoints =
+ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; ImmutableList.of(
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND);
setupPlayback( setupPlayback(
CONTENT_TIMELINE, CONTENT_TIMELINE,
new Float[] { cuePoints,
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND
},
new ImaAdsLoader.Builder(ApplicationProvider.getApplicationContext()) new ImaAdsLoader.Builder(ApplicationProvider.getApplicationContext())
.setPlayAdBeforeStartPosition(false) .setPlayAdBeforeStartPosition(false)
.setImaFactory(mockImaFactory) .setImaFactory(mockImaFactory)
@ -566,8 +555,7 @@ public final class ImaAdsLoaderTest {
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND); .of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
assertThat(adsLoaderListener.adPlaybackState) assertThat(adsLoaderListener.adPlaybackState)
.isEqualTo( .isEqualTo(
new AdPlaybackState( AdPlaybackStateFactory.fromCuePoints(cuePoints)
/* adGroupTimesUs...= */ firstMidrollPeriodTimeUs, secondMidrollPeriodTimeUs)
.withSkippedAdGroup(/* adGroupIndex= */ 0) .withSkippedAdGroup(/* adGroupIndex= */ 0)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)); .withContentDurationUs(CONTENT_PERIOD_DURATION_US));
} }
@ -575,19 +563,16 @@ public final class ImaAdsLoaderTest {
@Test @Test
public void resumePlaybackAtSecondMidroll_withoutPlayAdBeforeStartPosition_skipsFirstMidroll() { public void resumePlaybackAtSecondMidroll_withoutPlayAdBeforeStartPosition_skipsFirstMidroll() {
long firstMidrollWindowTimeUs = 2 * C.MICROS_PER_SECOND; long firstMidrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
long firstMidrollPeriodTimeUs = long firstMidrollPeriodTimeUs = firstMidrollWindowTimeUs;
firstMidrollWindowTimeUs
+ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
long secondMidrollWindowTimeUs = 4 * C.MICROS_PER_SECOND; long secondMidrollWindowTimeUs = 4 * C.MICROS_PER_SECOND;
long secondMidrollPeriodTimeUs = long secondMidrollPeriodTimeUs = secondMidrollWindowTimeUs;
secondMidrollWindowTimeUs ImmutableList<Float> cuePoints =
+ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; ImmutableList.of(
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND);
setupPlayback( setupPlayback(
CONTENT_TIMELINE, CONTENT_TIMELINE,
new Float[] { cuePoints,
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND
},
new ImaAdsLoader.Builder(ApplicationProvider.getApplicationContext()) new ImaAdsLoader.Builder(ApplicationProvider.getApplicationContext())
.setPlayAdBeforeStartPosition(false) .setPlayAdBeforeStartPosition(false)
.setImaFactory(mockImaFactory) .setImaFactory(mockImaFactory)
@ -605,8 +590,7 @@ public final class ImaAdsLoaderTest {
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND); .of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
assertThat(adsLoaderListener.adPlaybackState) assertThat(adsLoaderListener.adPlaybackState)
.isEqualTo( .isEqualTo(
new AdPlaybackState( AdPlaybackStateFactory.fromCuePoints(cuePoints)
/* adGroupTimesUs...= */ firstMidrollPeriodTimeUs, secondMidrollPeriodTimeUs)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US) .withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withSkippedAdGroup(/* adGroupIndex= */ 0)); .withSkippedAdGroup(/* adGroupIndex= */ 0));
} }
@ -623,7 +607,7 @@ public final class ImaAdsLoaderTest {
inOrder.verify(mockAdDisplayContainer).unregisterAllVideoControlsOverlays(); inOrder.verify(mockAdDisplayContainer).unregisterAllVideoControlsOverlays();
} }
private void setupPlayback(Timeline contentTimeline, Float[] cuePoints) { private void setupPlayback(Timeline contentTimeline, List<Float> cuePoints) {
setupPlayback( setupPlayback(
contentTimeline, contentTimeline,
cuePoints, cuePoints,
@ -634,10 +618,10 @@ public final class ImaAdsLoaderTest {
} }
private void setupPlayback( private void setupPlayback(
Timeline contentTimeline, Float[] cuePoints, ImaAdsLoader imaAdsLoader) { Timeline contentTimeline, List<Float> cuePoints, ImaAdsLoader imaAdsLoader) {
fakeExoPlayer = new FakePlayer(); fakeExoPlayer = new FakePlayer();
adsLoaderListener = new TestAdsLoaderListener(fakeExoPlayer, contentTimeline); adsLoaderListener = new TestAdsLoaderListener(fakeExoPlayer, contentTimeline);
when(mockAdsManager.getAdCuePoints()).thenReturn(Arrays.asList(cuePoints)); when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
this.imaAdsLoader = imaAdsLoader; this.imaAdsLoader = imaAdsLoader;
imaAdsLoader.setPlayer(fakeExoPlayer); imaAdsLoader.setPlayer(fakeExoPlayer);
} }