Mask ad media periods before the URI is available
Previously `MediaPeriodQueue` would return null if an ad media URI hadn't loaded yet, but this meant that the player could be stuck in `STATE_READY` if an `AdsLoader` unexpectedly didn't provide an ad URI. Fix this behavior by masking ad media periods. `MaskingMediaPeriod` no longer requires a `MediaSource` to instantiate it. This also fixes a specific case where playback gets stuck when using the IMA extension with an empty ad where the IMA SDK unexpectedly doesn't notify the ad group fetch error. Issue: #8205 PiperOrigin-RevId: 344984824
This commit is contained in:
parent
d8df5411b8
commit
fe754f313e
@ -1,9 +1,15 @@
|
||||
# Release notes
|
||||
|
||||
### 2.12.3 (???-??-??) ###
|
||||
|
||||
* IMA extension:
|
||||
* Fix a condition where playback can get stuck before an empty ad
|
||||
([#8205](https://github.com/google/ExoPlayer/issues/8205)).
|
||||
|
||||
### 2.12.2 (2020-12-01) ###
|
||||
|
||||
* Core library:
|
||||
* Suppress exceptions from registering/unregistering the stream volume
|
||||
* Suppress exceptions from registering and unregistering the stream volume
|
||||
receiver ([#8087](https://github.com/google/ExoPlayer/issues/8087)),
|
||||
([#8106](https://github.com/google/ExoPlayer/issues/8106)).
|
||||
* Suppress ProGuard warnings caused by Guava's compile-only dependencies
|
||||
|
@ -672,9 +672,7 @@ import com.google.common.collect.ImmutableList;
|
||||
period.getNextAdIndexToPlay(adGroupIndex, currentPeriodId.adIndexInAdGroup);
|
||||
if (nextAdIndexInAdGroup < adCountInCurrentAdGroup) {
|
||||
// Play the next ad in the ad group if it's available.
|
||||
return !period.isAdAvailable(adGroupIndex, nextAdIndexInAdGroup)
|
||||
? null
|
||||
: getMediaPeriodInfoForAd(
|
||||
return getMediaPeriodInfoForAd(
|
||||
timeline,
|
||||
currentPeriodId.periodUid,
|
||||
adGroupIndex,
|
||||
@ -720,9 +718,7 @@ import com.google.common.collect.ImmutableList;
|
||||
currentPeriodId.windowSequenceNumber);
|
||||
}
|
||||
int adIndexInAdGroup = period.getFirstAdIndexToPlay(nextAdGroupIndex);
|
||||
return !period.isAdAvailable(nextAdGroupIndex, adIndexInAdGroup)
|
||||
? null
|
||||
: getMediaPeriodInfoForAd(
|
||||
return getMediaPeriodInfoForAd(
|
||||
timeline,
|
||||
currentPeriodId.periodUid,
|
||||
nextAdGroupIndex,
|
||||
@ -737,9 +733,6 @@ import com.google.common.collect.ImmutableList;
|
||||
Timeline timeline, MediaPeriodId id, long requestedContentPositionUs, long startPositionUs) {
|
||||
timeline.getPeriodByUid(id.periodUid, period);
|
||||
if (id.isAd()) {
|
||||
if (!period.isAdAvailable(id.adGroupIndex, id.adIndexInAdGroup)) {
|
||||
return null;
|
||||
}
|
||||
return getMediaPeriodInfoForAd(
|
||||
timeline,
|
||||
id.periodUid,
|
||||
|
@ -609,19 +609,6 @@ public abstract class Timeline {
|
||||
return adPlaybackState.adGroups[adGroupIndex].count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the URL for the specified ad is known.
|
||||
*
|
||||
* @param adGroupIndex The ad group index.
|
||||
* @param adIndexInAdGroup The ad index in the ad group.
|
||||
* @return Whether the URL for the specified ad is known.
|
||||
*/
|
||||
public boolean isAdAvailable(int adGroupIndex, int adIndexInAdGroup) {
|
||||
AdPlaybackState.AdGroup adGroup = adPlaybackState.adGroups[adGroupIndex];
|
||||
return adGroup.count != C.LENGTH_UNSET
|
||||
&& adGroup.states[adIndexInAdGroup] != AdPlaybackState.AD_STATE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of the ad at index {@code adIndexInAdGroup} in the ad group at
|
||||
* {@code adGroupIndex}, in microseconds, or {@link C#TIME_UNSET} if not yet known.
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.source;
|
||||
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
||||
import static com.google.android.exoplayer2.util.Util.castNonNull;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
@ -25,12 +27,13 @@ import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import java.io.IOException;
|
||||
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
/**
|
||||
* Media period that wraps a media source and defers calling its {@link
|
||||
* MediaSource#createPeriod(MediaPeriodId, Allocator, long)} method until {@link
|
||||
* #createPeriod(MediaPeriodId)} has been called. This is useful if you need to return a media
|
||||
* period immediately but the media source that should create it is not yet prepared.
|
||||
* Media period that defers calling {@link MediaSource#createPeriod(MediaPeriodId, Allocator, long)}
|
||||
* on a given source until {@link #createPeriod(MediaPeriodId)} has been called. This is useful if
|
||||
* you need to return a media period immediately but the media source that should create it is not
|
||||
* yet available or prepared.
|
||||
*/
|
||||
public final class MaskingMediaPeriod implements MediaPeriod, MediaPeriod.Callback {
|
||||
|
||||
@ -46,33 +49,32 @@ public final class MaskingMediaPeriod implements MediaPeriod, MediaPeriod.Callba
|
||||
void onPrepareError(MediaPeriodId mediaPeriodId, IOException exception);
|
||||
}
|
||||
|
||||
/** The {@link MediaSource} which will create the actual media period. */
|
||||
public final MediaSource mediaSource;
|
||||
/** The {@link MediaPeriodId} used to create the masking media period. */
|
||||
public final MediaPeriodId id;
|
||||
|
||||
private final long preparePositionUs;
|
||||
private final Allocator allocator;
|
||||
|
||||
@Nullable private MediaPeriod mediaPeriod;
|
||||
/** The {@link MediaSource} that will create the underlying media period. */
|
||||
private @MonotonicNonNull MediaSource mediaSource;
|
||||
|
||||
private @MonotonicNonNull MediaPeriod mediaPeriod;
|
||||
@Nullable private Callback callback;
|
||||
private long preparePositionUs;
|
||||
@Nullable private PrepareListener listener;
|
||||
private boolean notifiedPrepareError;
|
||||
private long preparePositionOverrideUs;
|
||||
|
||||
/**
|
||||
* Creates a new masking media period.
|
||||
* Creates a new masking media period. The media source must be set via {@link
|
||||
* #setMediaSource(MediaSource)} before preparation can start.
|
||||
*
|
||||
* @param mediaSource The media source to wrap.
|
||||
* @param id The identifier used to create the masking media period.
|
||||
* @param allocator The allocator used to create the media period.
|
||||
* @param preparePositionUs The expected start position, in microseconds.
|
||||
*/
|
||||
public MaskingMediaPeriod(
|
||||
MediaSource mediaSource, MediaPeriodId id, Allocator allocator, long preparePositionUs) {
|
||||
public MaskingMediaPeriod(MediaPeriodId id, Allocator allocator, long preparePositionUs) {
|
||||
this.id = id;
|
||||
this.allocator = allocator;
|
||||
this.mediaSource = mediaSource;
|
||||
this.preparePositionUs = preparePositionUs;
|
||||
preparePositionOverrideUs = C.TIME_UNSET;
|
||||
}
|
||||
@ -108,6 +110,12 @@ public final class MaskingMediaPeriod implements MediaPeriod, MediaPeriod.Callba
|
||||
return preparePositionOverrideUs;
|
||||
}
|
||||
|
||||
/** Sets the {@link MediaSource} that will create the underlying media period. */
|
||||
public void setMediaSource(MediaSource mediaSource) {
|
||||
checkState(this.mediaSource == null);
|
||||
this.mediaSource = mediaSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link MediaSource#createPeriod(MediaPeriodId, Allocator, long)} on the wrapped source
|
||||
* then prepares it if {@link #prepare(Callback, long)} has been called. Call {@link
|
||||
@ -117,18 +125,16 @@ public final class MaskingMediaPeriod implements MediaPeriod, MediaPeriod.Callba
|
||||
*/
|
||||
public void createPeriod(MediaPeriodId id) {
|
||||
long preparePositionUs = getPreparePositionWithOverride(this.preparePositionUs);
|
||||
mediaPeriod = mediaSource.createPeriod(id, allocator, preparePositionUs);
|
||||
mediaPeriod = checkNotNull(mediaSource).createPeriod(id, allocator, preparePositionUs);
|
||||
if (callback != null) {
|
||||
mediaPeriod.prepare(this, preparePositionUs);
|
||||
mediaPeriod.prepare(/* callback= */ this, preparePositionUs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the period.
|
||||
*/
|
||||
/** Releases the period. */
|
||||
public void releasePeriod() {
|
||||
if (mediaPeriod != null) {
|
||||
mediaSource.releasePeriod(mediaPeriod);
|
||||
checkNotNull(mediaSource).releasePeriod(mediaPeriod);
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +142,8 @@ public final class MaskingMediaPeriod implements MediaPeriod, MediaPeriod.Callba
|
||||
public void prepare(Callback callback, long preparePositionUs) {
|
||||
this.callback = callback;
|
||||
if (mediaPeriod != null) {
|
||||
mediaPeriod.prepare(this, getPreparePositionWithOverride(this.preparePositionUs));
|
||||
mediaPeriod.prepare(
|
||||
/* callback= */ this, getPreparePositionWithOverride(this.preparePositionUs));
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,10 +152,10 @@ public final class MaskingMediaPeriod implements MediaPeriod, MediaPeriod.Callba
|
||||
try {
|
||||
if (mediaPeriod != null) {
|
||||
mediaPeriod.maybeThrowPrepareError();
|
||||
} else {
|
||||
} else if (mediaSource != null) {
|
||||
mediaSource.maybeThrowSourceInfoRefreshError();
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
} catch (IOException e) {
|
||||
if (listener == null) {
|
||||
throw e;
|
||||
}
|
||||
|
@ -111,8 +111,8 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
|
||||
@Override
|
||||
public MaskingMediaPeriod createPeriod(
|
||||
MediaPeriodId id, Allocator allocator, long startPositionUs) {
|
||||
MaskingMediaPeriod mediaPeriod =
|
||||
new MaskingMediaPeriod(mediaSource, id, allocator, startPositionUs);
|
||||
MaskingMediaPeriod mediaPeriod = new MaskingMediaPeriod(id, allocator, startPositionUs);
|
||||
mediaPeriod.setMediaSource(mediaSource);
|
||||
if (isPrepared) {
|
||||
MediaPeriodId idInSource = id.copyWithPeriodUid(getInternalPeriodUid(id.periodUid));
|
||||
mediaPeriod.createPeriod(idInSource);
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.source.ads;
|
||||
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@ -116,7 +118,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
*/
|
||||
public RuntimeException getRuntimeExceptionForUnexpected() {
|
||||
Assertions.checkState(type == TYPE_UNEXPECTED);
|
||||
return (RuntimeException) Assertions.checkNotNull(getCause());
|
||||
return (RuntimeException) checkNotNull(getCause());
|
||||
}
|
||||
}
|
||||
|
||||
@ -257,12 +259,10 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
|
||||
AdPlaybackState adPlaybackState = Assertions.checkNotNull(this.adPlaybackState);
|
||||
AdPlaybackState adPlaybackState = checkNotNull(this.adPlaybackState);
|
||||
if (adPlaybackState.adGroupCount > 0 && id.isAd()) {
|
||||
int adGroupIndex = id.adGroupIndex;
|
||||
int adIndexInAdGroup = id.adIndexInAdGroup;
|
||||
Uri adUri =
|
||||
Assertions.checkNotNull(adPlaybackState.adGroups[adGroupIndex].uris[adIndexInAdGroup]);
|
||||
if (adMediaSourceHolders[adGroupIndex].length <= adIndexInAdGroup) {
|
||||
int adCount = adIndexInAdGroup + 1;
|
||||
adMediaSourceHolders[adGroupIndex] =
|
||||
@ -272,16 +272,14 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
AdMediaSourceHolder adMediaSourceHolder =
|
||||
adMediaSourceHolders[adGroupIndex][adIndexInAdGroup];
|
||||
if (adMediaSourceHolder == null) {
|
||||
MediaSource adMediaSource =
|
||||
adMediaSourceFactory.createMediaSource(MediaItem.fromUri(adUri));
|
||||
adMediaSourceHolder = new AdMediaSourceHolder(adMediaSource);
|
||||
adMediaSourceHolder = new AdMediaSourceHolder(id);
|
||||
adMediaSourceHolders[adGroupIndex][adIndexInAdGroup] = adMediaSourceHolder;
|
||||
prepareChildSource(id, adMediaSource);
|
||||
maybeUpdateAdMediaSources();
|
||||
}
|
||||
return adMediaSourceHolder.createMediaPeriod(adUri, id, allocator, startPositionUs);
|
||||
return adMediaSourceHolder.createMediaPeriod(id, allocator, startPositionUs);
|
||||
} else {
|
||||
MaskingMediaPeriod mediaPeriod =
|
||||
new MaskingMediaPeriod(contentMediaSource, id, allocator, startPositionUs);
|
||||
MaskingMediaPeriod mediaPeriod = new MaskingMediaPeriod(id, allocator, startPositionUs);
|
||||
mediaPeriod.setMediaSource(contentMediaSource);
|
||||
mediaPeriod.createPeriod(id);
|
||||
return mediaPeriod;
|
||||
}
|
||||
@ -293,10 +291,10 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
MediaPeriodId id = maskingMediaPeriod.id;
|
||||
if (id.isAd()) {
|
||||
AdMediaSourceHolder adMediaSourceHolder =
|
||||
Assertions.checkNotNull(adMediaSourceHolders[id.adGroupIndex][id.adIndexInAdGroup]);
|
||||
checkNotNull(adMediaSourceHolders[id.adGroupIndex][id.adIndexInAdGroup]);
|
||||
adMediaSourceHolder.releaseMediaPeriod(maskingMediaPeriod);
|
||||
if (adMediaSourceHolder.isInactive()) {
|
||||
releaseChildSource(id);
|
||||
adMediaSourceHolder.release();
|
||||
adMediaSourceHolders[id.adGroupIndex][id.adIndexInAdGroup] = null;
|
||||
}
|
||||
} else {
|
||||
@ -307,7 +305,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
@Override
|
||||
protected void releaseSourceInternal() {
|
||||
super.releaseSourceInternal();
|
||||
Assertions.checkNotNull(componentListener).release();
|
||||
checkNotNull(componentListener).release();
|
||||
componentListener = null;
|
||||
contentTimeline = null;
|
||||
adPlaybackState = null;
|
||||
@ -321,7 +319,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
if (mediaPeriodId.isAd()) {
|
||||
int adGroupIndex = mediaPeriodId.adGroupIndex;
|
||||
int adIndexInAdGroup = mediaPeriodId.adIndexInAdGroup;
|
||||
Assertions.checkNotNull(adMediaSourceHolders[adGroupIndex][adIndexInAdGroup])
|
||||
checkNotNull(adMediaSourceHolders[adGroupIndex][adIndexInAdGroup])
|
||||
.handleSourceInfoRefresh(timeline);
|
||||
} else {
|
||||
Assertions.checkArgument(timeline.getPeriodCount() == 1);
|
||||
@ -346,9 +344,41 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
Arrays.fill(adMediaSourceHolders, new AdMediaSourceHolder[0]);
|
||||
}
|
||||
this.adPlaybackState = adPlaybackState;
|
||||
maybeUpdateAdMediaSources();
|
||||
maybeUpdateSourceInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes any {@link AdMediaSourceHolder AdMediaSourceHolders} where the ad media URI is
|
||||
* newly known.
|
||||
*/
|
||||
private void maybeUpdateAdMediaSources() {
|
||||
@Nullable AdPlaybackState adPlaybackState = this.adPlaybackState;
|
||||
if (adPlaybackState == null) {
|
||||
return;
|
||||
}
|
||||
for (int adGroupIndex = 0; adGroupIndex < adMediaSourceHolders.length; adGroupIndex++) {
|
||||
for (int adIndexInAdGroup = 0;
|
||||
adIndexInAdGroup < this.adMediaSourceHolders[adGroupIndex].length;
|
||||
adIndexInAdGroup++) {
|
||||
@Nullable
|
||||
AdMediaSourceHolder adMediaSourceHolder =
|
||||
this.adMediaSourceHolders[adGroupIndex][adIndexInAdGroup];
|
||||
if (adMediaSourceHolder != null
|
||||
&& !adMediaSourceHolder.hasMediaSource()
|
||||
&& adPlaybackState.adGroups[adGroupIndex] != null
|
||||
&& adIndexInAdGroup < adPlaybackState.adGroups[adGroupIndex].uris.length) {
|
||||
@Nullable Uri adUri = adPlaybackState.adGroups[adGroupIndex].uris[adIndexInAdGroup];
|
||||
if (adUri != null) {
|
||||
MediaSource adMediaSource =
|
||||
adMediaSourceFactory.createMediaSource(MediaItem.fromUri(adUri));
|
||||
adMediaSourceHolder.initializeWithMediaSource(adMediaSource, adUri);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeUpdateSourceInfo() {
|
||||
@Nullable Timeline contentTimeline = this.contentTimeline;
|
||||
if (adPlaybackState != null && contentTimeline != null) {
|
||||
@ -461,22 +491,38 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
|
||||
private final class AdMediaSourceHolder {
|
||||
|
||||
private final MediaSource adMediaSource;
|
||||
private final MediaPeriodId id;
|
||||
private final List<MaskingMediaPeriod> activeMediaPeriods;
|
||||
|
||||
private @MonotonicNonNull Uri adUri;
|
||||
private @MonotonicNonNull MediaSource adMediaSource;
|
||||
private @MonotonicNonNull Timeline timeline;
|
||||
|
||||
public AdMediaSourceHolder(MediaSource adMediaSource) {
|
||||
this.adMediaSource = adMediaSource;
|
||||
public AdMediaSourceHolder(MediaPeriodId id) {
|
||||
this.id = id;
|
||||
activeMediaPeriods = new ArrayList<>();
|
||||
}
|
||||
|
||||
public MediaPeriod createMediaPeriod(
|
||||
Uri adUri, MediaPeriodId id, Allocator allocator, long startPositionUs) {
|
||||
MaskingMediaPeriod maskingMediaPeriod =
|
||||
new MaskingMediaPeriod(adMediaSource, id, allocator, startPositionUs);
|
||||
public void initializeWithMediaSource(MediaSource adMediaSource, Uri adUri) {
|
||||
this.adMediaSource = adMediaSource;
|
||||
this.adUri = adUri;
|
||||
for (int i = 0; i < activeMediaPeriods.size(); i++) {
|
||||
MaskingMediaPeriod maskingMediaPeriod = activeMediaPeriods.get(i);
|
||||
maskingMediaPeriod.setMediaSource(adMediaSource);
|
||||
maskingMediaPeriod.setPrepareListener(new AdPrepareListener(adUri));
|
||||
}
|
||||
prepareChildSource(id, adMediaSource);
|
||||
}
|
||||
|
||||
public MediaPeriod createMediaPeriod(
|
||||
MediaPeriodId id, Allocator allocator, long startPositionUs) {
|
||||
MaskingMediaPeriod maskingMediaPeriod =
|
||||
new MaskingMediaPeriod(id, allocator, startPositionUs);
|
||||
activeMediaPeriods.add(maskingMediaPeriod);
|
||||
if (adMediaSource != null) {
|
||||
maskingMediaPeriod.setMediaSource(adMediaSource);
|
||||
maskingMediaPeriod.setPrepareListener(new AdPrepareListener(checkNotNull(adUri)));
|
||||
}
|
||||
if (timeline != null) {
|
||||
Object periodUid = timeline.getUidOfPeriod(/* periodIndex= */ 0);
|
||||
MediaPeriodId adSourceMediaPeriodId = new MediaPeriodId(periodUid, id.windowSequenceNumber);
|
||||
@ -510,6 +556,16 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
maskingMediaPeriod.releasePeriod();
|
||||
}
|
||||
|
||||
public void release() {
|
||||
if (hasMediaSource()) {
|
||||
releaseChildSource(id);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasMediaSource() {
|
||||
return adMediaSource != null;
|
||||
}
|
||||
|
||||
public boolean isInactive() {
|
||||
return activeMediaPeriods.isEmpty();
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
@ -103,7 +102,8 @@ public final class MediaPeriodQueueTest {
|
||||
public void getNextMediaPeriodInfo_withPrerollAd_returnsCorrectMediaPeriodInfos() {
|
||||
setupAdTimeline(/* adGroupTimesUs...= */ 0);
|
||||
setAdGroupLoaded(/* adGroupIndex= */ 0);
|
||||
assertNextMediaPeriodInfoIsAd(/* adGroupIndex= */ 0, /* contentPositionUs= */ C.TIME_UNSET);
|
||||
assertNextMediaPeriodInfoIsAd(
|
||||
/* adGroupIndex= */ 0, AD_DURATION_US, /* contentPositionUs= */ C.TIME_UNSET);
|
||||
advance();
|
||||
assertGetNextMediaPeriodInfoReturnsContentMediaPeriod(
|
||||
/* periodUid= */ firstPeriodUid,
|
||||
@ -128,12 +128,14 @@ public final class MediaPeriodQueueTest {
|
||||
/* isLastInPeriod= */ false,
|
||||
/* isLastInWindow= */ false,
|
||||
/* nextAdGroupIndex= */ 0);
|
||||
// The next media period info should be null as we haven't loaded the ad yet.
|
||||
advance();
|
||||
assertNull(getNextMediaPeriodInfo());
|
||||
assertNextMediaPeriodInfoIsAd(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adDurationUs= */ C.TIME_UNSET,
|
||||
/* contentPositionUs= */ FIRST_AD_START_TIME_US);
|
||||
setAdGroupLoaded(/* adGroupIndex= */ 0);
|
||||
assertNextMediaPeriodInfoIsAd(
|
||||
/* adGroupIndex= */ 0, /* contentPositionUs= */ FIRST_AD_START_TIME_US);
|
||||
/* adGroupIndex= */ 0, AD_DURATION_US, /* contentPositionUs= */ FIRST_AD_START_TIME_US);
|
||||
advance();
|
||||
assertGetNextMediaPeriodInfoReturnsContentMediaPeriod(
|
||||
/* periodUid= */ firstPeriodUid,
|
||||
@ -147,7 +149,7 @@ public final class MediaPeriodQueueTest {
|
||||
advance();
|
||||
setAdGroupLoaded(/* adGroupIndex= */ 1);
|
||||
assertNextMediaPeriodInfoIsAd(
|
||||
/* adGroupIndex= */ 1, /* contentPositionUs= */ SECOND_AD_START_TIME_US);
|
||||
/* adGroupIndex= */ 1, AD_DURATION_US, /* contentPositionUs= */ SECOND_AD_START_TIME_US);
|
||||
advance();
|
||||
assertGetNextMediaPeriodInfoReturnsContentMediaPeriod(
|
||||
/* periodUid= */ firstPeriodUid,
|
||||
@ -175,7 +177,7 @@ public final class MediaPeriodQueueTest {
|
||||
advance();
|
||||
setAdGroupLoaded(/* adGroupIndex= */ 0);
|
||||
assertNextMediaPeriodInfoIsAd(
|
||||
/* adGroupIndex= */ 0, /* contentPositionUs= */ FIRST_AD_START_TIME_US);
|
||||
/* adGroupIndex= */ 0, AD_DURATION_US, /* contentPositionUs= */ FIRST_AD_START_TIME_US);
|
||||
advance();
|
||||
assertGetNextMediaPeriodInfoReturnsContentMediaPeriod(
|
||||
/* periodUid= */ firstPeriodUid,
|
||||
@ -189,7 +191,7 @@ public final class MediaPeriodQueueTest {
|
||||
advance();
|
||||
setAdGroupLoaded(/* adGroupIndex= */ 1);
|
||||
assertNextMediaPeriodInfoIsAd(
|
||||
/* adGroupIndex= */ 1, /* contentPositionUs= */ CONTENT_DURATION_US);
|
||||
/* adGroupIndex= */ 1, AD_DURATION_US, /* contentPositionUs= */ CONTENT_DURATION_US);
|
||||
advance();
|
||||
assertGetNextMediaPeriodInfoReturnsContentMediaPeriod(
|
||||
/* periodUid= */ firstPeriodUid,
|
||||
@ -531,7 +533,8 @@ public final class MediaPeriodQueueTest {
|
||||
/* isFinal= */ isLastInWindow));
|
||||
}
|
||||
|
||||
private void assertNextMediaPeriodInfoIsAd(int adGroupIndex, long contentPositionUs) {
|
||||
private void assertNextMediaPeriodInfoIsAd(
|
||||
int adGroupIndex, long adDurationUs, long contentPositionUs) {
|
||||
assertThat(getNextMediaPeriodInfo())
|
||||
.isEqualTo(
|
||||
new MediaPeriodInfo(
|
||||
@ -543,7 +546,7 @@ public final class MediaPeriodQueueTest {
|
||||
/* startPositionUs= */ 0,
|
||||
contentPositionUs,
|
||||
/* endPositionUs= */ C.TIME_UNSET,
|
||||
/* durationUs= */ AD_DURATION_US,
|
||||
adDurationUs,
|
||||
/* isLastInTimelinePeriod= */ false,
|
||||
/* isLastInTimelineWindow= */ false,
|
||||
/* isFinal= */ false));
|
||||
|
Loading…
x
Reference in New Issue
Block a user