diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b32c6e5fd8..26b91f9312 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -191,6 +191,9 @@ waiting for the response. This fixes (harmless) `IllegalStateException: sending message to a Handler on a dead thread` log messages ([#8328](https://github.com/google/ExoPlayer/issues/8328)). + * Allow apps to fully customize DRM behaviour per-`MediaItem` by passing a + `DrmSessionManagerProvider` to `MediaSourceFactory` + ([#8466](https://github.com/google/ExoPlayer/issues/8466)). * Analytics: * Pass a `DecoderReuseEvaluation` to `AnalyticsListener`'s `onVideoInputFormatChanged` and `onAudioInputFormatChanged` methods. The diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSessionManagerProvider.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSessionManagerProvider.java index c88daa8f48..9fa0d1a9c2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSessionManagerProvider.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSessionManagerProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java index 985c2baf2b..8b3e78bd9d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java @@ -25,6 +25,7 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.drm.DefaultDrmSessionManagerProvider; import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.DrmSessionManagerProvider; import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; import com.google.android.exoplayer2.extractor.ExtractorsFactory; import com.google.android.exoplayer2.offline.StreamKey; @@ -101,14 +102,14 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { private static final String TAG = "DefaultMediaSourceFactory"; - private final DefaultDrmSessionManagerProvider drmSessionManagerProvider; private final DataSource.Factory dataSourceFactory; private final SparseArray mediaSourceFactories; @C.ContentType private final int[] supportedTypes; @Nullable private AdsLoaderProvider adsLoaderProvider; @Nullable private AdViewProvider adViewProvider; - @Nullable private DrmSessionManager drmSessionManager; + private boolean usingCustomDrmSessionManagerProvider; + private DrmSessionManagerProvider drmSessionManagerProvider; @Nullable private List streamKeys; @Nullable private LoadErrorHandlingPolicy loadErrorHandlingPolicy; private long liveTargetOffsetMs; @@ -258,20 +259,42 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { @Override public DefaultMediaSourceFactory setDrmHttpDataSourceFactory( @Nullable HttpDataSource.Factory drmHttpDataSourceFactory) { - drmSessionManagerProvider.setDrmHttpDataSourceFactory(drmHttpDataSourceFactory); + if (!usingCustomDrmSessionManagerProvider) { + ((DefaultDrmSessionManagerProvider) drmSessionManagerProvider) + .setDrmHttpDataSourceFactory(drmHttpDataSourceFactory); + } return this; } @Override public DefaultMediaSourceFactory setDrmUserAgent(@Nullable String userAgent) { - drmSessionManagerProvider.setDrmUserAgent(userAgent); + if (!usingCustomDrmSessionManagerProvider) { + ((DefaultDrmSessionManagerProvider) drmSessionManagerProvider).setDrmUserAgent(userAgent); + } return this; } @Override public DefaultMediaSourceFactory setDrmSessionManager( @Nullable DrmSessionManager drmSessionManager) { - this.drmSessionManager = drmSessionManager; + if (drmSessionManager == null) { + setDrmSessionManagerProvider(null); + } else { + setDrmSessionManagerProvider(unusedMediaItem -> drmSessionManager); + } + return this; + } + + @Override + public DefaultMediaSourceFactory setDrmSessionManagerProvider( + @Nullable DrmSessionManagerProvider drmSessionManagerProvider) { + if (drmSessionManagerProvider != null) { + this.drmSessionManagerProvider = drmSessionManagerProvider; + this.usingCustomDrmSessionManagerProvider = true; + } else { + this.drmSessionManagerProvider = new DefaultDrmSessionManagerProvider(); + this.usingCustomDrmSessionManagerProvider = false; + } return this; } @@ -310,8 +333,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { @Nullable MediaSourceFactory mediaSourceFactory = mediaSourceFactories.get(type); Assertions.checkNotNull( mediaSourceFactory, "No suitable media source factory found for content type: " + type); - mediaSourceFactory.setDrmSessionManager( - drmSessionManager != null ? drmSessionManager : drmSessionManagerProvider.get(mediaItem)); + mediaSourceFactory.setDrmSessionManagerProvider(drmSessionManagerProvider); mediaSourceFactory.setStreamKeys( !mediaItem.playbackProperties.streamKeys.isEmpty() ? mediaItem.playbackProperties.streamKeys diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java index 30f85d2dc4..77a1c1d8ac 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java @@ -23,6 +23,7 @@ import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.DrmSessionManagerProvider; import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.ExtractorsFactory; @@ -154,6 +155,18 @@ public final class ExtractorMediaSource extends CompositeMediaSource { return this; } + /** + * @deprecated Use {@link + * ProgressiveMediaSource.Factory#setDrmSessionManagerProvider(DrmSessionManagerProvider)} + * instead. + */ + @Deprecated + @Override + public Factory setDrmSessionManagerProvider( + @Nullable DrmSessionManagerProvider drmSessionManagerProvider) { + throw new UnsupportedOperationException(); + } + /** @deprecated Use {@link ProgressiveMediaSource.Factory#setDrmSessionManager} instead. */ @Deprecated @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSourceFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSourceFactory.java index 204220e334..7242c2a214 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSourceFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSourceFactory.java @@ -20,7 +20,9 @@ import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.drm.DefaultDrmSessionManager; +import com.google.android.exoplayer2.drm.DefaultDrmSessionManagerProvider; import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.DrmSessionManagerProvider; import com.google.android.exoplayer2.drm.HttpMediaDrmCallback; import com.google.android.exoplayer2.offline.StreamKey; import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; @@ -56,41 +58,80 @@ public interface MediaSourceFactory { return this; } + /** + * Sets the {@link DrmSessionManagerProvider} used to obtain a {@link DrmSessionManager} for a + * {@link MediaItem}. + * + *

If not set, {@link DefaultDrmSessionManagerProvider} is used. + * + *

If set, calls to the following (deprecated) methods are ignored: + * + *

    + *
  • {@link #setDrmUserAgent(String)} + *
  • {@link #setDrmHttpDataSourceFactory(HttpDataSource.Factory)} + *
+ * + * @return This factory, for convenience. + */ + MediaSourceFactory setDrmSessionManagerProvider( + @Nullable DrmSessionManagerProvider drmSessionManagerProvider); + /** * Sets the {@link DrmSessionManager} to use for all media items regardless of their {@link * MediaItem.DrmConfiguration}. * + *

Calling this with a non-null {@code drmSessionManager} is equivalent to calling {@code + * setDrmSessionManagerProvider(unusedMediaItem -> drmSessionManager)}. + * * @param drmSessionManager The {@link DrmSessionManager}, or {@code null} to use the {@link * DefaultDrmSessionManager}. * @return This factory, for convenience. + * @deprecated Use {@link #setDrmSessionManagerProvider(DrmSessionManagerProvider)} and pass an + * implementation that always returns the same instance. */ + @Deprecated MediaSourceFactory setDrmSessionManager(@Nullable DrmSessionManager drmSessionManager); /** * Sets the {@link HttpDataSource.Factory} to be used for creating {@link HttpMediaDrmCallback * HttpMediaDrmCallbacks} to execute key and provisioning requests over HTTP. * - *

In case a {@link DrmSessionManager} has been set by {@link - * #setDrmSessionManager(DrmSessionManager)}, this data source factory is ignored. + *

Calls to this method are ignored if either a {@link + * #setDrmSessionManagerProvider(DrmSessionManagerProvider) DrmSessionManager provider} or {@link + * #setDrmSessionManager(DrmSessionManager) concrete DrmSessionManager} are provided. * * @param drmHttpDataSourceFactory The HTTP data source factory, or {@code null} to use {@link * DefaultHttpDataSourceFactory}. * @return This factory, for convenience. + * @deprecated Use {@link #setDrmSessionManagerProvider(DrmSessionManagerProvider)} and pass an + * implementation that configures the returned {@link DrmSessionManager} with the desired + * {@link HttpDataSource.Factory}. */ + @Deprecated MediaSourceFactory setDrmHttpDataSourceFactory( @Nullable HttpDataSource.Factory drmHttpDataSourceFactory); /** * Sets the optional user agent to be used for DRM requests. * - *

In case a factory has been set by {@link - * #setDrmHttpDataSourceFactory(HttpDataSource.Factory)} or a {@link DrmSessionManager} has been - * set by {@link #setDrmSessionManager(DrmSessionManager)}, this user agent is ignored. + *

Calls to this method are ignored if any of the following are provided: + * + *

    + *
  • A {@link #setDrmSessionManagerProvider(DrmSessionManagerProvider) DrmSessionManager + * provider}. + *
  • A {@link #setDrmSessionManager(DrmSessionManager) concrete DrmSessionManager}. + *
  • A {@link #setDrmHttpDataSourceFactory(HttpDataSource.Factory) DRM + * HttpDataSource.Factory}. + *
* * @param userAgent The user agent to be used for DRM requests, or {@code null} to use the * default. * @return This factory, for convenience. + * @deprecated Use {@link #setDrmSessionManagerProvider(DrmSessionManagerProvider)} and pass an + * implementation that configures the returned {@link DrmSessionManager} with the desired + * {@code userAgent}. */ + @Deprecated MediaSourceFactory setDrmUserAgent(@Nullable String userAgent); /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java index 9e4bef641c..fe249df6ff 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java @@ -24,6 +24,7 @@ import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.drm.DefaultDrmSessionManagerProvider; import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.DrmSessionManagerProvider; import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.ExtractorsFactory; @@ -52,10 +53,10 @@ public final class ProgressiveMediaSource extends BaseMediaSource public static final class Factory implements MediaSourceFactory { private final DataSource.Factory dataSourceFactory; - private final DefaultDrmSessionManagerProvider drmSessionManagerProvider; private ExtractorsFactory extractorsFactory; - @Nullable private DrmSessionManager drmSessionManager; + private boolean usingCustomDrmSessionManagerProvider; + private DrmSessionManagerProvider drmSessionManagerProvider; private LoadErrorHandlingPolicy loadErrorHandlingPolicy; private int continueLoadingCheckIntervalBytes; @Nullable private String customCacheKey; @@ -149,21 +150,42 @@ public final class ProgressiveMediaSource extends BaseMediaSource } @Override + public Factory setDrmSessionManagerProvider( + @Nullable DrmSessionManagerProvider drmSessionManagerProvider) { + if (drmSessionManagerProvider != null) { + this.drmSessionManagerProvider = drmSessionManagerProvider; + this.usingCustomDrmSessionManagerProvider = true; + } else { + this.drmSessionManagerProvider = new DefaultDrmSessionManagerProvider(); + this.usingCustomDrmSessionManagerProvider = false; + } + return this; + } + public Factory setDrmSessionManager(@Nullable DrmSessionManager drmSessionManager) { - this.drmSessionManager = drmSessionManager; + if (drmSessionManager == null) { + setDrmSessionManagerProvider(null); + } else { + setDrmSessionManagerProvider(unusedMediaItem -> drmSessionManager); + } return this; } @Override public Factory setDrmHttpDataSourceFactory( @Nullable HttpDataSource.Factory drmHttpDataSourceFactory) { - drmSessionManagerProvider.setDrmHttpDataSourceFactory(drmHttpDataSourceFactory); + if (!usingCustomDrmSessionManagerProvider) { + ((DefaultDrmSessionManagerProvider) drmSessionManagerProvider) + .setDrmHttpDataSourceFactory(drmHttpDataSourceFactory); + } return this; } @Override public Factory setDrmUserAgent(@Nullable String userAgent) { - drmSessionManagerProvider.setDrmUserAgent(userAgent); + if (!usingCustomDrmSessionManagerProvider) { + ((DefaultDrmSessionManagerProvider) drmSessionManagerProvider).setDrmUserAgent(userAgent); + } return this; } @@ -199,7 +221,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource mediaItem, dataSourceFactory, extractorsFactory, - drmSessionManager != null ? drmSessionManager : drmSessionManagerProvider.get(mediaItem), + drmSessionManagerProvider.get(mediaItem), loadErrorHandlingPolicy, continueLoadingCheckIntervalBytes); } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index f695c8650e..6737e747f0 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -36,6 +36,7 @@ import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.drm.DefaultDrmSessionManagerProvider; import com.google.android.exoplayer2.drm.DrmSessionEventListener; import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.DrmSessionManagerProvider; import com.google.android.exoplayer2.offline.FilteringManifestParser; import com.google.android.exoplayer2.offline.StreamKey; import com.google.android.exoplayer2.source.BaseMediaSource; @@ -99,10 +100,10 @@ public final class DashMediaSource extends BaseMediaSource { public static final class Factory implements MediaSourceFactory { private final DashChunkSource.Factory chunkSourceFactory; - private final DefaultDrmSessionManagerProvider drmSessionManagerProvider; @Nullable private final DataSource.Factory manifestDataSourceFactory; - @Nullable private DrmSessionManager drmSessionManager; + private boolean usingCustomDrmSessionManagerProvider; + private DrmSessionManagerProvider drmSessionManagerProvider; private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; private LoadErrorHandlingPolicy loadErrorHandlingPolicy; private long targetLiveOffsetOverrideMs; @@ -165,22 +166,44 @@ public final class DashMediaSource extends BaseMediaSource { return this; } + @Override + public Factory setDrmSessionManagerProvider( + @Nullable DrmSessionManagerProvider drmSessionManagerProvider) { + if (drmSessionManagerProvider != null) { + this.drmSessionManagerProvider = drmSessionManagerProvider; + this.usingCustomDrmSessionManagerProvider = true; + } else { + this.drmSessionManagerProvider = new DefaultDrmSessionManagerProvider(); + this.usingCustomDrmSessionManagerProvider = false; + } + return this; + } + @Override public Factory setDrmSessionManager(@Nullable DrmSessionManager drmSessionManager) { - this.drmSessionManager = drmSessionManager; + if (drmSessionManager == null) { + setDrmSessionManagerProvider(null); + } else { + setDrmSessionManagerProvider(unusedMediaItem -> drmSessionManager); + } return this; } @Override public Factory setDrmHttpDataSourceFactory( @Nullable HttpDataSource.Factory drmHttpDataSourceFactory) { - drmSessionManagerProvider.setDrmHttpDataSourceFactory(drmHttpDataSourceFactory); + if (!usingCustomDrmSessionManagerProvider) { + ((DefaultDrmSessionManagerProvider) drmSessionManagerProvider) + .setDrmHttpDataSourceFactory(drmHttpDataSourceFactory); + } return this; } @Override public Factory setDrmUserAgent(@Nullable String userAgent) { - drmSessionManagerProvider.setDrmUserAgent(userAgent); + if (!usingCustomDrmSessionManagerProvider) { + ((DefaultDrmSessionManagerProvider) drmSessionManagerProvider).setDrmUserAgent(userAgent); + } return this; } @@ -319,7 +342,7 @@ public final class DashMediaSource extends BaseMediaSource { /* manifestParser= */ null, chunkSourceFactory, compositeSequenceableLoaderFactory, - drmSessionManager != null ? drmSessionManager : drmSessionManagerProvider.get(mediaItem), + drmSessionManagerProvider.get(mediaItem), loadErrorHandlingPolicy, fallbackTargetLiveOffsetMs); } @@ -385,7 +408,7 @@ public final class DashMediaSource extends BaseMediaSource { manifestParser, chunkSourceFactory, compositeSequenceableLoaderFactory, - drmSessionManager != null ? drmSessionManager : drmSessionManagerProvider.get(mediaItem), + drmSessionManagerProvider.get(mediaItem), loadErrorHandlingPolicy, fallbackTargetLiveOffsetMs); } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index 6e8f650be9..e5c233ef43 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -29,6 +29,7 @@ import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.drm.DefaultDrmSessionManagerProvider; import com.google.android.exoplayer2.drm.DrmSessionEventListener; import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.DrmSessionManagerProvider; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.offline.StreamKey; import com.google.android.exoplayer2.source.BaseMediaSource; @@ -94,13 +95,13 @@ public final class HlsMediaSource extends BaseMediaSource public static final class Factory implements MediaSourceFactory { private final HlsDataSourceFactory hlsDataSourceFactory; - private final DefaultDrmSessionManagerProvider drmSessionManagerProvider; private HlsExtractorFactory extractorFactory; private HlsPlaylistParserFactory playlistParserFactory; private HlsPlaylistTracker.Factory playlistTrackerFactory; private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; - @Nullable private DrmSessionManager drmSessionManager; + private boolean usingCustomDrmSessionManagerProvider; + private DrmSessionManagerProvider drmSessionManagerProvider; private LoadErrorHandlingPolicy loadErrorHandlingPolicy; private boolean allowChunklessPreparation; @MetadataType private int metadataType; @@ -280,22 +281,44 @@ public final class HlsMediaSource extends BaseMediaSource return this; } + @Override + public Factory setDrmSessionManagerProvider( + @Nullable DrmSessionManagerProvider drmSessionManagerProvider) { + if (drmSessionManagerProvider != null) { + this.drmSessionManagerProvider = drmSessionManagerProvider; + this.usingCustomDrmSessionManagerProvider = true; + } else { + this.drmSessionManagerProvider = new DefaultDrmSessionManagerProvider(); + this.usingCustomDrmSessionManagerProvider = false; + } + return this; + } + @Override public Factory setDrmSessionManager(@Nullable DrmSessionManager drmSessionManager) { - this.drmSessionManager = drmSessionManager; + if (drmSessionManager == null) { + setDrmSessionManagerProvider(null); + } else { + setDrmSessionManagerProvider(unusedMediaItem -> drmSessionManager); + } return this; } @Override public Factory setDrmHttpDataSourceFactory( @Nullable HttpDataSource.Factory drmHttpDataSourceFactory) { - drmSessionManagerProvider.setDrmHttpDataSourceFactory(drmHttpDataSourceFactory); + if (!usingCustomDrmSessionManagerProvider) { + ((DefaultDrmSessionManagerProvider) drmSessionManagerProvider) + .setDrmHttpDataSourceFactory(drmHttpDataSourceFactory); + } return this; } @Override - public MediaSourceFactory setDrmUserAgent(@Nullable String userAgent) { - drmSessionManagerProvider.setDrmUserAgent(userAgent); + public Factory setDrmUserAgent(@Nullable String userAgent) { + if (!usingCustomDrmSessionManagerProvider) { + ((DefaultDrmSessionManagerProvider) drmSessionManagerProvider).setDrmUserAgent(userAgent); + } return this; } @@ -369,7 +392,7 @@ public final class HlsMediaSource extends BaseMediaSource hlsDataSourceFactory, extractorFactory, compositeSequenceableLoaderFactory, - drmSessionManager != null ? drmSessionManager : drmSessionManagerProvider.get(mediaItem), + drmSessionManagerProvider.get(mediaItem), loadErrorHandlingPolicy, playlistTrackerFactory.createTracker( hlsDataSourceFactory, loadErrorHandlingPolicy, playlistParserFactory), diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java index 8f69a8b4dd..bd6f5df197 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java @@ -30,6 +30,7 @@ import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.drm.DefaultDrmSessionManagerProvider; import com.google.android.exoplayer2.drm.DrmSessionEventListener; import com.google.android.exoplayer2.drm.DrmSessionManager; +import com.google.android.exoplayer2.drm.DrmSessionManagerProvider; import com.google.android.exoplayer2.offline.FilteringManifestParser; import com.google.android.exoplayer2.offline.StreamKey; import com.google.android.exoplayer2.source.BaseMediaSource; @@ -78,11 +79,11 @@ public final class SsMediaSource extends BaseMediaSource public static final class Factory implements MediaSourceFactory { private final SsChunkSource.Factory chunkSourceFactory; - private final DefaultDrmSessionManagerProvider drmSessionManagerProvider; @Nullable private final DataSource.Factory manifestDataSourceFactory; private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; - @Nullable private DrmSessionManager drmSessionManager; + private boolean usingCustomDrmSessionManagerProvider; + private DrmSessionManagerProvider drmSessionManagerProvider; private LoadErrorHandlingPolicy loadErrorHandlingPolicy; private long livePresentationDelayMs; @Nullable private ParsingLoadable.Parser manifestParser; @@ -191,22 +192,44 @@ public final class SsMediaSource extends BaseMediaSource return this; } + @Override + public Factory setDrmSessionManagerProvider( + @Nullable DrmSessionManagerProvider drmSessionManagerProvider) { + if (drmSessionManagerProvider != null) { + this.drmSessionManagerProvider = drmSessionManagerProvider; + this.usingCustomDrmSessionManagerProvider = true; + } else { + this.drmSessionManagerProvider = new DefaultDrmSessionManagerProvider(); + this.usingCustomDrmSessionManagerProvider = false; + } + return this; + } + @Override public Factory setDrmSessionManager(@Nullable DrmSessionManager drmSessionManager) { - this.drmSessionManager = drmSessionManager; + if (drmSessionManager == null) { + setDrmSessionManagerProvider(null); + } else { + setDrmSessionManagerProvider(unusedMediaItem -> drmSessionManager); + } return this; } @Override public Factory setDrmHttpDataSourceFactory( @Nullable HttpDataSource.Factory drmHttpDataSourceFactory) { - drmSessionManagerProvider.setDrmHttpDataSourceFactory(drmHttpDataSourceFactory); + if (!usingCustomDrmSessionManagerProvider) { + ((DefaultDrmSessionManagerProvider) drmSessionManagerProvider) + .setDrmHttpDataSourceFactory(drmHttpDataSourceFactory); + } return this; } @Override public Factory setDrmUserAgent(@Nullable String userAgent) { - drmSessionManagerProvider.setDrmUserAgent(userAgent); + if (!usingCustomDrmSessionManagerProvider) { + ((DefaultDrmSessionManagerProvider) drmSessionManagerProvider).setDrmUserAgent(userAgent); + } return this; } @@ -277,7 +300,7 @@ public final class SsMediaSource extends BaseMediaSource /* manifestParser= */ null, chunkSourceFactory, compositeSequenceableLoaderFactory, - drmSessionManager != null ? drmSessionManager : drmSessionManagerProvider.get(mediaItem), + drmSessionManagerProvider.get(mediaItem), loadErrorHandlingPolicy, livePresentationDelayMs); } @@ -321,7 +344,7 @@ public final class SsMediaSource extends BaseMediaSource manifestParser, chunkSourceFactory, compositeSequenceableLoaderFactory, - drmSessionManager != null ? drmSessionManager : drmSessionManagerProvider.get(mediaItem), + drmSessionManagerProvider.get(mediaItem), loadErrorHandlingPolicy, livePresentationDelayMs); }