Promote IMA DAI API to stable

PiperOrigin-RevId: 626064956
This commit is contained in:
bachinger 2024-04-18 09:47:26 -07:00 committed by Copybara-Service
parent 300e83414d
commit 09f2cda43c
6 changed files with 70 additions and 13 deletions

View File

@ -29,6 +29,9 @@
* Effect: * Effect:
* Muxers: * Muxers:
* IMA extension: * IMA extension:
* Promote API that is required for apps to play
[DAI ad streams](https://developers.google.com/ad-manager/dynamic-ad-insertion/full-service)
to stable.
* Session: * Session:
* Hide seekbar in the media notification for live streams by not setting * Hide seekbar in the media notification for live streams by not setting
the duration into the platform session metadata the duration into the platform session metadata

24
api.txt
View File

@ -1388,6 +1388,29 @@ package androidx.media3.exoplayer.ima {
method public androidx.media3.exoplayer.ima.ImaAdsLoader build(); method public androidx.media3.exoplayer.ima.ImaAdsLoader build();
} }
public final class ImaServerSideAdInsertionMediaSource implements androidx.media3.exoplayer.source.MediaSource {
}
public static final class ImaServerSideAdInsertionMediaSource.AdsLoader {
method public androidx.media3.exoplayer.ima.ImaServerSideAdInsertionMediaSource.AdsLoader.State release();
method public void setPlayer(androidx.media3.common.Player);
}
public static final class ImaServerSideAdInsertionMediaSource.AdsLoader.Builder {
ctor public ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(android.content.Context, androidx.media3.common.AdViewProvider);
method public androidx.media3.exoplayer.ima.ImaServerSideAdInsertionMediaSource.AdsLoader build();
method public androidx.media3.exoplayer.ima.ImaServerSideAdInsertionMediaSource.AdsLoader.Builder setAdsLoaderState(androidx.media3.exoplayer.ima.ImaServerSideAdInsertionMediaSource.AdsLoader.State);
}
public static class ImaServerSideAdInsertionMediaSource.AdsLoader.State {
method public static androidx.media3.exoplayer.ima.ImaServerSideAdInsertionMediaSource.AdsLoader.State fromBundle(android.os.Bundle);
method public android.os.Bundle toBundle();
}
public static final class ImaServerSideAdInsertionMediaSource.Factory implements androidx.media3.exoplayer.source.MediaSource.Factory {
ctor public ImaServerSideAdInsertionMediaSource.Factory(androidx.media3.exoplayer.ima.ImaServerSideAdInsertionMediaSource.AdsLoader, androidx.media3.exoplayer.source.MediaSource.Factory);
}
} }
package androidx.media3.exoplayer.source { package androidx.media3.exoplayer.source {
@ -1397,6 +1420,7 @@ package androidx.media3.exoplayer.source {
method public androidx.media3.exoplayer.source.DefaultMediaSourceFactory clearLocalAdInsertionComponents(); method public androidx.media3.exoplayer.source.DefaultMediaSourceFactory clearLocalAdInsertionComponents();
method public androidx.media3.exoplayer.source.DefaultMediaSourceFactory setDataSourceFactory(androidx.media3.datasource.DataSource.Factory); method public androidx.media3.exoplayer.source.DefaultMediaSourceFactory setDataSourceFactory(androidx.media3.datasource.DataSource.Factory);
method public androidx.media3.exoplayer.source.DefaultMediaSourceFactory setLocalAdInsertionComponents(androidx.media3.exoplayer.source.ads.AdsLoader.Provider, androidx.media3.common.AdViewProvider); method public androidx.media3.exoplayer.source.DefaultMediaSourceFactory setLocalAdInsertionComponents(androidx.media3.exoplayer.source.ads.AdsLoader.Provider, androidx.media3.common.AdViewProvider);
method public androidx.media3.exoplayer.source.DefaultMediaSourceFactory setServerSideAdInsertionMediaSourceFactory(@Nullable androidx.media3.exoplayer.source.MediaSource.Factory);
} }
public interface MediaSource { public interface MediaSource {

View File

@ -93,11 +93,8 @@ public class PlayerActivity extends AppCompatActivity
@Nullable private AdsLoader clientSideAdsLoader; @Nullable private AdsLoader clientSideAdsLoader;
@OptIn(markerClass = UnstableApi.class) @Nullable private ImaServerSideAdInsertionMediaSource.AdsLoader serverSideAdsLoader;
@Nullable
private ImaServerSideAdInsertionMediaSource.AdsLoader serverSideAdsLoader;
@OptIn(markerClass = UnstableApi.class)
private ImaServerSideAdInsertionMediaSource.AdsLoader.@MonotonicNonNull State private ImaServerSideAdInsertionMediaSource.AdsLoader.@MonotonicNonNull State
serverSideAdsLoaderState; serverSideAdsLoaderState;
@ -301,7 +298,7 @@ public class PlayerActivity extends AppCompatActivity
return true; return true;
} }
@OptIn(markerClass = UnstableApi.class) // SSAI configuration @OptIn(markerClass = UnstableApi.class) // DRM configuration
private MediaSource.Factory createMediaSourceFactory() { private MediaSource.Factory createMediaSourceFactory() {
DefaultDrmSessionManagerProvider drmSessionManagerProvider = DefaultDrmSessionManagerProvider drmSessionManagerProvider =
new DefaultDrmSessionManagerProvider(); new DefaultDrmSessionManagerProvider();
@ -334,7 +331,6 @@ public class PlayerActivity extends AppCompatActivity
playerBuilder.setRenderersFactory(renderersFactory); playerBuilder.setRenderersFactory(renderersFactory);
} }
@OptIn(markerClass = UnstableApi.class)
private void configurePlayerWithServerSideAdsLoader() { private void configurePlayerWithServerSideAdsLoader() {
serverSideAdsLoader.setPlayer(player); serverSideAdsLoader.setPlayer(player);
} }
@ -403,7 +399,6 @@ public class PlayerActivity extends AppCompatActivity
} }
} }
@OptIn(markerClass = UnstableApi.class)
private void releaseServerSideAdsLoader() { private void releaseServerSideAdsLoader() {
serverSideAdsLoaderState = serverSideAdsLoader.release(); serverSideAdsLoaderState = serverSideAdsLoader.release();
serverSideAdsLoader = null; serverSideAdsLoader = null;
@ -417,14 +412,12 @@ public class PlayerActivity extends AppCompatActivity
} }
} }
@OptIn(markerClass = UnstableApi.class)
private void saveServerSideAdsLoaderState(Bundle outState) { private void saveServerSideAdsLoaderState(Bundle outState) {
if (serverSideAdsLoaderState != null) { if (serverSideAdsLoaderState != null) {
outState.putBundle(KEY_SERVER_SIDE_ADS_LOADER_STATE, serverSideAdsLoaderState.toBundle()); outState.putBundle(KEY_SERVER_SIDE_ADS_LOADER_STATE, serverSideAdsLoaderState.toBundle());
} }
} }
@OptIn(markerClass = UnstableApi.class)
private void restoreServerSideAdsLoaderState(Bundle savedInstanceState) { private void restoreServerSideAdsLoaderState(Bundle savedInstanceState) {
Bundle adsLoaderStateBundle = savedInstanceState.getBundle(KEY_SERVER_SIDE_ADS_LOADER_STATE); Bundle adsLoaderStateBundle = savedInstanceState.getBundle(KEY_SERVER_SIDE_ADS_LOADER_STATE);
if (adsLoaderStateBundle != null) { if (adsLoaderStateBundle != null) {
@ -513,7 +506,7 @@ public class PlayerActivity extends AppCompatActivity
private class PlayerErrorMessageProvider implements ErrorMessageProvider<PlaybackException> { private class PlayerErrorMessageProvider implements ErrorMessageProvider<PlaybackException> {
@OptIn(markerClass = androidx.media3.common.util.UnstableApi.class) @OptIn(markerClass = UnstableApi.class) // Using decoder exceptions
@Override @Override
public Pair<Integer, String> getErrorMessage(PlaybackException e) { public Pair<Integer, String> getErrorMessage(PlaybackException e) {
String errorString = getString(R.string.error_generic); String errorString = getString(R.string.error_generic);
@ -554,7 +547,7 @@ public class PlayerActivity extends AppCompatActivity
return mediaItems; return mediaItems;
} }
@OptIn(markerClass = androidx.media3.common.util.UnstableApi.class) @OptIn(markerClass = UnstableApi.class) // Using Download API
private static MediaItem maybeSetDownloadProperties( private static MediaItem maybeSetDownloadProperties(
MediaItem item, @Nullable DownloadRequest downloadRequest) { MediaItem item, @Nullable DownloadRequest downloadRequest) {
if (downloadRequest == null) { if (downloadRequest == null) {

View File

@ -202,6 +202,7 @@ public abstract class BaseMediaSource implements MediaSource {
return !mediaSourceCallers.isEmpty(); return !mediaSourceCallers.isEmpty();
} }
@UnstableApi
@Override @Override
public final void addEventListener(Handler handler, MediaSourceEventListener eventListener) { public final void addEventListener(Handler handler, MediaSourceEventListener eventListener) {
Assertions.checkNotNull(handler); Assertions.checkNotNull(handler);
@ -209,11 +210,13 @@ public abstract class BaseMediaSource implements MediaSource {
eventDispatcher.addEventListener(handler, eventListener); eventDispatcher.addEventListener(handler, eventListener);
} }
@UnstableApi
@Override @Override
public final void removeEventListener(MediaSourceEventListener eventListener) { public final void removeEventListener(MediaSourceEventListener eventListener) {
eventDispatcher.removeEventListener(eventListener); eventDispatcher.removeEventListener(eventListener);
} }
@UnstableApi
@Override @Override
public final void addDrmEventListener(Handler handler, DrmSessionEventListener eventListener) { public final void addDrmEventListener(Handler handler, DrmSessionEventListener eventListener) {
Assertions.checkNotNull(handler); Assertions.checkNotNull(handler);
@ -221,11 +224,13 @@ public abstract class BaseMediaSource implements MediaSource {
drmEventDispatcher.addEventListener(handler, eventListener); drmEventDispatcher.addEventListener(handler, eventListener);
} }
@UnstableApi
@Override @Override
public final void removeDrmEventListener(DrmSessionEventListener eventListener) { public final void removeDrmEventListener(DrmSessionEventListener eventListener) {
drmEventDispatcher.removeEventListener(eventListener); drmEventDispatcher.removeEventListener(eventListener);
} }
@UnstableApi
@SuppressWarnings("deprecation") // Overriding deprecated method to make it final. @SuppressWarnings("deprecation") // Overriding deprecated method to make it final.
@Override @Override
public final void prepareSource( public final void prepareSource(
@ -233,6 +238,7 @@ public abstract class BaseMediaSource implements MediaSource {
prepareSource(caller, mediaTransferListener, PlayerId.UNSET); prepareSource(caller, mediaTransferListener, PlayerId.UNSET);
} }
@UnstableApi
@Override @Override
public final void prepareSource( public final void prepareSource(
MediaSourceCaller caller, MediaSourceCaller caller,
@ -253,6 +259,7 @@ public abstract class BaseMediaSource implements MediaSource {
} }
} }
@UnstableApi
@Override @Override
public final void enable(MediaSourceCaller caller) { public final void enable(MediaSourceCaller caller) {
Assertions.checkNotNull(looper); Assertions.checkNotNull(looper);
@ -263,6 +270,7 @@ public abstract class BaseMediaSource implements MediaSource {
} }
} }
@UnstableApi
@Override @Override
public final void disable(MediaSourceCaller caller) { public final void disable(MediaSourceCaller caller) {
boolean wasEnabled = !enabledMediaSourceCallers.isEmpty(); boolean wasEnabled = !enabledMediaSourceCallers.isEmpty();
@ -272,6 +280,7 @@ public abstract class BaseMediaSource implements MediaSource {
} }
} }
@UnstableApi
@Override @Override
public final void releaseSource(MediaSourceCaller caller) { public final void releaseSource(MediaSourceCaller caller) {
mediaSourceCallers.remove(caller); mediaSourceCallers.remove(caller);

View File

@ -313,7 +313,6 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* @return This factory, for convenience. * @return This factory, for convenience.
*/ */
@CanIgnoreReturnValue @CanIgnoreReturnValue
@UnstableApi
public DefaultMediaSourceFactory setServerSideAdInsertionMediaSourceFactory( public DefaultMediaSourceFactory setServerSideAdInsertionMediaSourceFactory(
@Nullable MediaSource.Factory serverSideAdInsertionMediaSourceFactory) { @Nullable MediaSource.Factory serverSideAdInsertionMediaSourceFactory) {
this.serverSideAdInsertionMediaSourceFactory = serverSideAdInsertionMediaSourceFactory; this.serverSideAdInsertionMediaSourceFactory = serverSideAdInsertionMediaSourceFactory;

View File

@ -112,10 +112,10 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
/** MediaSource for IMA server side inserted ad streams. */ /** MediaSource for IMA server side inserted ad streams. */
@UnstableApi
public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSource<Void> { public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSource<Void> {
/** A listener to be notified of stream events. */ /** A listener to be notified of stream events. */
@UnstableApi
public interface StreamEventListener { public interface StreamEventListener {
/** /**
@ -154,6 +154,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
this.contentMediaSourceFactory = contentMediaSourceFactory; this.contentMediaSourceFactory = contentMediaSourceFactory;
} }
@UnstableApi
@CanIgnoreReturnValue @CanIgnoreReturnValue
@Override @Override
public MediaSource.Factory setLoadErrorHandlingPolicy( public MediaSource.Factory setLoadErrorHandlingPolicy(
@ -162,6 +163,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
return this; return this;
} }
@UnstableApi
@CanIgnoreReturnValue @CanIgnoreReturnValue
@Override @Override
public MediaSource.Factory setDrmSessionManagerProvider( public MediaSource.Factory setDrmSessionManagerProvider(
@ -170,11 +172,13 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
return this; return this;
} }
@UnstableApi
@Override @Override
public @C.ContentType int[] getSupportedTypes() { public @C.ContentType int[] getSupportedTypes() {
return contentMediaSourceFactory.getSupportedTypes(); return contentMediaSourceFactory.getSupportedTypes();
} }
@UnstableApi
@Override @Override
public MediaSource createMediaSource(MediaItem mediaItem) { public MediaSource createMediaSource(MediaItem mediaItem) {
checkNotNull(mediaItem.localConfiguration); checkNotNull(mediaItem.localConfiguration);
@ -248,6 +252,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
* @param imaSdkSettings The {@link ImaSdkSettings}. * @param imaSdkSettings The {@link ImaSdkSettings}.
* @return This builder, for convenience. * @return This builder, for convenience.
*/ */
@UnstableApi
@CanIgnoreReturnValue @CanIgnoreReturnValue
public AdsLoader.Builder setImaSdkSettings(ImaSdkSettings imaSdkSettings) { public AdsLoader.Builder setImaSdkSettings(ImaSdkSettings imaSdkSettings) {
this.imaSdkSettings = imaSdkSettings; this.imaSdkSettings = imaSdkSettings;
@ -260,6 +265,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
* @param streamEventListener The stream event listener. * @param streamEventListener The stream event listener.
* @return This builder, for convenience. * @return This builder, for convenience.
*/ */
@UnstableApi
@CanIgnoreReturnValue @CanIgnoreReturnValue
public AdsLoader.Builder setStreamEventListener(StreamEventListener streamEventListener) { public AdsLoader.Builder setStreamEventListener(StreamEventListener streamEventListener) {
this.streamEventListener = streamEventListener; this.streamEventListener = streamEventListener;
@ -271,9 +277,14 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
* StreamManager#addAdEventListener(AdEventListener)} when the stream manager becomes * StreamManager#addAdEventListener(AdEventListener)} when the stream manager becomes
* available. * available.
* *
* <p>Note: This method can be considered a stable API as long as the {@link AdEventListener}
* is provided by the IMA library. We can't declare this method stable because we don't have
* the same guarantee from the library we depend on.
*
* @param adEventListener The ad event listener. * @param adEventListener The ad event listener.
* @return This builder, for convenience. * @return This builder, for convenience.
*/ */
@UnstableApi
@CanIgnoreReturnValue @CanIgnoreReturnValue
public AdsLoader.Builder setAdEventListener(AdEventListener adEventListener) { public AdsLoader.Builder setAdEventListener(AdEventListener adEventListener) {
this.adEventListener = adEventListener; this.adEventListener = adEventListener;
@ -285,9 +296,14 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
* StreamManager#addAdErrorListener(AdErrorEvent.AdErrorListener)} when the stream manager * StreamManager#addAdErrorListener(AdErrorEvent.AdErrorListener)} when the stream manager
* becomes available. * becomes available.
* *
* <p>Note: This method can be considered a stable API as long as the {@link
* AdErrorEvent.AdErrorListener} is provided by the IMA library. We can't declare this method
* stable because we don't have the same guarantee from the library we depend on.
*
* @param adErrorListener The {@link AdErrorEvent.AdErrorListener}. * @param adErrorListener The {@link AdErrorEvent.AdErrorListener}.
* @return This builder, for convenience. * @return This builder, for convenience.
*/ */
@UnstableApi
@CanIgnoreReturnValue @CanIgnoreReturnValue
public AdsLoader.Builder setAdErrorListener(AdErrorEvent.AdErrorListener adErrorListener) { public AdsLoader.Builder setAdErrorListener(AdErrorEvent.AdErrorListener adErrorListener) {
this.adErrorListener = adErrorListener; this.adErrorListener = adErrorListener;
@ -301,6 +317,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
* @return This builder, for convenience. * @return This builder, for convenience.
* @see AdDisplayContainer#setCompanionSlots(Collection) * @see AdDisplayContainer#setCompanionSlots(Collection)
*/ */
@UnstableApi
@CanIgnoreReturnValue @CanIgnoreReturnValue
public AdsLoader.Builder setCompanionAdSlots(Collection<CompanionAdSlot> companionAdSlots) { public AdsLoader.Builder setCompanionAdSlots(Collection<CompanionAdSlot> companionAdSlots) {
this.companionAdSlots = ImmutableList.copyOf(companionAdSlots); this.companionAdSlots = ImmutableList.copyOf(companionAdSlots);
@ -330,6 +347,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
* @return This builder, for convenience. * @return This builder, for convenience.
* @see AdsRenderingSettings#setFocusSkipButtonWhenAvailable(boolean) * @see AdsRenderingSettings#setFocusSkipButtonWhenAvailable(boolean)
*/ */
@UnstableApi
@CanIgnoreReturnValue @CanIgnoreReturnValue
public AdsLoader.Builder setFocusSkipButtonWhenAvailable( public AdsLoader.Builder setFocusSkipButtonWhenAvailable(
boolean focusSkipButtonWhenAvailable) { boolean focusSkipButtonWhenAvailable) {
@ -405,6 +423,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
* *
* @deprecated Use {@link #fromBundle} instead. * @deprecated Use {@link #fromBundle} instead.
*/ */
@UnstableApi
@Deprecated @Deprecated
@SuppressWarnings("deprecation") // Deprecated instance of deprecated class @SuppressWarnings("deprecation") // Deprecated instance of deprecated class
public static final Bundleable.Creator<State> CREATOR = State::fromBundle; public static final Bundleable.Creator<State> CREATOR = State::fromBundle;
@ -458,6 +477,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
* *
* @see StreamManager#focus() * @see StreamManager#focus()
*/ */
@UnstableApi
public void focusSkipButton() { public void focusSkipButton() {
if (player == null) { if (player == null) {
return; return;
@ -600,11 +620,13 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
adPlaybackState = adsLoader.getAdPlaybackState(adsId); adPlaybackState = adsLoader.getAdPlaybackState(adsId);
} }
@UnstableApi
@Override @Override
public synchronized MediaItem getMediaItem() { public synchronized MediaItem getMediaItem() {
return mediaItem; return mediaItem;
} }
@UnstableApi
@Override @Override
public boolean canUpdateMediaItem(MediaItem mediaItem) { public boolean canUpdateMediaItem(MediaItem mediaItem) {
MediaItem existingMediaItem = getMediaItem(); MediaItem existingMediaItem = getMediaItem();
@ -619,11 +641,13 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
&& existingMediaItem.liveConfiguration.equals(mediaItem.liveConfiguration); && existingMediaItem.liveConfiguration.equals(mediaItem.liveConfiguration);
} }
@UnstableApi
@Override @Override
public synchronized void updateMediaItem(MediaItem mediaItem) { public synchronized void updateMediaItem(MediaItem mediaItem) {
this.mediaItem = mediaItem; this.mediaItem = mediaItem;
} }
@UnstableApi
@Override @Override
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) { public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
mainHandler.post(() -> assertSingleInstanceInPlaylist(checkNotNull(player))); mainHandler.post(() -> assertSingleInstanceInPlaylist(checkNotNull(player)));
@ -646,6 +670,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
} }
} }
@UnstableApi
@Override @Override
protected void onChildSourceInfoRefreshed( protected void onChildSourceInfoRefreshed(
Void childSourceId, MediaSource mediaSource, Timeline newTimeline) { Void childSourceId, MediaSource mediaSource, Timeline newTimeline) {
@ -662,17 +687,20 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
}); });
} }
@UnstableApi
@Override @Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
return checkNotNull(serverSideAdInsertionMediaSource) return checkNotNull(serverSideAdInsertionMediaSource)
.createPeriod(id, allocator, startPositionUs); .createPeriod(id, allocator, startPositionUs);
} }
@UnstableApi
@Override @Override
public void releasePeriod(MediaPeriod mediaPeriod) { public void releasePeriod(MediaPeriod mediaPeriod) {
checkNotNull(serverSideAdInsertionMediaSource).releasePeriod(mediaPeriod); checkNotNull(serverSideAdInsertionMediaSource).releasePeriod(mediaPeriod);
} }
@UnstableApi
@Override @Override
public void maybeThrowSourceInfoRefreshError() throws IOException { public void maybeThrowSourceInfoRefreshError() throws IOException {
super.maybeThrowSourceInfoRefreshError(); super.maybeThrowSourceInfoRefreshError();
@ -683,6 +711,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
} }
} }
@UnstableApi
@Override @Override
protected void releaseSourceInternal() { protected void releaseSourceInternal() {
super.releaseSourceInternal(); super.releaseSourceInternal();