Commit 3b605848 by aquilescanta Committed by Oliver Woodman

Add a release callback to DefaultDrmSession

In preparation for reference counting in DrmSession

PiperOrigin-RevId: 247428114
parent 0a6f81a2
...@@ -42,20 +42,16 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; ...@@ -42,20 +42,16 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull; import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** /** A {@link DrmSession} that supports playbacks using {@link ExoMediaDrm}. */
* A {@link DrmSession} that supports playbacks using {@link ExoMediaDrm}.
*/
@TargetApi(18) @TargetApi(18)
/* package */ class DefaultDrmSession<T extends ExoMediaCrypto> implements DrmSession<T> { /* package */ class DefaultDrmSession<T extends ExoMediaCrypto> implements DrmSession<T> {
/** /** Manages provisioning requests. */
* Manages provisioning requests.
*/
public interface ProvisioningManager<T extends ExoMediaCrypto> { public interface ProvisioningManager<T extends ExoMediaCrypto> {
/** /**
* Called when a session requires provisioning. The manager <em>may</em> call * Called when a session requires provisioning. The manager <em>may</em> call {@link
* {@link #provision()} to have this session perform the provisioning operation. The manager * #provision()} to have this session perform the provisioning operation. The manager
* <em>will</em> call {@link DefaultDrmSession#onProvisionCompleted()} when provisioning has * <em>will</em> call {@link DefaultDrmSession#onProvisionCompleted()} when provisioning has
* completed, or {@link DefaultDrmSession#onProvisionError} if provisioning fails. * completed, or {@link DefaultDrmSession#onProvisionError} if provisioning fails.
* *
...@@ -70,11 +66,19 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -70,11 +66,19 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
*/ */
void onProvisionError(Exception error); void onProvisionError(Exception error);
/** /** Called by a session when it successfully completes a provisioning operation. */
* Called by a session when it successfully completes a provisioning operation.
*/
void onProvisionCompleted(); void onProvisionCompleted();
}
/** Callback to be notified when the session is released. */
public interface ReleaseCallback<T extends ExoMediaCrypto> {
/**
* Called when the session is released.
*
* @param session The session.
*/
void onSessionReleased(DefaultDrmSession<T> session);
} }
private static final String TAG = "DefaultDrmSession"; private static final String TAG = "DefaultDrmSession";
...@@ -88,6 +92,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -88,6 +92,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private final ExoMediaDrm<T> mediaDrm; private final ExoMediaDrm<T> mediaDrm;
private final ProvisioningManager<T> provisioningManager; private final ProvisioningManager<T> provisioningManager;
private final ReleaseCallback<T> releaseCallback;
private final @DefaultDrmSessionManager.Mode int mode; private final @DefaultDrmSessionManager.Mode int mode;
private final @Nullable HashMap<String, String> optionalKeyRequestParameters; private final @Nullable HashMap<String, String> optionalKeyRequestParameters;
private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher; private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher;
...@@ -115,6 +120,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -115,6 +120,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
* @param uuid The UUID of the drm scheme. * @param uuid The UUID of the drm scheme.
* @param mediaDrm The media DRM. * @param mediaDrm The media DRM.
* @param provisioningManager The manager for provisioning. * @param provisioningManager The manager for provisioning.
* @param releaseCallback The {@link ReleaseCallback}.
* @param schemeDatas DRM scheme datas for this session, or null if an {@code * @param schemeDatas DRM scheme datas for this session, or null if an {@code
* offlineLicenseKeySetId} is provided. * offlineLicenseKeySetId} is provided.
* @param mode The DRM mode. * @param mode The DRM mode.
...@@ -131,6 +137,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -131,6 +137,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
UUID uuid, UUID uuid,
ExoMediaDrm<T> mediaDrm, ExoMediaDrm<T> mediaDrm,
ProvisioningManager<T> provisioningManager, ProvisioningManager<T> provisioningManager,
ReleaseCallback<T> releaseCallback,
@Nullable List<SchemeData> schemeDatas, @Nullable List<SchemeData> schemeDatas,
@DefaultDrmSessionManager.Mode int mode, @DefaultDrmSessionManager.Mode int mode,
@Nullable byte[] offlineLicenseKeySetId, @Nullable byte[] offlineLicenseKeySetId,
...@@ -145,6 +152,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -145,6 +152,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
} }
this.uuid = uuid; this.uuid = uuid;
this.provisioningManager = provisioningManager; this.provisioningManager = provisioningManager;
this.releaseCallback = releaseCallback;
this.mediaDrm = mediaDrm; this.mediaDrm = mediaDrm;
this.mode = mode; this.mode = mode;
if (offlineLicenseKeySetId != null) { if (offlineLicenseKeySetId != null) {
...@@ -178,10 +186,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -178,10 +186,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
} }
} }
/** @return True if the session is closed and cleaned up, false otherwise. */
// Assigning null to various non-null variables for clean-up. Class won't be used after release. // Assigning null to various non-null variables for clean-up. Class won't be used after release.
@SuppressWarnings("assignment.type.incompatible") @SuppressWarnings("assignment.type.incompatible")
public boolean release() { public void release() {
if (--openCount == 0) { if (--openCount == 0) {
state = STATE_RELEASED; state = STATE_RELEASED;
postResponseHandler.removeCallbacksAndMessages(null); postResponseHandler.removeCallbacksAndMessages(null);
...@@ -198,9 +205,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -198,9 +205,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
sessionId = null; sessionId = null;
eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmSessionReleased); eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmSessionReleased);
} }
return true; releaseCallback.onSessionReleased(this);
} }
return false;
} }
public boolean hasSessionId(byte[] sessionId) { public boolean hasSessionId(byte[] sessionId) {
...@@ -330,8 +336,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -330,8 +336,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
long licenseDurationRemainingSec = getLicenseDurationRemainingSec(); long licenseDurationRemainingSec = getLicenseDurationRemainingSec();
if (mode == DefaultDrmSessionManager.MODE_PLAYBACK if (mode == DefaultDrmSessionManager.MODE_PLAYBACK
&& licenseDurationRemainingSec <= MAX_LICENSE_DURATION_TO_RENEW) { && licenseDurationRemainingSec <= MAX_LICENSE_DURATION_TO_RENEW) {
Log.d(TAG, "Offline license has expired or will expire soon. " Log.d(
+ "Remaining seconds: " + licenseDurationRemainingSec); TAG,
"Offline license has expired or will expire soon. "
+ "Remaining seconds: "
+ licenseDurationRemainingSec);
postKeyRequest(sessionId, ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry); postKeyRequest(sessionId, ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry);
} else if (licenseDurationRemainingSec <= 0) { } else if (licenseDurationRemainingSec <= 0) {
onError(new KeysExpiredException()); onError(new KeysExpiredException());
...@@ -415,8 +424,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -415,8 +424,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
} else { } else {
byte[] keySetId = mediaDrm.provideKeyResponse(sessionId, responseData); byte[] keySetId = mediaDrm.provideKeyResponse(sessionId, responseData);
if ((mode == DefaultDrmSessionManager.MODE_DOWNLOAD if ((mode == DefaultDrmSessionManager.MODE_DOWNLOAD
|| (mode == DefaultDrmSessionManager.MODE_PLAYBACK && offlineLicenseKeySetId != null)) || (mode == DefaultDrmSessionManager.MODE_PLAYBACK
&& keySetId != null && keySetId.length != 0) { && offlineLicenseKeySetId != null))
&& keySetId != null
&& keySetId.length != 0) {
offlineLicenseKeySetId = keySetId; offlineLicenseKeySetId = keySetId;
} }
state = STATE_OPENED_WITH_KEYS; state = STATE_OPENED_WITH_KEYS;
...@@ -480,10 +491,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -480,10 +491,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
break; break;
default: default:
break; break;
} }
} }
} }
@SuppressLint("HandlerLeak") @SuppressLint("HandlerLeak")
...@@ -541,6 +550,5 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -541,6 +550,5 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private long getRetryDelayMillis(int errorCount) { private long getRetryDelayMillis(int errorCount) {
return Math.min((errorCount - 1) * 1000, 5000); return Math.min((errorCount - 1) * 1000, 5000);
} }
} }
} }
...@@ -40,12 +40,10 @@ import java.util.HashMap; ...@@ -40,12 +40,10 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /** A {@link DrmSessionManager} that supports playbacks using {@link ExoMediaDrm}. */
* A {@link DrmSessionManager} that supports playbacks using {@link ExoMediaDrm}.
*/
@TargetApi(18) @TargetApi(18)
public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSessionManager<T>, public class DefaultDrmSessionManager<T extends ExoMediaCrypto>
ProvisioningManager<T> { implements DrmSessionManager<T>, ProvisioningManager<T> {
/** /**
* Signals that the {@link DrmInitData} passed to {@link #acquireSession} does not contain does * Signals that the {@link DrmInitData} passed to {@link #acquireSession} does not contain does
...@@ -76,9 +74,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe ...@@ -76,9 +74,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
* licenses. * licenses.
*/ */
public static final int MODE_PLAYBACK = 0; public static final int MODE_PLAYBACK = 0;
/** /** Restores an offline license to allow its status to be queried. */
* Restores an offline license to allow its status to be queried.
*/
public static final int MODE_QUERY = 1; public static final int MODE_QUERY = 1;
/** Downloads an offline license or renews an existing one. */ /** Downloads an offline license or renews an existing one. */
public static final int MODE_DOWNLOAD = 2; public static final int MODE_DOWNLOAD = 2;
...@@ -272,8 +268,8 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe ...@@ -272,8 +268,8 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
/** /**
* Provides access to {@link ExoMediaDrm#getPropertyString(String)}. * Provides access to {@link ExoMediaDrm#getPropertyString(String)}.
* <p> *
* This method may be called when the manager is in any state. * <p>This method may be called when the manager is in any state.
* *
* @param key The key to request. * @param key The key to request.
* @return The retrieved property. * @return The retrieved property.
...@@ -284,8 +280,8 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe ...@@ -284,8 +280,8 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
/** /**
* Provides access to {@link ExoMediaDrm#setPropertyString(String, String)}. * Provides access to {@link ExoMediaDrm#setPropertyString(String, String)}.
* <p> *
* This method may be called when the manager is in any state. * <p>This method may be called when the manager is in any state.
* *
* @param key The property to write. * @param key The property to write.
* @param value The value to write. * @param value The value to write.
...@@ -296,8 +292,8 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe ...@@ -296,8 +292,8 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
/** /**
* Provides access to {@link ExoMediaDrm#getPropertyByteArray(String)}. * Provides access to {@link ExoMediaDrm#getPropertyByteArray(String)}.
* <p> *
* This method may be called when the manager is in any state. * <p>This method may be called when the manager is in any state.
* *
* @param key The key to request. * @param key The key to request.
* @return The retrieved property. * @return The retrieved property.
...@@ -308,8 +304,8 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe ...@@ -308,8 +304,8 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
/** /**
* Provides access to {@link ExoMediaDrm#setPropertyByteArray(String, byte[])}. * Provides access to {@link ExoMediaDrm#setPropertyByteArray(String, byte[])}.
* <p> *
* This method may be called when the manager is in any state. * <p>This method may be called when the manager is in any state.
* *
* @param key The property to write. * @param key The property to write.
* @param value The value to write. * @param value The value to write.
...@@ -373,7 +369,8 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe ...@@ -373,7 +369,8 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
if (schemeType == null || C.CENC_TYPE_cenc.equals(schemeType)) { if (schemeType == null || C.CENC_TYPE_cenc.equals(schemeType)) {
// If there is no scheme information, assume patternless AES-CTR. // If there is no scheme information, assume patternless AES-CTR.
return true; return true;
} else if (C.CENC_TYPE_cbc1.equals(schemeType) || C.CENC_TYPE_cbcs.equals(schemeType) } else if (C.CENC_TYPE_cbc1.equals(schemeType)
|| C.CENC_TYPE_cbcs.equals(schemeType)
|| C.CENC_TYPE_cens.equals(schemeType)) { || C.CENC_TYPE_cens.equals(schemeType)) {
// API support for AES-CBC and pattern encryption was added in API 24. However, the // API support for AES-CBC and pattern encryption was added in API 24. However, the
// implementation was not stable until API 25. // implementation was not stable until API 25.
...@@ -423,7 +420,8 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe ...@@ -423,7 +420,8 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
new DefaultDrmSession<>( new DefaultDrmSession<>(
uuid, uuid,
mediaDrm, mediaDrm,
this, /* provisioningManager= */ this,
/* releaseCallback= */ this::onSessionReleased,
schemeDatas, schemeDatas,
mode, mode,
offlineLicenseKeySetId, offlineLicenseKeySetId,
...@@ -444,17 +442,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe ...@@ -444,17 +442,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
// Do nothing. // Do nothing.
return; return;
} }
((DefaultDrmSession<T>) session).release();
DefaultDrmSession<T> drmSession = (DefaultDrmSession<T>) session;
if (drmSession.release()) {
sessions.remove(drmSession);
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.
provisioningSessions.get(1).provision();
}
provisioningSessions.remove(drmSession);
}
} }
// ProvisioningManager implementation. // ProvisioningManager implementation.
...@@ -490,6 +478,16 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe ...@@ -490,6 +478,16 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
// Internal methods. // Internal methods.
private void onSessionReleased(DefaultDrmSession<T> drmSession) {
sessions.remove(drmSession);
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.
provisioningSessions.get(1).provision();
}
provisioningSessions.remove(drmSession);
}
/** /**
* Extracts {@link SchemeData} instances suitable for the given DRM scheme {@link UUID}. * Extracts {@link SchemeData} instances suitable for the given DRM scheme {@link UUID}.
* *
...@@ -506,8 +504,9 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe ...@@ -506,8 +504,9 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
List<SchemeData> matchingSchemeDatas = new ArrayList<>(drmInitData.schemeDataCount); List<SchemeData> matchingSchemeDatas = new ArrayList<>(drmInitData.schemeDataCount);
for (int i = 0; i < drmInitData.schemeDataCount; i++) { for (int i = 0; i < drmInitData.schemeDataCount; i++) {
SchemeData schemeData = drmInitData.get(i); SchemeData schemeData = drmInitData.get(i);
boolean uuidMatches = schemeData.matches(uuid) boolean uuidMatches =
|| (C.CLEARKEY_UUID.equals(uuid) && schemeData.matches(C.COMMON_PSSH_UUID)); schemeData.matches(uuid)
|| (C.CLEARKEY_UUID.equals(uuid) && schemeData.matches(C.COMMON_PSSH_UUID));
if (uuidMatches && (schemeData.data != null || allowMissingData)) { if (uuidMatches && (schemeData.data != null || allowMissingData)) {
matchingSchemeDatas.add(schemeData); matchingSchemeDatas.add(schemeData);
} }
...@@ -536,7 +535,6 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe ...@@ -536,7 +535,6 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
} }
} }
} }
} }
private class MediaDrmEventListener implements OnEventListener<T> { private class MediaDrmEventListener implements OnEventListener<T> {
...@@ -550,7 +548,5 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe ...@@ -550,7 +548,5 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
@Nullable byte[] data) { @Nullable byte[] data) {
Assertions.checkNotNull(mediaDrmHandler).obtainMessage(event, sessionId).sendToTarget(); Assertions.checkNotNull(mediaDrmHandler).obtainMessage(event, sessionId).sendToTarget();
} }
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment