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:
parent
8f69bb0d9d
commit
03a23bef8f
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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 =
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user