Support simple ad serving with the stable API

This involves stabilising AdsLoader and ImaAdsLoader, as well
as (Default)MediaSourceFactory and the following methods on
ExoPlayer.Builder:
* setMediaSourceFactory
* setAdsLoaderProvider
* setAdViewProvider

Most of ImaAdsLoader.Builder and (Default)MediaSourceFactory remain
unstable for now.

PiperOrigin-RevId: 417814106
This commit is contained in:
ibaker 2021-12-22 15:08:58 +00:00 committed by tonihei
parent bf2c652b5f
commit 58db50699f
7 changed files with 53 additions and 9 deletions

View File

@ -31,7 +31,6 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** Provides information about an overlay view shown on top of an ad view group. */
@UnstableApi
public final class AdOverlayInfo {
/**
@ -97,12 +96,14 @@ public final class AdOverlayInfo {
@Nullable public final String reasonDetail;
/** @deprecated Use {@link Builder} instead. */
@UnstableApi
@Deprecated
public AdOverlayInfo(View view, @Purpose int purpose) {
this(view, purpose, /* detailedReason= */ null);
}
/** @deprecated Use {@link Builder} instead. */
@UnstableApi
@Deprecated
public AdOverlayInfo(View view, @Purpose int purpose, @Nullable String detailedReason) {
this.view = view;

View File

@ -17,12 +17,10 @@ package androidx.media3.common;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi;
import com.google.common.collect.ImmutableList;
import java.util.List;
/** Provides information about views for the ad playback UI. */
@UnstableApi
public interface AdViewProvider {
/**

View File

@ -630,7 +630,6 @@ public interface ExoPlayer extends Player {
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
@UnstableApi
public Builder setMediaSourceFactory(MediaSourceFactory mediaSourceFactory) {
checkState(!buildCalled);
this.mediaSourceFactorySupplier = () -> mediaSourceFactory;

View File

@ -93,10 +93,10 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
* configuration}, {@link #setAdsLoaderProvider} and {@link #setAdViewProvider} need to be called to
* configure the factory with the required providers.
*/
@UnstableApi
public final class DefaultMediaSourceFactory implements MediaSourceFactory {
/** @deprecated Use {@link AdsLoader.Provider} instead. */
@UnstableApi
@Deprecated
public interface AdsLoaderProvider extends AdsLoader.Provider {}
@ -132,6 +132,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* @param extractorsFactory An {@link ExtractorsFactory} used to extract progressive media from
* its container.
*/
@UnstableApi
public DefaultMediaSourceFactory(Context context, ExtractorsFactory extractorsFactory) {
this(
new DefaultDataSource.Factory(context),
@ -145,6 +146,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* @param dataSourceFactory A {@link DataSource.Factory} to create {@link DataSource} instances
* for requesting media data.
*/
@UnstableApi
public DefaultMediaSourceFactory(DataSource.Factory dataSourceFactory) {
this(
dataSourceFactory,
@ -162,6 +164,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* @param serverSideDaiMediaSourceFactory A {@link MediaSourceFactory} for creating server side
* inserted ad media sources.
*/
@UnstableApi
public DefaultMediaSourceFactory(
DataSource.Factory dataSourceFactory,
ExtractorsFactory extractorsFactory,
@ -189,6 +192,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* should be used for subtitles instead of {@link SingleSampleMediaSource}.
* @return This factory, for convenience.
*/
@UnstableApi
public DefaultMediaSourceFactory experimentalUseProgressiveMediaSourceForSubtitles(
boolean useProgressiveMediaSourceForSubtitles) {
this.useProgressiveMediaSourceForSubtitles = useProgressiveMediaSourceForSubtitles;
@ -226,6 +230,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* use the media-defined default.
* @return This factory, for convenience.
*/
@UnstableApi
public DefaultMediaSourceFactory setLiveTargetOffsetMs(long liveTargetOffsetMs) {
this.liveTargetOffsetMs = liveTargetOffsetMs;
return this;
@ -238,6 +243,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* C#TIME_UNSET} to use the media-defined default.
* @return This factory, for convenience.
*/
@UnstableApi
public DefaultMediaSourceFactory setLiveMinOffsetMs(long liveMinOffsetMs) {
this.liveMinOffsetMs = liveMinOffsetMs;
return this;
@ -250,6 +256,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* C#TIME_UNSET} to use the media-defined default.
* @return This factory, for convenience.
*/
@UnstableApi
public DefaultMediaSourceFactory setLiveMaxOffsetMs(long liveMaxOffsetMs) {
this.liveMaxOffsetMs = liveMaxOffsetMs;
return this;
@ -262,6 +269,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* C#RATE_UNSET} to use the media-defined default.
* @return This factory, for convenience.
*/
@UnstableApi
public DefaultMediaSourceFactory setLiveMinSpeed(float minSpeed) {
this.liveMinSpeed = minSpeed;
return this;
@ -274,11 +282,13 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* C#RATE_UNSET} to use the media-defined default.
* @return This factory, for convenience.
*/
@UnstableApi
public DefaultMediaSourceFactory setLiveMaxSpeed(float maxSpeed) {
this.liveMaxSpeed = maxSpeed;
return this;
}
@UnstableApi
@Override
public DefaultMediaSourceFactory setDrmSessionManagerProvider(
@Nullable DrmSessionManagerProvider drmSessionManagerProvider) {
@ -286,6 +296,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
return this;
}
@UnstableApi
@Override
public DefaultMediaSourceFactory setLoadErrorHandlingPolicy(
@Nullable LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
@ -294,11 +305,13 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
return this;
}
@UnstableApi
@Override
public int[] getSupportedTypes() {
return delegateFactoryLoader.getSupportedTypes();
}
@UnstableApi
@Override
public MediaSource createMediaSource(MediaItem mediaItem) {
Assertions.checkNotNull(mediaItem.localConfiguration);

View File

@ -26,13 +26,13 @@ import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy;
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
/** Factory for creating {@link MediaSource MediaSources} from {@link MediaItem MediaItems}. */
@UnstableApi
public interface MediaSourceFactory {
/**
* An instance that throws {@link UnsupportedOperationException} from {@link #createMediaSource}
* and {@link #getSupportedTypes()}.
*/
@UnstableApi
MediaSourceFactory UNSUPPORTED =
new MediaSourceFactory() {
@Override
@ -67,6 +67,7 @@ public interface MediaSourceFactory {
*
* @return This factory, for convenience.
*/
@UnstableApi
MediaSourceFactory setDrmSessionManagerProvider(
@Nullable DrmSessionManagerProvider drmSessionManagerProvider);
@ -77,6 +78,7 @@ public interface MediaSourceFactory {
* {@link DefaultLoadErrorHandlingPolicy}.
* @return This factory, for convenience.
*/
@UnstableApi
MediaSourceFactory setLoadErrorHandlingPolicy(
@Nullable LoadErrorHandlingPolicy loadErrorHandlingPolicy);
@ -84,6 +86,7 @@ public interface MediaSourceFactory {
* Returns the {@link C.ContentType content types} supported by media sources created by this
* factory.
*/
@UnstableApi
@C.ContentType
int[] getSupportedTypes();
@ -93,5 +96,6 @@ public interface MediaSourceFactory {
* @param mediaItem The media item to play.
* @return The new {@link MediaSource media source}.
*/
@UnstableApi
MediaSource createMediaSource(MediaItem mediaItem);
}

View File

@ -47,7 +47,6 @@ import java.io.IOException;
* implementation of {@link #start(AdsMediaSource, DataSpec, Object, AdViewProvider, EventListener)}
* should invoke the same listener to provide the existing playback state to the new player.
*/
@UnstableApi
public interface AdsLoader {
/**
@ -69,6 +68,7 @@ public interface AdsLoader {
}
/** Listener for ads loader events. All methods are called on the main thread. */
@UnstableApi
interface EventListener {
/**
@ -126,6 +126,7 @@ public interface AdsLoader {
* @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}.
*/
@UnstableApi
void setSupportedContentTypes(@C.ContentType int... contentTypes);
/**
@ -137,6 +138,7 @@ public interface AdsLoader {
* @param adViewProvider Provider of views for the ad UI.
* @param eventListener Listener for ads loader events.
*/
@UnstableApi
void start(
AdsMediaSource adsMediaSource,
DataSpec adTagDataSpec,
@ -151,6 +153,7 @@ public interface AdsLoader {
* @param adsMediaSource The ads media source requesting to stop loading/playing ads.
* @param eventListener The ads media source's listener for ads loader events.
*/
@UnstableApi
void stop(AdsMediaSource adsMediaSource, EventListener eventListener);
/**
@ -161,6 +164,7 @@ public interface AdsLoader {
* @param adGroupIndex The index of the ad group.
* @param adIndexInAdGroup The index of the ad in the ad group.
*/
@UnstableApi
void handlePrepareComplete(AdsMediaSource adsMediaSource, int adGroupIndex, int adIndexInAdGroup);
/**
@ -173,6 +177,7 @@ public interface AdsLoader {
* @param adIndexInAdGroup The index of the ad in the ad group.
* @param exception The preparation error.
*/
@UnstableApi
void handlePrepareError(
AdsMediaSource adsMediaSource, int adGroupIndex, int adIndexInAdGroup, IOException exception);
}

View File

@ -87,7 +87,6 @@ import java.util.Set;
* href="https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/omsdk">IMA
* SDK Open Measurement documentation</a> for more information.
*/
@UnstableApi
public final class ImaAdsLoader implements AdsLoader {
static {
@ -106,7 +105,7 @@ public final class ImaAdsLoader implements AdsLoader {
*
* @see #setAdPreloadTimeoutMs(long)
*/
public static final long DEFAULT_AD_PRELOAD_TIMEOUT_MS = 10 * C.MILLIS_PER_SECOND;
@UnstableApi public static final long DEFAULT_AD_PRELOAD_TIMEOUT_MS = 10 * C.MILLIS_PER_SECOND;
private final Context context;
@ -152,6 +151,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @param imaSdkSettings The {@link ImaSdkSettings}.
* @return This builder, for convenience.
*/
@UnstableApi
public Builder setImaSdkSettings(ImaSdkSettings imaSdkSettings) {
this.imaSdkSettings = checkNotNull(imaSdkSettings);
return this;
@ -165,6 +165,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @param adErrorListener The ad error listener.
* @return This builder, for convenience.
*/
@UnstableApi
public Builder setAdErrorListener(AdErrorListener adErrorListener) {
this.adErrorListener = checkNotNull(adErrorListener);
return this;
@ -177,6 +178,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @param adEventListener The ad event listener.
* @return This builder, for convenience.
*/
@UnstableApi
public Builder setAdEventListener(AdEventListener adEventListener) {
this.adEventListener = checkNotNull(adEventListener);
return this;
@ -192,6 +194,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @return This builder, for convenience.
* @see com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer.VideoAdPlayerCallback
*/
@UnstableApi
public Builder setVideoAdPlayerCallback(
VideoAdPlayer.VideoAdPlayerCallback videoAdPlayerCallback) {
this.videoAdPlayerCallback = checkNotNull(videoAdPlayerCallback);
@ -205,6 +208,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @return This builder, for convenience.
* @see AdsRenderingSettings#setUiElements(Set)
*/
@UnstableApi
public Builder setAdUiElements(Set<UiElement> adUiElements) {
this.adUiElements = ImmutableSet.copyOf(checkNotNull(adUiElements));
return this;
@ -217,6 +221,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @return This builder, for convenience.
* @see AdDisplayContainer#setCompanionSlots(Collection)
*/
@UnstableApi
public Builder setCompanionAdSlots(Collection<CompanionAdSlot> companionAdSlots) {
this.companionAdSlots = ImmutableList.copyOf(checkNotNull(companionAdSlots));
return this;
@ -234,6 +239,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @return This builder, for convenience.
* @see AdsRenderingSettings#setMimeTypes(List)
*/
@UnstableApi
public Builder setAdMediaMimeTypes(List<String> adMediaMimeTypes) {
this.adMediaMimeTypes = ImmutableList.copyOf(checkNotNull(adMediaMimeTypes));
return this;
@ -248,6 +254,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @return This builder, for convenience.
* @see AdsRequest#setContinuousPlayback(boolean)
*/
@UnstableApi
public Builder setEnableContinuousPlayback(boolean enableContinuousPlayback) {
this.enableContinuousPlayback = enableContinuousPlayback;
return this;
@ -266,6 +273,7 @@ public final class ImaAdsLoader implements AdsLoader {
* C#TIME_UNSET} for no timeout.
* @return This builder, for convenience.
*/
@UnstableApi
public Builder setAdPreloadTimeoutMs(long adPreloadTimeoutMs) {
checkArgument(adPreloadTimeoutMs == C.TIME_UNSET || adPreloadTimeoutMs > 0);
this.adPreloadTimeoutMs = adPreloadTimeoutMs;
@ -279,6 +287,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @return This builder, for convenience.
* @see AdsRequest#setVastLoadTimeout(float)
*/
@UnstableApi
public Builder setVastLoadTimeoutMs(@IntRange(from = 1) int vastLoadTimeoutMs) {
checkArgument(vastLoadTimeoutMs > 0);
this.vastLoadTimeoutMs = vastLoadTimeoutMs;
@ -292,6 +301,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @return This builder, for convenience.
* @see AdsRenderingSettings#setLoadVideoTimeout(int)
*/
@UnstableApi
public Builder setMediaLoadTimeoutMs(@IntRange(from = 1) int mediaLoadTimeoutMs) {
checkArgument(mediaLoadTimeoutMs > 0);
this.mediaLoadTimeoutMs = mediaLoadTimeoutMs;
@ -305,6 +315,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @return This builder, for convenience.
* @see AdsRenderingSettings#setBitrateKbps(int)
*/
@UnstableApi
public Builder setMaxMediaBitrate(@IntRange(from = 1) int bitrate) {
checkArgument(bitrate > 0);
this.mediaBitrate = bitrate;
@ -320,6 +331,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @return This builder, for convenience.
* @see AdsRenderingSettings#setFocusSkipButtonWhenAvailable(boolean)
*/
@UnstableApi
public Builder setFocusSkipButtonWhenAvailable(boolean focusSkipButtonWhenAvailable) {
this.focusSkipButtonWhenAvailable = focusSkipButtonWhenAvailable;
return this;
@ -335,6 +347,7 @@ public final class ImaAdsLoader implements AdsLoader {
* beginning playback.
* @return This builder, for convenience.
*/
@UnstableApi
public Builder setPlayAdBeforeStartPosition(boolean playAdBeforeStartPosition) {
this.playAdBeforeStartPosition = playAdBeforeStartPosition;
return this;
@ -350,6 +363,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @return This builder, for convenience.
* @see ImaSdkSettings#setDebugMode(boolean)
*/
@UnstableApi
public Builder setDebugModeEnabled(boolean debugModeEnabled) {
this.debugModeEnabled = debugModeEnabled;
return this;
@ -417,6 +431,7 @@ public final class ImaAdsLoader implements AdsLoader {
* Returns the underlying {@link com.google.ads.interactivemedia.v3.api.AdsLoader} wrapped by this
* instance, or {@code null} if ads have not been requested yet.
*/
@UnstableApi
@Nullable
public com.google.ads.interactivemedia.v3.api.AdsLoader getAdsLoader() {
return currentAdTagLoader != null ? currentAdTagLoader.getAdsLoader() : null;
@ -433,6 +448,7 @@ public final class ImaAdsLoader implements AdsLoader {
* the {@link AdViewProvider} when creating the media source to benefit from automatic
* registration.
*/
@UnstableApi
@Nullable
public AdDisplayContainer getAdDisplayContainer() {
return currentAdTagLoader != null ? currentAdTagLoader.getAdDisplayContainer() : null;
@ -451,6 +467,7 @@ public final class ImaAdsLoader implements AdsLoader {
* @param adViewGroup A {@link ViewGroup} on top of the player that will show any ad UI, or {@code
* null} if playing audio-only ads.
*/
@UnstableApi
public void requestAds(DataSpec adTagDataSpec, Object adsId, @Nullable ViewGroup adViewGroup) {
if (!adTagLoaderByAdsId.containsKey(adsId)) {
AdTagLoader adTagLoader =
@ -473,6 +490,7 @@ public final class ImaAdsLoader implements AdsLoader {
* UI for users to skip skippable ads. Apps showing video ads should not call this method, as the
* IMA SDK provides the UI to skip ads in the ad view group passed via {@link AdViewProvider}.
*/
@UnstableApi
public void skipAd() {
if (currentAdTagLoader != null) {
currentAdTagLoader.skipAd();
@ -483,6 +501,7 @@ public final class ImaAdsLoader implements AdsLoader {
* Moves UI focus to the skip button (or other interactive elements), if currently shown. See
* {@link AdsManager#focus()}.
*/
@UnstableApi
public void focusSkipButton() {
if (currentAdTagLoader != null) {
currentAdTagLoader.focusSkipButton();
@ -499,6 +518,7 @@ public final class ImaAdsLoader implements AdsLoader {
wasSetPlayerCalled = true;
}
@UnstableApi
@Override
public void setSupportedContentTypes(@C.ContentType int... contentTypes) {
List<String> supportedMimeTypes = new ArrayList<>();
@ -521,6 +541,7 @@ public final class ImaAdsLoader implements AdsLoader {
this.supportedMimeTypes = Collections.unmodifiableList(supportedMimeTypes);
}
@UnstableApi
@Override
public void start(
AdsMediaSource adsMediaSource,
@ -549,6 +570,7 @@ public final class ImaAdsLoader implements AdsLoader {
maybeUpdateCurrentAdTagLoader();
}
@UnstableApi
@Override
public void stop(AdsMediaSource adsMediaSource, EventListener eventListener) {
@Nullable AdTagLoader removedAdTagLoader = adTagLoaderByAdsMediaSource.remove(adsMediaSource);
@ -583,6 +605,7 @@ public final class ImaAdsLoader implements AdsLoader {
adTagLoaderByAdsId.clear();
}
@UnstableApi
@Override
public void handlePrepareComplete(
AdsMediaSource adsMediaSource, int adGroupIndex, int adIndexInAdGroup) {
@ -593,6 +616,7 @@ public final class ImaAdsLoader implements AdsLoader {
.handlePrepareComplete(adGroupIndex, adIndexInAdGroup);
}
@UnstableApi
@Override
public void handlePrepareError(
AdsMediaSource adsMediaSource,