Use full MediaItem to define ad playbacks

Currently, ads are only defined by a single URL, which makes it
impossible to define additional fields needed to play ads correctly.

This can be fixed by using a full MediaItem in AdPlaybackState,
replacing the previous Uri field.

PiperOrigin-RevId: 582331588
This commit is contained in:
tonihei 2023-11-14 08:32:48 -08:00 committed by Copybara-Service
parent 8f69bb0d9d
commit 03a23bef8f
10 changed files with 272 additions and 121 deletions

View File

@ -9,6 +9,8 @@
correctly implemented until now. correctly implemented until now.
* Normalize MIME types set by app code or read from media to be fully * Normalize MIME types set by app code or read from media to be fully
lower-case. lower-case.
* Define ads with a full `MediaItem` instead of a single `Uri` in
`AdPlaybackState`.
* ExoPlayer: * ExoPlayer:
* Add `PreloadMediaSource` and `PreloadMediaPeriod` that allows apps to * Add `PreloadMediaSource` and `PreloadMediaPeriod` that allows apps to
preload the media source at a specific start position before playback, preload the media source at a specific start position before playback,

View File

@ -16,6 +16,7 @@
package androidx.media3.common; package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static java.lang.Math.max; import static java.lang.Math.max;
import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.FIELD;
@ -30,6 +31,7 @@ import androidx.annotation.CheckResult;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.IntRange; import androidx.annotation.IntRange;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.media3.common.util.NullableType; import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
@ -74,8 +76,13 @@ public final class AdPlaybackState implements Bundleable {
*/ */
public final int originalCount; public final int originalCount;
/** The URI of each ad in the ad group. */ /**
public final @NullableType Uri[] uris; * @deprecated Use {@link #mediaItems} instead.
*/
@Deprecated public final @NullableType Uri[] uris;
/** The {@link MediaItem} instances for each ad in the ad group, or null if not yet known. */
public final @NullableType MediaItem[] mediaItems;
/** The state of each ad in the ad group. */ /** The state of each ad in the ad group. */
public final @AdState int[] states; public final @AdState int[] states;
@ -104,7 +111,7 @@ public final class AdPlaybackState implements Bundleable {
/* count= */ C.LENGTH_UNSET, /* count= */ C.LENGTH_UNSET,
/* originalCount= */ C.LENGTH_UNSET, /* originalCount= */ C.LENGTH_UNSET,
/* states= */ new int[0], /* states= */ new int[0],
/* uris= */ new Uri[0], /* mediaItems= */ new MediaItem[0],
/* durationsUs= */ new long[0], /* durationsUs= */ new long[0],
/* contentResumeOffsetUs= */ 0, /* contentResumeOffsetUs= */ 0,
/* isServerSideInserted= */ false); /* isServerSideInserted= */ false);
@ -115,19 +122,23 @@ public final class AdPlaybackState implements Bundleable {
int count, int count,
int originalCount, int originalCount,
@AdState int[] states, @AdState int[] states,
@NullableType Uri[] uris, @NullableType MediaItem[] mediaItems,
long[] durationsUs, long[] durationsUs,
long contentResumeOffsetUs, long contentResumeOffsetUs,
boolean isServerSideInserted) { boolean isServerSideInserted) {
checkArgument(states.length == uris.length); checkArgument(states.length == mediaItems.length);
this.timeUs = timeUs; this.timeUs = timeUs;
this.count = count; this.count = count;
this.originalCount = originalCount; this.originalCount = originalCount;
this.states = states; this.states = states;
this.uris = uris; this.mediaItems = mediaItems;
this.durationsUs = durationsUs; this.durationsUs = durationsUs;
this.contentResumeOffsetUs = contentResumeOffsetUs; this.contentResumeOffsetUs = contentResumeOffsetUs;
this.isServerSideInserted = isServerSideInserted; this.isServerSideInserted = isServerSideInserted;
this.uris = new Uri[mediaItems.length];
for (int i = 0; i < uris.length; i++) {
uris[i] = mediaItems[i] == null ? null : checkNotNull(mediaItems[i].localConfiguration).uri;
}
} }
/** /**
@ -195,7 +206,7 @@ public final class AdPlaybackState implements Bundleable {
return timeUs == adGroup.timeUs return timeUs == adGroup.timeUs
&& count == adGroup.count && count == adGroup.count
&& originalCount == adGroup.originalCount && originalCount == adGroup.originalCount
&& Arrays.equals(uris, adGroup.uris) && Arrays.equals(mediaItems, adGroup.mediaItems)
&& Arrays.equals(states, adGroup.states) && Arrays.equals(states, adGroup.states)
&& Arrays.equals(durationsUs, adGroup.durationsUs) && Arrays.equals(durationsUs, adGroup.durationsUs)
&& contentResumeOffsetUs == adGroup.contentResumeOffsetUs && contentResumeOffsetUs == adGroup.contentResumeOffsetUs
@ -207,7 +218,7 @@ public final class AdPlaybackState implements Bundleable {
int result = count; int result = count;
result = 31 * result + originalCount; result = 31 * result + originalCount;
result = 31 * result + (int) (timeUs ^ (timeUs >>> 32)); result = 31 * result + (int) (timeUs ^ (timeUs >>> 32));
result = 31 * result + Arrays.hashCode(uris); result = 31 * result + Arrays.hashCode(mediaItems);
result = 31 * result + Arrays.hashCode(states); result = 31 * result + Arrays.hashCode(states);
result = 31 * result + Arrays.hashCode(durationsUs); result = 31 * result + Arrays.hashCode(durationsUs);
result = 31 * result + (int) (contentResumeOffsetUs ^ (contentResumeOffsetUs >>> 32)); result = 31 * result + (int) (contentResumeOffsetUs ^ (contentResumeOffsetUs >>> 32));
@ -223,7 +234,7 @@ public final class AdPlaybackState implements Bundleable {
count, count,
originalCount, originalCount,
states, states,
uris, mediaItems,
durationsUs, durationsUs,
contentResumeOffsetUs, contentResumeOffsetUs,
isServerSideInserted); isServerSideInserted);
@ -234,38 +245,47 @@ public final class AdPlaybackState implements Bundleable {
public AdGroup withAdCount(int count) { public AdGroup withAdCount(int count) {
@AdState int[] states = copyStatesWithSpaceForAdCount(this.states, count); @AdState int[] states = copyStatesWithSpaceForAdCount(this.states, count);
long[] durationsUs = copyDurationsUsWithSpaceForAdCount(this.durationsUs, count); long[] durationsUs = copyDurationsUsWithSpaceForAdCount(this.durationsUs, count);
@NullableType Uri[] uris = Arrays.copyOf(this.uris, count); @NullableType MediaItem[] mediaItems = Arrays.copyOf(this.mediaItems, count);
return new AdGroup( return new AdGroup(
timeUs, timeUs,
count, count,
originalCount, originalCount,
states, states,
uris, mediaItems,
durationsUs, durationsUs,
contentResumeOffsetUs, contentResumeOffsetUs,
isServerSideInserted); isServerSideInserted);
} }
/** /**
* Returns a new instance with the specified {@code uri} set for the specified ad, and the ad * @deprecated Use {@link #withAdMediaItem} instead.
* marked as {@link #AD_STATE_AVAILABLE}.
*/ */
@Deprecated
@CheckResult @CheckResult
public AdGroup withAdUri(Uri uri, @IntRange(from = 0) int index) { public AdGroup withAdUri(Uri uri, @IntRange(from = 0) int index) {
return withAdMediaItem(MediaItem.fromUri(uri), index);
}
/**
* Returns a new instance with the specified {@link MediaItem} set for the specified ad, and the
* ad marked as {@link #AD_STATE_AVAILABLE}.
*/
@CheckResult
public AdGroup withAdMediaItem(MediaItem mediaItem, @IntRange(from = 0) int index) {
@AdState int[] states = copyStatesWithSpaceForAdCount(this.states, index + 1); @AdState int[] states = copyStatesWithSpaceForAdCount(this.states, index + 1);
long[] durationsUs = long[] durationsUs =
this.durationsUs.length == states.length this.durationsUs.length == states.length
? this.durationsUs ? this.durationsUs
: copyDurationsUsWithSpaceForAdCount(this.durationsUs, states.length); : copyDurationsUsWithSpaceForAdCount(this.durationsUs, states.length);
@NullableType Uri[] uris = Arrays.copyOf(this.uris, states.length); @NullableType MediaItem[] mediaItems = Arrays.copyOf(this.mediaItems, states.length);
uris[index] = uri; mediaItems[index] = mediaItem;
states[index] = AD_STATE_AVAILABLE; states[index] = AD_STATE_AVAILABLE;
return new AdGroup( return new AdGroup(
timeUs, timeUs,
count, count,
originalCount, originalCount,
states, states,
uris, mediaItems,
durationsUs, durationsUs,
contentResumeOffsetUs, contentResumeOffsetUs,
isServerSideInserted); isServerSideInserted);
@ -292,15 +312,17 @@ public final class AdPlaybackState implements Bundleable {
? this.durationsUs ? this.durationsUs
: copyDurationsUsWithSpaceForAdCount(this.durationsUs, states.length); : copyDurationsUsWithSpaceForAdCount(this.durationsUs, states.length);
@NullableType @NullableType
Uri[] uris = MediaItem[] mediaItems =
this.uris.length == states.length ? this.uris : Arrays.copyOf(this.uris, states.length); this.mediaItems.length == states.length
? this.mediaItems
: Arrays.copyOf(this.mediaItems, states.length);
states[index] = state; states[index] = state;
return new AdGroup( return new AdGroup(
timeUs, timeUs,
count, count,
originalCount, originalCount,
states, states,
uris, mediaItems,
durationsUs, durationsUs,
contentResumeOffsetUs, contentResumeOffsetUs,
isServerSideInserted); isServerSideInserted);
@ -309,17 +331,17 @@ public final class AdPlaybackState implements Bundleable {
/** Returns a new instance with the specified ad durations, in microseconds. */ /** Returns a new instance with the specified ad durations, in microseconds. */
@CheckResult @CheckResult
public AdGroup withAdDurationsUs(long[] durationsUs) { public AdGroup withAdDurationsUs(long[] durationsUs) {
if (durationsUs.length < uris.length) { if (durationsUs.length < mediaItems.length) {
durationsUs = copyDurationsUsWithSpaceForAdCount(durationsUs, uris.length); durationsUs = copyDurationsUsWithSpaceForAdCount(durationsUs, mediaItems.length);
} else if (count != C.LENGTH_UNSET && durationsUs.length > uris.length) { } else if (count != C.LENGTH_UNSET && durationsUs.length > mediaItems.length) {
durationsUs = Arrays.copyOf(durationsUs, uris.length); durationsUs = Arrays.copyOf(durationsUs, mediaItems.length);
} }
return new AdGroup( return new AdGroup(
timeUs, timeUs,
count, count,
originalCount, originalCount,
states, states,
uris, mediaItems,
durationsUs, durationsUs,
contentResumeOffsetUs, contentResumeOffsetUs,
isServerSideInserted); isServerSideInserted);
@ -333,7 +355,7 @@ public final class AdPlaybackState implements Bundleable {
count, count,
originalCount, originalCount,
states, states,
uris, mediaItems,
durationsUs, durationsUs,
contentResumeOffsetUs, contentResumeOffsetUs,
isServerSideInserted); isServerSideInserted);
@ -347,7 +369,7 @@ public final class AdPlaybackState implements Bundleable {
count, count,
originalCount, originalCount,
states, states,
uris, mediaItems,
durationsUs, durationsUs,
contentResumeOffsetUs, contentResumeOffsetUs,
isServerSideInserted); isServerSideInserted);
@ -360,7 +382,7 @@ public final class AdPlaybackState implements Bundleable {
count, count,
originalCount, originalCount,
states, states,
uris, mediaItems,
durationsUs, durationsUs,
contentResumeOffsetUs, contentResumeOffsetUs,
isServerSideInserted); isServerSideInserted);
@ -370,7 +392,7 @@ public final class AdPlaybackState implements Bundleable {
public AdGroup withLastAdRemoved() { public AdGroup withLastAdRemoved() {
int newCount = states.length - 1; int newCount = states.length - 1;
@AdState int[] newStates = Arrays.copyOf(states, newCount); @AdState int[] newStates = Arrays.copyOf(states, newCount);
@NullableType Uri[] newUris = Arrays.copyOf(uris, newCount); @NullableType MediaItem[] newMediaItems = Arrays.copyOf(mediaItems, newCount);
long[] newDurationsUs = durationsUs; long[] newDurationsUs = durationsUs;
if (durationsUs.length > newCount) { if (durationsUs.length > newCount) {
newDurationsUs = Arrays.copyOf(durationsUs, newCount); newDurationsUs = Arrays.copyOf(durationsUs, newCount);
@ -380,7 +402,7 @@ public final class AdPlaybackState implements Bundleable {
newCount, newCount,
originalCount, originalCount,
newStates, newStates,
newUris, newMediaItems,
newDurationsUs, newDurationsUs,
/* contentResumeOffsetUs= */ Util.sum(newDurationsUs), /* contentResumeOffsetUs= */ Util.sum(newDurationsUs),
isServerSideInserted); isServerSideInserted);
@ -398,7 +420,7 @@ public final class AdPlaybackState implements Bundleable {
/* count= */ 0, /* count= */ 0,
originalCount, originalCount,
/* states= */ new int[0], /* states= */ new int[0],
/* uris= */ new Uri[0], /* mediaItems= */ new MediaItem[0],
/* durationsUs= */ new long[0], /* durationsUs= */ new long[0],
contentResumeOffsetUs, contentResumeOffsetUs,
isServerSideInserted); isServerSideInserted);
@ -415,7 +437,7 @@ public final class AdPlaybackState implements Bundleable {
count, count,
originalCount, originalCount,
states, states,
uris, mediaItems,
durationsUs, durationsUs,
contentResumeOffsetUs, contentResumeOffsetUs,
isServerSideInserted); isServerSideInserted);
@ -436,7 +458,7 @@ public final class AdPlaybackState implements Bundleable {
if (states[i] == AD_STATE_PLAYED if (states[i] == AD_STATE_PLAYED
|| states[i] == AD_STATE_SKIPPED || states[i] == AD_STATE_SKIPPED
|| states[i] == AD_STATE_ERROR) { || states[i] == AD_STATE_ERROR) {
states[i] = uris[i] == null ? AD_STATE_UNAVAILABLE : AD_STATE_AVAILABLE; states[i] = mediaItems[i] == null ? AD_STATE_UNAVAILABLE : AD_STATE_AVAILABLE;
} }
} }
return new AdGroup( return new AdGroup(
@ -444,7 +466,7 @@ public final class AdPlaybackState implements Bundleable {
count, count,
originalCount, originalCount,
states, states,
uris, mediaItems,
durationsUs, durationsUs,
contentResumeOffsetUs, contentResumeOffsetUs,
isServerSideInserted); isServerSideInserted);
@ -478,6 +500,7 @@ public final class AdPlaybackState implements Bundleable {
private static final String FIELD_CONTENT_RESUME_OFFSET_US = Util.intToStringMaxRadix(5); private static final String FIELD_CONTENT_RESUME_OFFSET_US = Util.intToStringMaxRadix(5);
private static final String FIELD_IS_SERVER_SIDE_INSERTED = Util.intToStringMaxRadix(6); private static final String FIELD_IS_SERVER_SIDE_INSERTED = Util.intToStringMaxRadix(6);
private static final String FIELD_ORIGINAL_COUNT = Util.intToStringMaxRadix(7); private static final String FIELD_ORIGINAL_COUNT = Util.intToStringMaxRadix(7);
@VisibleForTesting static final String FIELD_MEDIA_ITEMS = Util.intToStringMaxRadix(8);
// putParcelableArrayList actually supports null elements. // putParcelableArrayList actually supports null elements.
@SuppressWarnings("nullness:argument") @SuppressWarnings("nullness:argument")
@ -489,6 +512,7 @@ public final class AdPlaybackState implements Bundleable {
bundle.putInt(FIELD_ORIGINAL_COUNT, originalCount); bundle.putInt(FIELD_ORIGINAL_COUNT, originalCount);
bundle.putParcelableArrayList( bundle.putParcelableArrayList(
FIELD_URIS, new ArrayList<@NullableType Uri>(Arrays.asList(uris))); FIELD_URIS, new ArrayList<@NullableType Uri>(Arrays.asList(uris)));
bundle.putParcelableArrayList(FIELD_MEDIA_ITEMS, getMediaItemsArrayBundles());
bundle.putIntArray(FIELD_STATES, states); bundle.putIntArray(FIELD_STATES, states);
bundle.putLongArray(FIELD_DURATIONS_US, durationsUs); bundle.putLongArray(FIELD_DURATIONS_US, durationsUs);
bundle.putLong(FIELD_CONTENT_RESUME_OFFSET_US, contentResumeOffsetUs); bundle.putLong(FIELD_CONTENT_RESUME_OFFSET_US, contentResumeOffsetUs);
@ -514,6 +538,9 @@ public final class AdPlaybackState implements Bundleable {
int originalCount = bundle.getInt(FIELD_ORIGINAL_COUNT); int originalCount = bundle.getInt(FIELD_ORIGINAL_COUNT);
@Nullable ArrayList<@NullableType Uri> uriList = bundle.getParcelableArrayList(FIELD_URIS); @Nullable ArrayList<@NullableType Uri> uriList = bundle.getParcelableArrayList(FIELD_URIS);
@Nullable @Nullable
ArrayList<@NullableType Bundle> mediaItemBundleList =
bundle.getParcelableArrayList(FIELD_MEDIA_ITEMS);
@Nullable
@AdState @AdState
int[] states = bundle.getIntArray(FIELD_STATES); int[] states = bundle.getIntArray(FIELD_STATES);
@Nullable long[] durationsUs = bundle.getLongArray(FIELD_DURATIONS_US); @Nullable long[] durationsUs = bundle.getLongArray(FIELD_DURATIONS_US);
@ -524,11 +551,41 @@ public final class AdPlaybackState implements Bundleable {
count, count,
originalCount, originalCount,
states == null ? new int[0] : states, states == null ? new int[0] : states,
uriList == null ? new Uri[0] : uriList.toArray(new Uri[0]), getMediaItemsFromBundleArrays(mediaItemBundleList, uriList),
durationsUs == null ? new long[0] : durationsUs, durationsUs == null ? new long[0] : durationsUs,
contentResumeOffsetUs, contentResumeOffsetUs,
isServerSideInserted); isServerSideInserted);
} }
private ArrayList<@NullableType Bundle> getMediaItemsArrayBundles() {
ArrayList<@NullableType Bundle> bundles = new ArrayList<>();
for (@Nullable MediaItem mediaItem : mediaItems) {
bundles.add(mediaItem == null ? null : mediaItem.toBundleIncludeLocalConfiguration());
}
return bundles;
}
private static @NullableType MediaItem[] getMediaItemsFromBundleArrays(
@Nullable ArrayList<@NullableType Bundle> mediaItemBundleList,
@Nullable ArrayList<@NullableType Uri> uriList) {
if (mediaItemBundleList != null) {
@NullableType MediaItem[] mediaItems = new MediaItem[mediaItemBundleList.size()];
for (int i = 0; i < mediaItemBundleList.size(); i++) {
@Nullable Bundle mediaItemBundle = mediaItemBundleList.get(i);
mediaItems[i] = mediaItemBundle == null ? null : MediaItem.fromBundle(mediaItemBundle);
}
return mediaItems;
} else if (uriList != null) {
@NullableType MediaItem[] mediaItems = new MediaItem[uriList.size()];
for (int i = 0; i < uriList.size(); i++) {
@Nullable Uri uri = uriList.get(i);
mediaItems[i] = uri == null ? null : MediaItem.fromUri(uri);
}
return mediaItems;
} else {
return new MediaItem[0];
}
}
} }
/** /**
@ -764,19 +821,35 @@ public final class AdPlaybackState implements Bundleable {
} }
/** /**
* Returns an instance with the specified ad URI and the ad marked as {@linkplain * @deprecated Use {@link #withAvailableAdMediaItem} instead.
* #AD_STATE_AVAILABLE available}.
*
* @throws IllegalStateException If {@link Uri#EMPTY} is passed as argument for a client-side
* inserted ad group.
*/ */
@Deprecated
@CheckResult @CheckResult
public AdPlaybackState withAvailableAdUri( public AdPlaybackState withAvailableAdUri(
@IntRange(from = 0) int adGroupIndex, @IntRange(from = 0) int adIndexInAdGroup, Uri uri) { @IntRange(from = 0) int adGroupIndex, @IntRange(from = 0) int adIndexInAdGroup, Uri uri) {
return withAvailableAdMediaItem(adGroupIndex, adIndexInAdGroup, MediaItem.fromUri(uri));
}
/**
* Returns an instance with the specified ad {@link MediaItem} and the ad marked as {@linkplain
* #AD_STATE_AVAILABLE available}.
*
* @throws IllegalStateException If a {@link MediaItem} with an empty {@link
* MediaItem.LocalConfiguration#uri} is passed as argument for a client-side inserted ad
* group.
*/
@CheckResult
public AdPlaybackState withAvailableAdMediaItem(
@IntRange(from = 0) int adGroupIndex,
@IntRange(from = 0) int adIndexInAdGroup,
MediaItem mediaItem) {
int adjustedIndex = adGroupIndex - removedAdGroupCount; int adjustedIndex = adGroupIndex - removedAdGroupCount;
AdGroup[] adGroups = Util.nullSafeArrayCopy(this.adGroups, this.adGroups.length); AdGroup[] adGroups = Util.nullSafeArrayCopy(this.adGroups, this.adGroups.length);
checkState(!Uri.EMPTY.equals(uri) || adGroups[adjustedIndex].isServerSideInserted); checkState(
adGroups[adjustedIndex] = adGroups[adjustedIndex].withAdUri(uri, adIndexInAdGroup); adGroups[adjustedIndex].isServerSideInserted
|| (mediaItem.localConfiguration != null
&& !mediaItem.localConfiguration.uri.equals(Uri.EMPTY)));
adGroups[adjustedIndex] = adGroups[adjustedIndex].withAdMediaItem(mediaItem, adIndexInAdGroup);
return new AdPlaybackState( return new AdPlaybackState(
adsId, adGroups, adResumePositionUs, contentDurationUs, removedAdGroupCount); adsId, adGroups, adResumePositionUs, contentDurationUs, removedAdGroupCount);
} }
@ -785,7 +858,7 @@ public final class AdPlaybackState implements Bundleable {
* Returns an instance with the specified ad marked as {@linkplain #AD_STATE_AVAILABLE available}. * Returns an instance with the specified ad marked as {@linkplain #AD_STATE_AVAILABLE available}.
* *
* <p>Must not be called with client side inserted ad groups. Client side inserted ads should use * <p>Must not be called with client side inserted ad groups. Client side inserted ads should use
* {@link #withAvailableAdUri}. * {@link #withAvailableAdMediaItem}.
* *
* @throws IllegalStateException in case this methods is called on an ad group that {@linkplain * @throws IllegalStateException in case this methods is called on an ad group that {@linkplain
* AdGroup#isServerSideInserted is not server side inserted}. * AdGroup#isServerSideInserted is not server side inserted}.
@ -793,7 +866,7 @@ public final class AdPlaybackState implements Bundleable {
@CheckResult @CheckResult
public AdPlaybackState withAvailableAd( public AdPlaybackState withAvailableAd(
@IntRange(from = 0) int adGroupIndex, @IntRange(from = 0) int adIndexInAdGroup) { @IntRange(from = 0) int adGroupIndex, @IntRange(from = 0) int adIndexInAdGroup) {
return withAvailableAdUri(adGroupIndex, adIndexInAdGroup, Uri.EMPTY); return withAvailableAdMediaItem(adGroupIndex, adIndexInAdGroup, MediaItem.fromUri(Uri.EMPTY));
} }
/** Returns an instance with the specified ad marked as {@linkplain #AD_STATE_PLAYED played}. */ /** Returns an instance with the specified ad marked as {@linkplain #AD_STATE_PLAYED played}. */
@ -1058,7 +1131,7 @@ public final class AdPlaybackState implements Bundleable {
adGroup.count, adGroup.count,
adGroup.originalCount, adGroup.originalCount,
Arrays.copyOf(adGroup.states, adGroup.states.length), Arrays.copyOf(adGroup.states, adGroup.states.length),
Arrays.copyOf(adGroup.uris, adGroup.uris.length), Arrays.copyOf(adGroup.mediaItems, adGroup.mediaItems.length),
Arrays.copyOf(adGroup.durationsUs, adGroup.durationsUs.length), Arrays.copyOf(adGroup.durationsUs, adGroup.durationsUs.length),
adGroup.contentResumeOffsetUs, adGroup.contentResumeOffsetUs,
adGroup.isServerSideInserted); adGroup.isServerSideInserted);

View File

@ -35,7 +35,7 @@ import org.junit.runner.RunWith;
public class AdPlaybackStateTest { public class AdPlaybackStateTest {
private static final long[] TEST_AD_GROUP_TIMES_US = new long[] {0, 5_000_000, 10_000_000}; private static final long[] TEST_AD_GROUP_TIMES_US = new long[] {0, 5_000_000, 10_000_000};
private static final Uri TEST_URI = Uri.parse("http://www.google.com"); private static final MediaItem TEST_MEDIA_ITEM = MediaItem.fromUri("http://www.google.com");
private static final Object TEST_ADS_ID = new Object(); private static final Object TEST_ADS_ID = new Object();
@Test @Test
@ -50,16 +50,18 @@ public class AdPlaybackStateTest {
} }
@Test @Test
public void setAdUriBeforeAdCount() { public void setAdMediaItemBeforeAdCount() {
AdPlaybackState state = AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1); new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_URI); state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_MEDIA_ITEM);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 2); state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 2);
assertThat(state.getAdGroup(1).uris[0]).isNull(); assertThat(state.getAdGroup(1).mediaItems[0]).isNull();
assertThat(state.getAdGroup(1).states[0]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE); assertThat(state.getAdGroup(1).states[0]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE);
assertThat(state.getAdGroup(1).uris[1]).isSameInstanceAs(TEST_URI); assertThat(state.getAdGroup(1).mediaItems[1]).isSameInstanceAs(TEST_MEDIA_ITEM);
assertThat(state.getAdGroup(1).states[1]).isEqualTo(AdPlaybackState.AD_STATE_AVAILABLE); assertThat(state.getAdGroup(1).states[1]).isEqualTo(AdPlaybackState.AD_STATE_AVAILABLE);
} }
@ -71,7 +73,7 @@ public class AdPlaybackStateTest {
state = state.withAdLoadError(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0); state = state.withAdLoadError(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 2); state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 2);
assertThat(state.getAdGroup(1).uris[0]).isNull(); assertThat(state.getAdGroup(1).mediaItems[0]).isNull();
assertThat(state.getAdGroup(1).states[0]).isEqualTo(AdPlaybackState.AD_STATE_ERROR); assertThat(state.getAdGroup(1).states[0]).isEqualTo(AdPlaybackState.AD_STATE_ERROR);
assertThat(state.isAdInErrorState(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0)).isTrue(); assertThat(state.isAdInErrorState(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0)).isTrue();
assertThat(state.getAdGroup(1).states[1]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE); assertThat(state.getAdGroup(1).states[1]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE);
@ -101,7 +103,8 @@ public class AdPlaybackStateTest {
.withRemovedAdGroupCount(1) .withRemovedAdGroupCount(1)
.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 2) .withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 2)
.withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 1) .withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 1)
.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_URI) .withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_MEDIA_ITEM)
.withSkippedAd(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 0); .withSkippedAd(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 0);
state = state =
@ -113,7 +116,7 @@ public class AdPlaybackStateTest {
assertThat(state.adGroupCount).isEqualTo(6); assertThat(state.adGroupCount).isEqualTo(6);
assertThat(state.getAdGroup(1).count).isEqualTo(C.INDEX_UNSET); assertThat(state.getAdGroup(1).count).isEqualTo(C.INDEX_UNSET);
assertThat(state.getAdGroup(2).count).isEqualTo(2); assertThat(state.getAdGroup(2).count).isEqualTo(2);
assertThat(state.getAdGroup(2).uris[1]).isSameInstanceAs(TEST_URI); assertThat(state.getAdGroup(2).mediaItems[1]).isSameInstanceAs(TEST_MEDIA_ITEM);
assertThat(state.getAdGroup(3).count).isEqualTo(C.INDEX_UNSET); assertThat(state.getAdGroup(3).count).isEqualTo(C.INDEX_UNSET);
assertThat(state.getAdGroup(4).count).isEqualTo(1); assertThat(state.getAdGroup(4).count).isEqualTo(1);
assertThat(state.getAdGroup(4).states[0]).isEqualTo(AdPlaybackState.AD_STATE_SKIPPED); assertThat(state.getAdGroup(4).states[0]).isEqualTo(AdPlaybackState.AD_STATE_SKIPPED);
@ -141,8 +144,12 @@ public class AdPlaybackStateTest {
AdPlaybackState state = AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1); new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3); state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI); state =
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI); state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_MEDIA_ITEM);
state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_MEDIA_ITEM);
assertThat(state.getAdGroup(1).getFirstAdIndexToPlay()).isEqualTo(0); assertThat(state.getAdGroup(1).getFirstAdIndexToPlay()).isEqualTo(0);
} }
@ -152,8 +159,12 @@ public class AdPlaybackStateTest {
AdPlaybackState state = AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1); new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3); state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI); state =
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI); state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_MEDIA_ITEM);
state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_MEDIA_ITEM);
state = state.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0); state = state.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0);
@ -167,8 +178,12 @@ public class AdPlaybackStateTest {
AdPlaybackState state = AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1); new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3); state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI); state =
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI); state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_MEDIA_ITEM);
state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_MEDIA_ITEM);
state = state.withSkippedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0); state = state.withSkippedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0);
@ -182,8 +197,12 @@ public class AdPlaybackStateTest {
AdPlaybackState state = AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1); new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3); state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI); state =
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI); state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_MEDIA_ITEM);
state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_MEDIA_ITEM);
state = state.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0); state = state.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0);
state = state.withAdLoadError(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1); state = state.withAdLoadError(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1);
@ -196,7 +215,9 @@ public class AdPlaybackStateTest {
AdPlaybackState state = AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1); new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3); state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_URI); state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_MEDIA_ITEM);
state = state.withAdLoadError(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1); state = state.withAdLoadError(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1);
@ -209,9 +230,15 @@ public class AdPlaybackStateTest {
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1); new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withIsServerSideInserted(/* adGroupIndex= */ 1, /* isServerSideInserted= */ true); state = state.withIsServerSideInserted(/* adGroupIndex= */ 1, /* isServerSideInserted= */ true);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3); state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI); state =
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_URI); state.withAvailableAdMediaItem(
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI); /* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_MEDIA_ITEM);
state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_MEDIA_ITEM);
state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_MEDIA_ITEM);
state = state.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0); state = state.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0);
@ -224,9 +251,15 @@ public class AdPlaybackStateTest {
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1); new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withIsServerSideInserted(/* adGroupIndex= */ 1, /* isServerSideInserted= */ true); state = state.withIsServerSideInserted(/* adGroupIndex= */ 1, /* isServerSideInserted= */ true);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3); state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI); state =
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_URI); state.withAvailableAdMediaItem(
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI); /* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_MEDIA_ITEM);
state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_MEDIA_ITEM);
state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_MEDIA_ITEM);
state = state.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0); state = state.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0);
state = state.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1); state = state.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1);
@ -265,9 +298,9 @@ public class AdPlaybackStateTest {
.asList() .asList()
.containsExactly(AD_STATE_UNAVAILABLE, AD_STATE_UNAVAILABLE, AD_STATE_AVAILABLE) .containsExactly(AD_STATE_UNAVAILABLE, AD_STATE_UNAVAILABLE, AD_STATE_AVAILABLE)
.inOrder(); .inOrder();
assertThat(state.getAdGroup(adGroupIndex).uris) assertThat(state.getAdGroup(adGroupIndex).mediaItems)
.asList() .asList()
.containsExactly(null, null, Uri.EMPTY) .containsExactly(null, null, MediaItem.fromUri(Uri.EMPTY))
.inOrder(); .inOrder();
state = state =
@ -364,10 +397,18 @@ public class AdPlaybackStateTest {
state = state =
state.withAdDurationsUs( state.withAdDurationsUs(
/* adGroupIndex= */ 1, /* adDurationsUs...= */ 1_000L, 2_000L, 3_000L, 4_000L, 5_000L); /* adGroupIndex= */ 1, /* adDurationsUs...= */ 1_000L, 2_000L, 3_000L, 4_000L, 5_000L);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_URI); state =
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI); state.withAvailableAdMediaItem(
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 3, TEST_URI); /* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_MEDIA_ITEM);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 4, TEST_URI); state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_MEDIA_ITEM);
state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 3, TEST_MEDIA_ITEM);
state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 4, TEST_MEDIA_ITEM);
state = state.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2); state = state.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2);
state = state.withSkippedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 3); state = state.withSkippedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 3);
state = state.withAdLoadError(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 4); state = state.withAdLoadError(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 4);
@ -393,9 +434,9 @@ public class AdPlaybackStateTest {
AD_STATE_AVAILABLE, AD_STATE_AVAILABLE,
AD_STATE_AVAILABLE) AD_STATE_AVAILABLE)
.inOrder(); .inOrder();
assertThat(state.getAdGroup(/* adGroupIndex= */ 1).uris) assertThat(state.getAdGroup(/* adGroupIndex= */ 1).mediaItems)
.asList() .asList()
.containsExactly(null, TEST_URI, TEST_URI, TEST_URI, TEST_URI) .containsExactly(null, TEST_MEDIA_ITEM, TEST_MEDIA_ITEM, TEST_MEDIA_ITEM, TEST_MEDIA_ITEM)
.inOrder(); .inOrder();
assertThat(state.getAdGroup(/* adGroupIndex= */ 1).durationsUs) assertThat(state.getAdGroup(/* adGroupIndex= */ 1).durationsUs)
.asList() .asList()
@ -445,12 +486,15 @@ public class AdPlaybackStateTest {
.withRemovedAdGroupCount(1) .withRemovedAdGroupCount(1)
.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 1) .withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 1)
.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0) .withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0)
.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI) .withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_MEDIA_ITEM)
.withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 2) .withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 2)
.withSkippedAd(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 0) .withSkippedAd(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 0)
.withPlayedAd(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 1) .withPlayedAd(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 1)
.withAvailableAdUri(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 0, TEST_URI) .withAvailableAdMediaItem(
.withAvailableAdUri(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 1, TEST_URI) /* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 0, TEST_MEDIA_ITEM)
.withAvailableAdMediaItem(
/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 1, TEST_MEDIA_ITEM)
.withContentResumeOffsetUs(/* adGroupIndex= */ 1, /* contentResumeOffsetUs= */ 4444) .withContentResumeOffsetUs(/* adGroupIndex= */ 1, /* contentResumeOffsetUs= */ 4444)
.withContentResumeOffsetUs(/* adGroupIndex= */ 2, /* contentResumeOffsetUs= */ 3333) .withContentResumeOffsetUs(/* adGroupIndex= */ 2, /* contentResumeOffsetUs= */ 3333)
.withIsServerSideInserted(/* adGroupIndex= */ 1, /* isServerSideInserted= */ true) .withIsServerSideInserted(/* adGroupIndex= */ 1, /* isServerSideInserted= */ true)
@ -478,8 +522,10 @@ public class AdPlaybackStateTest {
.withAdCount(2) .withAdCount(2)
.withAdState(AD_STATE_AVAILABLE, /* index= */ 0) .withAdState(AD_STATE_AVAILABLE, /* index= */ 0)
.withAdState(AD_STATE_PLAYED, /* index= */ 1) .withAdState(AD_STATE_PLAYED, /* index= */ 1)
.withAdUri(Uri.parse("https://www.google.com"), /* index= */ 0) .withAdMediaItem(
.withAdUri(Uri.EMPTY, /* index= */ 1) new MediaItem.Builder().setUri("https://www.google.com").setMediaId("id").build(),
/* index= */ 0)
.withAdMediaItem(new MediaItem.Builder().setUri(Uri.EMPTY).build(), /* index= */ 1)
.withAdDurationsUs(new long[] {1234, 5678}) .withAdDurationsUs(new long[] {1234, 5678})
.withContentResumeOffsetUs(4444) .withContentResumeOffsetUs(4444)
.withIsServerSideInserted(true); .withIsServerSideInserted(true);
@ -487,6 +533,25 @@ public class AdPlaybackStateTest {
assertThat(AdPlaybackState.AdGroup.fromBundle(adGroup.toBundle())).isEqualTo(adGroup); assertThat(AdPlaybackState.AdGroup.fromBundle(adGroup.toBundle())).isEqualTo(adGroup);
} }
@Test
public void fromBundle_ofAdGroupWithOnlyUris_yieldsCorrectInstance() {
AdPlaybackState.AdGroup adGroup =
new AdPlaybackState.AdGroup(/* timeUs= */ 42)
.withAdCount(2)
.withAdState(AD_STATE_AVAILABLE, /* index= */ 0)
.withAdState(AD_STATE_PLAYED, /* index= */ 1)
.withAdMediaItem(
new MediaItem.Builder().setUri("https://www.google.com").build(), /* index= */ 0)
.withAdMediaItem(new MediaItem.Builder().setUri(Uri.EMPTY).build(), /* index= */ 1)
.withAdDurationsUs(new long[] {1234, 5678})
.withContentResumeOffsetUs(4444)
.withIsServerSideInserted(true);
Bundle bundle = adGroup.toBundle();
bundle.remove(AdPlaybackState.AdGroup.FIELD_MEDIA_ITEMS);
assertThat(AdPlaybackState.AdGroup.fromBundle(bundle)).isEqualTo(adGroup);
}
@Test @Test
public void withLivePostrollPlaceholderAppended_emptyAdPlaybackState_insertsPlaceholder() { public void withLivePostrollPlaceholderAppended_emptyAdPlaybackState_insertsPlaceholder() {
AdPlaybackState adPlaybackState = AdPlaybackState adPlaybackState =

View File

@ -19,7 +19,6 @@ import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.ElementType.TYPE_USE;
import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.SystemClock; import android.os.SystemClock;
@ -331,16 +330,16 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex); AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex);
if (adMediaSourceHolder != null if (adMediaSourceHolder != null
&& !adMediaSourceHolder.hasMediaSource() && !adMediaSourceHolder.hasMediaSource()
&& adIndexInAdGroup < adGroup.uris.length) { && adIndexInAdGroup < adGroup.mediaItems.length) {
@Nullable Uri adUri = adGroup.uris[adIndexInAdGroup]; @Nullable MediaItem adMediaItem = adGroup.mediaItems[adIndexInAdGroup];
if (adUri != null) { if (adMediaItem != null) {
MediaItem.Builder adMediaItem = new MediaItem.Builder().setUri(adUri);
// Propagate the content's DRM config into the ad media source. // Propagate the content's DRM config into the ad media source.
if (contentDrmConfiguration != null) { if (contentDrmConfiguration != null) {
adMediaItem.setDrmConfiguration(contentDrmConfiguration); adMediaItem =
adMediaItem.buildUpon().setDrmConfiguration(contentDrmConfiguration).build();
} }
MediaSource adMediaSource = adMediaSourceFactory.createMediaSource(adMediaItem.build()); MediaSource adMediaSource = adMediaSourceFactory.createMediaSource(adMediaItem);
adMediaSourceHolder.initializeWithMediaSource(adMediaSource, adUri); adMediaSourceHolder.initializeWithMediaSource(adMediaSource, adMediaItem);
} }
} }
} }
@ -432,10 +431,10 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
private final class AdPrepareListener implements MaskingMediaPeriod.PrepareListener { private final class AdPrepareListener implements MaskingMediaPeriod.PrepareListener {
private final Uri adUri; private final MediaItem adMediaItem;
public AdPrepareListener(Uri adUri) { public AdPrepareListener(MediaItem adMediaItem) {
this.adUri = adUri; this.adMediaItem = adMediaItem;
} }
@Override @Override
@ -454,7 +453,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
.loadError( .loadError(
new LoadEventInfo( new LoadEventInfo(
LoadEventInfo.getNewId(), LoadEventInfo.getNewId(),
new DataSpec(adUri), new DataSpec(checkNotNull(adMediaItem.localConfiguration).uri),
/* elapsedRealtimeMs= */ SystemClock.elapsedRealtime()), /* elapsedRealtimeMs= */ SystemClock.elapsedRealtime()),
C.DATA_TYPE_AD, C.DATA_TYPE_AD,
AdLoadException.createForAd(exception), AdLoadException.createForAd(exception),
@ -474,7 +473,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
private final MediaPeriodId id; private final MediaPeriodId id;
private final List<MaskingMediaPeriod> activeMediaPeriods; private final List<MaskingMediaPeriod> activeMediaPeriods;
private @MonotonicNonNull Uri adUri; private @MonotonicNonNull MediaItem adMediaItem;
private @MonotonicNonNull MediaSource adMediaSource; private @MonotonicNonNull MediaSource adMediaSource;
private @MonotonicNonNull Timeline timeline; private @MonotonicNonNull Timeline timeline;
@ -483,13 +482,13 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
activeMediaPeriods = new ArrayList<>(); activeMediaPeriods = new ArrayList<>();
} }
public void initializeWithMediaSource(MediaSource adMediaSource, Uri adUri) { public void initializeWithMediaSource(MediaSource adMediaSource, MediaItem adMediaItem) {
this.adMediaSource = adMediaSource; this.adMediaSource = adMediaSource;
this.adUri = adUri; this.adMediaItem = adMediaItem;
for (int i = 0; i < activeMediaPeriods.size(); i++) { for (int i = 0; i < activeMediaPeriods.size(); i++) {
MaskingMediaPeriod maskingMediaPeriod = activeMediaPeriods.get(i); MaskingMediaPeriod maskingMediaPeriod = activeMediaPeriods.get(i);
maskingMediaPeriod.setMediaSource(adMediaSource); maskingMediaPeriod.setMediaSource(adMediaSource);
maskingMediaPeriod.setPrepareListener(new AdPrepareListener(adUri)); maskingMediaPeriod.setPrepareListener(new AdPrepareListener(adMediaItem));
} }
prepareChildSource(id, adMediaSource); prepareChildSource(id, adMediaSource);
} }
@ -501,7 +500,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
activeMediaPeriods.add(maskingMediaPeriod); activeMediaPeriods.add(maskingMediaPeriod);
if (adMediaSource != null) { if (adMediaSource != null) {
maskingMediaPeriod.setMediaSource(adMediaSource); maskingMediaPeriod.setMediaSource(adMediaSource);
maskingMediaPeriod.setPrepareListener(new AdPrepareListener(checkNotNull(adUri))); maskingMediaPeriod.setPrepareListener(new AdPrepareListener(checkNotNull(adMediaItem)));
} }
if (timeline != null) { if (timeline != null) {
Object periodUid = timeline.getUidOfPeriod(/* periodIndex= */ 0); Object periodUid = timeline.getUidOfPeriod(/* periodIndex= */ 0);

View File

@ -4989,8 +4989,10 @@ public final class ExoPlayerTest {
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0); new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0);
adPlaybackState = adPlaybackState.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1); adPlaybackState = adPlaybackState.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1);
adPlaybackState = adPlaybackState =
adPlaybackState.withAvailableAdUri( adPlaybackState.withAvailableAdMediaItem(
/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, Uri.parse("https://google.com/ad")); /* adGroupIndex= */ 0,
/* adIndexInAdGroup= */ 0,
MediaItem.fromUri("https://google.com/ad"));
long[][] durationsUs = new long[1][]; long[][] durationsUs = new long[1][];
durationsUs[0] = new long[] {Util.msToUs(adDurationMs)}; durationsUs[0] = new long[] {Util.msToUs(adDurationMs)};
adPlaybackState = adPlaybackState.withAdDurationsUs(durationsUs); adPlaybackState = adPlaybackState.withAdDurationsUs(durationsUs);
@ -5091,8 +5093,10 @@ public final class ExoPlayerTest {
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0); new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0);
adPlaybackState = adPlaybackState.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1); adPlaybackState = adPlaybackState.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1);
adPlaybackState = adPlaybackState =
adPlaybackState.withAvailableAdUri( adPlaybackState.withAvailableAdMediaItem(
/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, Uri.parse("https://google.com/ad")); /* adGroupIndex= */ 0,
/* adIndexInAdGroup= */ 0,
MediaItem.fromUri("https://google.com/ad"));
long[][] durationsUs = new long[1][]; long[][] durationsUs = new long[1][];
durationsUs[0] = new long[] {Util.msToUs(adDurationMs)}; durationsUs[0] = new long[] {Util.msToUs(adDurationMs)};
adPlaybackState = adPlaybackState.withAdDurationsUs(durationsUs); adPlaybackState = adPlaybackState.withAdDurationsUs(durationsUs);
@ -5173,10 +5177,10 @@ public final class ExoPlayerTest {
AdPlaybackState adPlaybackState = AdPlaybackState adPlaybackState =
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0) new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1) .withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri( .withAvailableAdMediaItem(
/* adGroupIndex= */ 0, /* adGroupIndex= */ 0,
/* adIndexInAdGroup= */ 0, /* adIndexInAdGroup= */ 0,
Uri.parse("https://google.com/ad")); MediaItem.fromUri("https://google.com/ad"));
long[][] durationsUs = new long[1][]; long[][] durationsUs = new long[1][];
durationsUs[0] = new long[] {Util.msToUs(adDurationMs)}; durationsUs[0] = new long[] {Util.msToUs(adDurationMs)};
adPlaybackState = adPlaybackState.withAdDurationsUs(durationsUs); adPlaybackState = adPlaybackState.withAdDurationsUs(durationsUs);
@ -9505,10 +9509,10 @@ public final class ExoPlayerTest {
AdPlaybackState adPlaybackState = AdPlaybackState adPlaybackState =
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0) new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1) .withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri( .withAvailableAdMediaItem(
/* adGroupIndex= */ 0, /* adGroupIndex= */ 0,
/* adIndexInAdGroup= */ 0, /* adIndexInAdGroup= */ 0,
Uri.parse("https://google.com/ad")) MediaItem.fromUri("https://google.com/ad"))
.withAdDurationsUs(/* adDurationUs= */ new long[][] {{Util.msToUs(4_000)}}); .withAdDurationsUs(/* adDurationUs= */ new long[][] {{Util.msToUs(4_000)}});
Timeline adTimeline = Timeline adTimeline =
new FakeTimeline( new FakeTimeline(

View File

@ -28,7 +28,6 @@ import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.robolectric.Shadows.shadowOf; import static org.robolectric.Shadows.shadowOf;
import android.net.Uri;
import android.os.Looper; import android.os.Looper;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -77,7 +76,7 @@ public final class MediaPeriodQueueTest {
private static final long FIRST_AD_START_TIME_US = 10 * C.MICROS_PER_SECOND; private static final long FIRST_AD_START_TIME_US = 10 * C.MICROS_PER_SECOND;
private static final long SECOND_AD_START_TIME_US = 20 * C.MICROS_PER_SECOND; private static final long SECOND_AD_START_TIME_US = 20 * C.MICROS_PER_SECOND;
private static final Uri AD_URI = Uri.parse("https://google.com/empty"); private static final MediaItem AD_MEDIA_ITEM = MediaItem.fromUri("https://google.com/empty");
private static final Timeline CONTENT_TIMELINE = private static final Timeline CONTENT_TIMELINE =
new SinglePeriodTimeline( new SinglePeriodTimeline(
CONTENT_DURATION_US, CONTENT_DURATION_US,
@ -85,7 +84,7 @@ public final class MediaPeriodQueueTest {
/* isDynamic= */ false, /* isDynamic= */ false,
/* useLiveConfiguration= */ false, /* useLiveConfiguration= */ false,
/* manifest= */ null, /* manifest= */ null,
MediaItem.fromUri(AD_URI)); AD_MEDIA_ITEM);
private MediaPeriodQueue mediaPeriodQueue; private MediaPeriodQueue mediaPeriodQueue;
private AdPlaybackState adPlaybackState; private AdPlaybackState adPlaybackState;
@ -1487,7 +1486,7 @@ public final class MediaPeriodQueueTest {
adPlaybackState = adPlaybackState =
adPlaybackState adPlaybackState
.withAdCount(adGroupIndex, /* adCount= */ 1) .withAdCount(adGroupIndex, /* adCount= */ 1)
.withAvailableAdUri(adGroupIndex, /* adIndexInAdGroup= */ 0, AD_URI) .withAvailableAdMediaItem(adGroupIndex, /* adIndexInAdGroup= */ 0, AD_MEDIA_ITEM)
.withAdDurationsUs(newDurations); .withAdDurationsUs(newDurations);
updateTimeline(); updateTimeline();
} }

View File

@ -89,8 +89,10 @@ public final class AdsMediaSourceTest {
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0) new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0)
.withContentDurationUs(CONTENT_DURATION_US) .withContentDurationUs(CONTENT_DURATION_US)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1) .withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri( .withAvailableAdMediaItem(
/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, Uri.parse("https://google.com/ad")) /* adGroupIndex= */ 0,
/* adIndexInAdGroup= */ 0,
MediaItem.fromUri("https://google.com/ad"))
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0) .withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)
.withAdResumePositionUs(/* adResumePositionUs= */ 0); .withAdResumePositionUs(/* adResumePositionUs= */ 0);

View File

@ -27,7 +27,6 @@ import static java.lang.Math.max;
import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.ElementType.TYPE_USE;
import android.content.Context; import android.content.Context;
import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import android.os.SystemClock; import android.os.SystemClock;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -37,6 +36,7 @@ import androidx.media3.common.AdOverlayInfo;
import androidx.media3.common.AdPlaybackState; import androidx.media3.common.AdPlaybackState;
import androidx.media3.common.AdViewProvider; import androidx.media3.common.AdViewProvider;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaLibraryInfo; import androidx.media3.common.MediaLibraryInfo;
import androidx.media3.common.PlaybackException; import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player; import androidx.media3.common.Player;
@ -980,9 +980,10 @@ import java.util.Map;
} }
} }
Uri adUri = Uri.parse(adMediaInfo.getUrl()); MediaItem.Builder adMediaItem = new MediaItem.Builder().setUri(adMediaInfo.getUrl());
adPlaybackState = adPlaybackState =
adPlaybackState.withAvailableAdUri(adInfo.adGroupIndex, adInfo.adIndexInAdGroup, adUri); adPlaybackState.withAvailableAdMediaItem(
adInfo.adGroupIndex, adInfo.adIndexInAdGroup, adMediaItem.build());
updateAdPlaybackState(); updateAdPlaybackState();
} }

View File

@ -42,6 +42,7 @@ import androidx.media3.common.AdOverlayInfo;
import androidx.media3.common.AdPlaybackState; import androidx.media3.common.AdPlaybackState;
import androidx.media3.common.AdViewProvider; import androidx.media3.common.AdViewProvider;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.PlaybackException; import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player; import androidx.media3.common.Player;
@ -108,6 +109,7 @@ public final class ImaAdsLoaderTest {
private static final long CONTENT_PERIOD_DURATION_US = private static final long CONTENT_PERIOD_DURATION_US =
CONTENT_TIMELINE.getPeriod(/* periodIndex= */ 0, new Period()).durationUs; CONTENT_TIMELINE.getPeriod(/* periodIndex= */ 0, new Period()).durationUs;
private static final Uri TEST_URI = Uri.parse("https://www.google.com"); private static final Uri TEST_URI = Uri.parse("https://www.google.com");
private static final MediaItem TEST_MEDIA_ITEM = MediaItem.fromUri(TEST_URI);
private static final DataSpec TEST_DATA_SPEC = new DataSpec(TEST_URI); private static final DataSpec TEST_DATA_SPEC = new DataSpec(TEST_URI);
private static final Object TEST_ADS_ID = new Object(); private static final Object TEST_ADS_ID = new Object();
private static final AdMediaInfo TEST_AD_MEDIA_INFO = new AdMediaInfo("https://www.google.com"); private static final AdMediaInfo TEST_AD_MEDIA_INFO = new AdMediaInfo("https://www.google.com");
@ -315,7 +317,8 @@ public final class ImaAdsLoaderTest {
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0) new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US) .withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1) .withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI) .withAvailableAdMediaItem(
/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_MEDIA_ITEM)
.withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}}) .withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}})
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0) .withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)
.withAdResumePositionUs(/* adResumePositionUs= */ 0)); .withAdResumePositionUs(/* adResumePositionUs= */ 0));
@ -1063,7 +1066,8 @@ public final class ImaAdsLoaderTest {
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints)) new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
.withContentDurationUs(CONTENT_PERIOD_DURATION_US) .withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1) .withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI) .withAvailableAdMediaItem(
/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_MEDIA_ITEM)
.withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}})); .withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}}));
} }
@ -1117,7 +1121,8 @@ public final class ImaAdsLoaderTest {
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0) new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US) .withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1) .withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI) .withAvailableAdMediaItem(
/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_MEDIA_ITEM)
.withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}}) .withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}})
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0) .withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)
.withAdResumePositionUs(/* adResumePositionUs= */ 0)); .withAdResumePositionUs(/* adResumePositionUs= */ 0));
@ -1184,7 +1189,8 @@ public final class ImaAdsLoaderTest {
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0) new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US) .withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1) .withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI) .withAvailableAdMediaItem(
/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_MEDIA_ITEM)
.withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}}) .withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}})
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0) .withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)
.withAdResumePositionUs(/* adResumePositionUs= */ 0)); .withAdResumePositionUs(/* adResumePositionUs= */ 0));
@ -1404,7 +1410,7 @@ public final class ImaAdsLoaderTest {
long[][] adDurationsUs = new long[adPlaybackState.adGroupCount][]; long[][] adDurationsUs = new long[adPlaybackState.adGroupCount][];
for (int adGroupIndex = 0; adGroupIndex < adPlaybackState.adGroupCount; adGroupIndex++) { for (int adGroupIndex = 0; adGroupIndex < adPlaybackState.adGroupCount; adGroupIndex++) {
adDurationsUs[adGroupIndex] = adDurationsUs[adGroupIndex] =
new long[adPlaybackState.getAdGroup(adGroupIndex).uris.length]; new long[adPlaybackState.getAdGroup(adGroupIndex).mediaItems.length];
Arrays.fill(adDurationsUs[adGroupIndex], TEST_AD_DURATION_US); Arrays.fill(adDurationsUs[adGroupIndex], TEST_AD_DURATION_US);
} }
adPlaybackState = adPlaybackState.withAdDurationsUs(adDurationsUs); adPlaybackState = adPlaybackState.withAdDurationsUs(adDurationsUs);

View File

@ -295,10 +295,10 @@ public final class FakeTimeline extends Timeline {
adPlaybackState = adPlaybackState.withAdCount(/* adGroupIndex= */ i, adsPerAdGroup); adPlaybackState = adPlaybackState.withAdCount(/* adGroupIndex= */ i, adsPerAdGroup);
for (int j = 0; j < adsPerAdGroup; j++) { for (int j = 0; j < adsPerAdGroup; j++) {
adPlaybackState = adPlaybackState =
adPlaybackState.withAvailableAdUri( adPlaybackState.withAvailableAdMediaItem(
/* adGroupIndex= */ i, /* adGroupIndex= */ i,
/* adIndexInAdGroup= */ j, /* adIndexInAdGroup= */ j,
Uri.parse("https://example.com/ad/" + i + "/" + j)); MediaItem.fromUri("https://example.com/ad/" + i + "/" + j));
} }
adDurationsUs[i] = new long[adsPerAdGroup]; adDurationsUs[i] = new long[adsPerAdGroup];
Arrays.fill(adDurationsUs[i], AD_DURATION_US); Arrays.fill(adDurationsUs[i], AD_DURATION_US);