Implement acquirePlaceholderSession in DefaultDrmSessionManager

Issue:#4867
PiperOrigin-RevId: 268497377
This commit is contained in:
aquilescanta 2019-09-11 19:04:45 +01:00 committed by Oliver Woodman
parent f7e9e185f7
commit 143d7d6cca
3 changed files with 70 additions and 33 deletions

View File

@ -93,11 +93,13 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto>
@Nullable private final HashMap<String, String> optionalKeyRequestParameters;
private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher;
private final boolean multiSession;
private final boolean allowPlaceholderSessions;
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
private final List<DefaultDrmSession<T>> sessions;
private final List<DefaultDrmSession<T>> provisioningSessions;
@Nullable private DefaultDrmSession<T> placeholderDrmSession;
@Nullable private Looper playbackLooper;
private int mode;
@Nullable private byte[] offlineLicenseKeySetId;
@ -232,6 +234,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto>
callback,
optionalKeyRequestParameters,
multiSession,
/* allowPlaceholderSessions= */ false,
new DefaultLoadErrorHandlingPolicy(initialDrmRequestRetryCount));
}
@ -241,6 +244,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto>
MediaDrmCallback callback,
@Nullable HashMap<String, String> optionalKeyRequestParameters,
boolean multiSession,
boolean allowPlaceholderSessions,
LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
Assertions.checkNotNull(uuid);
Assertions.checkNotNull(mediaDrm);
@ -251,6 +255,11 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto>
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<T extends ExoMediaCrypto>
}
@Override
public DrmSession<T> 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<T> acquirePlaceholderSession(Looper playbackLooper) {
if (!allowPlaceholderSessions) {
return null;
}
maybeCreateMediaDrmHandler(playbackLooper);
if (placeholderDrmSession == null) {
DefaultDrmSession<T> placeholderDrmSession =
createNewDefaultSession(/* schemeDatas= */ null, /* isPlaceholderSession= */ true);
sessions.add(placeholderDrmSession);
this.placeholderDrmSession = placeholderDrmSession;
}
placeholderDrmSession.acquireReference();
return placeholderDrmSession;
}
@Override
public DrmSession<T> acquireSession(Looper playbackLooper, DrmInitData drmInitData) {
maybeCreateMediaDrmHandler(playbackLooper);
List<SchemeData> schemeDatas = null;
if (offlineLicenseKeySetId == null) {
@ -434,27 +454,41 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto>
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<T> createNewDefaultSession(
@Nullable List<SchemeData> 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<T> getExoMediaCryptoType(DrmInitData drmInitData) {
@ -496,6 +530,9 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto>
private void onSessionReleased(DefaultDrmSession<T> 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.

View File

@ -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. */

View File

@ -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.
* <p>