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.
* Normalize MIME types set by app code or read from media to be fully
lower-case.
* Define ads with a full `MediaItem` instead of a single `Uri` in
`AdPlaybackState`.
* ExoPlayer:
* Add `PreloadMediaSource` and `PreloadMediaPeriod` that allows apps to
preload the media source at a specific start position before playback,

View File

@ -16,6 +16,7 @@
package androidx.media3.common;
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 java.lang.Math.max;
import static java.lang.annotation.ElementType.FIELD;
@ -30,6 +31,7 @@ import androidx.annotation.CheckResult;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
@ -74,8 +76,13 @@ public final class AdPlaybackState implements Bundleable {
*/
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. */
public final @AdState int[] states;
@ -104,7 +111,7 @@ public final class AdPlaybackState implements Bundleable {
/* count= */ C.LENGTH_UNSET,
/* originalCount= */ C.LENGTH_UNSET,
/* states= */ new int[0],
/* uris= */ new Uri[0],
/* mediaItems= */ new MediaItem[0],
/* durationsUs= */ new long[0],
/* contentResumeOffsetUs= */ 0,
/* isServerSideInserted= */ false);
@ -115,19 +122,23 @@ public final class AdPlaybackState implements Bundleable {
int count,
int originalCount,
@AdState int[] states,
@NullableType Uri[] uris,
@NullableType MediaItem[] mediaItems,
long[] durationsUs,
long contentResumeOffsetUs,
boolean isServerSideInserted) {
checkArgument(states.length == uris.length);
checkArgument(states.length == mediaItems.length);
this.timeUs = timeUs;
this.count = count;
this.originalCount = originalCount;
this.states = states;
this.uris = uris;
this.mediaItems = mediaItems;
this.durationsUs = durationsUs;
this.contentResumeOffsetUs = contentResumeOffsetUs;
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
&& count == adGroup.count
&& originalCount == adGroup.originalCount
&& Arrays.equals(uris, adGroup.uris)
&& Arrays.equals(mediaItems, adGroup.mediaItems)
&& Arrays.equals(states, adGroup.states)
&& Arrays.equals(durationsUs, adGroup.durationsUs)
&& contentResumeOffsetUs == adGroup.contentResumeOffsetUs
@ -207,7 +218,7 @@ public final class AdPlaybackState implements Bundleable {
int result = count;
result = 31 * result + originalCount;
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(durationsUs);
result = 31 * result + (int) (contentResumeOffsetUs ^ (contentResumeOffsetUs >>> 32));
@ -223,7 +234,7 @@ public final class AdPlaybackState implements Bundleable {
count,
originalCount,
states,
uris,
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
@ -234,38 +245,47 @@ public final class AdPlaybackState implements Bundleable {
public AdGroup withAdCount(int count) {
@AdState int[] states = copyStatesWithSpaceForAdCount(this.states, 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(
timeUs,
count,
originalCount,
states,
uris,
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
}
/**
* Returns a new instance with the specified {@code uri} set for the specified ad, and the ad
* marked as {@link #AD_STATE_AVAILABLE}.
* @deprecated Use {@link #withAdMediaItem} instead.
*/
@Deprecated
@CheckResult
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);
long[] durationsUs =
this.durationsUs.length == states.length
? this.durationsUs
: copyDurationsUsWithSpaceForAdCount(this.durationsUs, states.length);
@NullableType Uri[] uris = Arrays.copyOf(this.uris, states.length);
uris[index] = uri;
@NullableType MediaItem[] mediaItems = Arrays.copyOf(this.mediaItems, states.length);
mediaItems[index] = mediaItem;
states[index] = AD_STATE_AVAILABLE;
return new AdGroup(
timeUs,
count,
originalCount,
states,
uris,
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
@ -292,15 +312,17 @@ public final class AdPlaybackState implements Bundleable {
? this.durationsUs
: copyDurationsUsWithSpaceForAdCount(this.durationsUs, states.length);
@NullableType
Uri[] uris =
this.uris.length == states.length ? this.uris : Arrays.copyOf(this.uris, states.length);
MediaItem[] mediaItems =
this.mediaItems.length == states.length
? this.mediaItems
: Arrays.copyOf(this.mediaItems, states.length);
states[index] = state;
return new AdGroup(
timeUs,
count,
originalCount,
states,
uris,
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
@ -309,17 +331,17 @@ public final class AdPlaybackState implements Bundleable {
/** Returns a new instance with the specified ad durations, in microseconds. */
@CheckResult
public AdGroup withAdDurationsUs(long[] durationsUs) {
if (durationsUs.length < uris.length) {
durationsUs = copyDurationsUsWithSpaceForAdCount(durationsUs, uris.length);
} else if (count != C.LENGTH_UNSET && durationsUs.length > uris.length) {
durationsUs = Arrays.copyOf(durationsUs, uris.length);
if (durationsUs.length < mediaItems.length) {
durationsUs = copyDurationsUsWithSpaceForAdCount(durationsUs, mediaItems.length);
} else if (count != C.LENGTH_UNSET && durationsUs.length > mediaItems.length) {
durationsUs = Arrays.copyOf(durationsUs, mediaItems.length);
}
return new AdGroup(
timeUs,
count,
originalCount,
states,
uris,
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
@ -333,7 +355,7 @@ public final class AdPlaybackState implements Bundleable {
count,
originalCount,
states,
uris,
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
@ -347,7 +369,7 @@ public final class AdPlaybackState implements Bundleable {
count,
originalCount,
states,
uris,
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
@ -360,7 +382,7 @@ public final class AdPlaybackState implements Bundleable {
count,
originalCount,
states,
uris,
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
@ -370,7 +392,7 @@ public final class AdPlaybackState implements Bundleable {
public AdGroup withLastAdRemoved() {
int newCount = states.length - 1;
@AdState int[] newStates = Arrays.copyOf(states, newCount);
@NullableType Uri[] newUris = Arrays.copyOf(uris, newCount);
@NullableType MediaItem[] newMediaItems = Arrays.copyOf(mediaItems, newCount);
long[] newDurationsUs = durationsUs;
if (durationsUs.length > newCount) {
newDurationsUs = Arrays.copyOf(durationsUs, newCount);
@ -380,7 +402,7 @@ public final class AdPlaybackState implements Bundleable {
newCount,
originalCount,
newStates,
newUris,
newMediaItems,
newDurationsUs,
/* contentResumeOffsetUs= */ Util.sum(newDurationsUs),
isServerSideInserted);
@ -398,7 +420,7 @@ public final class AdPlaybackState implements Bundleable {
/* count= */ 0,
originalCount,
/* states= */ new int[0],
/* uris= */ new Uri[0],
/* mediaItems= */ new MediaItem[0],
/* durationsUs= */ new long[0],
contentResumeOffsetUs,
isServerSideInserted);
@ -415,7 +437,7 @@ public final class AdPlaybackState implements Bundleable {
count,
originalCount,
states,
uris,
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
@ -436,7 +458,7 @@ public final class AdPlaybackState implements Bundleable {
if (states[i] == AD_STATE_PLAYED
|| states[i] == AD_STATE_SKIPPED
|| 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(
@ -444,7 +466,7 @@ public final class AdPlaybackState implements Bundleable {
count,
originalCount,
states,
uris,
mediaItems,
durationsUs,
contentResumeOffsetUs,
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_IS_SERVER_SIDE_INSERTED = Util.intToStringMaxRadix(6);
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.
@SuppressWarnings("nullness:argument")
@ -489,6 +512,7 @@ public final class AdPlaybackState implements Bundleable {
bundle.putInt(FIELD_ORIGINAL_COUNT, originalCount);
bundle.putParcelableArrayList(
FIELD_URIS, new ArrayList<@NullableType Uri>(Arrays.asList(uris)));
bundle.putParcelableArrayList(FIELD_MEDIA_ITEMS, getMediaItemsArrayBundles());
bundle.putIntArray(FIELD_STATES, states);
bundle.putLongArray(FIELD_DURATIONS_US, durationsUs);
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);
@Nullable ArrayList<@NullableType Uri> uriList = bundle.getParcelableArrayList(FIELD_URIS);
@Nullable
ArrayList<@NullableType Bundle> mediaItemBundleList =
bundle.getParcelableArrayList(FIELD_MEDIA_ITEMS);
@Nullable
@AdState
int[] states = bundle.getIntArray(FIELD_STATES);
@Nullable long[] durationsUs = bundle.getLongArray(FIELD_DURATIONS_US);
@ -524,11 +551,41 @@ public final class AdPlaybackState implements Bundleable {
count,
originalCount,
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,
contentResumeOffsetUs,
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
* #AD_STATE_AVAILABLE available}.
*
* @throws IllegalStateException If {@link Uri#EMPTY} is passed as argument for a client-side
* inserted ad group.
* @deprecated Use {@link #withAvailableAdMediaItem} instead.
*/
@Deprecated
@CheckResult
public AdPlaybackState withAvailableAdUri(
@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;
AdGroup[] adGroups = Util.nullSafeArrayCopy(this.adGroups, this.adGroups.length);
checkState(!Uri.EMPTY.equals(uri) || adGroups[adjustedIndex].isServerSideInserted);
adGroups[adjustedIndex] = adGroups[adjustedIndex].withAdUri(uri, adIndexInAdGroup);
checkState(
adGroups[adjustedIndex].isServerSideInserted
|| (mediaItem.localConfiguration != null
&& !mediaItem.localConfiguration.uri.equals(Uri.EMPTY)));
adGroups[adjustedIndex] = adGroups[adjustedIndex].withAdMediaItem(mediaItem, adIndexInAdGroup);
return new AdPlaybackState(
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}.
*
* <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
* AdGroup#isServerSideInserted is not server side inserted}.
@ -793,7 +866,7 @@ public final class AdPlaybackState implements Bundleable {
@CheckResult
public AdPlaybackState withAvailableAd(
@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}. */
@ -1058,7 +1131,7 @@ public final class AdPlaybackState implements Bundleable {
adGroup.count,
adGroup.originalCount,
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),
adGroup.contentResumeOffsetUs,
adGroup.isServerSideInserted);

View File

@ -35,7 +35,7 @@ import org.junit.runner.RunWith;
public class AdPlaybackStateTest {
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();
@Test
@ -50,16 +50,18 @@ public class AdPlaybackStateTest {
}
@Test
public void setAdUriBeforeAdCount() {
public void setAdMediaItemBeforeAdCount() {
AdPlaybackState state =
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);
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).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);
}
@ -71,7 +73,7 @@ public class AdPlaybackStateTest {
state = state.withAdLoadError(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0);
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.isAdInErrorState(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0)).isTrue();
assertThat(state.getAdGroup(1).states[1]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE);
@ -101,7 +103,8 @@ public class AdPlaybackStateTest {
.withRemovedAdGroupCount(1)
.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 2)
.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);
state =
@ -113,7 +116,7 @@ public class AdPlaybackStateTest {
assertThat(state.adGroupCount).isEqualTo(6);
assertThat(state.getAdGroup(1).count).isEqualTo(C.INDEX_UNSET);
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(4).count).isEqualTo(1);
assertThat(state.getAdGroup(4).states[0]).isEqualTo(AdPlaybackState.AD_STATE_SKIPPED);
@ -141,8 +144,12 @@ public class AdPlaybackStateTest {
AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI);
state =
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);
}
@ -152,8 +159,12 @@ public class AdPlaybackStateTest {
AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI);
state =
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);
@ -167,8 +178,12 @@ public class AdPlaybackStateTest {
AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI);
state =
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);
@ -182,8 +197,12 @@ public class AdPlaybackStateTest {
AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI);
state =
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.withAdLoadError(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1);
@ -196,7 +215,9 @@ public class AdPlaybackStateTest {
AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
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);
@ -209,9 +230,15 @@ public class AdPlaybackStateTest {
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withIsServerSideInserted(/* adGroupIndex= */ 1, /* isServerSideInserted= */ true);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_URI);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI);
state =
state.withAvailableAdMediaItem(
/* 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);
@ -224,9 +251,15 @@ public class AdPlaybackStateTest {
new AdPlaybackState(TEST_ADS_ID, TEST_AD_GROUP_TIMES_US).withRemovedAdGroupCount(1);
state = state.withIsServerSideInserted(/* adGroupIndex= */ 1, /* isServerSideInserted= */ true);
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 3);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_URI);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI);
state =
state.withAvailableAdMediaItem(
/* 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= */ 1);
@ -265,9 +298,9 @@ public class AdPlaybackStateTest {
.asList()
.containsExactly(AD_STATE_UNAVAILABLE, AD_STATE_UNAVAILABLE, AD_STATE_AVAILABLE)
.inOrder();
assertThat(state.getAdGroup(adGroupIndex).uris)
assertThat(state.getAdGroup(adGroupIndex).mediaItems)
.asList()
.containsExactly(null, null, Uri.EMPTY)
.containsExactly(null, null, MediaItem.fromUri(Uri.EMPTY))
.inOrder();
state =
@ -364,10 +397,18 @@ public class AdPlaybackStateTest {
state =
state.withAdDurationsUs(
/* adGroupIndex= */ 1, /* adDurationsUs...= */ 1_000L, 2_000L, 3_000L, 4_000L, 5_000L);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_URI);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 3, TEST_URI);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 4, TEST_URI);
state =
state.withAvailableAdMediaItem(
/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_MEDIA_ITEM);
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.withSkippedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 3);
state = state.withAdLoadError(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 4);
@ -393,9 +434,9 @@ public class AdPlaybackStateTest {
AD_STATE_AVAILABLE,
AD_STATE_AVAILABLE)
.inOrder();
assertThat(state.getAdGroup(/* adGroupIndex= */ 1).uris)
assertThat(state.getAdGroup(/* adGroupIndex= */ 1).mediaItems)
.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();
assertThat(state.getAdGroup(/* adGroupIndex= */ 1).durationsUs)
.asList()
@ -445,12 +486,15 @@ public class AdPlaybackStateTest {
.withRemovedAdGroupCount(1)
.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 1)
.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)
.withSkippedAd(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 0)
.withPlayedAd(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 1)
.withAvailableAdUri(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 0, TEST_URI)
.withAvailableAdUri(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 1, TEST_URI)
.withAvailableAdMediaItem(
/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 0, TEST_MEDIA_ITEM)
.withAvailableAdMediaItem(
/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 1, TEST_MEDIA_ITEM)
.withContentResumeOffsetUs(/* adGroupIndex= */ 1, /* contentResumeOffsetUs= */ 4444)
.withContentResumeOffsetUs(/* adGroupIndex= */ 2, /* contentResumeOffsetUs= */ 3333)
.withIsServerSideInserted(/* adGroupIndex= */ 1, /* isServerSideInserted= */ true)
@ -478,8 +522,10 @@ public class AdPlaybackStateTest {
.withAdCount(2)
.withAdState(AD_STATE_AVAILABLE, /* index= */ 0)
.withAdState(AD_STATE_PLAYED, /* index= */ 1)
.withAdUri(Uri.parse("https://www.google.com"), /* index= */ 0)
.withAdUri(Uri.EMPTY, /* index= */ 1)
.withAdMediaItem(
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})
.withContentResumeOffsetUs(4444)
.withIsServerSideInserted(true);
@ -487,6 +533,25 @@ public class AdPlaybackStateTest {
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
public void withLivePostrollPlaceholderAppended_emptyAdPlaybackState_insertsPlaceholder() {
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 java.lang.annotation.ElementType.TYPE_USE;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
@ -331,16 +330,16 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex);
if (adMediaSourceHolder != null
&& !adMediaSourceHolder.hasMediaSource()
&& adIndexInAdGroup < adGroup.uris.length) {
@Nullable Uri adUri = adGroup.uris[adIndexInAdGroup];
if (adUri != null) {
MediaItem.Builder adMediaItem = new MediaItem.Builder().setUri(adUri);
&& adIndexInAdGroup < adGroup.mediaItems.length) {
@Nullable MediaItem adMediaItem = adGroup.mediaItems[adIndexInAdGroup];
if (adMediaItem != null) {
// Propagate the content's DRM config into the ad media source.
if (contentDrmConfiguration != null) {
adMediaItem.setDrmConfiguration(contentDrmConfiguration);
adMediaItem =
adMediaItem.buildUpon().setDrmConfiguration(contentDrmConfiguration).build();
}
MediaSource adMediaSource = adMediaSourceFactory.createMediaSource(adMediaItem.build());
adMediaSourceHolder.initializeWithMediaSource(adMediaSource, adUri);
MediaSource adMediaSource = adMediaSourceFactory.createMediaSource(adMediaItem);
adMediaSourceHolder.initializeWithMediaSource(adMediaSource, adMediaItem);
}
}
}
@ -432,10 +431,10 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
private final class AdPrepareListener implements MaskingMediaPeriod.PrepareListener {
private final Uri adUri;
private final MediaItem adMediaItem;
public AdPrepareListener(Uri adUri) {
this.adUri = adUri;
public AdPrepareListener(MediaItem adMediaItem) {
this.adMediaItem = adMediaItem;
}
@Override
@ -454,7 +453,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
.loadError(
new LoadEventInfo(
LoadEventInfo.getNewId(),
new DataSpec(adUri),
new DataSpec(checkNotNull(adMediaItem.localConfiguration).uri),
/* elapsedRealtimeMs= */ SystemClock.elapsedRealtime()),
C.DATA_TYPE_AD,
AdLoadException.createForAd(exception),
@ -474,7 +473,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
private final MediaPeriodId id;
private final List<MaskingMediaPeriod> activeMediaPeriods;
private @MonotonicNonNull Uri adUri;
private @MonotonicNonNull MediaItem adMediaItem;
private @MonotonicNonNull MediaSource adMediaSource;
private @MonotonicNonNull Timeline timeline;
@ -483,13 +482,13 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
activeMediaPeriods = new ArrayList<>();
}
public void initializeWithMediaSource(MediaSource adMediaSource, Uri adUri) {
public void initializeWithMediaSource(MediaSource adMediaSource, MediaItem adMediaItem) {
this.adMediaSource = adMediaSource;
this.adUri = adUri;
this.adMediaItem = adMediaItem;
for (int i = 0; i < activeMediaPeriods.size(); i++) {
MaskingMediaPeriod maskingMediaPeriod = activeMediaPeriods.get(i);
maskingMediaPeriod.setMediaSource(adMediaSource);
maskingMediaPeriod.setPrepareListener(new AdPrepareListener(adUri));
maskingMediaPeriod.setPrepareListener(new AdPrepareListener(adMediaItem));
}
prepareChildSource(id, adMediaSource);
}
@ -501,7 +500,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
activeMediaPeriods.add(maskingMediaPeriod);
if (adMediaSource != null) {
maskingMediaPeriod.setMediaSource(adMediaSource);
maskingMediaPeriod.setPrepareListener(new AdPrepareListener(checkNotNull(adUri)));
maskingMediaPeriod.setPrepareListener(new AdPrepareListener(checkNotNull(adMediaItem)));
}
if (timeline != null) {
Object periodUid = timeline.getUidOfPeriod(/* periodIndex= */ 0);

View File

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

View File

@ -28,7 +28,6 @@ import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.robolectric.Shadows.shadowOf;
import android.net.Uri;
import android.os.Looper;
import android.util.Pair;
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 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 =
new SinglePeriodTimeline(
CONTENT_DURATION_US,
@ -85,7 +84,7 @@ public final class MediaPeriodQueueTest {
/* isDynamic= */ false,
/* useLiveConfiguration= */ false,
/* manifest= */ null,
MediaItem.fromUri(AD_URI));
AD_MEDIA_ITEM);
private MediaPeriodQueue mediaPeriodQueue;
private AdPlaybackState adPlaybackState;
@ -1487,7 +1486,7 @@ public final class MediaPeriodQueueTest {
adPlaybackState =
adPlaybackState
.withAdCount(adGroupIndex, /* adCount= */ 1)
.withAvailableAdUri(adGroupIndex, /* adIndexInAdGroup= */ 0, AD_URI)
.withAvailableAdMediaItem(adGroupIndex, /* adIndexInAdGroup= */ 0, AD_MEDIA_ITEM)
.withAdDurationsUs(newDurations);
updateTimeline();
}

View File

@ -89,8 +89,10 @@ public final class AdsMediaSourceTest {
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0)
.withContentDurationUs(CONTENT_DURATION_US)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri(
/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, Uri.parse("https://google.com/ad"))
.withAvailableAdMediaItem(
/* adGroupIndex= */ 0,
/* adIndexInAdGroup= */ 0,
MediaItem.fromUri("https://google.com/ad"))
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 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 android.content.Context;
import android.net.Uri;
import android.os.Handler;
import android.os.SystemClock;
import android.view.ViewGroup;
@ -37,6 +36,7 @@ import androidx.media3.common.AdOverlayInfo;
import androidx.media3.common.AdPlaybackState;
import androidx.media3.common.AdViewProvider;
import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaLibraryInfo;
import androidx.media3.common.PlaybackException;
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.withAvailableAdUri(adInfo.adGroupIndex, adInfo.adIndexInAdGroup, adUri);
adPlaybackState.withAvailableAdMediaItem(
adInfo.adGroupIndex, adInfo.adIndexInAdGroup, adMediaItem.build());
updateAdPlaybackState();
}

View File

@ -42,6 +42,7 @@ import androidx.media3.common.AdOverlayInfo;
import androidx.media3.common.AdPlaybackState;
import androidx.media3.common.AdViewProvider;
import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player;
@ -108,6 +109,7 @@ public final class ImaAdsLoaderTest {
private static final long CONTENT_PERIOD_DURATION_US =
CONTENT_TIMELINE.getPeriod(/* periodIndex= */ 0, new Period()).durationUs;
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 Object TEST_ADS_ID = new Object();
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)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.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}})
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)
.withAdResumePositionUs(/* adResumePositionUs= */ 0));
@ -1063,7 +1066,8 @@ public final class ImaAdsLoaderTest {
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.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}}));
}
@ -1117,7 +1121,8 @@ public final class ImaAdsLoaderTest {
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.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}})
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)
.withAdResumePositionUs(/* adResumePositionUs= */ 0));
@ -1184,7 +1189,8 @@ public final class ImaAdsLoaderTest {
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.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}})
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)
.withAdResumePositionUs(/* adResumePositionUs= */ 0));
@ -1404,7 +1410,7 @@ public final class ImaAdsLoaderTest {
long[][] adDurationsUs = new long[adPlaybackState.adGroupCount][];
for (int adGroupIndex = 0; adGroupIndex < adPlaybackState.adGroupCount; 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);
}
adPlaybackState = adPlaybackState.withAdDurationsUs(adDurationsUs);

View File

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