mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add Builder for ImaAdsLoader and allow early requestAds
Also fix propagation of ad errors that occur when no player is attached. Issue: #3548 Issue: #3556 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=178767997
This commit is contained in:
parent
a4ae206ebe
commit
e2bba1567e
@ -51,6 +51,10 @@
|
|||||||
* Fix ad loading when there is no preroll.
|
* Fix ad loading when there is no preroll.
|
||||||
* Add an option to turn off hiding controls during ad playback
|
* Add an option to turn off hiding controls during ad playback
|
||||||
([#3532](https://github.com/google/ExoPlayer/issues/3532)).
|
([#3532](https://github.com/google/ExoPlayer/issues/3532)).
|
||||||
|
* Support specifying an ads response instead of an ad tag
|
||||||
|
([#3548](https://github.com/google/ExoPlayer/issues/3548)).
|
||||||
|
* Support overriding the ad load timeout
|
||||||
|
([#3556](https://github.com/google/ExoPlayer/issues/3556)).
|
||||||
|
|
||||||
### 2.6.0 ###
|
### 2.6.0 ###
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import android.content.Context;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.support.annotation.IntDef;
|
import android.support.annotation.IntDef;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
@ -65,10 +66,80 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public final class ImaAdsLoader extends Player.DefaultEventListener implements AdsLoader,
|
public final class ImaAdsLoader extends Player.DefaultEventListener implements AdsLoader,
|
||||||
VideoAdPlayer, ContentProgressProvider, AdErrorListener, AdsLoadedListener, AdEventListener {
|
VideoAdPlayer, ContentProgressProvider, AdErrorListener, AdsLoadedListener, AdEventListener {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ExoPlayerLibraryInfo.registerModule("goog.exo.ima");
|
ExoPlayerLibraryInfo.registerModule("goog.exo.ima");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Builder for {@link ImaAdsLoader}. */
|
||||||
|
public static final class Builder {
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
private @Nullable ImaSdkSettings imaSdkSettings;
|
||||||
|
private long vastLoadTimeoutMs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new builder for {@link ImaAdsLoader}.
|
||||||
|
*
|
||||||
|
* @param context The context;
|
||||||
|
*/
|
||||||
|
public Builder(Context context) {
|
||||||
|
this.context = Assertions.checkNotNull(context);
|
||||||
|
vastLoadTimeoutMs = C.TIME_UNSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the IMA SDK settings. The provided settings instance's player type and version fields
|
||||||
|
* may be overwritten.
|
||||||
|
*
|
||||||
|
* <p>If this method is not called the default settings will be used.
|
||||||
|
*
|
||||||
|
* @param imaSdkSettings The {@link ImaSdkSettings}.
|
||||||
|
* @return This builder, for convenience.
|
||||||
|
*/
|
||||||
|
public Builder setImaSdkSettings(ImaSdkSettings imaSdkSettings) {
|
||||||
|
this.imaSdkSettings = Assertions.checkNotNull(imaSdkSettings);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the VAST load timeout, in milliseconds.
|
||||||
|
*
|
||||||
|
* @param vastLoadTimeoutMs The VAST load timeout, in milliseconds.
|
||||||
|
* @return This builder, for convenience.
|
||||||
|
* @see AdsRequest#setVastLoadTimeout(float)
|
||||||
|
*/
|
||||||
|
public Builder setVastLoadTimeoutMs(long vastLoadTimeoutMs) {
|
||||||
|
Assertions.checkArgument(vastLoadTimeoutMs >= 0);
|
||||||
|
this.vastLoadTimeoutMs = vastLoadTimeoutMs;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link ImaAdsLoader} for the specified ad tag.
|
||||||
|
*
|
||||||
|
* @param adTagUri The URI of a compatible ad tag to load. See
|
||||||
|
* https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for
|
||||||
|
* information on compatible ad tags.
|
||||||
|
* @return The new {@link ImaAdsLoader}.
|
||||||
|
*/
|
||||||
|
public ImaAdsLoader buildForAdTag(Uri adTagUri) {
|
||||||
|
return new ImaAdsLoader(context, adTagUri, imaSdkSettings, null, vastLoadTimeoutMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link ImaAdsLoader} with the specified sideloaded ads response.
|
||||||
|
*
|
||||||
|
* @param adsResponse The sideloaded VAST, VMAP, or ad rules response to be used instead of
|
||||||
|
* making a request via an ad tag URL.
|
||||||
|
* @return The new {@link ImaAdsLoader}.
|
||||||
|
*/
|
||||||
|
public ImaAdsLoader buildForAdsResponse(String adsResponse) {
|
||||||
|
return new ImaAdsLoader(context, null, imaSdkSettings, adsResponse, vastLoadTimeoutMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
private static final String TAG = "ImaAdsLoader";
|
private static final String TAG = "ImaAdsLoader";
|
||||||
|
|
||||||
@ -94,9 +165,7 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
private static final String FOCUS_SKIP_BUTTON_WORKAROUND_JS = "javascript:"
|
private static final String FOCUS_SKIP_BUTTON_WORKAROUND_JS = "javascript:"
|
||||||
+ "try{ document.getElementsByClassName(\"videoAdUiSkipButton\")[0].focus(); } catch (e) {}";
|
+ "try{ document.getElementsByClassName(\"videoAdUiSkipButton\")[0].focus(); } catch (e) {}";
|
||||||
|
|
||||||
/**
|
/** The state of ad playback. */
|
||||||
* The state of ad playback based on IMA's calls to {@link #playAd()} and {@link #pauseAd()}.
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef({IMA_AD_STATE_NONE, IMA_AD_STATE_PLAYING, IMA_AD_STATE_PAUSED})
|
@IntDef({IMA_AD_STATE_NONE, IMA_AD_STATE_PLAYING, IMA_AD_STATE_PAUSED})
|
||||||
private @interface ImaAdState {}
|
private @interface ImaAdState {}
|
||||||
@ -113,7 +182,9 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
*/
|
*/
|
||||||
private static final int IMA_AD_STATE_PAUSED = 2;
|
private static final int IMA_AD_STATE_PAUSED = 2;
|
||||||
|
|
||||||
private final Uri adTagUri;
|
private final @Nullable Uri adTagUri;
|
||||||
|
private final @Nullable String adsResponse;
|
||||||
|
private final long vastLoadTimeoutMs;
|
||||||
private final Timeline.Period period;
|
private final Timeline.Period period;
|
||||||
private final List<VideoAdPlayerCallback> adCallbacks;
|
private final List<VideoAdPlayerCallback> adCallbacks;
|
||||||
private final ImaSdkFactory imaSdkFactory;
|
private final ImaSdkFactory imaSdkFactory;
|
||||||
@ -129,6 +200,7 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
private VideoProgressUpdate lastAdProgress;
|
private VideoProgressUpdate lastAdProgress;
|
||||||
|
|
||||||
private AdsManager adsManager;
|
private AdsManager adsManager;
|
||||||
|
private AdErrorEvent pendingAdErrorEvent;
|
||||||
private Timeline timeline;
|
private Timeline timeline;
|
||||||
private long contentDurationMs;
|
private long contentDurationMs;
|
||||||
private int podIndexOffset;
|
private int podIndexOffset;
|
||||||
@ -144,9 +216,7 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
* Whether IMA has sent an ad event to pause content since the last resume content event.
|
* Whether IMA has sent an ad event to pause content since the last resume content event.
|
||||||
*/
|
*/
|
||||||
private boolean imaPausedContent;
|
private boolean imaPausedContent;
|
||||||
/**
|
/** The current ad playback state. */
|
||||||
* The current ad playback state based on IMA's calls to {@link #playAd()} and {@link #stopAd()}.
|
|
||||||
*/
|
|
||||||
private @ImaAdState int imaAdState;
|
private @ImaAdState int imaAdState;
|
||||||
/**
|
/**
|
||||||
* Whether {@link com.google.ads.interactivemedia.v3.api.AdsLoader#contentComplete()} has been
|
* Whether {@link com.google.ads.interactivemedia.v3.api.AdsLoader#contentComplete()} has been
|
||||||
@ -189,13 +259,15 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
/**
|
/**
|
||||||
* Creates a new IMA ads loader.
|
* Creates a new IMA ads loader.
|
||||||
*
|
*
|
||||||
|
* <p>If you need to customize the ad request, use {@link ImaAdsLoader.Builder} instead.
|
||||||
|
*
|
||||||
* @param context The context.
|
* @param context The context.
|
||||||
* @param adTagUri The {@link Uri} of an ad tag compatible with the Android IMA SDK. See
|
* @param adTagUri The {@link Uri} of an ad tag compatible with the Android IMA SDK. See
|
||||||
* https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for
|
* https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for
|
||||||
* more information.
|
* more information.
|
||||||
*/
|
*/
|
||||||
public ImaAdsLoader(Context context, Uri adTagUri) {
|
public ImaAdsLoader(Context context, Uri adTagUri) {
|
||||||
this(context, adTagUri, null);
|
this(context, adTagUri, null, null, C.TIME_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -207,9 +279,23 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
* more information.
|
* more information.
|
||||||
* @param imaSdkSettings {@link ImaSdkSettings} used to configure the IMA SDK, or {@code null} to
|
* @param imaSdkSettings {@link ImaSdkSettings} used to configure the IMA SDK, or {@code null} to
|
||||||
* use the default settings. If set, the player type and version fields may be overwritten.
|
* use the default settings. If set, the player type and version fields may be overwritten.
|
||||||
|
* @deprecated Use {@link ImaAdsLoader.Builder}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public ImaAdsLoader(Context context, Uri adTagUri, ImaSdkSettings imaSdkSettings) {
|
public ImaAdsLoader(Context context, Uri adTagUri, ImaSdkSettings imaSdkSettings) {
|
||||||
|
this(context, adTagUri, imaSdkSettings, null, C.TIME_UNSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImaAdsLoader(
|
||||||
|
Context context,
|
||||||
|
@Nullable Uri adTagUri,
|
||||||
|
@Nullable ImaSdkSettings imaSdkSettings,
|
||||||
|
@Nullable String adsResponse,
|
||||||
|
long vastLoadTimeoutMs) {
|
||||||
|
Assertions.checkArgument(adTagUri != null || adsResponse != null);
|
||||||
this.adTagUri = adTagUri;
|
this.adTagUri = adTagUri;
|
||||||
|
this.adsResponse = adsResponse;
|
||||||
|
this.vastLoadTimeoutMs = vastLoadTimeoutMs;
|
||||||
period = new Timeline.Period();
|
period = new Timeline.Period();
|
||||||
adCallbacks = new ArrayList<>(1);
|
adCallbacks = new ArrayList<>(1);
|
||||||
imaSdkFactory = ImaSdkFactory.getInstance();
|
imaSdkFactory = ImaSdkFactory.getInstance();
|
||||||
@ -238,6 +324,37 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
return adsLoader;
|
return adsLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests ads, if they have not already been requested. Must be called on the main thread.
|
||||||
|
*
|
||||||
|
* <p>Ads will be requested automatically when the player is prepared if this method has not been
|
||||||
|
* called, so it is only necessary to call this method if you want to request ads before preparing
|
||||||
|
* the player
|
||||||
|
*
|
||||||
|
* @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI.
|
||||||
|
*/
|
||||||
|
public void requestAds(ViewGroup adUiViewGroup) {
|
||||||
|
if (adPlaybackState != null || adsManager != null || pendingAdRequestContext != null) {
|
||||||
|
// Ads have already been requested.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
adDisplayContainer.setAdContainer(adUiViewGroup);
|
||||||
|
pendingAdRequestContext = new Object();
|
||||||
|
AdsRequest request = imaSdkFactory.createAdsRequest();
|
||||||
|
if (adTagUri != null) {
|
||||||
|
request.setAdTagUrl(adTagUri.toString());
|
||||||
|
} else /* adsResponse != null */ {
|
||||||
|
request.setAdsResponse(adsResponse);
|
||||||
|
}
|
||||||
|
if (vastLoadTimeoutMs != C.TIME_UNSET) {
|
||||||
|
request.setVastLoadTimeout(vastLoadTimeoutMs);
|
||||||
|
}
|
||||||
|
request.setAdDisplayContainer(adDisplayContainer);
|
||||||
|
request.setContentProgressProvider(this);
|
||||||
|
request.setUserRequestContext(pendingAdRequestContext);
|
||||||
|
adsLoader.requestAds(request);
|
||||||
|
}
|
||||||
|
|
||||||
// AdsLoader implementation.
|
// AdsLoader implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -268,14 +385,19 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
lastContentProgress = null;
|
lastContentProgress = null;
|
||||||
adDisplayContainer.setAdContainer(adUiViewGroup);
|
adDisplayContainer.setAdContainer(adUiViewGroup);
|
||||||
player.addListener(this);
|
player.addListener(this);
|
||||||
|
maybeNotifyAdError();
|
||||||
if (adPlaybackState != null) {
|
if (adPlaybackState != null) {
|
||||||
|
// Pass the ad playback state to the player, and resume ads if necessary.
|
||||||
eventListener.onAdPlaybackState(adPlaybackState.copy());
|
eventListener.onAdPlaybackState(adPlaybackState.copy());
|
||||||
if (imaPausedContent && player.getPlayWhenReady()) {
|
if (imaPausedContent && player.getPlayWhenReady()) {
|
||||||
adsManager.resume();
|
adsManager.resume();
|
||||||
}
|
}
|
||||||
|
} else if (adsManager != null) {
|
||||||
|
// Ads have loaded but the ads manager is not initialized.
|
||||||
|
startAdPlayback();
|
||||||
} else {
|
} else {
|
||||||
pendingContentPositionMs = player.getCurrentPosition();
|
// Ads haven't loaded yet, so request them.
|
||||||
requestAds();
|
requestAds(adUiViewGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,49 +434,13 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pendingAdRequestContext = null;
|
pendingAdRequestContext = null;
|
||||||
|
|
||||||
long[] adGroupTimesUs = getAdGroupTimesUs(adsManager.getAdCuePoints());
|
|
||||||
adPlaybackState = new AdPlaybackState(adGroupTimesUs);
|
|
||||||
|
|
||||||
this.adsManager = adsManager;
|
this.adsManager = adsManager;
|
||||||
adsManager.addAdErrorListener(this);
|
adsManager.addAdErrorListener(this);
|
||||||
adsManager.addAdEventListener(this);
|
adsManager.addAdEventListener(this);
|
||||||
|
if (player != null) {
|
||||||
ImaSdkFactory imaSdkFactory = ImaSdkFactory.getInstance();
|
// If a player is attached already, start playback immediately.
|
||||||
AdsRenderingSettings adsRenderingSettings = imaSdkFactory.createAdsRenderingSettings();
|
startAdPlayback();
|
||||||
adsRenderingSettings.setEnablePreloading(ENABLE_PRELOADING);
|
|
||||||
adsRenderingSettings.setMimeTypes(supportedMimeTypes);
|
|
||||||
int adGroupIndexForPosition =
|
|
||||||
getAdGroupIndexForPosition(adGroupTimesUs, C.msToUs(pendingContentPositionMs));
|
|
||||||
if (adGroupIndexForPosition == 0) {
|
|
||||||
podIndexOffset = 0;
|
|
||||||
} else if (adGroupIndexForPosition == C.INDEX_UNSET) {
|
|
||||||
pendingContentPositionMs = C.TIME_UNSET;
|
|
||||||
// There is no preroll and midroll pod indices start at 1.
|
|
||||||
podIndexOffset = -1;
|
|
||||||
} else /* adGroupIndexForPosition > 0 */ {
|
|
||||||
// Skip ad groups before the one at or immediately before the playback position.
|
|
||||||
for (int i = 0; i < adGroupIndexForPosition; i++) {
|
|
||||||
adPlaybackState.playedAdGroup(i);
|
|
||||||
}
|
}
|
||||||
// Play ads after the midpoint between the ad to play and the one before it, to avoid issues
|
|
||||||
// with rounding one of the two ad times.
|
|
||||||
long adGroupForPositionTimeUs = adGroupTimesUs[adGroupIndexForPosition];
|
|
||||||
long adGroupBeforeTimeUs = adGroupTimesUs[adGroupIndexForPosition - 1];
|
|
||||||
double midpointTimeUs = (adGroupForPositionTimeUs + adGroupBeforeTimeUs) / 2d;
|
|
||||||
adsRenderingSettings.setPlayAdsAfterTime(midpointTimeUs / C.MICROS_PER_SECOND);
|
|
||||||
|
|
||||||
// We're removing one or more ads, which means that the earliest ad (if any) will be a
|
|
||||||
// midroll/postroll. Midroll pod indices start at 1.
|
|
||||||
podIndexOffset = adGroupIndexForPosition - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
adsManager.init(adsRenderingSettings);
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "Initialized with ads rendering settings: " + adsRenderingSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateAdPlaybackState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdEvent.AdEventListener implementation.
|
// AdEvent.AdEventListener implementation.
|
||||||
@ -384,14 +470,12 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
adGroupIndex =
|
adGroupIndex =
|
||||||
podIndex == -1 ? (adPlaybackState.adGroupCount - 1) : (podIndex + podIndexOffset);
|
podIndex == -1 ? (adPlaybackState.adGroupCount - 1) : (podIndex + podIndexOffset);
|
||||||
int adPosition = adPodInfo.getAdPosition();
|
int adPosition = adPodInfo.getAdPosition();
|
||||||
int adCountInAdGroup = adPodInfo.getTotalAds();
|
int adCount = adPodInfo.getTotalAds();
|
||||||
adsManager.start();
|
adsManager.start();
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(
|
Log.d(TAG, "Loaded ad " + adPosition + " of " + adCount + " in group " + adGroupIndex);
|
||||||
TAG,
|
|
||||||
"Loaded ad " + adPosition + " of " + adCountInAdGroup + " in group " + adGroupIndex);
|
|
||||||
}
|
}
|
||||||
adPlaybackState.setAdCount(adGroupIndex, adCountInAdGroup);
|
adPlaybackState.setAdCount(adGroupIndex, adCount);
|
||||||
updateAdPlaybackState();
|
updateAdPlaybackState();
|
||||||
break;
|
break;
|
||||||
case CONTENT_PAUSE_REQUESTED:
|
case CONTENT_PAUSE_REQUESTED:
|
||||||
@ -434,14 +518,15 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
Log.d(TAG, "onAdError " + adErrorEvent);
|
Log.d(TAG, "onAdError " + adErrorEvent);
|
||||||
}
|
}
|
||||||
if (adsManager == null) {
|
if (adsManager == null) {
|
||||||
|
// No ads were loaded, so allow playback to start without any ads.
|
||||||
pendingAdRequestContext = null;
|
pendingAdRequestContext = null;
|
||||||
adPlaybackState = new AdPlaybackState(new long[0]);
|
adPlaybackState = new AdPlaybackState(new long[0]);
|
||||||
updateAdPlaybackState();
|
updateAdPlaybackState();
|
||||||
}
|
}
|
||||||
if (eventListener != null) {
|
if (pendingAdErrorEvent == null) {
|
||||||
IOException exception = new IOException("Ad error: " + adErrorEvent, adErrorEvent.getError());
|
pendingAdErrorEvent = adErrorEvent;
|
||||||
eventListener.onLoadError(exception);
|
|
||||||
}
|
}
|
||||||
|
maybeNotifyAdError();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContentProgressProvider implementation.
|
// ContentProgressProvider implementation.
|
||||||
@ -654,18 +739,56 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
|
|||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
private void requestAds() {
|
private void startAdPlayback() {
|
||||||
if (pendingAdRequestContext != null) {
|
ImaSdkFactory imaSdkFactory = ImaSdkFactory.getInstance();
|
||||||
// Ad request already in flight.
|
AdsRenderingSettings adsRenderingSettings = imaSdkFactory.createAdsRenderingSettings();
|
||||||
return;
|
adsRenderingSettings.setEnablePreloading(ENABLE_PRELOADING);
|
||||||
|
adsRenderingSettings.setMimeTypes(supportedMimeTypes);
|
||||||
|
|
||||||
|
// Set up the ad playback state, skipping ads based on the start position as required.
|
||||||
|
pendingContentPositionMs = player.getCurrentPosition();
|
||||||
|
long[] adGroupTimesUs = getAdGroupTimesUs(adsManager.getAdCuePoints());
|
||||||
|
adPlaybackState = new AdPlaybackState(adGroupTimesUs);
|
||||||
|
int adGroupIndexForPosition =
|
||||||
|
getAdGroupIndexForPosition(adGroupTimesUs, C.msToUs(pendingContentPositionMs));
|
||||||
|
if (adGroupIndexForPosition == 0) {
|
||||||
|
podIndexOffset = 0;
|
||||||
|
} else if (adGroupIndexForPosition == C.INDEX_UNSET) {
|
||||||
|
pendingContentPositionMs = C.TIME_UNSET;
|
||||||
|
// There is no preroll and midroll pod indices start at 1.
|
||||||
|
podIndexOffset = -1;
|
||||||
|
} else /* adGroupIndexForPosition > 0 */ {
|
||||||
|
// Skip ad groups before the one at or immediately before the playback position.
|
||||||
|
for (int i = 0; i < adGroupIndexForPosition; i++) {
|
||||||
|
adPlaybackState.playedAdGroup(i);
|
||||||
|
}
|
||||||
|
// Play ads after the midpoint between the ad to play and the one before it, to avoid issues
|
||||||
|
// with rounding one of the two ad times.
|
||||||
|
long adGroupForPositionTimeUs = adGroupTimesUs[adGroupIndexForPosition];
|
||||||
|
long adGroupBeforeTimeUs = adGroupTimesUs[adGroupIndexForPosition - 1];
|
||||||
|
double midpointTimeUs = (adGroupForPositionTimeUs + adGroupBeforeTimeUs) / 2d;
|
||||||
|
adsRenderingSettings.setPlayAdsAfterTime(midpointTimeUs / C.MICROS_PER_SECOND);
|
||||||
|
|
||||||
|
// We're removing one or more ads, which means that the earliest ad (if any) will be a
|
||||||
|
// midroll/postroll. Midroll pod indices start at 1.
|
||||||
|
podIndexOffset = adGroupIndexForPosition - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start ad playback.
|
||||||
|
adsManager.init(adsRenderingSettings);
|
||||||
|
updateAdPlaybackState();
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Initialized with ads rendering settings: " + adsRenderingSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void maybeNotifyAdError() {
|
||||||
|
if (eventListener != null && pendingAdErrorEvent != null) {
|
||||||
|
IOException exception =
|
||||||
|
new IOException("Ad error: " + pendingAdErrorEvent, pendingAdErrorEvent.getError());
|
||||||
|
eventListener.onLoadError(exception);
|
||||||
|
pendingAdErrorEvent = null;
|
||||||
}
|
}
|
||||||
pendingAdRequestContext = new Object();
|
|
||||||
AdsRequest request = imaSdkFactory.createAdsRequest();
|
|
||||||
request.setAdTagUrl(adTagUri.toString());
|
|
||||||
request.setAdDisplayContainer(adDisplayContainer);
|
|
||||||
request.setContentProgressProvider(this);
|
|
||||||
request.setUserRequestContext(pendingAdRequestContext);
|
|
||||||
adsLoader.requestAds(request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateImaStateForPlayerState() {
|
private void updateImaStateForPlayerState() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user