mirror of
https://github.com/androidx/media.git
synced 2025-05-04 06:00:37 +08:00
Add support for ad playlists with ImaAdsLoader
Issue: #3750 PiperOrigin-RevId: 343878310
This commit is contained in:
parent
689e89e5f3
commit
05f6d24821
@ -17,8 +17,8 @@ package com.google.android.exoplayer2.ext.ima;
|
|||||||
|
|
||||||
import static com.google.android.exoplayer2.ext.ima.ImaUtil.BITRATE_UNSET;
|
import static com.google.android.exoplayer2.ext.ima.ImaUtil.BITRATE_UNSET;
|
||||||
import static com.google.android.exoplayer2.ext.ima.ImaUtil.TIMEOUT_UNSET;
|
import static com.google.android.exoplayer2.ext.ima.ImaUtil.TIMEOUT_UNSET;
|
||||||
|
import static com.google.android.exoplayer2.ext.ima.ImaUtil.getAdGroupTimesUsForCuePoints;
|
||||||
import static com.google.android.exoplayer2.ext.ima.ImaUtil.getImaLooper;
|
import static com.google.android.exoplayer2.ext.ima.ImaUtil.getImaLooper;
|
||||||
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
|
|
||||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
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.Assertions.checkState;
|
||||||
import static java.lang.Math.max;
|
import static java.lang.Math.max;
|
||||||
@ -280,11 +280,11 @@ import java.util.Map;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Starts using the ads loader for playback. */
|
/**
|
||||||
public void start(Player player, AdViewProvider adViewProvider, EventListener eventListener) {
|
* Starts passing events from this instance (including any pending ad playback state) and
|
||||||
this.player = player;
|
* registers obstructions.
|
||||||
player.addListener(this);
|
*/
|
||||||
boolean playWhenReady = player.getPlayWhenReady();
|
public void start(AdViewProvider adViewProvider, EventListener eventListener) {
|
||||||
this.eventListener = eventListener;
|
this.eventListener = eventListener;
|
||||||
lastVolumePercent = 0;
|
lastVolumePercent = 0;
|
||||||
lastAdProgress = VideoProgressUpdate.VIDEO_TIME_NOT_READY;
|
lastAdProgress = VideoProgressUpdate.VIDEO_TIME_NOT_READY;
|
||||||
@ -293,13 +293,9 @@ import java.util.Map;
|
|||||||
if (!AdPlaybackState.NONE.equals(adPlaybackState)) {
|
if (!AdPlaybackState.NONE.equals(adPlaybackState)) {
|
||||||
// Pass the ad playback state to the player, and resume ads if necessary.
|
// Pass the ad playback state to the player, and resume ads if necessary.
|
||||||
eventListener.onAdPlaybackState(adPlaybackState);
|
eventListener.onAdPlaybackState(adPlaybackState);
|
||||||
if (adsManager != null && imaPausedContent && playWhenReady) {
|
|
||||||
adsManager.resume();
|
|
||||||
}
|
|
||||||
} else if (adsManager != null) {
|
} else if (adsManager != null) {
|
||||||
adPlaybackState =
|
adPlaybackState =
|
||||||
new AdPlaybackState(
|
new AdPlaybackState(adsId, getAdGroupTimesUsForCuePoints(adsManager.getAdCuePoints()));
|
||||||
adsId, ImaUtil.getAdGroupTimesUsForCuePoints(adsManager.getAdCuePoints()));
|
|
||||||
updateAdPlaybackState();
|
updateAdPlaybackState();
|
||||||
}
|
}
|
||||||
for (OverlayInfo overlayInfo : adViewProvider.getAdOverlayInfos()) {
|
for (OverlayInfo overlayInfo : adViewProvider.getAdOverlayInfos()) {
|
||||||
@ -311,14 +307,36 @@ import java.util.Map;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Stops using the ads loader for playback. */
|
/**
|
||||||
public void stop() {
|
* Populates the ad playback state with loaded cue points, if available. Any preroll will be
|
||||||
@Nullable Player player = this.player;
|
* paused immediately while waiting for this instance to be {@link #activate(Player) activated}.
|
||||||
if (player == null) {
|
*/
|
||||||
return;
|
public void maybePreloadAds(long contentPositionMs, long contentDurationMs) {
|
||||||
|
maybeInitializeAdsManager(contentPositionMs, contentDurationMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Activates playback. */
|
||||||
|
public void activate(Player player) {
|
||||||
|
this.player = player;
|
||||||
|
player.addListener(this);
|
||||||
|
|
||||||
|
boolean playWhenReady = player.getPlayWhenReady();
|
||||||
|
onTimelineChanged(player.getCurrentTimeline(), Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE);
|
||||||
|
if (!AdPlaybackState.NONE.equals(adPlaybackState)
|
||||||
|
&& adsManager != null
|
||||||
|
&& imaPausedContent
|
||||||
|
&& playWhenReady) {
|
||||||
|
adsManager.resume();
|
||||||
}
|
}
|
||||||
if (adsManager != null && imaPausedContent) {
|
}
|
||||||
adsManager.pause();
|
|
||||||
|
/** Deactivates playback. */
|
||||||
|
public void deactivate() {
|
||||||
|
Player player = checkNotNull(this.player);
|
||||||
|
if (!AdPlaybackState.NONE.equals(adPlaybackState) && imaPausedContent) {
|
||||||
|
if (adsManager != null) {
|
||||||
|
adsManager.pause();
|
||||||
|
}
|
||||||
adPlaybackState =
|
adPlaybackState =
|
||||||
adPlaybackState.withAdResumePositionUs(
|
adPlaybackState.withAdResumePositionUs(
|
||||||
playingAd ? C.msToUs(player.getCurrentPosition()) : 0);
|
playingAd ? C.msToUs(player.getCurrentPosition()) : 0);
|
||||||
@ -326,10 +344,15 @@ import java.util.Map;
|
|||||||
lastVolumePercent = getPlayerVolumePercent();
|
lastVolumePercent = getPlayerVolumePercent();
|
||||||
lastAdProgress = getAdVideoProgressUpdate();
|
lastAdProgress = getAdVideoProgressUpdate();
|
||||||
lastContentProgress = getContentVideoProgressUpdate();
|
lastContentProgress = getContentVideoProgressUpdate();
|
||||||
adDisplayContainer.unregisterAllFriendlyObstructions();
|
|
||||||
player.removeListener(this);
|
player.removeListener(this);
|
||||||
this.player = null;
|
this.player = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Stops passing of events from this instance and unregisters obstructions. */
|
||||||
|
public void stop() {
|
||||||
eventListener = null;
|
eventListener = null;
|
||||||
|
adDisplayContainer.unregisterAllFriendlyObstructions();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Releases all resources used by the ad tag loader. */
|
/** Releases all resources used by the ad tag loader. */
|
||||||
@ -392,7 +415,6 @@ import java.util.Map;
|
|||||||
// The player is being reset or contains no media.
|
// The player is being reset or contains no media.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checkArgument(timeline.getPeriodCount() == 1);
|
|
||||||
this.timeline = timeline;
|
this.timeline = timeline;
|
||||||
Player player = checkNotNull(this.player);
|
Player player = checkNotNull(this.player);
|
||||||
long contentDurationUs = timeline.getPeriod(player.getCurrentPeriodIndex(), period).durationUs;
|
long contentDurationUs = timeline.getPeriod(player.getCurrentPeriodIndex(), period).durationUs;
|
||||||
@ -592,14 +614,13 @@ import java.util.Map;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private VideoProgressUpdate getContentVideoProgressUpdate() {
|
private VideoProgressUpdate getContentVideoProgressUpdate() {
|
||||||
if (player == null) {
|
|
||||||
return lastContentProgress;
|
|
||||||
}
|
|
||||||
boolean hasContentDuration = contentDurationMs != C.TIME_UNSET;
|
boolean hasContentDuration = contentDurationMs != C.TIME_UNSET;
|
||||||
long contentPositionMs;
|
long contentPositionMs;
|
||||||
if (pendingContentPositionMs != C.TIME_UNSET) {
|
if (pendingContentPositionMs != C.TIME_UNSET) {
|
||||||
sentPendingContentPositionMs = true;
|
sentPendingContentPositionMs = true;
|
||||||
contentPositionMs = pendingContentPositionMs;
|
contentPositionMs = pendingContentPositionMs;
|
||||||
|
} else if (player == null) {
|
||||||
|
return lastContentProgress;
|
||||||
} else if (fakeContentProgressElapsedRealtimeMs != C.TIME_UNSET) {
|
} else if (fakeContentProgressElapsedRealtimeMs != C.TIME_UNSET) {
|
||||||
long elapsedSinceEndMs = SystemClock.elapsedRealtime() - fakeContentProgressElapsedRealtimeMs;
|
long elapsedSinceEndMs = SystemClock.elapsedRealtime() - fakeContentProgressElapsedRealtimeMs;
|
||||||
contentPositionMs = fakeContentProgressOffsetMs + elapsedSinceEndMs;
|
contentPositionMs = fakeContentProgressOffsetMs + elapsedSinceEndMs;
|
||||||
@ -923,7 +944,8 @@ import java.util.Map;
|
|||||||
adCallbacks.get(i).onResume(adMediaInfo);
|
adCallbacks.get(i).onResume(adMediaInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!checkNotNull(player).getPlayWhenReady()) {
|
if (player == null || !player.getPlayWhenReady()) {
|
||||||
|
// Either this loader hasn't been activated yet, or the player is paused now.
|
||||||
checkNotNull(adsManager).pause();
|
checkNotNull(adsManager).pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -941,7 +963,14 @@ import java.util.Map;
|
|||||||
// to a different position, so drop the event. See also [Internal: b/159111848].
|
// to a different position, so drop the event. See also [Internal: b/159111848].
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checkState(adMediaInfo.equals(imaAdMediaInfo));
|
if (configuration.debugModeEnabled && !adMediaInfo.equals(imaAdMediaInfo)) {
|
||||||
|
Log.w(
|
||||||
|
TAG,
|
||||||
|
"Unexpected pauseAd for "
|
||||||
|
+ getAdMediaInfoString(adMediaInfo)
|
||||||
|
+ ", expected "
|
||||||
|
+ getAdMediaInfoString(imaAdMediaInfo));
|
||||||
|
}
|
||||||
imaAdState = IMA_AD_STATE_PAUSED;
|
imaAdState = IMA_AD_STATE_PAUSED;
|
||||||
for (int i = 0; i < adCallbacks.size(); i++) {
|
for (int i = 0; i < adCallbacks.size(); i++) {
|
||||||
adCallbacks.get(i).onPause(adMediaInfo);
|
adCallbacks.get(i).onPause(adMediaInfo);
|
||||||
@ -1157,9 +1186,13 @@ import java.util.Map;
|
|||||||
throw new IllegalStateException("Failed to find cue point");
|
throw new IllegalStateException("Failed to find cue point");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getAdMediaInfoString(AdMediaInfo adMediaInfo) {
|
private String getAdMediaInfoString(@Nullable AdMediaInfo adMediaInfo) {
|
||||||
@Nullable AdInfo adInfo = adInfoByAdMediaInfo.get(adMediaInfo);
|
@Nullable AdInfo adInfo = adInfoByAdMediaInfo.get(adMediaInfo);
|
||||||
return "AdMediaInfo[" + adMediaInfo.getUrl() + (adInfo != null ? ", " + adInfo : "") + "]";
|
return "AdMediaInfo["
|
||||||
|
+ (adMediaInfo == null ? "null" : adMediaInfo.getUrl())
|
||||||
|
+ ", "
|
||||||
|
+ adInfo
|
||||||
|
+ "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long getContentPeriodPositionMs(
|
private static long getContentPeriodPositionMs(
|
||||||
@ -1226,16 +1259,12 @@ import java.util.Map;
|
|||||||
if (configuration.applicationAdEventListener != null) {
|
if (configuration.applicationAdEventListener != null) {
|
||||||
adsManager.addAdEventListener(configuration.applicationAdEventListener);
|
adsManager.addAdEventListener(configuration.applicationAdEventListener);
|
||||||
}
|
}
|
||||||
if (player != null) {
|
try {
|
||||||
// If a player is attached already, start playback immediately.
|
adPlaybackState =
|
||||||
try {
|
new AdPlaybackState(adsId, getAdGroupTimesUsForCuePoints(adsManager.getAdCuePoints()));
|
||||||
adPlaybackState =
|
updateAdPlaybackState();
|
||||||
new AdPlaybackState(
|
} catch (RuntimeException e) {
|
||||||
adsId, ImaUtil.getAdGroupTimesUsForCuePoints(adsManager.getAdCuePoints()));
|
maybeNotifyInternalError("onAdsManagerLoaded", e);
|
||||||
updateAdPlaybackState();
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
maybeNotifyInternalError("onAdsManagerLoaded", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer;
|
|||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
|
import com.google.android.exoplayer2.Timeline;
|
||||||
import com.google.android.exoplayer2.source.MediaSourceFactory;
|
import com.google.android.exoplayer2.source.MediaSourceFactory;
|
||||||
import com.google.android.exoplayer2.source.ads.AdsLoader;
|
import com.google.android.exoplayer2.source.ads.AdsLoader;
|
||||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
||||||
@ -57,6 +58,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -371,12 +373,16 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
|
|||||||
private final ImaUtil.Configuration configuration;
|
private final ImaUtil.Configuration configuration;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final ImaUtil.ImaFactory imaFactory;
|
private final ImaUtil.ImaFactory imaFactory;
|
||||||
|
private final HashMap<Object, AdTagLoader> adTagLoaderByAdsId;
|
||||||
|
private final HashMap<AdsMediaSource, AdTagLoader> adTagLoaderByAdsMediaSource;
|
||||||
|
private final Timeline.Period period;
|
||||||
|
private final Timeline.Window window;
|
||||||
|
|
||||||
private boolean wasSetPlayerCalled;
|
private boolean wasSetPlayerCalled;
|
||||||
@Nullable private Player nextPlayer;
|
@Nullable private Player nextPlayer;
|
||||||
@Nullable private AdTagLoader adTagLoader;
|
|
||||||
private List<String> supportedMimeTypes;
|
private List<String> supportedMimeTypes;
|
||||||
@Nullable private Player player;
|
@Nullable private Player player;
|
||||||
|
@Nullable private AdTagLoader currentAdTagLoader;
|
||||||
|
|
||||||
private ImaAdsLoader(
|
private ImaAdsLoader(
|
||||||
Context context, ImaUtil.Configuration configuration, ImaUtil.ImaFactory imaFactory) {
|
Context context, ImaUtil.Configuration configuration, ImaUtil.ImaFactory imaFactory) {
|
||||||
@ -384,6 +390,10 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
|
|||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.imaFactory = imaFactory;
|
this.imaFactory = imaFactory;
|
||||||
supportedMimeTypes = ImmutableList.of();
|
supportedMimeTypes = ImmutableList.of();
|
||||||
|
adTagLoaderByAdsId = new HashMap<>();
|
||||||
|
adTagLoaderByAdsMediaSource = new HashMap<>();
|
||||||
|
period = new Timeline.Period();
|
||||||
|
window = new Timeline.Window();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -394,7 +404,7 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
|
|||||||
@SuppressWarnings("nullness:nullness.on.outer")
|
@SuppressWarnings("nullness:nullness.on.outer")
|
||||||
@Nullable
|
@Nullable
|
||||||
public com.google.ads.interactivemedia.v3.api.AdsLoader getAdsLoader() {
|
public com.google.ads.interactivemedia.v3.api.AdsLoader getAdsLoader() {
|
||||||
return adTagLoader != null ? adTagLoader.getAdsLoader() : null;
|
return currentAdTagLoader != null ? currentAdTagLoader.getAdsLoader() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -410,7 +420,7 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
|
|||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public AdDisplayContainer getAdDisplayContainer() {
|
public AdDisplayContainer getAdDisplayContainer() {
|
||||||
return adTagLoader != null ? adTagLoader.getAdDisplayContainer() : null;
|
return currentAdTagLoader != null ? currentAdTagLoader.getAdDisplayContainer() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -427,8 +437,8 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
|
|||||||
* null} if playing audio-only ads.
|
* null} if playing audio-only ads.
|
||||||
*/
|
*/
|
||||||
public void requestAds(DataSpec adTagDataSpec, Object adsId, @Nullable ViewGroup adViewGroup) {
|
public void requestAds(DataSpec adTagDataSpec, Object adsId, @Nullable ViewGroup adViewGroup) {
|
||||||
if (adTagLoader == null) {
|
if (!adTagLoaderByAdsId.containsKey(adsId)) {
|
||||||
adTagLoader =
|
AdTagLoader adTagLoader =
|
||||||
new AdTagLoader(
|
new AdTagLoader(
|
||||||
context,
|
context,
|
||||||
configuration,
|
configuration,
|
||||||
@ -437,6 +447,7 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
|
|||||||
adTagDataSpec,
|
adTagDataSpec,
|
||||||
adsId,
|
adsId,
|
||||||
adViewGroup);
|
adViewGroup);
|
||||||
|
adTagLoaderByAdsId.put(adsId, adTagLoader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,8 +459,8 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
|
|||||||
* IMA SDK provides the UI to skip ads in the ad view group passed via {@link AdViewProvider}.
|
* IMA SDK provides the UI to skip ads in the ad view group passed via {@link AdViewProvider}.
|
||||||
*/
|
*/
|
||||||
public void skipAd() {
|
public void skipAd() {
|
||||||
if (adTagLoader != null) {
|
if (currentAdTagLoader != null) {
|
||||||
adTagLoader.skipAd();
|
currentAdTagLoader.skipAd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,37 +505,67 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
|
|||||||
EventListener eventListener) {
|
EventListener eventListener) {
|
||||||
checkState(
|
checkState(
|
||||||
wasSetPlayerCalled, "Set player using adsLoader.setPlayer before preparing the player.");
|
wasSetPlayerCalled, "Set player using adsLoader.setPlayer before preparing the player.");
|
||||||
player = nextPlayer;
|
if (adTagLoaderByAdsMediaSource.isEmpty()) {
|
||||||
@Nullable Player player = this.player;
|
player = nextPlayer;
|
||||||
if (player == null) {
|
@Nullable Player player = this.player;
|
||||||
return;
|
if (player == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
player.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable AdTagLoader adTagLoader = adTagLoaderByAdsId.get(adsId);
|
||||||
if (adTagLoader == null) {
|
if (adTagLoader == null) {
|
||||||
requestAds(adTagDataSpec, adsId, adViewProvider.getAdViewGroup());
|
requestAds(adTagDataSpec, adsId, adViewProvider.getAdViewGroup());
|
||||||
|
adTagLoader = adTagLoaderByAdsId.get(adsId);
|
||||||
}
|
}
|
||||||
checkNotNull(adTagLoader).start(player, adViewProvider, eventListener);
|
adTagLoaderByAdsMediaSource.put(adsMediaSource, checkNotNull(adTagLoader));
|
||||||
|
checkNotNull(adTagLoader).start(adViewProvider, eventListener);
|
||||||
|
maybeUpdateCurrentAdTagLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop(AdsMediaSource adsMediaSource) {
|
public void stop(AdsMediaSource adsMediaSource) {
|
||||||
if (player != null && adTagLoader != null) {
|
@Nullable AdTagLoader removedAdTagLoader = adTagLoaderByAdsMediaSource.remove(adsMediaSource);
|
||||||
adTagLoader.stop();
|
maybeUpdateCurrentAdTagLoader();
|
||||||
|
if (removedAdTagLoader != null) {
|
||||||
|
removedAdTagLoader.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player != null && adTagLoaderByAdsMediaSource.isEmpty()) {
|
||||||
|
player.removeListener(this);
|
||||||
|
player = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
if (adTagLoader != null) {
|
if (player != null) {
|
||||||
|
player.removeListener(this);
|
||||||
|
player = null;
|
||||||
|
maybeUpdateCurrentAdTagLoader();
|
||||||
|
}
|
||||||
|
nextPlayer = null;
|
||||||
|
|
||||||
|
for (AdTagLoader adTagLoader : adTagLoaderByAdsMediaSource.values()) {
|
||||||
adTagLoader.release();
|
adTagLoader.release();
|
||||||
}
|
}
|
||||||
|
adTagLoaderByAdsMediaSource.clear();
|
||||||
|
|
||||||
|
for (AdTagLoader adTagLoader : adTagLoaderByAdsId.values()) {
|
||||||
|
adTagLoader.release();
|
||||||
|
}
|
||||||
|
adTagLoaderByAdsId.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handlePrepareComplete(
|
public void handlePrepareComplete(
|
||||||
AdsMediaSource adsMediaSource, int adGroupIndex, int adIndexInAdGroup) {
|
AdsMediaSource adsMediaSource, int adGroupIndex, int adIndexInAdGroup) {
|
||||||
if (adTagLoader != null) {
|
if (player == null) {
|
||||||
adTagLoader.handlePrepareComplete(adGroupIndex, adIndexInAdGroup);
|
return;
|
||||||
}
|
}
|
||||||
|
checkNotNull(adTagLoaderByAdsMediaSource.get(adsMediaSource))
|
||||||
|
.handlePrepareComplete(adGroupIndex, adIndexInAdGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -533,9 +574,112 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
|
|||||||
int adGroupIndex,
|
int adGroupIndex,
|
||||||
int adIndexInAdGroup,
|
int adIndexInAdGroup,
|
||||||
IOException exception) {
|
IOException exception) {
|
||||||
if (adTagLoader != null) {
|
if (player == null) {
|
||||||
adTagLoader.handlePrepareError(adGroupIndex, adIndexInAdGroup, exception);
|
return;
|
||||||
}
|
}
|
||||||
|
checkNotNull(adTagLoaderByAdsMediaSource.get(adsMediaSource))
|
||||||
|
.handlePrepareError(adGroupIndex, adIndexInAdGroup, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Player.EventListener implementation.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTimelineChanged(Timeline timeline, @Player.TimelineChangeReason int reason) {
|
||||||
|
if (timeline.isEmpty()) {
|
||||||
|
// The player is being reset or contains no media.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
maybeUpdateCurrentAdTagLoader();
|
||||||
|
maybePreloadNextPeriodAds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
|
||||||
|
maybeUpdateCurrentAdTagLoader();
|
||||||
|
maybePreloadNextPeriodAds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
|
||||||
|
maybePreloadNextPeriodAds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRepeatModeChanged(@Player.RepeatMode int repeatMode) {
|
||||||
|
maybePreloadNextPeriodAds();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal methods.
|
||||||
|
|
||||||
|
private void maybeUpdateCurrentAdTagLoader() {
|
||||||
|
@Nullable AdTagLoader oldAdTagLoader = currentAdTagLoader;
|
||||||
|
@Nullable AdTagLoader newAdTagLoader = getCurrentAdTagLoader();
|
||||||
|
if (!Util.areEqual(oldAdTagLoader, newAdTagLoader)) {
|
||||||
|
if (oldAdTagLoader != null) {
|
||||||
|
oldAdTagLoader.deactivate();
|
||||||
|
}
|
||||||
|
currentAdTagLoader = newAdTagLoader;
|
||||||
|
if (newAdTagLoader != null) {
|
||||||
|
newAdTagLoader.activate(checkNotNull(player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private AdTagLoader getCurrentAdTagLoader() {
|
||||||
|
@Nullable Player player = this.player;
|
||||||
|
if (player == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Timeline timeline = player.getCurrentTimeline();
|
||||||
|
if (timeline.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int periodIndex = player.getCurrentPeriodIndex();
|
||||||
|
@Nullable Object adsId = timeline.getPeriod(periodIndex, period).getAdsId();
|
||||||
|
if (adsId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Nullable AdTagLoader adTagLoader = adTagLoaderByAdsId.get(adsId);
|
||||||
|
if (adTagLoader == null || !adTagLoaderByAdsMediaSource.containsValue(adTagLoader)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return adTagLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void maybePreloadNextPeriodAds() {
|
||||||
|
@Nullable Player player = this.player;
|
||||||
|
if (player == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Timeline timeline = player.getCurrentTimeline();
|
||||||
|
if (timeline.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int nextPeriodIndex =
|
||||||
|
timeline.getNextPeriodIndex(
|
||||||
|
player.getCurrentPeriodIndex(),
|
||||||
|
period,
|
||||||
|
window,
|
||||||
|
player.getRepeatMode(),
|
||||||
|
player.getShuffleModeEnabled());
|
||||||
|
if (nextPeriodIndex == C.INDEX_UNSET) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
timeline.getPeriod(nextPeriodIndex, period);
|
||||||
|
@Nullable Object nextAdsId = period.getAdsId();
|
||||||
|
if (nextAdsId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@Nullable AdTagLoader nextAdTagLoader = adTagLoaderByAdsId.get(nextAdsId);
|
||||||
|
if (nextAdTagLoader == null || nextAdTagLoader == currentAdTagLoader) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long periodPositionUs =
|
||||||
|
timeline.getPeriodPosition(
|
||||||
|
window, period, period.windowIndex, /* windowPositionUs= */ C.TIME_UNSET)
|
||||||
|
.second;
|
||||||
|
nextAdTagLoader.maybePreloadAds(C.usToMs(periodPositionUs), C.usToMs(period.durationUs));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,25 +21,30 @@ import com.google.android.exoplayer2.Player;
|
|||||||
import com.google.android.exoplayer2.Timeline;
|
import com.google.android.exoplayer2.Timeline;
|
||||||
import com.google.android.exoplayer2.testutil.StubExoPlayer;
|
import com.google.android.exoplayer2.testutil.StubExoPlayer;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||||
import java.util.ArrayList;
|
import com.google.android.exoplayer2.util.ListenerSet;
|
||||||
|
|
||||||
/** A fake player for testing content/ad playback. */
|
/** A fake player for testing content/ad playback. */
|
||||||
/* package */ final class FakePlayer extends StubExoPlayer {
|
/* package */ final class FakePlayer extends StubExoPlayer {
|
||||||
|
|
||||||
private final ArrayList<Player.EventListener> listeners;
|
private final ListenerSet<EventListener, Events> listeners;
|
||||||
private final Timeline.Period period;
|
private final Timeline.Period period;
|
||||||
private final Timeline timeline;
|
|
||||||
|
|
||||||
|
private Timeline timeline;
|
||||||
@Player.State private int state;
|
@Player.State private int state;
|
||||||
private boolean playWhenReady;
|
private boolean playWhenReady;
|
||||||
private long position;
|
private int periodIndex;
|
||||||
private long contentPosition;
|
private long positionMs;
|
||||||
|
private long contentPositionMs;
|
||||||
private boolean isPlayingAd;
|
private boolean isPlayingAd;
|
||||||
private int adGroupIndex;
|
private int adGroupIndex;
|
||||||
private int adIndexInAdGroup;
|
private int adIndexInAdGroup;
|
||||||
|
|
||||||
public FakePlayer() {
|
public FakePlayer() {
|
||||||
listeners = new ArrayList<>();
|
listeners =
|
||||||
|
new ListenerSet<>(
|
||||||
|
Looper.getMainLooper(),
|
||||||
|
Player.Events::new,
|
||||||
|
(listener, eventFlags) -> listener.onEvents(/* player= */ this, eventFlags));
|
||||||
period = new Timeline.Period();
|
period = new Timeline.Period();
|
||||||
state = Player.STATE_IDLE;
|
state = Player.STATE_IDLE;
|
||||||
playWhenReady = true;
|
playWhenReady = true;
|
||||||
@ -48,26 +53,27 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
/** Sets the timeline on this fake player, which notifies listeners with the changed timeline. */
|
/** Sets the timeline on this fake player, which notifies listeners with the changed timeline. */
|
||||||
public void updateTimeline(Timeline timeline, @TimelineChangeReason int reason) {
|
public void updateTimeline(Timeline timeline, @TimelineChangeReason int reason) {
|
||||||
for (Player.EventListener listener : listeners) {
|
this.timeline = timeline;
|
||||||
listener.onTimelineChanged(timeline, reason);
|
listeners.sendEvent(
|
||||||
}
|
Player.EVENT_TIMELINE_CHANGED, listener -> listener.onTimelineChanged(timeline, reason));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the state of this player as if it were playing content at the given {@code position}. If
|
* Sets the state of this player as if it were playing content at the given {@code position}. If
|
||||||
* an ad is currently playing, this will trigger a position discontinuity.
|
* an ad is currently playing, this will trigger a position discontinuity.
|
||||||
*/
|
*/
|
||||||
public void setPlayingContentPosition(long position) {
|
public void setPlayingContentPosition(int periodIndex, long positionMs) {
|
||||||
boolean notify = isPlayingAd;
|
boolean notify = isPlayingAd;
|
||||||
isPlayingAd = false;
|
isPlayingAd = false;
|
||||||
adGroupIndex = C.INDEX_UNSET;
|
adGroupIndex = C.INDEX_UNSET;
|
||||||
adIndexInAdGroup = C.INDEX_UNSET;
|
adIndexInAdGroup = C.INDEX_UNSET;
|
||||||
this.position = position;
|
this.periodIndex = periodIndex;
|
||||||
contentPosition = position;
|
this.positionMs = positionMs;
|
||||||
|
contentPositionMs = positionMs;
|
||||||
if (notify) {
|
if (notify) {
|
||||||
for (Player.EventListener listener : listeners) {
|
listeners.sendEvent(
|
||||||
listener.onPositionDiscontinuity(DISCONTINUITY_REASON_AD_INSERTION);
|
Player.EVENT_POSITION_DISCONTINUITY,
|
||||||
}
|
listener -> listener.onPositionDiscontinuity(DISCONTINUITY_REASON_AD_INSERTION));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,17 +83,22 @@ import java.util.ArrayList;
|
|||||||
* position discontinuity.
|
* position discontinuity.
|
||||||
*/
|
*/
|
||||||
public void setPlayingAdPosition(
|
public void setPlayingAdPosition(
|
||||||
int adGroupIndex, int adIndexInAdGroup, long position, long contentPosition) {
|
int periodIndex,
|
||||||
|
int adGroupIndex,
|
||||||
|
int adIndexInAdGroup,
|
||||||
|
long positionMs,
|
||||||
|
long contentPositionMs) {
|
||||||
boolean notify = !isPlayingAd || this.adIndexInAdGroup != adIndexInAdGroup;
|
boolean notify = !isPlayingAd || this.adIndexInAdGroup != adIndexInAdGroup;
|
||||||
isPlayingAd = true;
|
isPlayingAd = true;
|
||||||
|
this.periodIndex = periodIndex;
|
||||||
this.adGroupIndex = adGroupIndex;
|
this.adGroupIndex = adGroupIndex;
|
||||||
this.adIndexInAdGroup = adIndexInAdGroup;
|
this.adIndexInAdGroup = adIndexInAdGroup;
|
||||||
this.position = position;
|
this.positionMs = positionMs;
|
||||||
this.contentPosition = contentPosition;
|
this.contentPositionMs = contentPositionMs;
|
||||||
if (notify) {
|
if (notify) {
|
||||||
for (Player.EventListener listener : listeners) {
|
listeners.sendEvent(
|
||||||
listener.onPositionDiscontinuity(DISCONTINUITY_REASON_AD_INSERTION);
|
EVENT_POSITION_DISCONTINUITY,
|
||||||
}
|
listener -> listener.onPositionDiscontinuity(DISCONTINUITY_REASON_AD_INSERTION));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,16 +110,18 @@ import java.util.ArrayList;
|
|||||||
this.state = state;
|
this.state = state;
|
||||||
this.playWhenReady = playWhenReady;
|
this.playWhenReady = playWhenReady;
|
||||||
if (playbackStateChanged || playWhenReadyChanged) {
|
if (playbackStateChanged || playWhenReadyChanged) {
|
||||||
for (Player.EventListener listener : listeners) {
|
listeners.sendEvent(
|
||||||
listener.onPlayerStateChanged(playWhenReady, state);
|
Player.EVENT_PLAYBACK_STATE_CHANGED,
|
||||||
if (playbackStateChanged) {
|
listener -> {
|
||||||
listener.onPlaybackStateChanged(state);
|
listener.onPlayerStateChanged(playWhenReady, state);
|
||||||
}
|
if (playbackStateChanged) {
|
||||||
if (playWhenReadyChanged) {
|
listener.onPlaybackStateChanged(state);
|
||||||
listener.onPlayWhenReadyChanged(
|
}
|
||||||
playWhenReady, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
if (playWhenReadyChanged) {
|
||||||
}
|
listener.onPlayWhenReadyChanged(
|
||||||
}
|
playWhenReady, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +158,17 @@ import java.util.ArrayList;
|
|||||||
return playWhenReady;
|
return playWhenReady;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RepeatMode
|
||||||
|
public int getRepeatMode() {
|
||||||
|
return REPEAT_MODE_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getShuffleModeEnabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRendererCount() {
|
public int getRendererCount() {
|
||||||
return 0;
|
return 0;
|
||||||
@ -162,7 +186,7 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCurrentPeriodIndex() {
|
public int getCurrentPeriodIndex() {
|
||||||
return 0;
|
return periodIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -186,7 +210,7 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getCurrentPosition() {
|
public long getCurrentPosition() {
|
||||||
return position;
|
return positionMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -206,6 +230,6 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getContentPosition() {
|
public long getContentPosition() {
|
||||||
return contentPosition;
|
return contentPositionMs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,18 +53,15 @@ import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer;
|
|||||||
import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate;
|
import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.MediaItem;
|
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.Timeline;
|
import com.google.android.exoplayer2.Timeline;
|
||||||
import com.google.android.exoplayer2.Timeline.Period;
|
import com.google.android.exoplayer2.Timeline.Period;
|
||||||
import com.google.android.exoplayer2.ext.ima.ImaUtil.ImaFactory;
|
import com.google.android.exoplayer2.ext.ima.ImaUtil.ImaFactory;
|
||||||
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
|
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
|
||||||
import com.google.android.exoplayer2.source.MaskingMediaSource.PlaceholderTimeline;
|
|
||||||
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
|
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
|
||||||
import com.google.android.exoplayer2.source.ads.AdsLoader;
|
import com.google.android.exoplayer2.source.ads.AdsLoader;
|
||||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
||||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource.AdLoadException;
|
import com.google.android.exoplayer2.source.ads.AdsMediaSource.AdLoadException;
|
||||||
import com.google.android.exoplayer2.source.ads.SinglePeriodAdTimeline;
|
|
||||||
import com.google.android.exoplayer2.testutil.FakeMediaSource;
|
import com.google.android.exoplayer2.testutil.FakeMediaSource;
|
||||||
import com.google.android.exoplayer2.testutil.FakeTimeline;
|
import com.google.android.exoplayer2.testutil.FakeTimeline;
|
||||||
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
|
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
|
||||||
@ -133,12 +130,13 @@ public final class ImaAdsLoaderTest {
|
|||||||
private ContentProgressProvider contentProgressProvider;
|
private ContentProgressProvider contentProgressProvider;
|
||||||
private VideoAdPlayer videoAdPlayer;
|
private VideoAdPlayer videoAdPlayer;
|
||||||
private TestAdsLoaderListener adsLoaderListener;
|
private TestAdsLoaderListener adsLoaderListener;
|
||||||
private FakePlayer fakeExoPlayer;
|
private FakePlayer fakePlayer;
|
||||||
private ImaAdsLoader imaAdsLoader;
|
private ImaAdsLoader imaAdsLoader;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
setupMocks();
|
setupMocks();
|
||||||
|
fakePlayer = new FakePlayer();
|
||||||
adViewGroup = new FrameLayout(getApplicationContext());
|
adViewGroup = new FrameLayout(getApplicationContext());
|
||||||
View adOverlayView = new View(getApplicationContext());
|
View adOverlayView = new View(getApplicationContext());
|
||||||
adViewProvider =
|
adViewProvider =
|
||||||
@ -166,19 +164,32 @@ public final class ImaAdsLoaderTest {
|
|||||||
return ImmutableList.of();
|
return ImmutableList.of();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
imaAdsLoader =
|
||||||
|
new ImaAdsLoader.Builder(getApplicationContext())
|
||||||
|
.setImaFactory(mockImaFactory)
|
||||||
|
.setImaSdkSettings(mockImaSdkSettings)
|
||||||
|
.build();
|
||||||
|
imaAdsLoader.setPlayer(fakePlayer);
|
||||||
|
adsMediaSource =
|
||||||
|
new AdsMediaSource(
|
||||||
|
new FakeMediaSource(CONTENT_TIMELINE),
|
||||||
|
TEST_DATA_SPEC,
|
||||||
|
TEST_ADS_ID,
|
||||||
|
new DefaultMediaSourceFactory((Context) getApplicationContext()),
|
||||||
|
imaAdsLoader,
|
||||||
|
adViewProvider);
|
||||||
|
adsLoaderListener = new TestAdsLoaderListener(getInitialTimelineWindowDefinition(TEST_ADS_ID));
|
||||||
|
when(mockAdsManager.getAdCuePoints()).thenReturn(PREROLL_CUE_POINTS_SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void teardown() {
|
public void teardown() {
|
||||||
if (imaAdsLoader != null) {
|
imaAdsLoader.release();
|
||||||
imaAdsLoader.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void builder_overridesPlayerType() {
|
public void loader_overridesCustomPlayerType() {
|
||||||
when(mockImaSdkSettings.getPlayerType()).thenReturn("test player type");
|
when(mockImaSdkSettings.getPlayerType()).thenReturn("test player type");
|
||||||
setupPlayback(CONTENT_TIMELINE, PREROLL_CUE_POINTS_SECONDS);
|
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
@ -187,7 +198,6 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void start_setsAdUiViewGroup() {
|
public void start_setsAdUiViewGroup() {
|
||||||
setupPlayback(CONTENT_TIMELINE, PREROLL_CUE_POINTS_SECONDS);
|
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
@ -198,7 +208,6 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startForAudioOnlyAds_createsAudioOnlyAdDisplayContainer() {
|
public void startForAudioOnlyAds_createsAudioOnlyAdDisplayContainer() {
|
||||||
setupPlayback(CONTENT_TIMELINE, PREROLL_CUE_POINTS_SECONDS);
|
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, audioAdsAdViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, audioAdsAdViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
@ -210,8 +219,11 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void start_withPlaceholderContent_initializedAdsLoader() {
|
public void start_withPlaceholderContent_initializedAdsLoader() {
|
||||||
Timeline placeholderTimeline = new PlaceholderTimeline(MediaItem.fromUri(Uri.EMPTY));
|
adsLoaderListener =
|
||||||
setupPlayback(placeholderTimeline, PREROLL_CUE_POINTS_SECONDS);
|
new TestAdsLoaderListener(
|
||||||
|
getInitialTimelineWindowDefinition(TEST_ADS_ID, /* isPlaceholder= */ true));
|
||||||
|
|
||||||
|
when(mockAdsManager.getAdCuePoints()).thenReturn(PREROLL_CUE_POINTS_SECONDS);
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
@ -221,11 +233,10 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void start_updatesAdPlaybackState() {
|
public void start_updatesAdPlaybackState() {
|
||||||
setupPlayback(CONTENT_TIMELINE, PREROLL_CUE_POINTS_SECONDS);
|
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
|
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US));
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US));
|
||||||
@ -233,7 +244,6 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startAfterRelease() {
|
public void startAfterRelease() {
|
||||||
setupPlayback(CONTENT_TIMELINE, PREROLL_CUE_POINTS_SECONDS);
|
|
||||||
imaAdsLoader.release();
|
imaAdsLoader.release();
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
@ -241,14 +251,13 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startAndCallbacksAfterRelease() {
|
public void startAndCallbacksAfterRelease() {
|
||||||
setupPlayback(CONTENT_TIMELINE, PREROLL_CUE_POINTS_SECONDS);
|
|
||||||
// Request ads in order to get a reference to the ad event listener.
|
// Request ads in order to get a reference to the ad event listener.
|
||||||
imaAdsLoader.requestAds(TEST_DATA_SPEC, TEST_ADS_ID, adViewGroup);
|
imaAdsLoader.requestAds(TEST_DATA_SPEC, TEST_ADS_ID, adViewGroup);
|
||||||
imaAdsLoader.release();
|
imaAdsLoader.release();
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
fakeExoPlayer.setPlayingContentPosition(/* position= */ 0);
|
fakePlayer.setPlayingContentPosition(/* periodIndex= */ 0, /* positionMs= */ 0);
|
||||||
fakeExoPlayer.setState(Player.STATE_READY, true);
|
fakePlayer.setState(Player.STATE_READY, true);
|
||||||
|
|
||||||
// If callbacks are invoked there is no crash.
|
// If callbacks are invoked there is no crash.
|
||||||
// Note: we can't currently call getContentProgress/getAdProgress as a VerifyError is thrown
|
// Note: we can't currently call getContentProgress/getAdProgress as a VerifyError is thrown
|
||||||
@ -271,8 +280,6 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void playback_withPrerollAd_marksAdAsPlayed() {
|
public void playback_withPrerollAd_marksAdAsPlayed() {
|
||||||
setupPlayback(CONTENT_TIMELINE, PREROLL_CUE_POINTS_SECONDS);
|
|
||||||
|
|
||||||
// Load the preroll ad.
|
// Load the preroll ad.
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
@ -282,24 +289,25 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
// Play the preroll ad.
|
// Play the preroll ad.
|
||||||
videoAdPlayer.playAd(TEST_AD_MEDIA_INFO);
|
videoAdPlayer.playAd(TEST_AD_MEDIA_INFO);
|
||||||
fakeExoPlayer.setPlayingAdPosition(
|
fakePlayer.setPlayingAdPosition(
|
||||||
|
/* periodIndex= */ 0,
|
||||||
/* adGroupIndex= */ 0,
|
/* adGroupIndex= */ 0,
|
||||||
/* adIndexInAdGroup= */ 0,
|
/* adIndexInAdGroup= */ 0,
|
||||||
/* position= */ 0,
|
/* position= */ 0,
|
||||||
/* contentPosition= */ 0);
|
/* contentPosition= */ 0);
|
||||||
fakeExoPlayer.setState(Player.STATE_READY, true);
|
fakePlayer.setState(Player.STATE_READY, true);
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.STARTED, mockPrerollSingleAd));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.STARTED, mockPrerollSingleAd));
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.FIRST_QUARTILE, mockPrerollSingleAd));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.FIRST_QUARTILE, mockPrerollSingleAd));
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.MIDPOINT, mockPrerollSingleAd));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.MIDPOINT, mockPrerollSingleAd));
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.THIRD_QUARTILE, mockPrerollSingleAd));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.THIRD_QUARTILE, mockPrerollSingleAd));
|
||||||
|
|
||||||
// Play the content.
|
// Play the content.
|
||||||
fakeExoPlayer.setPlayingContentPosition(0);
|
fakePlayer.setPlayingContentPosition(/* periodIndex= */ 0, /* positionMs= */ 0);
|
||||||
videoAdPlayer.stopAd(TEST_AD_MEDIA_INFO);
|
videoAdPlayer.stopAd(TEST_AD_MEDIA_INFO);
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.CONTENT_RESUME_REQUESTED, /* ad= */ null));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.CONTENT_RESUME_REQUESTED, /* ad= */ null));
|
||||||
|
|
||||||
// Verify that the preroll ad has been marked as played.
|
// Verify that the preroll ad has been marked as played.
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
|
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
@ -316,14 +324,14 @@ public final class ImaAdsLoaderTest {
|
|||||||
when(mockMidrollFetchErrorAdEvent.getType()).thenReturn(AdEventType.AD_BREAK_FETCH_ERROR);
|
when(mockMidrollFetchErrorAdEvent.getType()).thenReturn(AdEventType.AD_BREAK_FETCH_ERROR);
|
||||||
when(mockMidrollFetchErrorAdEvent.getAdData())
|
when(mockMidrollFetchErrorAdEvent.getAdData())
|
||||||
.thenReturn(ImmutableMap.of("adBreakTime", "20.5"));
|
.thenReturn(ImmutableMap.of("adBreakTime", "20.5"));
|
||||||
setupPlayback(CONTENT_TIMELINE, ImmutableList.of(20.5f));
|
when(mockAdsManager.getAdCuePoints()).thenReturn(ImmutableList.of(20.5f));
|
||||||
|
|
||||||
// Simulate loading an empty midroll ad.
|
// Simulate loading an empty midroll ad.
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
adEventListener.onAdEvent(mockMidrollFetchErrorAdEvent);
|
adEventListener.onAdEvent(mockMidrollFetchErrorAdEvent);
|
||||||
|
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 20_500_000)
|
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 20_500_000)
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
@ -338,7 +346,7 @@ public final class ImaAdsLoaderTest {
|
|||||||
when(mockMidrollFetchErrorAdEvent.getType()).thenReturn(AdEventType.AD_BREAK_FETCH_ERROR);
|
when(mockMidrollFetchErrorAdEvent.getType()).thenReturn(AdEventType.AD_BREAK_FETCH_ERROR);
|
||||||
when(mockMidrollFetchErrorAdEvent.getAdData())
|
when(mockMidrollFetchErrorAdEvent.getAdData())
|
||||||
.thenReturn(ImmutableMap.of("adBreakTime", "5.5"));
|
.thenReturn(ImmutableMap.of("adBreakTime", "5.5"));
|
||||||
setupPlayback(CONTENT_TIMELINE, ImmutableList.of(5.5f));
|
when(mockAdsManager.getAdCuePoints()).thenReturn(ImmutableList.of(5.5f));
|
||||||
|
|
||||||
// Simulate loading an empty midroll ad and advancing the player position.
|
// Simulate loading an empty midroll ad and advancing the player position.
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
@ -349,7 +357,7 @@ public final class ImaAdsLoaderTest {
|
|||||||
playerPositionUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
playerPositionUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
||||||
long periodDurationUs =
|
long periodDurationUs =
|
||||||
CONTENT_TIMELINE.getPeriod(/* periodIndex= */ 0, new Period()).durationUs;
|
CONTENT_TIMELINE.getPeriod(/* periodIndex= */ 0, new Period()).durationUs;
|
||||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(playerPositionUs));
|
fakePlayer.setPlayingContentPosition(/* periodIndex= */ 0, C.usToMs(playerPositionUs));
|
||||||
|
|
||||||
// Verify the content progress is updated to reflect the new player position.
|
// Verify the content progress is updated to reflect the new player position.
|
||||||
assertThat(contentProgressProvider.getContentProgress())
|
assertThat(contentProgressProvider.getContentProgress())
|
||||||
@ -364,14 +372,14 @@ public final class ImaAdsLoaderTest {
|
|||||||
when(mockPostrollFetchErrorAdEvent.getType()).thenReturn(AdEventType.AD_BREAK_FETCH_ERROR);
|
when(mockPostrollFetchErrorAdEvent.getType()).thenReturn(AdEventType.AD_BREAK_FETCH_ERROR);
|
||||||
when(mockPostrollFetchErrorAdEvent.getAdData())
|
when(mockPostrollFetchErrorAdEvent.getAdData())
|
||||||
.thenReturn(ImmutableMap.of("adBreakTime", "-1"));
|
.thenReturn(ImmutableMap.of("adBreakTime", "-1"));
|
||||||
setupPlayback(CONTENT_TIMELINE, ImmutableList.of(-1f));
|
when(mockAdsManager.getAdCuePoints()).thenReturn(ImmutableList.of(-1f));
|
||||||
|
|
||||||
// Simulate loading an empty postroll ad.
|
// Simulate loading an empty postroll ad.
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
adEventListener.onAdEvent(mockPostrollFetchErrorAdEvent);
|
adEventListener.onAdEvent(mockPostrollFetchErrorAdEvent);
|
||||||
|
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ C.TIME_END_OF_SOURCE)
|
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ C.TIME_END_OF_SOURCE)
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
@ -388,18 +396,18 @@ public final class ImaAdsLoaderTest {
|
|||||||
adGroupPositionInWindowUs
|
adGroupPositionInWindowUs
|
||||||
+ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
+ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
||||||
ImmutableList<Float> cuePoints = ImmutableList.of((float) adGroupTimeUs / C.MICROS_PER_SECOND);
|
ImmutableList<Float> cuePoints = ImmutableList.of((float) adGroupTimeUs / C.MICROS_PER_SECOND);
|
||||||
setupPlayback(CONTENT_TIMELINE, cuePoints);
|
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
||||||
|
|
||||||
// Advance playback to just before the midroll and simulate buffering.
|
// Advance playback to just before the midroll and simulate buffering.
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(adGroupPositionInWindowUs));
|
fakePlayer.setPlayingContentPosition(/* periodIndex= */ 0, C.usToMs(adGroupPositionInWindowUs));
|
||||||
fakeExoPlayer.setState(Player.STATE_BUFFERING, /* playWhenReady= */ true);
|
fakePlayer.setState(Player.STATE_BUFFERING, /* playWhenReady= */ true);
|
||||||
// Advance before the timeout and simulating polling content progress.
|
// Advance before the timeout and simulating polling content progress.
|
||||||
ShadowSystemClock.advanceBy(Duration.ofSeconds(1));
|
ShadowSystemClock.advanceBy(Duration.ofSeconds(1));
|
||||||
contentProgressProvider.getContentProgress();
|
contentProgressProvider.getContentProgress();
|
||||||
|
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US));
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US));
|
||||||
@ -413,18 +421,18 @@ public final class ImaAdsLoaderTest {
|
|||||||
adGroupPositionInWindowUs
|
adGroupPositionInWindowUs
|
||||||
+ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
+ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
||||||
ImmutableList<Float> cuePoints = ImmutableList.of((float) adGroupTimeUs / C.MICROS_PER_SECOND);
|
ImmutableList<Float> cuePoints = ImmutableList.of((float) adGroupTimeUs / C.MICROS_PER_SECOND);
|
||||||
setupPlayback(CONTENT_TIMELINE, cuePoints);
|
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
||||||
|
|
||||||
// Advance playback to just before the midroll and simulate buffering.
|
// Advance playback to just before the midroll and simulate buffering.
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(adGroupPositionInWindowUs));
|
fakePlayer.setPlayingContentPosition(/* periodIndex= */ 0, C.usToMs(adGroupPositionInWindowUs));
|
||||||
fakeExoPlayer.setState(Player.STATE_BUFFERING, /* playWhenReady= */ true);
|
fakePlayer.setState(Player.STATE_BUFFERING, /* playWhenReady= */ true);
|
||||||
// Advance past the timeout and simulate polling content progress.
|
// Advance past the timeout and simulate polling content progress.
|
||||||
ShadowSystemClock.advanceBy(Duration.ofSeconds(5));
|
ShadowSystemClock.advanceBy(Duration.ofSeconds(5));
|
||||||
contentProgressProvider.getContentProgress();
|
contentProgressProvider.getContentProgress();
|
||||||
|
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
@ -440,14 +448,15 @@ public final class ImaAdsLoaderTest {
|
|||||||
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
||||||
ImmutableList<Float> cuePoints =
|
ImmutableList<Float> cuePoints =
|
||||||
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
||||||
setupPlayback(CONTENT_TIMELINE, cuePoints);
|
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
||||||
|
|
||||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(midrollWindowTimeUs) - 1_000);
|
fakePlayer.setPlayingContentPosition(
|
||||||
|
/* periodIndex= */ 0, C.usToMs(midrollWindowTimeUs) - 1_000);
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
verify(mockAdsRenderingSettings, never()).setPlayAdsAfterTime(anyDouble());
|
verify(mockAdsRenderingSettings, never()).setPlayAdsAfterTime(anyDouble());
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US));
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US));
|
||||||
@ -460,9 +469,9 @@ public final class ImaAdsLoaderTest {
|
|||||||
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
||||||
ImmutableList<Float> cuePoints =
|
ImmutableList<Float> cuePoints =
|
||||||
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
||||||
setupPlayback(CONTENT_TIMELINE, cuePoints);
|
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
||||||
|
|
||||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(midrollWindowTimeUs));
|
fakePlayer.setPlayingContentPosition(/* periodIndex= */ 0, C.usToMs(midrollWindowTimeUs));
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
@ -472,7 +481,7 @@ public final class ImaAdsLoaderTest {
|
|||||||
assertThat(playAdsAfterTimeCaptor.getValue())
|
assertThat(playAdsAfterTimeCaptor.getValue())
|
||||||
.isWithin(0.1)
|
.isWithin(0.1)
|
||||||
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
@ -486,9 +495,10 @@ public final class ImaAdsLoaderTest {
|
|||||||
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
||||||
ImmutableList<Float> cuePoints =
|
ImmutableList<Float> cuePoints =
|
||||||
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
||||||
setupPlayback(CONTENT_TIMELINE, cuePoints);
|
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
||||||
|
|
||||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(midrollWindowTimeUs) + 1_000);
|
fakePlayer.setPlayingContentPosition(
|
||||||
|
/* periodIndex= */ 0, C.usToMs(midrollWindowTimeUs) + 1_000);
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
@ -498,7 +508,7 @@ public final class ImaAdsLoaderTest {
|
|||||||
assertThat(playAdsAfterTimeCaptor.getValue())
|
assertThat(playAdsAfterTimeCaptor.getValue())
|
||||||
.isWithin(0.1)
|
.isWithin(0.1)
|
||||||
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
@ -519,14 +529,15 @@ public final class ImaAdsLoaderTest {
|
|||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
|
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
|
||||||
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
||||||
setupPlayback(CONTENT_TIMELINE, cuePoints);
|
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
||||||
|
|
||||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(secondMidrollWindowTimeUs) - 1_000);
|
fakePlayer.setPlayingContentPosition(
|
||||||
|
/* periodIndex= */ 0, C.usToMs(secondMidrollWindowTimeUs) - 1_000);
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
verify(mockAdsRenderingSettings, never()).setPlayAdsAfterTime(anyDouble());
|
verify(mockAdsRenderingSettings, never()).setPlayAdsAfterTime(anyDouble());
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US));
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US));
|
||||||
@ -546,9 +557,9 @@ public final class ImaAdsLoaderTest {
|
|||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
|
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
|
||||||
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
||||||
setupPlayback(CONTENT_TIMELINE, cuePoints);
|
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
||||||
|
|
||||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(secondMidrollWindowTimeUs));
|
fakePlayer.setPlayingContentPosition(/* periodIndex= */ 0, C.usToMs(secondMidrollWindowTimeUs));
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
@ -558,7 +569,7 @@ public final class ImaAdsLoaderTest {
|
|||||||
assertThat(playAdsAfterTimeCaptor.getValue())
|
assertThat(playAdsAfterTimeCaptor.getValue())
|
||||||
.isWithin(0.1)
|
.isWithin(0.1)
|
||||||
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
@ -567,23 +578,30 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resumePlaybackBeforeMidroll_withoutPlayAdBeforeStartPosition_skipsPreroll() {
|
public void resumePlaybackBeforeMidroll_withoutPlayAdBeforeStartPosition_skipsPreroll() {
|
||||||
|
imaAdsLoader =
|
||||||
|
new ImaAdsLoader.Builder(getApplicationContext())
|
||||||
|
.setPlayAdBeforeStartPosition(false)
|
||||||
|
.setImaFactory(mockImaFactory)
|
||||||
|
.setImaSdkSettings(mockImaSdkSettings)
|
||||||
|
.build();
|
||||||
|
imaAdsLoader.setPlayer(fakePlayer);
|
||||||
|
adsMediaSource =
|
||||||
|
new AdsMediaSource(
|
||||||
|
new FakeMediaSource(CONTENT_TIMELINE),
|
||||||
|
TEST_DATA_SPEC,
|
||||||
|
TEST_ADS_ID,
|
||||||
|
new DefaultMediaSourceFactory((Context) getApplicationContext()),
|
||||||
|
imaAdsLoader,
|
||||||
|
adViewProvider);
|
||||||
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
|
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
|
||||||
long midrollPeriodTimeUs =
|
long midrollPeriodTimeUs =
|
||||||
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
||||||
ImmutableList<Float> cuePoints =
|
ImmutableList<Float> cuePoints =
|
||||||
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
||||||
setupPlayback(
|
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
||||||
CONTENT_TIMELINE,
|
|
||||||
cuePoints,
|
|
||||||
new ImaAdsLoader.Builder(getApplicationContext())
|
|
||||||
.setPlayAdBeforeStartPosition(false)
|
|
||||||
.setImaFactory(mockImaFactory)
|
|
||||||
.setImaSdkSettings(mockImaSdkSettings)
|
|
||||||
.build(),
|
|
||||||
TEST_DATA_SPEC,
|
|
||||||
TEST_ADS_ID);
|
|
||||||
|
|
||||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(midrollWindowTimeUs) - 1_000);
|
fakePlayer.setPlayingContentPosition(
|
||||||
|
/* periodIndex= */ 0, C.usToMs(midrollWindowTimeUs) - 1_000);
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
@ -593,7 +611,7 @@ public final class ImaAdsLoaderTest {
|
|||||||
assertThat(playAdsAfterTimeCaptor.getValue())
|
assertThat(playAdsAfterTimeCaptor.getValue())
|
||||||
.isWithin(0.1d)
|
.isWithin(0.1d)
|
||||||
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
||||||
.withSkippedAdGroup(/* adGroupIndex= */ 0)
|
.withSkippedAdGroup(/* adGroupIndex= */ 0)
|
||||||
@ -602,23 +620,29 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resumePlaybackAtMidroll_withoutPlayAdBeforeStartPosition_skipsPreroll() {
|
public void resumePlaybackAtMidroll_withoutPlayAdBeforeStartPosition_skipsPreroll() {
|
||||||
|
imaAdsLoader =
|
||||||
|
new ImaAdsLoader.Builder(getApplicationContext())
|
||||||
|
.setPlayAdBeforeStartPosition(false)
|
||||||
|
.setImaFactory(mockImaFactory)
|
||||||
|
.setImaSdkSettings(mockImaSdkSettings)
|
||||||
|
.build();
|
||||||
|
imaAdsLoader.setPlayer(fakePlayer);
|
||||||
|
adsMediaSource =
|
||||||
|
new AdsMediaSource(
|
||||||
|
new FakeMediaSource(CONTENT_TIMELINE),
|
||||||
|
TEST_DATA_SPEC,
|
||||||
|
TEST_ADS_ID,
|
||||||
|
new DefaultMediaSourceFactory((Context) getApplicationContext()),
|
||||||
|
imaAdsLoader,
|
||||||
|
adViewProvider);
|
||||||
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
|
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
|
||||||
long midrollPeriodTimeUs =
|
long midrollPeriodTimeUs =
|
||||||
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
||||||
ImmutableList<Float> cuePoints =
|
ImmutableList<Float> cuePoints =
|
||||||
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
||||||
setupPlayback(
|
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
||||||
CONTENT_TIMELINE,
|
|
||||||
cuePoints,
|
|
||||||
new ImaAdsLoader.Builder(getApplicationContext())
|
|
||||||
.setPlayAdBeforeStartPosition(false)
|
|
||||||
.setImaFactory(mockImaFactory)
|
|
||||||
.setImaSdkSettings(mockImaSdkSettings)
|
|
||||||
.build(),
|
|
||||||
TEST_DATA_SPEC,
|
|
||||||
TEST_ADS_ID);
|
|
||||||
|
|
||||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(midrollWindowTimeUs));
|
fakePlayer.setPlayingContentPosition(/* periodIndex= */ 0, C.usToMs(midrollWindowTimeUs));
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
@ -628,7 +652,7 @@ public final class ImaAdsLoaderTest {
|
|||||||
assertThat(playAdsAfterTimeCaptor.getValue())
|
assertThat(playAdsAfterTimeCaptor.getValue())
|
||||||
.isWithin(0.1d)
|
.isWithin(0.1d)
|
||||||
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
@ -637,28 +661,35 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resumePlaybackAfterMidroll_withoutPlayAdBeforeStartPosition_skipsMidroll() {
|
public void resumePlaybackAfterMidroll_withoutPlayAdBeforeStartPosition_skipsMidroll() {
|
||||||
|
imaAdsLoader =
|
||||||
|
new ImaAdsLoader.Builder(getApplicationContext())
|
||||||
|
.setPlayAdBeforeStartPosition(false)
|
||||||
|
.setImaFactory(mockImaFactory)
|
||||||
|
.setImaSdkSettings(mockImaSdkSettings)
|
||||||
|
.build();
|
||||||
|
imaAdsLoader.setPlayer(fakePlayer);
|
||||||
|
adsMediaSource =
|
||||||
|
new AdsMediaSource(
|
||||||
|
new FakeMediaSource(CONTENT_TIMELINE),
|
||||||
|
TEST_DATA_SPEC,
|
||||||
|
TEST_ADS_ID,
|
||||||
|
new DefaultMediaSourceFactory((Context) getApplicationContext()),
|
||||||
|
imaAdsLoader,
|
||||||
|
adViewProvider);
|
||||||
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
|
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
|
||||||
long midrollPeriodTimeUs =
|
long midrollPeriodTimeUs =
|
||||||
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
||||||
ImmutableList<Float> cuePoints =
|
ImmutableList<Float> cuePoints =
|
||||||
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
||||||
setupPlayback(
|
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
||||||
CONTENT_TIMELINE,
|
|
||||||
cuePoints,
|
|
||||||
new ImaAdsLoader.Builder(getApplicationContext())
|
|
||||||
.setPlayAdBeforeStartPosition(false)
|
|
||||||
.setImaFactory(mockImaFactory)
|
|
||||||
.setImaSdkSettings(mockImaSdkSettings)
|
|
||||||
.build(),
|
|
||||||
TEST_DATA_SPEC,
|
|
||||||
TEST_ADS_ID);
|
|
||||||
|
|
||||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(midrollWindowTimeUs) + 1_000);
|
fakePlayer.setPlayingContentPosition(
|
||||||
|
/* periodIndex= */ 0, C.usToMs(midrollWindowTimeUs) + 1_000);
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
verify(mockAdsManager).destroy();
|
verify(mockAdsManager).destroy();
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
@ -669,6 +700,21 @@ public final class ImaAdsLoaderTest {
|
|||||||
@Test
|
@Test
|
||||||
public void
|
public void
|
||||||
resumePlaybackBeforeSecondMidroll_withoutPlayAdBeforeStartPosition_skipsFirstMidroll() {
|
resumePlaybackBeforeSecondMidroll_withoutPlayAdBeforeStartPosition_skipsFirstMidroll() {
|
||||||
|
imaAdsLoader =
|
||||||
|
new ImaAdsLoader.Builder(getApplicationContext())
|
||||||
|
.setPlayAdBeforeStartPosition(false)
|
||||||
|
.setImaFactory(mockImaFactory)
|
||||||
|
.setImaSdkSettings(mockImaSdkSettings)
|
||||||
|
.build();
|
||||||
|
imaAdsLoader.setPlayer(fakePlayer);
|
||||||
|
adsMediaSource =
|
||||||
|
new AdsMediaSource(
|
||||||
|
new FakeMediaSource(CONTENT_TIMELINE),
|
||||||
|
TEST_DATA_SPEC,
|
||||||
|
TEST_ADS_ID,
|
||||||
|
new DefaultMediaSourceFactory((Context) getApplicationContext()),
|
||||||
|
imaAdsLoader,
|
||||||
|
adViewProvider);
|
||||||
long firstMidrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
|
long firstMidrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
|
||||||
long firstMidrollPeriodTimeUs =
|
long firstMidrollPeriodTimeUs =
|
||||||
firstMidrollWindowTimeUs
|
firstMidrollWindowTimeUs
|
||||||
@ -681,18 +727,10 @@ public final class ImaAdsLoaderTest {
|
|||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
|
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
|
||||||
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
||||||
setupPlayback(
|
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
||||||
CONTENT_TIMELINE,
|
|
||||||
cuePoints,
|
|
||||||
new ImaAdsLoader.Builder(getApplicationContext())
|
|
||||||
.setPlayAdBeforeStartPosition(false)
|
|
||||||
.setImaFactory(mockImaFactory)
|
|
||||||
.setImaSdkSettings(mockImaSdkSettings)
|
|
||||||
.build(),
|
|
||||||
TEST_DATA_SPEC,
|
|
||||||
TEST_ADS_ID);
|
|
||||||
|
|
||||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(secondMidrollWindowTimeUs) - 1_000);
|
fakePlayer.setPlayingContentPosition(
|
||||||
|
/* periodIndex= */ 0, C.usToMs(secondMidrollWindowTimeUs) - 1_000);
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
@ -702,7 +740,7 @@ public final class ImaAdsLoaderTest {
|
|||||||
assertThat(playAdsAfterTimeCaptor.getValue())
|
assertThat(playAdsAfterTimeCaptor.getValue())
|
||||||
.isWithin(0.1d)
|
.isWithin(0.1d)
|
||||||
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
||||||
.withSkippedAdGroup(/* adGroupIndex= */ 0)
|
.withSkippedAdGroup(/* adGroupIndex= */ 0)
|
||||||
@ -711,6 +749,21 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resumePlaybackAtSecondMidroll_withoutPlayAdBeforeStartPosition_skipsFirstMidroll() {
|
public void resumePlaybackAtSecondMidroll_withoutPlayAdBeforeStartPosition_skipsFirstMidroll() {
|
||||||
|
imaAdsLoader =
|
||||||
|
new ImaAdsLoader.Builder(getApplicationContext())
|
||||||
|
.setPlayAdBeforeStartPosition(false)
|
||||||
|
.setImaFactory(mockImaFactory)
|
||||||
|
.setImaSdkSettings(mockImaSdkSettings)
|
||||||
|
.build();
|
||||||
|
imaAdsLoader.setPlayer(fakePlayer);
|
||||||
|
adsMediaSource =
|
||||||
|
new AdsMediaSource(
|
||||||
|
new FakeMediaSource(CONTENT_TIMELINE),
|
||||||
|
TEST_DATA_SPEC,
|
||||||
|
TEST_ADS_ID,
|
||||||
|
new DefaultMediaSourceFactory((Context) getApplicationContext()),
|
||||||
|
imaAdsLoader,
|
||||||
|
adViewProvider);
|
||||||
long firstMidrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
|
long firstMidrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
|
||||||
long firstMidrollPeriodTimeUs =
|
long firstMidrollPeriodTimeUs =
|
||||||
firstMidrollWindowTimeUs
|
firstMidrollWindowTimeUs
|
||||||
@ -723,18 +776,9 @@ public final class ImaAdsLoaderTest {
|
|||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
|
(float) firstMidrollPeriodTimeUs / C.MICROS_PER_SECOND,
|
||||||
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
(float) secondMidrollPeriodTimeUs / C.MICROS_PER_SECOND);
|
||||||
setupPlayback(
|
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
||||||
CONTENT_TIMELINE,
|
|
||||||
cuePoints,
|
|
||||||
new ImaAdsLoader.Builder(getApplicationContext())
|
|
||||||
.setPlayAdBeforeStartPosition(false)
|
|
||||||
.setImaFactory(mockImaFactory)
|
|
||||||
.setImaSdkSettings(mockImaSdkSettings)
|
|
||||||
.build(),
|
|
||||||
TEST_DATA_SPEC,
|
|
||||||
TEST_ADS_ID);
|
|
||||||
|
|
||||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(secondMidrollWindowTimeUs));
|
fakePlayer.setPlayingContentPosition(/* periodIndex= */ 0, C.usToMs(secondMidrollWindowTimeUs));
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
@ -744,7 +788,7 @@ public final class ImaAdsLoaderTest {
|
|||||||
assertThat(playAdsAfterTimeCaptor.getValue())
|
assertThat(playAdsAfterTimeCaptor.getValue())
|
||||||
.isWithin(0.1d)
|
.isWithin(0.1d)
|
||||||
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
.of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
@ -762,16 +806,6 @@ public final class ImaAdsLoaderTest {
|
|||||||
+ " </Ad>\n"
|
+ " </Ad>\n"
|
||||||
+ "</VAST>";
|
+ "</VAST>";
|
||||||
DataSpec adDataSpec = new DataSpec(Util.getDataUriForString("text/xml", adsResponse));
|
DataSpec adDataSpec = new DataSpec(Util.getDataUriForString("text/xml", adsResponse));
|
||||||
|
|
||||||
setupPlayback(
|
|
||||||
CONTENT_TIMELINE,
|
|
||||||
ImmutableList.of(0f),
|
|
||||||
new ImaAdsLoader.Builder(getApplicationContext())
|
|
||||||
.setImaFactory(mockImaFactory)
|
|
||||||
.setImaSdkSettings(mockImaSdkSettings)
|
|
||||||
.build(),
|
|
||||||
adDataSpec,
|
|
||||||
TEST_ADS_ID);
|
|
||||||
imaAdsLoader.start(adsMediaSource, adDataSpec, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
imaAdsLoader.start(adsMediaSource, adDataSpec, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
verify(mockAdsRequest).setAdsResponse(adsResponse);
|
verify(mockAdsRequest).setAdsResponse(adsResponse);
|
||||||
@ -779,15 +813,6 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void requestAdTagWithUri_requestsWithAdTagUrl() throws Exception {
|
public void requestAdTagWithUri_requestsWithAdTagUrl() throws Exception {
|
||||||
setupPlayback(
|
|
||||||
CONTENT_TIMELINE,
|
|
||||||
ImmutableList.of(0f),
|
|
||||||
new ImaAdsLoader.Builder(getApplicationContext())
|
|
||||||
.setImaFactory(mockImaFactory)
|
|
||||||
.setImaSdkSettings(mockImaSdkSettings)
|
|
||||||
.build(),
|
|
||||||
TEST_DATA_SPEC,
|
|
||||||
TEST_ADS_ID);
|
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
@ -796,7 +821,6 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setsDefaultMimeTypes() throws Exception {
|
public void setsDefaultMimeTypes() throws Exception {
|
||||||
setupPlayback(CONTENT_TIMELINE, ImmutableList.of(0f));
|
|
||||||
imaAdsLoader.setSupportedContentTypes(C.TYPE_DASH, C.TYPE_OTHER);
|
imaAdsLoader.setSupportedContentTypes(C.TYPE_DASH, C.TYPE_OTHER);
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
@ -814,16 +838,23 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void buildWithAdMediaMimeTypes_setsMimeTypes() throws Exception {
|
public void buildWithAdMediaMimeTypes_setsMimeTypes() throws Exception {
|
||||||
setupPlayback(
|
imaAdsLoader =
|
||||||
CONTENT_TIMELINE,
|
|
||||||
ImmutableList.of(0f),
|
|
||||||
new ImaAdsLoader.Builder(getApplicationContext())
|
new ImaAdsLoader.Builder(getApplicationContext())
|
||||||
|
.setAdMediaMimeTypes(ImmutableList.of(MimeTypes.AUDIO_MPEG))
|
||||||
.setImaFactory(mockImaFactory)
|
.setImaFactory(mockImaFactory)
|
||||||
.setImaSdkSettings(mockImaSdkSettings)
|
.setImaSdkSettings(mockImaSdkSettings)
|
||||||
.setAdMediaMimeTypes(ImmutableList.of(MimeTypes.AUDIO_MPEG))
|
.build();
|
||||||
.build(),
|
imaAdsLoader.setPlayer(fakePlayer);
|
||||||
TEST_DATA_SPEC,
|
adsMediaSource =
|
||||||
TEST_ADS_ID);
|
new AdsMediaSource(
|
||||||
|
new FakeMediaSource(CONTENT_TIMELINE),
|
||||||
|
TEST_DATA_SPEC,
|
||||||
|
TEST_ADS_ID,
|
||||||
|
new DefaultMediaSourceFactory((Context) getApplicationContext()),
|
||||||
|
imaAdsLoader,
|
||||||
|
adViewProvider);
|
||||||
|
when(mockAdsManager.getAdCuePoints()).thenReturn(PREROLL_CUE_POINTS_SECONDS);
|
||||||
|
|
||||||
imaAdsLoader.setSupportedContentTypes(C.TYPE_OTHER);
|
imaAdsLoader.setSupportedContentTypes(C.TYPE_OTHER);
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
@ -833,7 +864,6 @@ public final class ImaAdsLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void stop_unregistersAllVideoControlOverlays() {
|
public void stop_unregistersAllVideoControlOverlays() {
|
||||||
setupPlayback(CONTENT_TIMELINE, PREROLL_CUE_POINTS_SECONDS);
|
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
imaAdsLoader.requestAds(TEST_DATA_SPEC, TEST_ADS_ID, adViewGroup);
|
imaAdsLoader.requestAds(TEST_DATA_SPEC, TEST_ADS_ID, adViewGroup);
|
||||||
@ -848,8 +878,9 @@ public final class ImaAdsLoaderTest {
|
|||||||
public void loadAd_withLargeAdCuePoint_updatesAdPlaybackStateWithLoadedAd() {
|
public void loadAd_withLargeAdCuePoint_updatesAdPlaybackStateWithLoadedAd() {
|
||||||
// Use a large enough value to test correct truncating of large cue points.
|
// Use a large enough value to test correct truncating of large cue points.
|
||||||
float midrollTimeSecs = Float.MAX_VALUE;
|
float midrollTimeSecs = Float.MAX_VALUE;
|
||||||
ImmutableList<Float> cuePoints = ImmutableList.of(midrollTimeSecs);
|
List<Float> cuePoints = ImmutableList.of(midrollTimeSecs);
|
||||||
setupPlayback(CONTENT_TIMELINE, cuePoints);
|
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
||||||
|
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
videoAdPlayer.loadAd(
|
videoAdPlayer.loadAd(
|
||||||
@ -886,7 +917,7 @@ public final class ImaAdsLoaderTest {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
assertThat(adsLoaderListener.adPlaybackState)
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints))
|
||||||
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
@ -895,37 +926,126 @@ public final class ImaAdsLoaderTest {
|
|||||||
.withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}}));
|
.withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupPlayback(Timeline contentTimeline, List<Float> cuePoints) {
|
@Test
|
||||||
setupPlayback(
|
public void playbackWithTwoAdsMediaSources_preloadsSecondAdTag() {
|
||||||
contentTimeline,
|
Object secondAdsId = new Object();
|
||||||
cuePoints,
|
AdsMediaSource secondAdsMediaSource =
|
||||||
new ImaAdsLoader.Builder(getApplicationContext())
|
|
||||||
.setImaFactory(mockImaFactory)
|
|
||||||
.setImaSdkSettings(mockImaSdkSettings)
|
|
||||||
.build(),
|
|
||||||
TEST_DATA_SPEC,
|
|
||||||
TEST_ADS_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupPlayback(
|
|
||||||
Timeline contentTimeline,
|
|
||||||
List<Float> cuePoints,
|
|
||||||
ImaAdsLoader imaAdsLoader,
|
|
||||||
DataSpec adTagDataSpec,
|
|
||||||
Object adsId) {
|
|
||||||
fakeExoPlayer = new FakePlayer();
|
|
||||||
adsLoaderListener = new TestAdsLoaderListener(fakeExoPlayer, contentTimeline);
|
|
||||||
adsMediaSource =
|
|
||||||
new AdsMediaSource(
|
new AdsMediaSource(
|
||||||
new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1)),
|
new FakeMediaSource(CONTENT_TIMELINE),
|
||||||
adTagDataSpec,
|
TEST_DATA_SPEC,
|
||||||
adsId,
|
secondAdsId,
|
||||||
new DefaultMediaSourceFactory((Context) getApplicationContext()),
|
new DefaultMediaSourceFactory((Context) getApplicationContext()),
|
||||||
imaAdsLoader,
|
imaAdsLoader,
|
||||||
adViewProvider);
|
adViewProvider);
|
||||||
when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
|
adsLoaderListener =
|
||||||
this.imaAdsLoader = imaAdsLoader;
|
new TestAdsLoaderListener(
|
||||||
imaAdsLoader.setPlayer(fakeExoPlayer);
|
getInitialTimelineWindowDefinition(TEST_ADS_ID),
|
||||||
|
getInitialTimelineWindowDefinition(secondAdsId));
|
||||||
|
|
||||||
|
// Load and play the preroll ad then content.
|
||||||
|
imaAdsLoader.start(
|
||||||
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.LOADED, mockPrerollSingleAd));
|
||||||
|
videoAdPlayer.loadAd(TEST_AD_MEDIA_INFO, mockAdPodInfo);
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.CONTENT_PAUSE_REQUESTED, mockPrerollSingleAd));
|
||||||
|
videoAdPlayer.playAd(TEST_AD_MEDIA_INFO);
|
||||||
|
fakePlayer.setPlayingAdPosition(
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
/* adGroupIndex= */ 0,
|
||||||
|
/* adIndexInAdGroup= */ 0,
|
||||||
|
/* position= */ 0,
|
||||||
|
/* contentPosition= */ 0);
|
||||||
|
fakePlayer.setState(Player.STATE_READY, true);
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.STARTED, mockPrerollSingleAd));
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.FIRST_QUARTILE, mockPrerollSingleAd));
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.MIDPOINT, mockPrerollSingleAd));
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.THIRD_QUARTILE, mockPrerollSingleAd));
|
||||||
|
fakePlayer.setPlayingContentPosition(/* periodIndex= */ 0, /* positionMs= */ 0);
|
||||||
|
videoAdPlayer.stopAd(TEST_AD_MEDIA_INFO);
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.CONTENT_RESUME_REQUESTED, /* ad= */ null));
|
||||||
|
|
||||||
|
// Simulate starting to buffer the second ads media source.
|
||||||
|
imaAdsLoader.start(
|
||||||
|
secondAdsMediaSource, TEST_DATA_SPEC, secondAdsId, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
|
// Verify that the preroll ad has been marked as played.
|
||||||
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
|
.isEqualTo(
|
||||||
|
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
|
||||||
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
|
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
|
||||||
|
.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI)
|
||||||
|
.withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}})
|
||||||
|
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)
|
||||||
|
.withAdResumePositionUs(/* adResumePositionUs= */ 0));
|
||||||
|
// Verify that the second source's ad cue points have preloaded.
|
||||||
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 1))
|
||||||
|
.isEqualTo(new AdPlaybackState(secondAdsId, /* adGroupTimesUs...= */ 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void playbackWithTwoAdsMediaSources_preloadsSecondAdTagWithBackgroundResume() {
|
||||||
|
Object secondAdsId = new Object();
|
||||||
|
AdsMediaSource secondAdsMediaSource =
|
||||||
|
new AdsMediaSource(
|
||||||
|
new FakeMediaSource(CONTENT_TIMELINE),
|
||||||
|
TEST_DATA_SPEC,
|
||||||
|
secondAdsId,
|
||||||
|
new DefaultMediaSourceFactory((Context) getApplicationContext()),
|
||||||
|
imaAdsLoader,
|
||||||
|
adViewProvider);
|
||||||
|
adsLoaderListener =
|
||||||
|
new TestAdsLoaderListener(
|
||||||
|
getInitialTimelineWindowDefinition(TEST_ADS_ID),
|
||||||
|
getInitialTimelineWindowDefinition(secondAdsId));
|
||||||
|
|
||||||
|
// Load and play the preroll ad then content.
|
||||||
|
imaAdsLoader.start(
|
||||||
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.LOADED, mockPrerollSingleAd));
|
||||||
|
videoAdPlayer.loadAd(TEST_AD_MEDIA_INFO, mockAdPodInfo);
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.CONTENT_PAUSE_REQUESTED, mockPrerollSingleAd));
|
||||||
|
videoAdPlayer.playAd(TEST_AD_MEDIA_INFO);
|
||||||
|
fakePlayer.setPlayingAdPosition(
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
/* adGroupIndex= */ 0,
|
||||||
|
/* adIndexInAdGroup= */ 0,
|
||||||
|
/* position= */ 0,
|
||||||
|
/* contentPosition= */ 0);
|
||||||
|
fakePlayer.setState(Player.STATE_READY, true);
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.STARTED, mockPrerollSingleAd));
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.FIRST_QUARTILE, mockPrerollSingleAd));
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.MIDPOINT, mockPrerollSingleAd));
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.THIRD_QUARTILE, mockPrerollSingleAd));
|
||||||
|
fakePlayer.setPlayingContentPosition(/* periodIndex= */ 0, /* positionMs= */ 0);
|
||||||
|
videoAdPlayer.stopAd(TEST_AD_MEDIA_INFO);
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.CONTENT_RESUME_REQUESTED, /* ad= */ null));
|
||||||
|
|
||||||
|
// Simulate starting to buffer the second ads media source.
|
||||||
|
imaAdsLoader.start(
|
||||||
|
secondAdsMediaSource, TEST_DATA_SPEC, secondAdsId, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
|
// Simulate backgrounding/resuming.
|
||||||
|
imaAdsLoader.stop(adsMediaSource);
|
||||||
|
imaAdsLoader.stop(secondAdsMediaSource);
|
||||||
|
imaAdsLoader.start(
|
||||||
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
imaAdsLoader.start(
|
||||||
|
secondAdsMediaSource, TEST_DATA_SPEC, secondAdsId, adViewProvider, adsLoaderListener);
|
||||||
|
|
||||||
|
// Verify that the preroll ad has been marked as played.
|
||||||
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 0))
|
||||||
|
.isEqualTo(
|
||||||
|
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
|
||||||
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
|
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
|
||||||
|
.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI)
|
||||||
|
.withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}})
|
||||||
|
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)
|
||||||
|
.withAdResumePositionUs(/* adResumePositionUs= */ 0));
|
||||||
|
// Verify that the second source's ad cue points have preloaded.
|
||||||
|
assertThat(adsLoaderListener.getAdPlaybackState(/* periodIndex= */ 1))
|
||||||
|
.isEqualTo(new AdPlaybackState(secondAdsId, /* adGroupTimesUs...= */ 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupMocks() {
|
private void setupMocks() {
|
||||||
@ -1023,16 +1143,16 @@ public final class ImaAdsLoaderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Ad loader event listener that forwards ad playback state to a fake player. */
|
/** Ad loader event listener that forwards ad playback state to a fake player. */
|
||||||
private static final class TestAdsLoaderListener implements AdsLoader.EventListener {
|
private final class TestAdsLoaderListener implements AdsLoader.EventListener {
|
||||||
|
|
||||||
private final FakePlayer fakeExoPlayer;
|
private final TimelineWindowDefinition[] timelineWindowDefinitions;
|
||||||
private final Timeline contentTimeline;
|
|
||||||
|
|
||||||
public AdPlaybackState adPlaybackState;
|
public TestAdsLoaderListener(TimelineWindowDefinition... timelineWindowDefinitions) {
|
||||||
|
this.timelineWindowDefinitions = timelineWindowDefinitions;
|
||||||
|
}
|
||||||
|
|
||||||
public TestAdsLoaderListener(FakePlayer fakeExoPlayer, Timeline contentTimeline) {
|
public AdPlaybackState getAdPlaybackState(int periodIndex) {
|
||||||
this.fakeExoPlayer = fakeExoPlayer;
|
return timelineWindowDefinitions[periodIndex].adPlaybackState;
|
||||||
this.contentTimeline = contentTimeline;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1043,10 +1163,28 @@ public final class ImaAdsLoaderTest {
|
|||||||
Arrays.fill(adDurationsUs[adGroupIndex], TEST_AD_DURATION_US);
|
Arrays.fill(adDurationsUs[adGroupIndex], TEST_AD_DURATION_US);
|
||||||
}
|
}
|
||||||
adPlaybackState = adPlaybackState.withAdDurationsUs(adDurationsUs);
|
adPlaybackState = adPlaybackState.withAdDurationsUs(adDurationsUs);
|
||||||
this.adPlaybackState = adPlaybackState;
|
|
||||||
fakeExoPlayer.updateTimeline(
|
// Update the timeline window definition(s) to reflect the new ad playback state.
|
||||||
new SinglePeriodAdTimeline(contentTimeline, adPlaybackState),
|
for (int i = 0; i < timelineWindowDefinitions.length; i++) {
|
||||||
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE);
|
TimelineWindowDefinition timelineWindowDefinition = timelineWindowDefinitions[i];
|
||||||
|
if (!Util.areEqual(timelineWindowDefinition.adPlaybackState.adsId, adPlaybackState.adsId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
timelineWindowDefinitions[i] =
|
||||||
|
new TimelineWindowDefinition(
|
||||||
|
timelineWindowDefinition.periodCount,
|
||||||
|
timelineWindowDefinition.id,
|
||||||
|
timelineWindowDefinition.isSeekable,
|
||||||
|
timelineWindowDefinition.isDynamic,
|
||||||
|
timelineWindowDefinition.isLive,
|
||||||
|
timelineWindowDefinition.isPlaceholder,
|
||||||
|
timelineWindowDefinition.durationUs,
|
||||||
|
timelineWindowDefinition.defaultPositionUs,
|
||||||
|
timelineWindowDefinition.windowOffsetInFirstPeriodUs,
|
||||||
|
adPlaybackState);
|
||||||
|
}
|
||||||
|
fakePlayer.updateTimeline(
|
||||||
|
new FakeTimeline(timelineWindowDefinitions), Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1064,4 +1202,24 @@ public final class ImaAdsLoaderTest {
|
|||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static TimelineWindowDefinition getInitialTimelineWindowDefinition(Object adsId) {
|
||||||
|
return getInitialTimelineWindowDefinition(adsId, /* isPlaceholder= */ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TimelineWindowDefinition getInitialTimelineWindowDefinition(
|
||||||
|
Object adsId, boolean isPlaceholder) {
|
||||||
|
return new TimelineWindowDefinition(
|
||||||
|
/* periodCount= */ 1,
|
||||||
|
/* id= */ new Object(),
|
||||||
|
/* isSeekable= */ true,
|
||||||
|
/* isDynamic= */ false,
|
||||||
|
/* isLive= */ false,
|
||||||
|
/* isPlaceholder= */ isPlaceholder,
|
||||||
|
/* durationUs= */ CONTENT_DURATION_US,
|
||||||
|
/* defaultPositionUs= */ 0,
|
||||||
|
/* windowOffsetInFirstPeriodUs= */ TimelineWindowDefinition
|
||||||
|
.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
|
||||||
|
new AdPlaybackState(adsId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user