diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MediaSource.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MediaSource.java index d9d496bccd..d3753bceb9 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MediaSource.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MediaSource.java @@ -46,9 +46,13 @@ import java.io.IOException; * way for the player to load and read the media. * * - * All methods are called on the player's internal playback thread, as described in the {@link - * ExoPlayer} Javadoc. They should not be called directly from application code. Instances can be - * re-used, but only for one {@link ExoPlayer} instance simultaneously. + *

{@code MediaSource} methods should not be called from application code. Instead, the playback + * logic in {@link ExoPlayer} will trigger methods at the right time. + * + *

Instances can be re-used, but only for one {@link ExoPlayer} instance simultaneously. + * + *

MediaSource methods will be called on one of two threads, an application thread or a playback + * thread. Each method is documented with the thread it is called on. */ public interface MediaSource { @@ -165,6 +169,10 @@ public interface MediaSource { * Adds a {@link MediaSourceEventListener} to the list of listeners which are notified of media * source events. * + *

Should not be called directly from application code. + * + *

This method must be called on the playback thread. + * * @param handler A handler on the which listener events will be posted. * @param eventListener The listener to be added. */ @@ -175,6 +183,10 @@ public interface MediaSource { * Removes a {@link MediaSourceEventListener} from the list of listeners which are notified of * media source events. * + *

Should not be called directly from application code. + * + *

This method must be called on the playback thread. + * * @param eventListener The listener to be removed. */ @UnstableApi @@ -184,6 +196,10 @@ public interface MediaSource { * Adds a {@link DrmSessionEventListener} to the list of listeners which are notified of DRM * events for this media source. * + *

Should not be called directly from application code. + * + *

This method must be called on the playback thread. + * * @param handler A handler on the which listener events will be posted. * @param eventListener The listener to be added. */ @@ -194,6 +210,10 @@ public interface MediaSource { * Removes a {@link DrmSessionEventListener} from the list of listeners which are notified of DRM * events for this media source. * + *

Should not be called directly from application code. + * + *

This method must be called on the playback thread. + * * @param eventListener The listener to be removed. */ @UnstableApi @@ -203,12 +223,16 @@ public interface MediaSource { * Returns the initial placeholder timeline that is returned immediately when the real timeline is * not yet known, or null to let the player create an initial timeline. * + *

Should not be called directly from application code. + * *

The initial timeline must use the same uids for windows and periods that the real timeline * will use. It also must provide windows which are marked as dynamic to indicate that the window * is expected to change when the real timeline arrives. * *

Any media source which has multiple windows should typically provide such an initial * timeline to make sure the player reports the correct number of windows immediately. + * + *

This method must be called on the application thread. */ @UnstableApi @Nullable @@ -219,8 +243,12 @@ public interface MediaSource { /** * Returns true if the media source is guaranteed to never have zero or more than one window. * + *

Should not be called directly from application code. + * *

The default implementation returns {@code true}. * + *

This method must be called on the application thread. + * * @return true if the source has exactly one window. */ @UnstableApi @@ -228,7 +256,13 @@ public interface MediaSource { return true; } - /** Returns the {@link MediaItem} whose media is provided by the source. */ + /** + * Returns the {@link MediaItem} whose media is provided by the source. + * + *

Should not be called directly from application code. + * + *

This method must be called on the application thread. + */ @UnstableApi MediaItem getMediaItem(); @@ -255,6 +289,8 @@ public interface MediaSource { *

For each call to this method, a call to {@link #releaseSource(MediaSourceCaller)} is needed * to remove the caller and to release the source if no longer required. * + *

This method must be called on the playback thread. + * * @param caller The {@link MediaSourceCaller} to be registered. * @param mediaTransferListener The transfer listener which should be informed of any media data * transfers. May be null if no listener is available. Note that this listener should be only @@ -273,8 +309,8 @@ public interface MediaSource { * *

Should not be called directly from application code. * - *

Must only be called after {@link #prepareSource(MediaSourceCaller, TransferListener, - * PlayerId)}. + *

This method must be called on the playback thread and only after {@link + * #prepareSource(MediaSourceCaller, TransferListener, PlayerId)}. */ @UnstableApi void maybeThrowSourceInfoRefreshError() throws IOException; @@ -284,8 +320,8 @@ public interface MediaSource { * *

Should not be called directly from application code. * - *

Must only be called after {@link #prepareSource(MediaSourceCaller, TransferListener, - * PlayerId)}. + *

This method must be called on the playback thread and only after {@link + * #prepareSource(MediaSourceCaller, TransferListener, PlayerId)}. * * @param caller The {@link MediaSourceCaller} enabling the source. */ @@ -297,7 +333,7 @@ public interface MediaSource { * *

Should not be called directly from application code. * - *

Must only be called if the source is enabled. + *

This method must be called on the playback thread and only if the source is enabled. * * @param id The identifier of the period. * @param allocator An {@link Allocator} from which to obtain media buffer allocations. @@ -312,6 +348,8 @@ public interface MediaSource { * *

Should not be called directly from application code. * + *

This method must be called on the playback thread. + * * @param mediaPeriod The period to release. */ @UnstableApi @@ -323,9 +361,9 @@ public interface MediaSource { * *

Should not be called directly from application code. * - *

Must only be called after all {@link MediaPeriod MediaPeriods} previously created by {@link - * #createPeriod(MediaPeriodId, Allocator, long)} have been released by {@link - * #releasePeriod(MediaPeriod)}. + *

This method must be called on the playback thread and only after all {@link MediaPeriod + * MediaPeriods} previously created by {@link #createPeriod(MediaPeriodId, Allocator, long)} have + * been released by {@link #releasePeriod(MediaPeriod)}. * * @param caller The {@link MediaSourceCaller} disabling the source. */ @@ -337,8 +375,8 @@ public interface MediaSource { * *

Should not be called directly from application code. * - *

Must only be called if all created {@link MediaPeriod MediaPeriods} have been released by - * {@link #releasePeriod(MediaPeriod)}. + *

This method must be called on the playback thread and only if all created {@link MediaPeriod + * MediaPeriods} have been released by {@link #releasePeriod(MediaPeriod)}. * * @param caller The {@link MediaSourceCaller} to be unregistered. */ diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ads/AdsMediaSource.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ads/AdsMediaSource.java index 1098bd23ec..6930e25f41 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ads/AdsMediaSource.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/ads/AdsMediaSource.java @@ -132,6 +132,7 @@ public final class AdsMediaSource extends CompositeMediaSource { new MediaPeriodId(/* periodUid= */ new Object()); private final MediaSource contentMediaSource; + @Nullable final MediaItem.DrmConfiguration contentDrmConfiguration; private final MediaSource.Factory adMediaSourceFactory; private final AdsLoader adsLoader; private final AdViewProvider adViewProvider; @@ -168,6 +169,8 @@ public final class AdsMediaSource extends CompositeMediaSource { AdsLoader adsLoader, AdViewProvider adViewProvider) { this.contentMediaSource = contentMediaSource; + this.contentDrmConfiguration = + checkNotNull(contentMediaSource.getMediaItem().localConfiguration).drmConfiguration; this.adMediaSourceFactory = adMediaSourceFactory; this.adsLoader = adsLoader; this.adViewProvider = adViewProvider; @@ -318,11 +321,8 @@ public final class AdsMediaSource extends CompositeMediaSource { if (adUri != null) { MediaItem.Builder adMediaItem = new MediaItem.Builder().setUri(adUri); // Propagate the content's DRM config into the ad media source. - @Nullable - MediaItem.LocalConfiguration contentLocalConfiguration = - contentMediaSource.getMediaItem().localConfiguration; - if (contentLocalConfiguration != null) { - adMediaItem.setDrmConfiguration(contentLocalConfiguration.drmConfiguration); + if (contentDrmConfiguration != null) { + adMediaItem.setDrmConfiguration(contentDrmConfiguration); } MediaSource adMediaSource = adMediaSourceFactory.createMediaSource(adMediaItem.build()); adMediaSourceHolder.initializeWithMediaSource(adMediaSource, adUri);