Store ad playback state in AdsLoader for resume after backgrounding

#minor-release

PiperOrigin-RevId: 428763656
This commit is contained in:
bachinger 2022-02-15 14:19:54 +00:00 committed by Ian Baker
parent 33afc4760b
commit b9b1be4f3e

View File

@ -151,6 +151,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
@Override @Override
public MediaSource createMediaSource(MediaItem mediaItem) { public MediaSource createMediaSource(MediaItem mediaItem) {
checkNotNull(mediaItem.localConfiguration);
Player player = checkNotNull(adsLoader.player); Player player = checkNotNull(adsLoader.player);
StreamPlayer streamPlayer = new StreamPlayer(player, mediaItem); StreamPlayer streamPlayer = new StreamPlayer(player, mediaItem);
ImaSdkFactory imaSdkFactory = ImaSdkFactory.getInstance(); ImaSdkFactory imaSdkFactory = ImaSdkFactory.getInstance();
@ -163,6 +164,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
new ImaServerSideAdInsertionMediaSource( new ImaServerSideAdInsertionMediaSource(
mediaItem, mediaItem,
player, player,
adsLoader,
imaAdsLoader, imaAdsLoader,
streamPlayer, streamPlayer,
contentMediaSourceFactory, contentMediaSourceFactory,
@ -185,6 +187,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
@Nullable private ImaSdkSettings imaSdkSettings; @Nullable private ImaSdkSettings imaSdkSettings;
@Nullable private AdEventListener adEventListener; @Nullable private AdEventListener adEventListener;
@Nullable private AdErrorEvent.AdErrorListener adErrorListener; @Nullable private AdErrorEvent.AdErrorListener adErrorListener;
private State state;
private ImmutableList<CompanionAdSlot> companionAdSlots; private ImmutableList<CompanionAdSlot> companionAdSlots;
/** /**
@ -197,6 +200,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
this.context = context; this.context = context;
this.adViewProvider = adViewProvider; this.adViewProvider = adViewProvider;
companionAdSlots = ImmutableList.of(); companionAdSlots = ImmutableList.of();
state = new State(ImmutableMap.of());
} }
/** /**
@ -248,6 +252,19 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
return this; return this;
} }
/**
* Sets the optional state to resume with.
*
* <p>The state can be received when {@link #release() releasing} the {@link AdsLoader}.
*
* @param state The state to resume with.
* @return This builder, for convenience.
*/
public AdsLoader.Builder setAdsLoaderState(State state) {
this.state = state;
return this;
}
/** Returns a new {@link AdsLoader}. */ /** Returns a new {@link AdsLoader}. */
public AdsLoader build() { public AdsLoader build() {
@Nullable ImaSdkSettings imaSdkSettings = this.imaSdkSettings; @Nullable ImaSdkSettings imaSdkSettings = this.imaSdkSettings;
@ -263,7 +280,17 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
adErrorListener, adErrorListener,
companionAdSlots, companionAdSlots,
imaSdkSettings.isDebugMode()); imaSdkSettings.isDebugMode());
return new AdsLoader(context, configuration); return new AdsLoader(context, configuration, state);
}
}
/** The state of the {@link AdsLoader}. */
public static class State {
private final ImmutableMap<String, AdPlaybackState> adPlaybackStates;
private State(ImmutableMap<String, AdPlaybackState> adPlaybackStates) {
this.adPlaybackStates = adPlaybackStates;
} }
} }
@ -271,13 +298,19 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
private final Context context; private final Context context;
private final Map<ImaServerSideAdInsertionMediaSource, MediaSourceResourceHolder> private final Map<ImaServerSideAdInsertionMediaSource, MediaSourceResourceHolder>
mediaSourceResources; mediaSourceResources;
private final Map<String, AdPlaybackState> adPlaybackStateMap;
@Nullable private Player player; @Nullable private Player player;
private AdsLoader(Context context, ImaUtil.ServerSideAdInsertionConfiguration configuration) { private AdsLoader(
Context context, ImaUtil.ServerSideAdInsertionConfiguration configuration, State state) {
this.context = context.getApplicationContext(); this.context = context.getApplicationContext();
this.configuration = configuration; this.configuration = configuration;
mediaSourceResources = new HashMap<>(); mediaSourceResources = new HashMap<>();
adPlaybackStateMap = new HashMap<>();
for (Map.Entry<String, AdPlaybackState> entry : state.adPlaybackStates.entrySet()) {
adPlaybackStateMap.put(entry.getKey(), entry.getValue());
}
} }
/** /**
@ -290,8 +323,12 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
this.player = player; this.player = player;
} }
/** Releases resources when the ads loader is no longer needed. */ /**
public void release() { * Releases resources.
*
* @return The {@link State} that can be used to resume with.
*/
public State release() {
for (MediaSourceResourceHolder resourceHolder : mediaSourceResources.values()) { for (MediaSourceResourceHolder resourceHolder : mediaSourceResources.values()) {
resourceHolder.streamPlayer.release(); resourceHolder.streamPlayer.release();
resourceHolder.adsLoader.release(); resourceHolder.adsLoader.release();
@ -300,9 +337,12 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
} }
mediaSourceResources.clear(); mediaSourceResources.clear();
player = null; player = null;
return new State(ImmutableMap.copyOf(adPlaybackStateMap));
} }
/* package */ void addMediaSourceResources( // Internal methods.
private void addMediaSourceResources(
ImaServerSideAdInsertionMediaSource mediaSource, ImaServerSideAdInsertionMediaSource mediaSource,
StreamPlayer streamPlayer, StreamPlayer streamPlayer,
com.google.ads.interactivemedia.v3.api.AdsLoader adsLoader) { com.google.ads.interactivemedia.v3.api.AdsLoader adsLoader) {
@ -310,6 +350,15 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
mediaSource, new MediaSourceResourceHolder(mediaSource, streamPlayer, adsLoader)); mediaSource, new MediaSourceResourceHolder(mediaSource, streamPlayer, adsLoader));
} }
private AdPlaybackState getAdPlaybackState(String adsId) {
@Nullable AdPlaybackState adPlaybackState = adPlaybackStateMap.get(adsId);
return adPlaybackState != null ? adPlaybackState : AdPlaybackState.NONE;
}
private void setAdPlaybackState(String adsId, AdPlaybackState adPlaybackState) {
this.adPlaybackStateMap.put(adsId, adPlaybackState);
}
private static final class MediaSourceResourceHolder { private static final class MediaSourceResourceHolder {
public final ImaServerSideAdInsertionMediaSource imaServerSideAdInsertionMediaSource; public final ImaServerSideAdInsertionMediaSource imaServerSideAdInsertionMediaSource;
public final StreamPlayer streamPlayer; public final StreamPlayer streamPlayer;
@ -329,7 +378,8 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
private final MediaItem mediaItem; private final MediaItem mediaItem;
private final Player player; private final Player player;
private final MediaSource.Factory contentMediaSourceFactory; private final MediaSource.Factory contentMediaSourceFactory;
private final com.google.ads.interactivemedia.v3.api.AdsLoader adsLoader; private final AdsLoader adsLoader;
private final com.google.ads.interactivemedia.v3.api.AdsLoader sdkAdsLoader;
@Nullable private final AdEventListener applicationAdEventListener; @Nullable private final AdEventListener applicationAdEventListener;
@Nullable private final AdErrorListener applicationAdErrorListener; @Nullable private final AdErrorListener applicationAdErrorListener;
private final boolean isLiveStream; private final boolean isLiveStream;
@ -350,7 +400,8 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
private ImaServerSideAdInsertionMediaSource( private ImaServerSideAdInsertionMediaSource(
MediaItem mediaItem, MediaItem mediaItem,
Player player, Player player,
com.google.ads.interactivemedia.v3.api.AdsLoader adsLoader, AdsLoader adsLoader,
com.google.ads.interactivemedia.v3.api.AdsLoader sdkAdsLoader,
StreamPlayer streamPlayer, StreamPlayer streamPlayer,
MediaSource.Factory contentMediaSourceFactory, MediaSource.Factory contentMediaSourceFactory,
@Nullable AdEventListener applicationAdEventListener, @Nullable AdEventListener applicationAdEventListener,
@ -358,18 +409,19 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
this.mediaItem = mediaItem; this.mediaItem = mediaItem;
this.player = player; this.player = player;
this.adsLoader = adsLoader; this.adsLoader = adsLoader;
this.sdkAdsLoader = sdkAdsLoader;
this.streamPlayer = streamPlayer; this.streamPlayer = streamPlayer;
this.contentMediaSourceFactory = contentMediaSourceFactory; this.contentMediaSourceFactory = contentMediaSourceFactory;
this.applicationAdEventListener = applicationAdEventListener; this.applicationAdEventListener = applicationAdEventListener;
this.applicationAdErrorListener = applicationAdErrorListener; this.applicationAdErrorListener = applicationAdErrorListener;
componentListener = new ComponentListener(); componentListener = new ComponentListener();
adPlaybackState = AdPlaybackState.NONE;
mainHandler = Util.createHandlerForCurrentLooper(); mainHandler = Util.createHandlerForCurrentLooper();
Uri streamRequestUri = checkNotNull(mediaItem.localConfiguration).uri; Uri streamRequestUri = checkNotNull(mediaItem.localConfiguration).uri;
isLiveStream = ImaServerSideAdInsertionUriBuilder.isLiveStream(streamRequestUri); isLiveStream = ImaServerSideAdInsertionUriBuilder.isLiveStream(streamRequestUri);
adsId = ImaServerSideAdInsertionUriBuilder.getAdsId(streamRequestUri); adsId = ImaServerSideAdInsertionUriBuilder.getAdsId(streamRequestUri);
loadVideoTimeoutMs = ImaServerSideAdInsertionUriBuilder.getLoadVideoTimeoutMs(streamRequestUri); loadVideoTimeoutMs = ImaServerSideAdInsertionUriBuilder.getLoadVideoTimeoutMs(streamRequestUri);
streamRequest = ImaServerSideAdInsertionUriBuilder.createStreamRequest(streamRequestUri); streamRequest = ImaServerSideAdInsertionUriBuilder.createStreamRequest(streamRequestUri);
adPlaybackState = adsLoader.getAdPlaybackState(adsId);
} }
@Override @Override
@ -386,7 +438,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
player.addListener(componentListener); player.addListener(componentListener);
StreamManagerLoadable streamManagerLoadable = StreamManagerLoadable streamManagerLoadable =
new StreamManagerLoadable( new StreamManagerLoadable(
adsLoader, sdkAdsLoader,
streamRequest, streamRequest,
streamPlayer, streamPlayer,
applicationAdErrorListener, applicationAdErrorListener,
@ -502,6 +554,10 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
splitAdPlaybackStateForPeriods(adPlaybackState, contentTimeline); splitAdPlaybackStateForPeriods(adPlaybackState, contentTimeline);
streamPlayer.setAdPlaybackStates(adsId, splitAdPlaybackStates, contentTimeline); streamPlayer.setAdPlaybackStates(adsId, splitAdPlaybackStates, contentTimeline);
checkNotNull(serverSideAdInsertionMediaSource).setAdPlaybackStates(splitAdPlaybackStates); checkNotNull(serverSideAdInsertionMediaSource).setAdPlaybackStates(splitAdPlaybackStates);
if (!ImaServerSideAdInsertionUriBuilder.isLiveStream(
checkNotNull(mediaItem.localConfiguration).uri)) {
adsLoader.setAdPlaybackState(adsId, adPlaybackState);
}
} }
} }