Cache the last DrmSessionManager instance inside the default provider

Without this a new manager is instantiated for every item in a playlist,
meaning the impact of caching improvements to DefaultDrmSessionManager
are reduced (since the cache doesn't persist across playlist items).

With this change, playlists of items with identical DRM config will use
the same manager instance (and thus share existing sessions).

Issue: #8523
#minor-release
PiperOrigin-RevId: 356690852
This commit is contained in:
ibaker 2021-02-10 09:48:04 +00:00 committed by Ian Baker
parent 753bccec1f
commit a062075462
3 changed files with 68 additions and 2 deletions

View File

@ -20,6 +20,10 @@
instead.
* Remove `extension-jobdispatcher` module. Use the `extension-workmanager`
module instead.
* DRM:
* Re-use the previous `DrmSessionManager` instance when playing a playlist
(if possible)
([#8523](https://github.com/google/ExoPlayer/issues/8523)).
### 2.13.0 (2021-02-04)

View File

@ -16,23 +16,39 @@
package com.google.android.exoplayer2.drm;
import static com.google.android.exoplayer2.drm.DefaultDrmSessionManager.MODE_PLAYBACK;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import com.google.common.primitives.Ints;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** Default implementation of {@link DrmSessionManagerProvider}. */
@RequiresApi(18)
public final class DefaultDrmSessionManagerProvider implements DrmSessionManagerProvider {
private final Object lock;
@GuardedBy("lock")
private MediaItem.@MonotonicNonNull DrmConfiguration drmConfiguration;
@GuardedBy("lock")
private @MonotonicNonNull DrmSessionManager manager;
@Nullable private HttpDataSource.Factory drmHttpDataSourceFactory;
@Nullable private String userAgent;
public DefaultDrmSessionManagerProvider() {
lock = new Object();
}
/**
* Sets the {@link HttpDataSource.Factory} to be used for creating {@link HttpMediaDrmCallback
* HttpMediaDrmCallbacks} which executes key and provisioning requests over HTTP. If {@code null}
@ -60,12 +76,23 @@ public final class DefaultDrmSessionManagerProvider implements DrmSessionManager
@Override
public DrmSessionManager get(MediaItem mediaItem) {
Assertions.checkNotNull(mediaItem.playbackProperties);
checkNotNull(mediaItem.playbackProperties);
@Nullable
MediaItem.DrmConfiguration drmConfiguration = mediaItem.playbackProperties.drmConfiguration;
if (drmConfiguration == null || Util.SDK_INT < 18) {
return DrmSessionManager.DRM_UNSUPPORTED;
}
synchronized (lock) {
if (!Util.areEqual(drmConfiguration, this.drmConfiguration)) {
this.drmConfiguration = drmConfiguration;
this.manager = createManager(drmConfiguration);
}
return checkNotNull(this.manager);
}
}
private DrmSessionManager createManager(MediaItem.DrmConfiguration drmConfiguration) {
HttpDataSource.Factory dataSourceFactory =
drmHttpDataSourceFactory != null
? drmHttpDataSourceFactory

View File

@ -51,4 +51,39 @@ public class DefaultDrmSessionManagerProviderTest {
assertThat(drmSessionManager).isNotEqualTo(DrmSessionManager.DRM_UNSUPPORTED);
}
@Test
public void create_reusesCachedInstanceWherePossible() {
MediaItem mediaItem1 =
new MediaItem.Builder()
.setUri("https://example.test/content-1")
.setDrmUuid(C.WIDEVINE_UUID)
.build();
// Same DRM info as item1, but different URL to check it doesn't prevent re-using a manager.
MediaItem mediaItem2 =
new MediaItem.Builder()
.setUri("https://example.test/content-2")
.setDrmUuid(C.WIDEVINE_UUID)
.build();
// Different DRM info to 1 and 2, needs a different manager instance.
MediaItem mediaItem3 =
new MediaItem.Builder()
.setUri("https://example.test/content-3")
.setDrmUuid(C.WIDEVINE_UUID)
.setDrmLicenseUri("https://example.test/license")
.build();
DefaultDrmSessionManagerProvider provider = new DefaultDrmSessionManagerProvider();
DrmSessionManager drmSessionManager1 = provider.get(mediaItem1);
DrmSessionManager drmSessionManager2 = provider.get(mediaItem2);
DrmSessionManager drmSessionManager3 = provider.get(mediaItem3);
// Get a manager for the first item again - expect it to be a different instance to last time
// since we only cache one.
DrmSessionManager drmSessionManager4 = provider.get(mediaItem1);
assertThat(drmSessionManager1).isSameInstanceAs(drmSessionManager2);
assertThat(drmSessionManager1).isNotSameInstanceAs(drmSessionManager3);
assertThat(drmSessionManager1).isNotSameInstanceAs(drmSessionManager4);
}
}