Handle detaching and reattaching the ads loader
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161526026
This commit is contained in:
parent
94683d1e8c
commit
0b58c33632
@ -73,6 +73,7 @@ import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.CookiePolicy;
|
||||
@ -124,6 +125,12 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
||||
private int resumeWindow;
|
||||
private long resumePosition;
|
||||
|
||||
// Fields used only for ad playback. The ads loader is loaded via reflection.
|
||||
|
||||
private Object imaAdsLoader; // com.google.android.exoplayer2.ext.ima.ImaAdsLoader
|
||||
private Uri loadedAdTagUri;
|
||||
private ViewGroup adOverlayViewGroup;
|
||||
|
||||
// Activity lifecycle
|
||||
|
||||
@Override
|
||||
@ -190,6 +197,12 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
releaseAdsLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||
@NonNull int[] grantResults) {
|
||||
@ -317,20 +330,19 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
||||
String adTagUriString = intent.getStringExtra(AD_TAG_URI_EXTRA);
|
||||
if (adTagUriString != null) {
|
||||
Uri adTagUri = Uri.parse(adTagUriString);
|
||||
ViewGroup adOverlayViewGroup = new FrameLayout(this);
|
||||
// Load the extension source using reflection so that demo app doesn't have to depend on it.
|
||||
if (!adTagUri.equals(loadedAdTagUri)) {
|
||||
releaseAdsLoader();
|
||||
loadedAdTagUri = adTagUri;
|
||||
}
|
||||
try {
|
||||
Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsMediaSource");
|
||||
Constructor<?> constructor = clazz.getConstructor(MediaSource.class,
|
||||
DataSource.Factory.class, Context.class, Uri.class, ViewGroup.class);
|
||||
mediaSource = (MediaSource) constructor.newInstance(mediaSource,
|
||||
mediaDataSourceFactory, this, adTagUri, adOverlayViewGroup);
|
||||
mediaSource = createAdsMediaSource(mediaSource, Uri.parse(adTagUriString));
|
||||
// The demo app has a non-null overlay frame layout.
|
||||
simpleExoPlayerView.getOverlayFrameLayout().addView(adOverlayViewGroup);
|
||||
} catch (Exception e) {
|
||||
// Throw if the media source class was not found, or there was an error instantiating it.
|
||||
showToast(R.string.ima_not_loaded);
|
||||
}
|
||||
} else {
|
||||
releaseAdsLoader();
|
||||
}
|
||||
boolean haveResumePosition = resumeWindow != C.INDEX_UNSET;
|
||||
if (haveResumePosition) {
|
||||
@ -429,6 +441,47 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
|
||||
.buildHttpDataSourceFactory(useBandwidthMeter ? BANDWIDTH_METER : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ads media source, reusing the ads loader if one exists.
|
||||
*
|
||||
* @throws Exception Thrown if it was not possible to create an ads media source, for example, due
|
||||
* to a missing dependency.
|
||||
*/
|
||||
private MediaSource createAdsMediaSource(MediaSource mediaSource, Uri adTagUri) throws Exception {
|
||||
// Load the extension source using reflection so the demo app doesn't have to depend on it.
|
||||
// The ads loader is reused for multiple playbacks, so that ad playback can resume.
|
||||
Class<?> loaderClass = Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsLoader");
|
||||
if (imaAdsLoader == null) {
|
||||
imaAdsLoader = loaderClass.getConstructor(Context.class, Uri.class)
|
||||
.newInstance(this, adTagUri);
|
||||
adOverlayViewGroup = new FrameLayout(this);
|
||||
// The demo app has a non-null overlay frame layout.
|
||||
simpleExoPlayerView.getOverlayFrameLayout().addView(adOverlayViewGroup);
|
||||
}
|
||||
Class<?> sourceClass =
|
||||
Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsMediaSource");
|
||||
Constructor<?> constructor = sourceClass.getConstructor(MediaSource.class,
|
||||
DataSource.Factory.class, loaderClass, ViewGroup.class);
|
||||
return (MediaSource) constructor.newInstance(mediaSource, mediaDataSourceFactory, imaAdsLoader,
|
||||
adOverlayViewGroup);
|
||||
}
|
||||
|
||||
private void releaseAdsLoader() {
|
||||
if (imaAdsLoader != null) {
|
||||
try {
|
||||
Class<?> loaderClass = Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsLoader");
|
||||
Method releaseMethod = loaderClass.getMethod("release");
|
||||
releaseMethod.invoke(imaAdsLoader);
|
||||
} catch (Exception e) {
|
||||
// Should never happen.
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
imaAdsLoader = null;
|
||||
loadedAdTagUri = null;
|
||||
simpleExoPlayerView.getOverlayFrameLayout().removeAllViews();
|
||||
}
|
||||
}
|
||||
|
||||
// ExoPlayer.EventListener implementation
|
||||
|
||||
@Override
|
||||
|
@ -54,7 +54,7 @@ import java.util.List;
|
||||
/**
|
||||
* Loads ads using the IMA SDK. All methods are called on the main thread.
|
||||
*/
|
||||
/* package */ final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlayer,
|
||||
public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlayer,
|
||||
ContentProgressProvider, AdErrorListener, AdsLoadedListener, AdEventListener {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
@ -95,19 +95,23 @@ import java.util.List;
|
||||
*/
|
||||
private static final long END_OF_CONTENT_POSITION_THRESHOLD_MS = 5000;
|
||||
|
||||
private final EventListener eventListener;
|
||||
private final ExoPlayer player;
|
||||
private final Uri adTagUri;
|
||||
private final Timeline.Period period;
|
||||
private final List<VideoAdPlayerCallback> adCallbacks;
|
||||
private final ImaSdkFactory imaSdkFactory;
|
||||
private final AdDisplayContainer adDisplayContainer;
|
||||
private final AdsLoader adsLoader;
|
||||
|
||||
private EventListener eventListener;
|
||||
private ExoPlayer player;
|
||||
private VideoProgressUpdate lastContentProgress;
|
||||
private VideoProgressUpdate lastAdProgress;
|
||||
|
||||
private AdsManager adsManager;
|
||||
private Timeline timeline;
|
||||
private long contentDurationMs;
|
||||
private AdPlaybackState adPlaybackState;
|
||||
|
||||
private boolean released;
|
||||
|
||||
// Fields tracking IMA's state.
|
||||
|
||||
/**
|
||||
@ -163,46 +167,80 @@ import java.util.List;
|
||||
* @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
|
||||
* more information.
|
||||
* @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI.
|
||||
*/
|
||||
public ImaAdsLoader(Context context, Uri adTagUri) {
|
||||
this(context, adTagUri, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new IMA ads loader.
|
||||
*
|
||||
* @param context The context.
|
||||
* @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
|
||||
* more information.
|
||||
* @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.
|
||||
* @param player The player instance that will play the loaded ad schedule.
|
||||
* @param eventListener Listener for ad loader events.
|
||||
*/
|
||||
public ImaAdsLoader(Context context, Uri adTagUri, ViewGroup adUiViewGroup,
|
||||
ImaSdkSettings imaSdkSettings, ExoPlayer player, EventListener eventListener) {
|
||||
this.eventListener = eventListener;
|
||||
this.player = player;
|
||||
public ImaAdsLoader(Context context, Uri adTagUri, ImaSdkSettings imaSdkSettings) {
|
||||
this.adTagUri = adTagUri;
|
||||
period = new Timeline.Period();
|
||||
adCallbacks = new ArrayList<>(1);
|
||||
|
||||
fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET;
|
||||
pendingContentPositionMs = C.TIME_UNSET;
|
||||
adGroupIndex = C.INDEX_UNSET;
|
||||
contentDurationMs = C.TIME_UNSET;
|
||||
|
||||
player.addListener(this);
|
||||
|
||||
ImaSdkFactory imaSdkFactory = ImaSdkFactory.getInstance();
|
||||
AdDisplayContainer adDisplayContainer = imaSdkFactory.createAdDisplayContainer();
|
||||
imaSdkFactory = ImaSdkFactory.getInstance();
|
||||
adDisplayContainer = imaSdkFactory.createAdDisplayContainer();
|
||||
adDisplayContainer.setPlayer(this);
|
||||
adDisplayContainer.setAdContainer(adUiViewGroup);
|
||||
|
||||
if (imaSdkSettings == null) {
|
||||
imaSdkSettings = imaSdkFactory.createImaSdkSettings();
|
||||
}
|
||||
imaSdkSettings.setPlayerType(IMA_SDK_SETTINGS_PLAYER_TYPE);
|
||||
imaSdkSettings.setPlayerVersion(IMA_SDK_SETTINGS_PLAYER_VERSION);
|
||||
|
||||
AdsRequest request = imaSdkFactory.createAdsRequest();
|
||||
request.setAdTagUrl(adTagUri.toString());
|
||||
request.setAdDisplayContainer(adDisplayContainer);
|
||||
request.setContentProgressProvider(this);
|
||||
|
||||
adsLoader = imaSdkFactory.createAdsLoader(context, imaSdkSettings);
|
||||
adsLoader.addAdErrorListener(this);
|
||||
adsLoader.addAdsLoadedListener(this);
|
||||
adsLoader.requestAds(request);
|
||||
fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET;
|
||||
pendingContentPositionMs = C.TIME_UNSET;
|
||||
adGroupIndex = C.INDEX_UNSET;
|
||||
contentDurationMs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a player that will play ads loaded using this instance.
|
||||
*
|
||||
* @param player The player instance that will play the loaded ads.
|
||||
* @param eventListener Listener for ads loader events.
|
||||
* @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI.
|
||||
*/
|
||||
public void attachPlayer(ExoPlayer player, EventListener eventListener, ViewGroup adUiViewGroup) {
|
||||
this.player = player;
|
||||
this.eventListener = eventListener;
|
||||
lastAdProgress = null;
|
||||
lastContentProgress = null;
|
||||
adDisplayContainer.setAdContainer(adUiViewGroup);
|
||||
player.addListener(this);
|
||||
if (adPlaybackState != null) {
|
||||
eventListener.onAdPlaybackState(adPlaybackState);
|
||||
// TODO: Call adsManager.resume if an ad is playing.
|
||||
} else if (adTagUri != null) {
|
||||
requestAds();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches any attached player and event listener. To attach a new player, call
|
||||
* {@link #attachPlayer(ExoPlayer, EventListener, ViewGroup)}. Call {@link #release()} to release
|
||||
* all resources associated with this instance.
|
||||
*/
|
||||
public void detachPlayer() {
|
||||
if (player != null) {
|
||||
if (adsManager != null && player.isPlayingAd()) {
|
||||
adsManager.pause();
|
||||
}
|
||||
lastAdProgress = getAdProgress();
|
||||
lastContentProgress = getContentProgress();
|
||||
player.removeListener(this);
|
||||
player = null;
|
||||
}
|
||||
eventListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -212,9 +250,8 @@ import java.util.List;
|
||||
if (adsManager != null) {
|
||||
adsManager.destroy();
|
||||
adsManager = null;
|
||||
detachPlayer();
|
||||
}
|
||||
player.removeListener(this);
|
||||
released = true;
|
||||
}
|
||||
|
||||
// AdsLoader.AdsLoadedListener implementation.
|
||||
@ -251,8 +288,8 @@ import java.util.List;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onAdEvent " + adEvent.getType());
|
||||
}
|
||||
if (released) {
|
||||
// The ads manager may pass CONTENT_RESUME_REQUESTED after it is destroyed.
|
||||
if (adsManager == null) {
|
||||
Log.w(TAG, "Dropping ad event while detached: " + adEvent);
|
||||
return;
|
||||
}
|
||||
switch (adEvent.getType()) {
|
||||
@ -274,11 +311,15 @@ import java.util.List;
|
||||
case CONTENT_PAUSE_REQUESTED:
|
||||
// After CONTENT_PAUSE_REQUESTED, IMA will playAd/pauseAd/stopAd to show one or more ads
|
||||
// before sending CONTENT_RESUME_REQUESTED.
|
||||
if (player != null) {
|
||||
pauseContentInternal();
|
||||
}
|
||||
break;
|
||||
case SKIPPED: // Fall through.
|
||||
case CONTENT_RESUME_REQUESTED:
|
||||
if (player != null) {
|
||||
resumeContentInternal();
|
||||
}
|
||||
break;
|
||||
case ALL_ADS_COMPLETED:
|
||||
// Do nothing. The ads manager will be released when the source is released.
|
||||
@ -294,8 +335,10 @@ import java.util.List;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onAdError " + adErrorEvent);
|
||||
}
|
||||
if (eventListener != null) {
|
||||
IOException exception = new IOException("Ad error: " + adErrorEvent, adErrorEvent.getError());
|
||||
eventListener.onLoadError(exception);
|
||||
}
|
||||
// TODO: Provide a timeline to the player if it doesn't have one yet, so the content can play.
|
||||
}
|
||||
|
||||
@ -303,33 +346,37 @@ import java.util.List;
|
||||
|
||||
@Override
|
||||
public VideoProgressUpdate getContentProgress() {
|
||||
if (pendingContentPositionMs != C.TIME_UNSET) {
|
||||
if (player == null) {
|
||||
return lastContentProgress;
|
||||
} else if (pendingContentPositionMs != C.TIME_UNSET) {
|
||||
sentPendingContentPositionMs = true;
|
||||
return new VideoProgressUpdate(pendingContentPositionMs, contentDurationMs);
|
||||
}
|
||||
if (fakeContentProgressElapsedRealtimeMs != C.TIME_UNSET) {
|
||||
} else if (fakeContentProgressElapsedRealtimeMs != C.TIME_UNSET) {
|
||||
long adGroupTimeMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]);
|
||||
if (adGroupTimeMs == C.TIME_END_OF_SOURCE) {
|
||||
adGroupTimeMs = contentDurationMs;
|
||||
}
|
||||
long elapsedSinceEndMs = SystemClock.elapsedRealtime() - fakeContentProgressElapsedRealtimeMs;
|
||||
return new VideoProgressUpdate(adGroupTimeMs + elapsedSinceEndMs, contentDurationMs);
|
||||
}
|
||||
if (player.isPlayingAd() || contentDurationMs == C.TIME_UNSET) {
|
||||
} else if (player.isPlayingAd() || contentDurationMs == C.TIME_UNSET) {
|
||||
return VideoProgressUpdate.VIDEO_TIME_NOT_READY;
|
||||
}
|
||||
} else {
|
||||
return new VideoProgressUpdate(player.getCurrentPosition(), contentDurationMs);
|
||||
}
|
||||
}
|
||||
|
||||
// VideoAdPlayer implementation.
|
||||
|
||||
@Override
|
||||
public VideoProgressUpdate getAdProgress() {
|
||||
if (!player.isPlayingAd()) {
|
||||
if (player == null) {
|
||||
return lastAdProgress;
|
||||
} else if (!player.isPlayingAd()) {
|
||||
return VideoProgressUpdate.VIDEO_TIME_NOT_READY;
|
||||
}
|
||||
} else {
|
||||
return new VideoProgressUpdate(player.getCurrentPosition(), player.getDuration());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAd(String adUriString) {
|
||||
@ -352,6 +399,7 @@ import java.util.List;
|
||||
|
||||
@Override
|
||||
public void playAd() {
|
||||
Assertions.checkState(player != null);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "playAd");
|
||||
}
|
||||
@ -379,6 +427,7 @@ import java.util.List;
|
||||
|
||||
@Override
|
||||
public void stopAd() {
|
||||
Assertions.checkState(player != null);
|
||||
if (!playingAd) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Ignoring unexpected stopAd");
|
||||
@ -396,7 +445,7 @@ import java.util.List;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "pauseAd");
|
||||
}
|
||||
if (released || !playingAd) {
|
||||
if (player == null || !playingAd) {
|
||||
// This method is called after content is resumed, and may also be called after release.
|
||||
return;
|
||||
}
|
||||
@ -513,9 +562,14 @@ import java.util.List;
|
||||
|
||||
// Internal methods.
|
||||
|
||||
/**
|
||||
* Resumes the player, ensuring the current period is a content period by seeking if necessary.
|
||||
*/
|
||||
private void requestAds() {
|
||||
AdsRequest request = imaSdkFactory.createAdsRequest();
|
||||
request.setAdTagUrl(adTagUri.toString());
|
||||
request.setAdDisplayContainer(adDisplayContainer);
|
||||
request.setContentProgressProvider(this);
|
||||
adsLoader.requestAds(request);
|
||||
}
|
||||
|
||||
private void resumeContentInternal() {
|
||||
if (contentDurationMs != C.TIME_UNSET) {
|
||||
if (playingAd) {
|
||||
@ -573,8 +627,11 @@ import java.util.List;
|
||||
}
|
||||
|
||||
private void updateAdPlaybackState() {
|
||||
// Ignore updates while detached. When a player is attached it will receive the latest state.
|
||||
if (eventListener != null) {
|
||||
eventListener.onAdPlaybackState(adPlaybackState.copy());
|
||||
}
|
||||
}
|
||||
|
||||
private static long[] getAdGroupTimesUs(List<Float> cuePoints) {
|
||||
if (cuePoints.isEmpty()) {
|
||||
|
@ -15,12 +15,9 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.ext.ima;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.ViewGroup;
|
||||
import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
@ -44,10 +41,8 @@ public final class ImaAdsMediaSource implements MediaSource {
|
||||
|
||||
private final MediaSource contentMediaSource;
|
||||
private final DataSource.Factory dataSourceFactory;
|
||||
private final Context context;
|
||||
private final Uri adTagUri;
|
||||
private final ImaAdsLoader imaAdsLoader;
|
||||
private final ViewGroup adUiViewGroup;
|
||||
private final ImaSdkSettings imaSdkSettings;
|
||||
private final Handler mainHandler;
|
||||
private final AdsLoaderListener adsLoaderListener;
|
||||
private final Map<MediaPeriod, MediaSource> adMediaSourceByMediaPeriod;
|
||||
@ -66,49 +61,20 @@ public final class ImaAdsMediaSource implements MediaSource {
|
||||
private MediaSource.Listener listener;
|
||||
private IOException adLoadError;
|
||||
|
||||
// Accessed on the main thread.
|
||||
private ImaAdsLoader imaAdsLoader;
|
||||
|
||||
/**
|
||||
* Constructs a new source that inserts ads linearly with the content specified by
|
||||
* {@code contentMediaSource}.
|
||||
*
|
||||
* @param contentMediaSource The {@link MediaSource} providing the content to play.
|
||||
* @param dataSourceFactory Factory for data sources used to load ad media.
|
||||
* @param context The context.
|
||||
* @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
|
||||
* more information.
|
||||
* @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad user
|
||||
* interface.
|
||||
* @param imaAdsLoader The loader for ads.
|
||||
*/
|
||||
public ImaAdsMediaSource(MediaSource contentMediaSource, DataSource.Factory dataSourceFactory,
|
||||
Context context, Uri adTagUri, ViewGroup adUiViewGroup) {
|
||||
this(contentMediaSource, dataSourceFactory, context, adTagUri, adUiViewGroup, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new source that inserts ads linearly with the content specified by
|
||||
* {@code contentMediaSource}.
|
||||
*
|
||||
* @param contentMediaSource The {@link MediaSource} providing the content to play.
|
||||
* @param dataSourceFactory Factory for data sources used to load ad media.
|
||||
* @param context The context.
|
||||
* @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
|
||||
* more information.
|
||||
* @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI.
|
||||
* @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.
|
||||
*/
|
||||
public ImaAdsMediaSource(MediaSource contentMediaSource, DataSource.Factory dataSourceFactory,
|
||||
Context context, Uri adTagUri, ViewGroup adUiViewGroup, ImaSdkSettings imaSdkSettings) {
|
||||
ImaAdsLoader imaAdsLoader, ViewGroup adUiViewGroup) {
|
||||
this.contentMediaSource = contentMediaSource;
|
||||
this.dataSourceFactory = dataSourceFactory;
|
||||
this.context = context;
|
||||
this.adTagUri = adTagUri;
|
||||
this.imaAdsLoader = imaAdsLoader;
|
||||
this.adUiViewGroup = adUiViewGroup;
|
||||
this.imaSdkSettings = imaSdkSettings;
|
||||
mainHandler = new Handler(Looper.getMainLooper());
|
||||
adsLoaderListener = new AdsLoaderListener();
|
||||
adMediaSourceByMediaPeriod = new HashMap<>();
|
||||
@ -118,24 +84,23 @@ public final class ImaAdsMediaSource implements MediaSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) {
|
||||
public void prepareSource(final ExoPlayer player, boolean isTopLevelSource, Listener listener) {
|
||||
Assertions.checkArgument(isTopLevelSource);
|
||||
this.listener = listener;
|
||||
this.player = player;
|
||||
playerHandler = new Handler();
|
||||
mainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
imaAdsLoader = new ImaAdsLoader(context, adTagUri, adUiViewGroup, imaSdkSettings,
|
||||
ImaAdsMediaSource.this.player, adsLoaderListener);
|
||||
}
|
||||
});
|
||||
contentMediaSource.prepareSource(player, false, new Listener() {
|
||||
@Override
|
||||
public void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
|
||||
ImaAdsMediaSource.this.onContentSourceInfoRefreshed(timeline, manifest);
|
||||
}
|
||||
});
|
||||
mainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
imaAdsLoader.attachPlayer(player, adsLoaderListener, adUiViewGroup);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -146,10 +111,12 @@ public final class ImaAdsMediaSource implements MediaSource {
|
||||
contentMediaSource.maybeThrowSourceInfoRefreshError();
|
||||
for (MediaSource[] mediaSources : adGroupMediaSources) {
|
||||
for (MediaSource mediaSource : mediaSources) {
|
||||
if (mediaSource != null) {
|
||||
mediaSource.maybeThrowSourceInfoRefreshError();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
||||
@ -201,17 +168,15 @@ public final class ImaAdsMediaSource implements MediaSource {
|
||||
contentMediaSource.releaseSource();
|
||||
for (MediaSource[] mediaSources : adGroupMediaSources) {
|
||||
for (MediaSource mediaSource : mediaSources) {
|
||||
if (mediaSource != null) {
|
||||
mediaSource.releaseSource();
|
||||
}
|
||||
}
|
||||
}
|
||||
mainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// TODO: The source will be released when the application is paused/stopped, which can occur
|
||||
// if the user taps on the ad. In this case, we should keep the ads manager alive but pause
|
||||
// it, instead of destroying it.
|
||||
imaAdsLoader.release();
|
||||
imaAdsLoader = null;
|
||||
imaAdsLoader.detachPlayer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user