mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Add a release callback to DefaultDrmSession
In preparation for reference counting in DrmSession PiperOrigin-RevId: 247428114
This commit is contained in:
parent
0a6f81a2cc
commit
3b60584813
2 changed files with 60 additions and 56 deletions
|
|
@ -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;
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
|
|
||||||
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;
|
||||||
* @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;
|
||||||
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;
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @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;
|
||||||
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;
|
||||||
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;
|
||||||
} 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;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("HandlerLeak")
|
@SuppressLint("HandlerLeak")
|
||||||
|
|
@ -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;
|
||||||
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
|
||||||
* 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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
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
|
||||||
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
|
||||||
// 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
|
||||||
|
|
||||||
// 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
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MediaDrmEventListener implements OnEventListener<T> {
|
private class MediaDrmEventListener implements OnEventListener<T> {
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue