Commit 58db5069 by ibaker Committed by tonihei

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
parent bf2c652b
......@@ -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;
......
......@@ -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 {
/**
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
}
......@@ -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);
}
......@@ -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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment