mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Allow the number of ad groups to grow with AdsMediaSource
This enables `AdsMediaSource` to be used with a live media source that has a growing `AdPlaybackState` to which ad groups can be appended. Before this change, `AdsMediaSource` asserted that the number of ad groups was kept the same, else an exception was thrown. After this change, the assertion checks the validity of the update and throws in case the update isn't considered valid. An update is valid if ad groups are appended to the existing `AdPlaybackState` or ads are appended to existing ad groups. Further the `adGroupIndex` and `timeUs`of an existing ad group can not be changed and once a media item is set for a given ad, that media item can't be changed either. PiperOrigin-RevId: 707244455
This commit is contained in:
parent
aa2ee8f702
commit
d4f4a2c1d4
@ -40,6 +40,9 @@
|
||||
* Disable use of asynchronous decryption in MediaCodec to avoid reported
|
||||
codec timeout issues with this platform API
|
||||
([#1641](https://github.com/androidx/media/issues/1641)).
|
||||
* Change `AdsMediaSource` to allow the `AdPlaybackStates` to grow by
|
||||
appending ad groups. Invalid modifications are detected and throw an
|
||||
exception.
|
||||
* Transformer:
|
||||
* Update parameters of `VideoFrameProcessor.registerInputStream` and
|
||||
`VideoFrameProcessor.Listener.onInputStreamRegistered` to use `Format`.
|
||||
|
@ -25,6 +25,7 @@ import android.os.SystemClock;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.AdPlaybackState;
|
||||
import androidx.media3.common.AdPlaybackState.AdGroup;
|
||||
import androidx.media3.common.AdViewProvider;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.MediaItem;
|
||||
@ -54,6 +55,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
/**
|
||||
* A {@link MediaSource} that inserts ads linearly into a provided content media source.
|
||||
@ -352,16 +354,61 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
|
||||
private void onAdPlaybackState(AdPlaybackState adPlaybackState) {
|
||||
if (this.adPlaybackState == null) {
|
||||
adMediaSourceHolders = new AdMediaSourceHolder[adPlaybackState.adGroupCount][];
|
||||
int playableAdGroupCount =
|
||||
adPlaybackState.adGroupCount
|
||||
- (adPlaybackState.endsWithLivePostrollPlaceHolder() ? 1 : 0);
|
||||
adMediaSourceHolders = new AdMediaSourceHolder[playableAdGroupCount][];
|
||||
Arrays.fill(adMediaSourceHolders, new AdMediaSourceHolder[0]);
|
||||
} else {
|
||||
checkState(adPlaybackState.adGroupCount == this.adPlaybackState.adGroupCount);
|
||||
int adGroupInsertionCount =
|
||||
checkValidAdPlaybackStateUpdate(this.adPlaybackState, adPlaybackState);
|
||||
if (adGroupInsertionCount > 0) {
|
||||
adMediaSourceHolders =
|
||||
growAdMediaSourceHolderGrid(adMediaSourceHolders, adGroupInsertionCount);
|
||||
}
|
||||
}
|
||||
this.adPlaybackState = adPlaybackState;
|
||||
maybeUpdateAdMediaSources();
|
||||
maybeUpdateSourceInfo();
|
||||
}
|
||||
|
||||
private static int checkValidAdPlaybackStateUpdate(
|
||||
AdPlaybackState oldAdPlaybackState, AdPlaybackState newAdPlaybackState) {
|
||||
checkState(
|
||||
oldAdPlaybackState.endsWithLivePostrollPlaceHolder()
|
||||
== newAdPlaybackState.endsWithLivePostrollPlaceHolder());
|
||||
int insertionCount = newAdPlaybackState.adGroupCount - oldAdPlaybackState.adGroupCount;
|
||||
checkState(insertionCount >= 0);
|
||||
for (int i = newAdPlaybackState.removedAdGroupCount; i < oldAdPlaybackState.adGroupCount; i++) {
|
||||
AdGroup oldAdGroup = oldAdPlaybackState.getAdGroup(i);
|
||||
if (oldAdGroup.isLivePostrollPlaceholder()) {
|
||||
// Post-roll placeholder must be at the last index.
|
||||
checkState(i == oldAdPlaybackState.adGroupCount - 1);
|
||||
break;
|
||||
}
|
||||
AdGroup newAdGroup = newAdPlaybackState.getAdGroup(i);
|
||||
checkState(oldAdGroup.count <= newAdGroup.count);
|
||||
checkState(oldAdGroup.timeUs == newAdGroup.timeUs);
|
||||
for (int j = 0; j < oldAdGroup.count; j++) {
|
||||
if (oldAdGroup.mediaItems[j] != null) {
|
||||
checkState(oldAdGroup.mediaItems[j].equals(newAdGroup.mediaItems[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
return insertionCount;
|
||||
}
|
||||
|
||||
private static @NullableType AdMediaSourceHolder[][] growAdMediaSourceHolderGrid(
|
||||
@NullableType AdMediaSourceHolder[][] grid, int insertionCount) {
|
||||
@NullableType
|
||||
AdMediaSourceHolder[][] grownGrid = new AdMediaSourceHolder[grid.length + insertionCount][];
|
||||
System.arraycopy(grid, 0, grownGrid, 0, grid.length);
|
||||
for (int i = grid.length; i < grownGrid.length; i++) {
|
||||
grownGrid[i] = new AdMediaSourceHolder[0];
|
||||
}
|
||||
return grownGrid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes any {@link AdMediaSourceHolder AdMediaSourceHolders} where the ad media URI is
|
||||
* newly known.
|
||||
@ -378,7 +425,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
@Nullable
|
||||
AdMediaSourceHolder adMediaSourceHolder =
|
||||
this.adMediaSourceHolders[adGroupIndex][adIndexInAdGroup];
|
||||
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex);
|
||||
AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex);
|
||||
if (adMediaSourceHolder != null
|
||||
&& !adMediaSourceHolder.hasMediaSource()
|
||||
&& adIndexInAdGroup < adGroup.mediaItems.length) {
|
||||
@ -409,8 +456,12 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresNonNull("adPlaybackState")
|
||||
private long[][] getAdDurationsUs() {
|
||||
long[][] adDurationsUs = new long[adMediaSourceHolders.length][];
|
||||
boolean hasPostRollPlaceholder =
|
||||
checkNotNull(adPlaybackState).endsWithLivePostrollPlaceHolder();
|
||||
int adGroupCount = adMediaSourceHolders.length + (hasPostRollPlaceholder ? 1 : 0);
|
||||
long[][] adDurationsUs = new long[adGroupCount][];
|
||||
for (int i = 0; i < adMediaSourceHolders.length; i++) {
|
||||
adDurationsUs[i] = new long[adMediaSourceHolders[i].length];
|
||||
for (int j = 0; j < adMediaSourceHolders[i].length; j++) {
|
||||
@ -418,6 +469,10 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
adDurationsUs[i][j] = holder == null ? C.TIME_UNSET : holder.getDurationUs();
|
||||
}
|
||||
}
|
||||
if (hasPostRollPlaceholder) {
|
||||
// Set the pseudo-durations of the placeholder that is not represented by the holders.
|
||||
adDurationsUs[adGroupCount - 1] = new long[0];
|
||||
}
|
||||
return adDurationsUs;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ package androidx.media3.exoplayer.source.ads;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
@ -100,7 +101,7 @@ public final class AdsMediaSourceTest {
|
||||
private static final Object CONTENT_PERIOD_UID =
|
||||
CONTENT_TIMELINE.getUidOfPeriod(/* periodIndex= */ 0);
|
||||
|
||||
private static final AdPlaybackState AD_PLAYBACK_STATE =
|
||||
private static final AdPlaybackState PREROLL_AD_PLAYBACK_STATE =
|
||||
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0)
|
||||
.withContentDurationUs(CONTENT_DURATION_US)
|
||||
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
|
||||
@ -121,6 +122,7 @@ public final class AdsMediaSourceTest {
|
||||
private FakeMediaSource prerollAdMediaSource;
|
||||
@Mock private MediaSourceCaller mockMediaSourceCaller;
|
||||
private AdsMediaSource adsMediaSource;
|
||||
private EventListener adsLoaderEventListener;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@ -156,15 +158,17 @@ public final class AdsMediaSourceTest {
|
||||
eq(TEST_ADS_ID),
|
||||
eq(mockAdViewProvider),
|
||||
eventListenerArgumentCaptor.capture());
|
||||
adsLoaderEventListener = eventListenerArgumentCaptor.getValue();
|
||||
}
|
||||
|
||||
// Simulate loading a preroll ad.
|
||||
AdsLoader.EventListener adsLoaderEventListener = eventListenerArgumentCaptor.getValue();
|
||||
adsLoaderEventListener.onAdPlaybackState(AD_PLAYBACK_STATE);
|
||||
private void setAdPlaybackState(AdPlaybackState adPlaybackState) {
|
||||
adsLoaderEventListener.onAdPlaybackState(adPlaybackState);
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPeriod_forPreroll_preparesChildAdMediaSourceAndRefreshesSourceInfo() {
|
||||
setAdPlaybackState(PREROLL_AD_PLAYBACK_STATE);
|
||||
// This should be unused if we only create the preroll period.
|
||||
contentMediaSource.setNewSourceInfo(CONTENT_TIMELINE);
|
||||
adsMediaSource.createPeriod(
|
||||
@ -181,12 +185,13 @@ public final class AdsMediaSourceTest {
|
||||
verify(mockMediaSourceCaller)
|
||||
.onSourceInfoRefreshed(
|
||||
adsMediaSource,
|
||||
new SinglePeriodAdTimeline(PLACEHOLDER_CONTENT_TIMELINE, AD_PLAYBACK_STATE));
|
||||
new SinglePeriodAdTimeline(PLACEHOLDER_CONTENT_TIMELINE, PREROLL_AD_PLAYBACK_STATE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
createPeriod_forPreroll_preparesChildAdMediaSourceAndRefreshesSourceInfoWithAdMediaSourceInfo() {
|
||||
setAdPlaybackState(PREROLL_AD_PLAYBACK_STATE);
|
||||
// This should be unused if we only create the preroll period.
|
||||
contentMediaSource.setNewSourceInfo(CONTENT_TIMELINE);
|
||||
adsMediaSource.createPeriod(
|
||||
@ -205,11 +210,13 @@ public final class AdsMediaSourceTest {
|
||||
adsMediaSource,
|
||||
new SinglePeriodAdTimeline(
|
||||
PLACEHOLDER_CONTENT_TIMELINE,
|
||||
AD_PLAYBACK_STATE.withAdDurationsUs(new long[][] {{PREROLL_AD_DURATION_US}})));
|
||||
PREROLL_AD_PLAYBACK_STATE.withAdDurationsUs(
|
||||
new long[][] {{PREROLL_AD_DURATION_US}})));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPeriod_forPreroll_createsChildPrerollAdMediaPeriod() {
|
||||
setAdPlaybackState(PREROLL_AD_PLAYBACK_STATE);
|
||||
adsMediaSource.createPeriod(
|
||||
new MediaPeriodId(
|
||||
CONTENT_PERIOD_UID,
|
||||
@ -227,6 +234,7 @@ public final class AdsMediaSourceTest {
|
||||
|
||||
@Test
|
||||
public void createPeriod_forContent_createsChildContentMediaPeriodAndLoadsContentTimeline() {
|
||||
setAdPlaybackState(PREROLL_AD_PLAYBACK_STATE);
|
||||
contentMediaSource.setNewSourceInfo(CONTENT_TIMELINE);
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
adsMediaSource.createPeriod(
|
||||
@ -241,11 +249,12 @@ public final class AdsMediaSourceTest {
|
||||
.onSourceInfoRefreshed(eq(adsMediaSource), adsTimelineCaptor.capture());
|
||||
TestUtil.timelinesAreSame(
|
||||
adsTimelineCaptor.getValue(),
|
||||
new SinglePeriodAdTimeline(CONTENT_TIMELINE, AD_PLAYBACK_STATE));
|
||||
new SinglePeriodAdTimeline(CONTENT_TIMELINE, PREROLL_AD_PLAYBACK_STATE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void releasePeriod_releasesChildMediaPeriodsAndSources() {
|
||||
setAdPlaybackState(PREROLL_AD_PLAYBACK_STATE);
|
||||
contentMediaSource.setNewSourceInfo(CONTENT_TIMELINE);
|
||||
MediaPeriod prerollAdMediaPeriod =
|
||||
adsMediaSource.createPeriod(
|
||||
@ -692,6 +701,239 @@ public final class AdsMediaSourceTest {
|
||||
.isEqualTo(133_000_000); // Overridden by AdsMediaSource with the actual source duration.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAdPlaybackState_correctAdPlaybackStateInTimeline() {
|
||||
ArgumentCaptor<Timeline> timelineCaptor = ArgumentCaptor.forClass(Timeline.class);
|
||||
|
||||
setAdPlaybackState(PREROLL_AD_PLAYBACK_STATE);
|
||||
|
||||
verify(mockMediaSourceCaller).onSourceInfoRefreshed(any(), timelineCaptor.capture());
|
||||
assertThat(
|
||||
timelineCaptor
|
||||
.getValue()
|
||||
.getPeriod(/* periodIndex= */ 0, new Timeline.Period())
|
||||
.adPlaybackState)
|
||||
.isEqualTo(PREROLL_AD_PLAYBACK_STATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAdPlaybackState_growingLiveAdPlaybackState_correctAdPlaybackStateInTimeline() {
|
||||
AdPlaybackState initialLiveAdPlaybackState =
|
||||
new AdPlaybackState("adsId")
|
||||
.withLivePostrollPlaceholderAppended(/* isServerSideInserted= */ false);
|
||||
AdPlaybackState singleAdInFirstAdGroup =
|
||||
initialLiveAdPlaybackState
|
||||
.withNewAdGroup(/* adGroupIndex= */ 0, /* adGroupTimeUs= */ 0L)
|
||||
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, 1_000L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 1_000L)
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
MediaItem.fromUri("https://example.com/ad0-0"));
|
||||
AdPlaybackState twoAdsInFirstAdGroup =
|
||||
singleAdInFirstAdGroup
|
||||
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 2)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, 1_000L, 2_000L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 3_000L)
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 1,
|
||||
MediaItem.fromUri("https://example.com/ad0-1"));
|
||||
AdPlaybackState singleAdInSecondAdGroup =
|
||||
twoAdsInFirstAdGroup
|
||||
.withNewAdGroup(/* adGroupIndex= */ 1, /* adGroupTimeUs= */ 10_000L)
|
||||
.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 1)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 1, 10_000L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 1, 10_000L)
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 1,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
MediaItem.fromUri("https://example.com/ad1-0"));
|
||||
AdPlaybackState twoAdsInSecondAdGroup =
|
||||
singleAdInSecondAdGroup
|
||||
.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 2)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 1, 10_000L, 20_000L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 1, 30_000L)
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 1,
|
||||
/* adIndexInAdGroup= */ 1,
|
||||
MediaItem.fromUri("https://example.com/ad1-1"));
|
||||
ArgumentCaptor<Timeline> timelineCaptor = ArgumentCaptor.forClass(Timeline.class);
|
||||
|
||||
setAdPlaybackState(initialLiveAdPlaybackState);
|
||||
setAdPlaybackState(singleAdInFirstAdGroup);
|
||||
setAdPlaybackState(twoAdsInFirstAdGroup);
|
||||
setAdPlaybackState(singleAdInSecondAdGroup);
|
||||
setAdPlaybackState(twoAdsInSecondAdGroup);
|
||||
|
||||
verify(mockMediaSourceCaller, times(5)).onSourceInfoRefreshed(any(), timelineCaptor.capture());
|
||||
assertThat(
|
||||
timelineCaptor
|
||||
.getAllValues()
|
||||
.get(0)
|
||||
.getPeriod(0, new Timeline.Period())
|
||||
.adPlaybackState)
|
||||
.isEqualTo(initialLiveAdPlaybackState);
|
||||
assertThat(
|
||||
timelineCaptor
|
||||
.getAllValues()
|
||||
.get(1)
|
||||
.getPeriod(0, new Timeline.Period())
|
||||
.adPlaybackState)
|
||||
.isEqualTo(
|
||||
singleAdInFirstAdGroup.withAdDurationsUs(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adDurationsUs...= */ C.TIME_UNSET)); // durations are overridden by ads source
|
||||
assertThat(
|
||||
timelineCaptor
|
||||
.getAllValues()
|
||||
.get(2)
|
||||
.getPeriod(0, new Timeline.Period())
|
||||
.adPlaybackState)
|
||||
.isEqualTo(
|
||||
twoAdsInFirstAdGroup.withAdDurationsUs(
|
||||
/* adGroupIndex= */ 0, /* adDurationsUs...= */ C.TIME_UNSET, C.TIME_UNSET));
|
||||
assertThat(
|
||||
timelineCaptor
|
||||
.getAllValues()
|
||||
.get(3)
|
||||
.getPeriod(0, new Timeline.Period())
|
||||
.adPlaybackState)
|
||||
.isEqualTo(
|
||||
singleAdInSecondAdGroup
|
||||
.withAdDurationsUs(
|
||||
/* adGroupIndex= */ 0, /* adDurationsUs...= */ C.TIME_UNSET, C.TIME_UNSET)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 1, /* adDurationsUs...= */ C.TIME_UNSET));
|
||||
assertThat(
|
||||
timelineCaptor
|
||||
.getAllValues()
|
||||
.get(4)
|
||||
.getPeriod(0, new Timeline.Period())
|
||||
.adPlaybackState)
|
||||
.isEqualTo(
|
||||
twoAdsInSecondAdGroup
|
||||
.withAdDurationsUs(
|
||||
/* adGroupIndex= */ 0, /* adDurationsUs...= */ C.TIME_UNSET, C.TIME_UNSET)
|
||||
.withAdDurationsUs(
|
||||
/* adGroupIndex= */ 1, /* adDurationsUs...= */ C.TIME_UNSET, C.TIME_UNSET));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
onAdPlaybackState_shrinkingAdPlaybackStateForLiveStream_throwsIllegalStateException() {
|
||||
AdPlaybackState initialLiveAdPlaybackState =
|
||||
new AdPlaybackState("adsId")
|
||||
.withLivePostrollPlaceholderAppended(/* isServerSideInserted= */ false)
|
||||
.withNewAdGroup(/* adGroupIndex= */ 0, /* adGroupTimeUs= */ 0L)
|
||||
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, 1_000L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 1_000L)
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
MediaItem.fromUri("https://example.com/ad0-0"));
|
||||
setAdPlaybackState(initialLiveAdPlaybackState);
|
||||
|
||||
assertThrows(
|
||||
IllegalStateException.class,
|
||||
() ->
|
||||
setAdPlaybackState(
|
||||
new AdPlaybackState("adsId")
|
||||
.withLivePostrollPlaceholderAppended(/* isServerSideInserted= */ false)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAdPlaybackState_timeUsOfAdGroupChanged_throwsIllegalStateException() {
|
||||
AdPlaybackState initialLiveAdPlaybackState =
|
||||
new AdPlaybackState("adsId")
|
||||
.withLivePostrollPlaceholderAppended(/* isServerSideInserted= */ false)
|
||||
.withNewAdGroup(/* adGroupIndex= */ 0, /* adGroupTimeUs= */ 0L)
|
||||
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, 1_000L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 1_000L)
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
MediaItem.fromUri("https://example.com/ad0-0"));
|
||||
setAdPlaybackState(initialLiveAdPlaybackState);
|
||||
|
||||
assertThrows(
|
||||
IllegalStateException.class,
|
||||
() ->
|
||||
setAdPlaybackState(
|
||||
initialLiveAdPlaybackState.withAdGroupTimeUs(
|
||||
/* adGroupIndex= */ 0, /* adGroupTimeUs= */ 1234L)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAdPlaybackState_mediaItemOfAdChanged_throwsIllegalStateException() {
|
||||
AdPlaybackState initialLiveAdPlaybackState =
|
||||
new AdPlaybackState("adsId")
|
||||
.withLivePostrollPlaceholderAppended(/* isServerSideInserted= */ false)
|
||||
.withNewAdGroup(/* adGroupIndex= */ 0, /* adGroupTimeUs= */ 0L)
|
||||
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, 1_000L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 1_000L)
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
MediaItem.fromUri("https://example.com/ad0-0"));
|
||||
setAdPlaybackState(initialLiveAdPlaybackState);
|
||||
|
||||
assertThrows(
|
||||
IllegalStateException.class,
|
||||
() ->
|
||||
setAdPlaybackState(
|
||||
initialLiveAdPlaybackState.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
MediaItem.fromUri("https://example.com/ad0-1"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAdPlaybackState_postRollAdded_throwsIllegalStateException() {
|
||||
AdPlaybackState withoutLivePostRollPlaceholder =
|
||||
new AdPlaybackState("adsId")
|
||||
.withNewAdGroup(/* adGroupIndex= */ 0, /* adGroupTimeUs= */ 0L)
|
||||
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, 1_000L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 1_000L)
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
MediaItem.fromUri("https://example.com/ad0-0"));
|
||||
|
||||
setAdPlaybackState(withoutLivePostRollPlaceholder);
|
||||
|
||||
assertThrows(
|
||||
IllegalStateException.class,
|
||||
() ->
|
||||
setAdPlaybackState(
|
||||
withoutLivePostRollPlaceholder.withLivePostrollPlaceholderAppended(
|
||||
/* isServerSideInserted= */ false)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAdPlaybackState_postRollRemoved_throwsIllegalStateException() {
|
||||
AdPlaybackState withoutLivePostRollPlaceholder =
|
||||
new AdPlaybackState("adsId")
|
||||
.withNewAdGroup(/* adGroupIndex= */ 0, /* adGroupTimeUs= */ 0L)
|
||||
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, 1_000L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 1_000L)
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
MediaItem.fromUri("https://example.com/ad0-0"));
|
||||
setAdPlaybackState(
|
||||
withoutLivePostRollPlaceholder.withLivePostrollPlaceholderAppended(
|
||||
/* isServerSideInserted= */ false));
|
||||
|
||||
assertThrows(
|
||||
IllegalStateException.class, () -> setAdPlaybackState(withoutLivePostRollPlaceholder));
|
||||
}
|
||||
|
||||
private static class NoOpAdsLoader implements AdsLoader {
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user