mirror of
https://github.com/androidx/media.git
synced 2025-05-05 06:30:24 +08:00
Set Player separately in AdsLoader interface.
Passing the player through MediaSource.prepare is only needed for the AdsLoader and complicates other usages of MediaSource. Providing the player directly to the AdsLoader is also in line with the usage pattern of PlayerView and other components. Also rename methods to start/stop to better reflect their usage. PiperOrigin-RevId: 227682112
This commit is contained in:
parent
de39925ce9
commit
caca14c5f9
@ -534,6 +534,9 @@ public class PlayerActivity extends Activity
|
||||
mediaSource = null;
|
||||
trackSelector = null;
|
||||
}
|
||||
if (adsLoader != null) {
|
||||
adsLoader.setPlayer(null);
|
||||
}
|
||||
releaseMediaDrm();
|
||||
}
|
||||
|
||||
@ -597,6 +600,7 @@ public class PlayerActivity extends Activity
|
||||
// The demo app has a non-null overlay frame layout.
|
||||
playerView.getOverlayFrameLayout().addView(adUiViewGroup);
|
||||
}
|
||||
adsLoader.setPlayer(player);
|
||||
AdsMediaSource.MediaSourceFactory adMediaSourceFactory =
|
||||
new AdsMediaSource.MediaSourceFactory() {
|
||||
@Override
|
||||
|
@ -46,7 +46,6 @@ import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer;
|
||||
import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
@ -73,7 +72,13 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/** Loads ads using the IMA SDK. All methods are called on the main thread. */
|
||||
/**
|
||||
* {@link AdsLoader} using the IMA SDK. All methods must be called on the main thread.
|
||||
*
|
||||
* <p>The player instance that will play the loaded ads must be set before playback using {@link
|
||||
* #setPlayer(Player)}. If the ads loader is no longer required, it must be released by calling
|
||||
* {@link #release()}.
|
||||
*/
|
||||
public final class ImaAdsLoader
|
||||
implements Player.EventListener,
|
||||
AdsLoader,
|
||||
@ -92,9 +97,9 @@ public final class ImaAdsLoader
|
||||
|
||||
private final Context context;
|
||||
|
||||
private @Nullable ImaSdkSettings imaSdkSettings;
|
||||
private @Nullable AdEventListener adEventListener;
|
||||
private @Nullable Set<UiElement> adUiElements;
|
||||
@Nullable private ImaSdkSettings imaSdkSettings;
|
||||
@Nullable private AdEventListener adEventListener;
|
||||
@Nullable private Set<UiElement> adUiElements;
|
||||
private int vastLoadTimeoutMs;
|
||||
private int mediaLoadTimeoutMs;
|
||||
private int mediaBitrate;
|
||||
@ -316,10 +321,11 @@ public final class ImaAdsLoader
|
||||
private final AdDisplayContainer adDisplayContainer;
|
||||
private final com.google.ads.interactivemedia.v3.api.AdsLoader adsLoader;
|
||||
|
||||
@Nullable private Player nextPlayer;
|
||||
private Object pendingAdRequestContext;
|
||||
private List<String> supportedMimeTypes;
|
||||
private EventListener eventListener;
|
||||
private Player player;
|
||||
@Nullable private EventListener eventListener;
|
||||
@Nullable private Player player;
|
||||
private VideoProgressUpdate lastContentProgress;
|
||||
private VideoProgressUpdate lastAdProgress;
|
||||
private int lastVolumePercentage;
|
||||
@ -525,6 +531,14 @@ public final class ImaAdsLoader
|
||||
|
||||
// AdsLoader implementation.
|
||||
|
||||
@Override
|
||||
public void setPlayer(@Nullable Player player) {
|
||||
Assertions.checkState(Looper.getMainLooper() == Looper.myLooper());
|
||||
Assertions.checkState(
|
||||
player == null || player.getApplicationLooper() == Looper.getMainLooper());
|
||||
nextPlayer = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSupportedContentTypes(@C.ContentType int... contentTypes) {
|
||||
List<String> supportedMimeTypes = new ArrayList<>();
|
||||
@ -549,9 +563,10 @@ public final class ImaAdsLoader
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachPlayer(ExoPlayer player, EventListener eventListener, ViewGroup adUiViewGroup) {
|
||||
Assertions.checkArgument(player.getApplicationLooper() == Looper.getMainLooper());
|
||||
this.player = player;
|
||||
public void start(EventListener eventListener, ViewGroup adUiViewGroup) {
|
||||
Assertions.checkNotNull(
|
||||
nextPlayer, "Set player using adsLoader.setPlayer before preparing the player.");
|
||||
player = nextPlayer;
|
||||
this.eventListener = eventListener;
|
||||
lastVolumePercentage = 0;
|
||||
lastAdProgress = null;
|
||||
@ -575,7 +590,7 @@ public final class ImaAdsLoader
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachPlayer() {
|
||||
public void stop() {
|
||||
if (adsManager != null && imaPausedContent) {
|
||||
adPlaybackState =
|
||||
adPlaybackState.withAdResumePositionUs(
|
||||
|
@ -111,7 +111,7 @@ public class ImaAdsLoaderTest {
|
||||
@Test
|
||||
public void testAttachPlayer_setsAdUiViewGroup() {
|
||||
setupPlayback(CONTENT_TIMELINE, PREROLL_ADS_DURATIONS_US, PREROLL_CUE_POINTS_SECONDS);
|
||||
imaAdsLoader.attachPlayer(fakeExoPlayer, adsLoaderListener, adUiViewGroup);
|
||||
imaAdsLoader.start(adsLoaderListener, adUiViewGroup);
|
||||
|
||||
verify(adDisplayContainer, atLeastOnce()).setAdContainer(adUiViewGroup);
|
||||
}
|
||||
@ -119,7 +119,7 @@ public class ImaAdsLoaderTest {
|
||||
@Test
|
||||
public void testAttachPlayer_updatesAdPlaybackState() {
|
||||
setupPlayback(CONTENT_TIMELINE, PREROLL_ADS_DURATIONS_US, PREROLL_CUE_POINTS_SECONDS);
|
||||
imaAdsLoader.attachPlayer(fakeExoPlayer, adsLoaderListener, adUiViewGroup);
|
||||
imaAdsLoader.start(adsLoaderListener, adUiViewGroup);
|
||||
|
||||
assertThat(adsLoaderListener.adPlaybackState)
|
||||
.isEqualTo(
|
||||
@ -131,14 +131,14 @@ public class ImaAdsLoaderTest {
|
||||
public void testAttachAfterRelease() {
|
||||
setupPlayback(CONTENT_TIMELINE, PREROLL_ADS_DURATIONS_US, PREROLL_CUE_POINTS_SECONDS);
|
||||
imaAdsLoader.release();
|
||||
imaAdsLoader.attachPlayer(fakeExoPlayer, adsLoaderListener, adUiViewGroup);
|
||||
imaAdsLoader.start(adsLoaderListener, adUiViewGroup);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttachAndCallbacksAfterRelease() {
|
||||
setupPlayback(CONTENT_TIMELINE, PREROLL_ADS_DURATIONS_US, PREROLL_CUE_POINTS_SECONDS);
|
||||
imaAdsLoader.release();
|
||||
imaAdsLoader.attachPlayer(fakeExoPlayer, adsLoaderListener, adUiViewGroup);
|
||||
imaAdsLoader.start(adsLoaderListener, adUiViewGroup);
|
||||
fakeExoPlayer.setPlayingContentPosition(/* position= */ 0);
|
||||
fakeExoPlayer.setState(Player.STATE_READY, true);
|
||||
|
||||
@ -166,7 +166,7 @@ public class ImaAdsLoaderTest {
|
||||
setupPlayback(CONTENT_TIMELINE, PREROLL_ADS_DURATIONS_US, PREROLL_CUE_POINTS_SECONDS);
|
||||
|
||||
// Load the preroll ad.
|
||||
imaAdsLoader.attachPlayer(fakeExoPlayer, adsLoaderListener, adUiViewGroup);
|
||||
imaAdsLoader.start(adsLoaderListener, adUiViewGroup);
|
||||
imaAdsLoader.onAdEvent(getAdEvent(AdEventType.LOADED, UNSKIPPABLE_AD));
|
||||
imaAdsLoader.loadAd(TEST_URI.toString());
|
||||
imaAdsLoader.onAdEvent(getAdEvent(AdEventType.CONTENT_PAUSE_REQUESTED, UNSKIPPABLE_AD));
|
||||
@ -210,6 +210,7 @@ public class ImaAdsLoaderTest {
|
||||
.setImaFactory(testImaFactory)
|
||||
.setImaSdkSettings(imaSdkSettings)
|
||||
.buildForAdTag(TEST_URI);
|
||||
imaAdsLoader.setPlayer(fakeExoPlayer);
|
||||
}
|
||||
|
||||
private static AdEvent getAdEvent(AdEventType adEventType, @Nullable Ad ad) {
|
||||
|
@ -15,9 +15,10 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.source.ads;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.ViewGroup;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource.AdLoadException;
|
||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||
import java.io.IOException;
|
||||
@ -30,16 +31,16 @@ import java.io.IOException;
|
||||
* with a new copy of the current {@link AdPlaybackState} whenever further information about ads
|
||||
* becomes known (for example, when an ad media URI is available, or an ad has played to the end).
|
||||
*
|
||||
* <p>{@link #attachPlayer(ExoPlayer, EventListener, ViewGroup)} will be called when the ads media
|
||||
* source first initializes, at which point the loader can request ads. If the player enters the
|
||||
* background, {@link #detachPlayer()} will be called. Loaders should maintain any ad playback state
|
||||
* in preparation for a later call to {@link #attachPlayer(ExoPlayer, EventListener, ViewGroup)}. If
|
||||
* an ad is playing when the player is detached, update the ad playback state with the current
|
||||
* playback position using {@link AdPlaybackState#withAdResumePositionUs(long)}.
|
||||
* <p>{@link #start(EventListener, ViewGroup)} will be called when the ads media source first
|
||||
* initializes, at which point the loader can request ads. If the player enters the background,
|
||||
* {@link #stop()} will be called. Loaders should maintain any ad playback state in preparation for
|
||||
* a later call to {@link #start(EventListener, ViewGroup)}. If an ad is playing when the player is
|
||||
* detached, update the ad playback state with the current playback position using {@link
|
||||
* AdPlaybackState#withAdResumePositionUs(long)}.
|
||||
*
|
||||
* <p>If {@link EventListener#onAdPlaybackState(AdPlaybackState)} has been called, the
|
||||
* implementation of {@link #attachPlayer(ExoPlayer, EventListener, ViewGroup)} should invoke the
|
||||
* same listener to provide the existing playback state to the new player.
|
||||
* implementation of {@link #start(EventListener, ViewGroup)} should invoke the same listener to
|
||||
* provide the existing playback state to the new player.
|
||||
*/
|
||||
public interface AdsLoader {
|
||||
|
||||
@ -75,9 +76,34 @@ public interface AdsLoader {
|
||||
|
||||
}
|
||||
|
||||
// Methods called by the application.
|
||||
|
||||
/**
|
||||
* Sets the supported content types for ad media. Must be called before the first call to
|
||||
* {@link #attachPlayer(ExoPlayer, EventListener, ViewGroup)}. Subsequent calls may be ignored.
|
||||
* Sets the player that will play the loaded ads.
|
||||
*
|
||||
* <p>This method must be called before the player is prepared with media using this ads loader.
|
||||
*
|
||||
* <p>This method must also be called on the main thread and only players which are accessed on
|
||||
* the main thread are supported ({@code player.getApplicationLooper() ==
|
||||
* Looper.getMainLooper()}).
|
||||
*
|
||||
* @param player The player instance that will play the loaded ads. May be null to delete the
|
||||
* reference to a previously set player.
|
||||
*/
|
||||
void setPlayer(@Nullable Player player);
|
||||
|
||||
/**
|
||||
* Releases the loader. Must be called by the application on the main thread when the instance is
|
||||
* no longer needed.
|
||||
*/
|
||||
void release();
|
||||
|
||||
// Methods called by AdsMediaSource.
|
||||
|
||||
/**
|
||||
* Sets the supported content types for ad media. Must be called before the first call to {@link
|
||||
* #start(EventListener, ViewGroup)}. Subsequent calls may be ignored. Called on the main thread
|
||||
* by {@link AdsMediaSource}.
|
||||
*
|
||||
* @param contentTypes The supported content types for ad media. Each element must be one of
|
||||
* {@link C#TYPE_DASH}, {@link C#TYPE_HLS}, {@link C#TYPE_SS} and {@link C#TYPE_OTHER}.
|
||||
@ -85,32 +111,23 @@ public interface AdsLoader {
|
||||
void setSupportedContentTypes(@C.ContentType int... contentTypes);
|
||||
|
||||
/**
|
||||
* Attaches a player that will play ads loaded using this instance. Called on the main thread by
|
||||
* {@link AdsMediaSource}.
|
||||
* Starts using the ads loader for playback. Called on the main thread by {@link AdsMediaSource}.
|
||||
*
|
||||
* @param player The player instance that will play the loaded ads. Only players which are
|
||||
* accessed on the main thread are supported ({@code player.getApplicationLooper() ==
|
||||
* Looper.getMainLooper()}).
|
||||
* @param eventListener Listener for ads loader events.
|
||||
* @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI.
|
||||
*/
|
||||
void attachPlayer(ExoPlayer player, EventListener eventListener, ViewGroup adUiViewGroup);
|
||||
void start(EventListener eventListener, ViewGroup adUiViewGroup);
|
||||
|
||||
/**
|
||||
* Detaches the attached player and event listener. Called on the main thread by
|
||||
* {@link AdsMediaSource}.
|
||||
* Stops using the ads loader for playback and deregisters the event listener. Called on the main
|
||||
* thread by {@link AdsMediaSource}.
|
||||
*/
|
||||
void detachPlayer();
|
||||
|
||||
/**
|
||||
* Releases the loader. Called by the application on the main thread when the instance is no
|
||||
* longer needed.
|
||||
*/
|
||||
void release();
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Notifies the ads loader that the player was not able to prepare media for a given ad.
|
||||
* Implementations should update the ad playback state as the specified ad has failed to load.
|
||||
* Called on the main thread by {@link AdsMediaSource}.
|
||||
*
|
||||
* @param adGroupIndex The index of the ad group.
|
||||
* @param adIndexInAdGroup The index of the ad in the ad group.
|
||||
|
@ -337,7 +337,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
final ComponentListener componentListener = new ComponentListener();
|
||||
this.componentListener = componentListener;
|
||||
prepareChildSource(DUMMY_CONTENT_MEDIA_PERIOD_ID, contentMediaSource);
|
||||
mainHandler.post(() -> adsLoader.attachPlayer(player, componentListener, adUiViewGroup));
|
||||
mainHandler.post(() -> adsLoader.start(componentListener, adUiViewGroup));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -406,7 +406,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
adPlaybackState = null;
|
||||
adGroupMediaSources = new MediaSource[0][];
|
||||
adGroupTimelines = new Timeline[0][];
|
||||
mainHandler.post(adsLoader::detachPlayer);
|
||||
mainHandler.post(adsLoader::stop);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user