From 143d7d6cca549e408ad60ce66aedf4ba933d8a08 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Wed, 11 Sep 2019 19:04:45 +0100 Subject: [PATCH] Implement acquirePlaceholderSession in DefaultDrmSessionManager Issue:#4867 PiperOrigin-RevId: 268497377 --- .../drm/DefaultDrmSessionManager.java | 81 ++++++++++++++----- .../exoplayer2/drm/FrameworkMediaCrypto.java | 10 +++ .../mediacodec/MediaCodecRenderer.java | 12 +-- 3 files changed, 70 insertions(+), 33 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java index 780ee5aac4..ab6627936e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java @@ -93,11 +93,13 @@ public class DefaultDrmSessionManager @Nullable private final HashMap optionalKeyRequestParameters; private final EventDispatcher eventDispatcher; private final boolean multiSession; + private final boolean allowPlaceholderSessions; private final LoadErrorHandlingPolicy loadErrorHandlingPolicy; private final List> sessions; private final List> provisioningSessions; + @Nullable private DefaultDrmSession placeholderDrmSession; @Nullable private Looper playbackLooper; private int mode; @Nullable private byte[] offlineLicenseKeySetId; @@ -232,6 +234,7 @@ public class DefaultDrmSessionManager callback, optionalKeyRequestParameters, multiSession, + /* allowPlaceholderSessions= */ false, new DefaultLoadErrorHandlingPolicy(initialDrmRequestRetryCount)); } @@ -241,6 +244,7 @@ public class DefaultDrmSessionManager MediaDrmCallback callback, @Nullable HashMap optionalKeyRequestParameters, boolean multiSession, + boolean allowPlaceholderSessions, LoadErrorHandlingPolicy loadErrorHandlingPolicy) { Assertions.checkNotNull(uuid); Assertions.checkNotNull(mediaDrm); @@ -251,6 +255,11 @@ public class DefaultDrmSessionManager this.optionalKeyRequestParameters = optionalKeyRequestParameters; this.eventDispatcher = new EventDispatcher<>(); this.multiSession = multiSession; + boolean canAcquirePlaceholderSessions = + !FrameworkMediaCrypto.class.equals(mediaDrm.getExoMediaCryptoType()) + || !FrameworkMediaCrypto.WORKAROUND_DEVICE_NEEDS_KEYS_TO_CONFIGURE_CODEC; + // TODO: Allow customization once this class has a Builder. + this.allowPlaceholderSessions = canAcquirePlaceholderSessions && allowPlaceholderSessions; this.loadErrorHandlingPolicy = loadErrorHandlingPolicy; mode = MODE_PLAYBACK; sessions = new ArrayList<>(); @@ -399,14 +408,25 @@ public class DefaultDrmSessionManager } @Override - public DrmSession acquireSession(Looper playbackLooper, DrmInitData drmInitData) { - Assertions.checkState(this.playbackLooper == null || this.playbackLooper == playbackLooper); - if (sessions.isEmpty()) { - this.playbackLooper = playbackLooper; - if (mediaDrmHandler == null) { - mediaDrmHandler = new MediaDrmHandler(playbackLooper); - } + @Nullable + public DrmSession acquirePlaceholderSession(Looper playbackLooper) { + if (!allowPlaceholderSessions) { + return null; } + maybeCreateMediaDrmHandler(playbackLooper); + if (placeholderDrmSession == null) { + DefaultDrmSession placeholderDrmSession = + createNewDefaultSession(/* schemeDatas= */ null, /* isPlaceholderSession= */ true); + sessions.add(placeholderDrmSession); + this.placeholderDrmSession = placeholderDrmSession; + } + placeholderDrmSession.acquireReference(); + return placeholderDrmSession; + } + + @Override + public DrmSession acquireSession(Looper playbackLooper, DrmInitData drmInitData) { + maybeCreateMediaDrmHandler(playbackLooper); List schemeDatas = null; if (offlineLicenseKeySetId == null) { @@ -434,27 +454,41 @@ public class DefaultDrmSessionManager if (session == null) { // Create a new session. - session = - new DefaultDrmSession<>( - uuid, - mediaDrm, - /* provisioningManager= */ this, - /* releaseCallback= */ this::onSessionReleased, - schemeDatas, - mode, - /* isPlaceholderSession= */ false, - offlineLicenseKeySetId, - optionalKeyRequestParameters, - callback, - playbackLooper, - eventDispatcher, - loadErrorHandlingPolicy); + session = createNewDefaultSession(schemeDatas, /* isPlaceholderSession= */ false); sessions.add(session); } session.acquireReference(); return session; } + private DefaultDrmSession createNewDefaultSession( + @Nullable List schemeDatas, boolean isPlaceholderSession) { + return new DefaultDrmSession<>( + uuid, + mediaDrm, + /* provisioningManager= */ this, + /* releaseCallback= */ this::onSessionReleased, + schemeDatas, + mode, + isPlaceholderSession, + offlineLicenseKeySetId, + optionalKeyRequestParameters, + callback, + Assertions.checkNotNull(playbackLooper), + eventDispatcher, + loadErrorHandlingPolicy); + } + + private void maybeCreateMediaDrmHandler(Looper playbackLooper) { + Assertions.checkState(this.playbackLooper == null || this.playbackLooper == playbackLooper); + if (sessions.isEmpty()) { + this.playbackLooper = playbackLooper; + if (mediaDrmHandler == null) { + mediaDrmHandler = new MediaDrmHandler(playbackLooper); + } + } + } + @Override @Nullable public Class getExoMediaCryptoType(DrmInitData drmInitData) { @@ -496,6 +530,9 @@ public class DefaultDrmSessionManager private void onSessionReleased(DefaultDrmSession drmSession) { sessions.remove(drmSession); + if (placeholderDrmSession == drmSession) { + placeholderDrmSession = null; + } if (provisioningSessions.size() > 1 && provisioningSessions.get(0) == drmSession) { // Other sessions were waiting for the released session to complete a provision operation. // We need to have one of those sessions perform the provision operation instead. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaCrypto.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaCrypto.java index 7211b5fcde..c139b522e9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaCrypto.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaCrypto.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.drm; import android.media.MediaCrypto; +import com.google.android.exoplayer2.util.Util; import java.util.UUID; /** @@ -24,6 +25,15 @@ import java.util.UUID; */ public final class FrameworkMediaCrypto implements ExoMediaCrypto { + /** + * Whether the device needs keys to have been loaded into the {@link DrmSession} before codec + * configuration. + */ + public static final boolean WORKAROUND_DEVICE_NEEDS_KEYS_TO_CONFIGURE_CODEC = + "Amazon".equals(Util.MANUFACTURER) + && ("AFTM".equals(Util.MODEL) // Fire TV Stick Gen 1 + || "AFTB".equals(Util.MODEL)); // Fire TV Gen 1 + /** The DRM scheme UUID. */ public final UUID uuid; /** The DRM session id. */ diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index f43b1461f8..14219b8dfd 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -521,7 +521,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { && mediaCrypto.requiresSecureDecoderComponent(mimeType); } } - if (deviceNeedsDrmKeysToConfigureCodecWorkaround()) { + if (FrameworkMediaCrypto.WORKAROUND_DEVICE_NEEDS_KEYS_TO_CONFIGURE_CODEC) { @DrmSession.State int drmSessionState = codecDrmSession.getState(); if (drmSessionState == DrmSession.STATE_ERROR) { throw ExoPlaybackException.createForRenderer(codecDrmSession.getError(), getIndex()); @@ -1754,16 +1754,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { return error instanceof MediaCodec.CodecException; } - /** - * Returns whether the device needs keys to have been loaded into the {@link DrmSession} before - * codec configuration. - */ - private boolean deviceNeedsDrmKeysToConfigureCodecWorkaround() { - return "Amazon".equals(Util.MANUFACTURER) - && ("AFTM".equals(Util.MODEL) // Fire TV Stick Gen 1 - || "AFTB".equals(Util.MODEL)); // Fire TV Gen 1 - } - /** * Returns whether the decoder is known to fail when flushed. *