Add new APIs to ExoMediaDrm

Changes
---
- Added `removeOfflineLicense(byte[])` and `getOfflineLicenseKeySetIds` and consumed them in their implementations

Background
---
- These APIs will help in addressing an increasing amount of `java.lang.IllegalArgumentException: Failed to restore keys: BAD_VALUE` which is our top playback error in our app
	- Based on our discussion with Widevine team and [this exoplayer issue](https://github.com/google/ExoPlayer/issues/11202#issuecomment-1708792594)
		- TL;DR: The failure occurs on startup if the user has 200+ offline licenses, we would like to add the functionality to remove offline licenses

**Note: Why we want these APIs in ExoMediaDrm and not in OfflineLicenseHelper**
	- As per the issue above, we would like to access these 2 public APIs in MediaDrm that don’t exist in `OfflineLicenseHelper` or `ExoMediaDrm`
		- APIs interested in:
			- [MediaDrm#removeOfflineLicense()](https://developer.android.com/reference/android/media/MediaDrm#removeOfflineLicense(byte%5B%5D)): To remove offline license
			- [MediaDrm#getOfflineLicenseKeySetIds()](https://developer.android.com/reference/android/media/MediaDrm#getOfflineLicenseKeySetIds()): To see number of offline licenses on startup

		- We use `OfflineLicenseHelper` to download license for L1 and we don't interact with `ExoMediaDrm` directly. But for the alternate Widevine integration, we directly depend on `ExoMediaDrm` APIs to override and call CDM Native APIs.
		- We would like to have the functionality of removing offline licenses for both integration which would need access to above APIs in `ExoMediaDrm`.

Links
---
- https://github.com/androidx/media/issues/659
This commit is contained in:
Shanuj Shekhar 2023-09-25 11:34:30 -04:00
parent ffd7bb5639
commit aba15b6952
4 changed files with 60 additions and 0 deletions

View File

@ -24,6 +24,7 @@ import androidx.media3.common.DrmInitData;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.decoder.CryptoConfig;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -156,4 +157,15 @@ public final class DummyExoMediaDrm implements ExoMediaDrm {
public @C.CryptoType int getCryptoType() {
return C.CRYPTO_TYPE_UNSUPPORTED;
}
@Override
public void removeOfflineLicense(byte[] keySetId) {
// Should not be invoked. No session should exist.
throw new IllegalStateException();
}
@Override
public List<byte[]> getOfflineLicenseKeySetIds() {
return Collections.emptyList();
}
}

View File

@ -583,4 +583,19 @@ public interface ExoMediaDrm {
*/
@C.CryptoType
int getCryptoType();
/**
* Removes an offline license.
* This method is generally not needed, and should only be used if the preferred approach of passing {@link MediaDrm#KEY_TYPE_RELEASE} to {@link #getKeyRequest} is not possible.
*
* See {@link MediaDrm#removeOfflineLicense(byte[])} for more details.
*/
void removeOfflineLicense(byte[] keySetId);
/**
* This method returns a list of the keySetIds for all offline licenses.
*
* See {@link MediaDrm#getOfflineLicenseKeySetIds()} for more details.
*/
List<byte[]> getOfflineLicenseKeySetIds();
}

View File

@ -26,6 +26,7 @@ import android.media.MediaDrmException;
import android.media.NotProvisionedException;
import android.media.UnsupportedSchemeException;
import android.media.metrics.LogSessionId;
import android.os.Build;
import android.os.PersistableBundle;
import android.text.TextUtils;
import androidx.annotation.DoNotInline;
@ -46,6 +47,7 @@ import com.google.common.base.Charsets;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -380,6 +382,26 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
return C.CRYPTO_TYPE_FRAMEWORK;
}
@Override
@RequiresApi(Build.VERSION_CODES.Q)
public void removeOfflineLicense(byte[] keySetId) {
if (Util.SDK_INT < Build.VERSION_CODES.Q) {
throw new UnsupportedOperationException();
}
mediaDrm.removeOfflineLicense(keySetId);
}
@Override
@RequiresApi(Build.VERSION_CODES.Q)
public List<byte[]> getOfflineLicenseKeySetIds() {
if (Util.SDK_INT < Build.VERSION_CODES.Q) {
return Collections.emptyList();
}
return mediaDrm.getOfflineLicenseKeySetIds();
}
private static SchemeData getSchemeData(UUID uuid, List<SchemeData> schemeDatas) {
if (!C.WIDEVINE_UUID.equals(uuid)) {
// For non-Widevine CDMs always use the first scheme data.

View File

@ -43,6 +43,7 @@ import com.google.common.primitives.Bytes;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -413,6 +414,16 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
return FakeCryptoConfig.TYPE;
}
@Override
public void removeOfflineLicense(byte[] keySetId) {
throw new UnsupportedOperationException();
}
@Override
public List<byte[]> getOfflineLicenseKeySetIds() {
return Collections.emptyList();
}
// Methods to facilitate testing
public int getReferenceCount() {