Skip to content

Commit e247c44

Browse files
authored
Improve support for multiple offline DRM keys (#29)
Support for multiple DRM offline keys was added in #28. Then I started to worry about a possible (although unlikely) hash collision between 2 different drmInitData. This PR replaces the hash by a string that is the encoded pssh. That way it's guaranteed to be unique to the initDrmData.
1 parent d38405f commit e247c44

File tree

1 file changed

+24
-14
lines changed

1 file changed

+24
-14
lines changed

libraries/exoplayer/src/main/java/androidx/media3/exoplayer/drm/DefaultDrmSessionManager.java

+24-14
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import android.os.Looper;
2828
import android.os.Message;
2929
import android.os.SystemClock;
30+
import android.util.Base64;
3031
import androidx.annotation.IntDef;
3132
import androidx.annotation.Nullable;
3233
import androidx.media3.common.C;
@@ -52,7 +53,6 @@
5253
import java.lang.annotation.RetentionPolicy;
5354
import java.lang.annotation.Target;
5455
import java.util.ArrayList;
55-
import java.util.Arrays;
5656
import java.util.Collections;
5757
import java.util.HashMap;
5858
import java.util.HashSet;
@@ -329,7 +329,7 @@ private MissingSchemeDataException(UUID uuid) {
329329

330330
// MIREGO: multiple offline DRM keys.
331331
private List<byte[]> offlineLicenseKeySetIdList;
332-
private List<Integer> drmInitDataHashList;
332+
private List<String> drmInitDataUidList;
333333

334334
private @MonotonicNonNull PlayerId playerId;
335335

@@ -396,19 +396,29 @@ public void setMode(@Mode int mode, @Nullable byte[] offlineLicenseKeySetId) {
396396
this.mode = mode;
397397
// MIREGO: multiple offline DRM keys.
398398
this.offlineLicenseKeySetIdList = (offlineLicenseKeySetId != null) ? ImmutableList.of(offlineLicenseKeySetId) : Collections.emptyList();
399-
this.drmInitDataHashList = Collections.emptyList();
399+
this.drmInitDataUidList = Collections.emptyList();
400400
}
401401

402402
// MIREGO: multiple offline DRM keys. Added function
403-
public void setMode(@Mode int mode, List<byte[]> offlineLicenseKeySetIdList, List<Integer> drmInitDataHashList) {
403+
public void setMode(@Mode int mode, List<byte[]> offlineLicenseKeySetIdList, List<String> drmInitDataUidList) {
404404
Log.d(TAG, "setMode %d offlineLicenseKeySetId size=%s", mode, offlineLicenseKeySetIdList.size());
405405
checkState(sessions.isEmpty());
406406
if (mode == MODE_QUERY || mode == MODE_RELEASE) {
407407
checkArgument(!offlineLicenseKeySetIdList.isEmpty());
408408
}
409409
this.mode = mode;
410410
this.offlineLicenseKeySetIdList = offlineLicenseKeySetIdList;
411-
this.drmInitDataHashList = drmInitDataHashList;
411+
this.drmInitDataUidList = drmInitDataUidList;
412+
}
413+
414+
public static String getDrmInitDataUuid(DrmInitData drmInitData) {
415+
for (int i = 0; i < drmInitData.schemeDataCount; i++) {
416+
SchemeData schemeData = drmInitData.get(i);
417+
if (schemeData.matches(C.WIDEVINE_UUID) && schemeData.hasData()) {
418+
return Base64.encodeToString(schemeData.data, Base64.DEFAULT);
419+
}
420+
}
421+
return "";
412422
}
413423

414424
// DrmSessionManager implementation.
@@ -535,7 +545,7 @@ private DrmSession acquireSession(
535545
session =
536546
createAndAcquireSessionWithRetry(
537547
schemeDatas,
538-
format.drmInitData.hashCode(), // MIREGO: multiple offline DRM keys
548+
getDrmInitDataUuid(format.drmInitData), // MIREGO: multiple offline DRM keys
539549
/* isPlaceholderSession= */ false,
540550
eventDispatcher,
541551
shouldReleasePreacquiredSessionsBeforeRetrying);
@@ -583,7 +593,7 @@ private DrmSession maybeAcquirePlaceholderSession(
583593
DefaultDrmSession placeholderDrmSession =
584594
createAndAcquireSessionWithRetry(
585595
/* schemeDatas= */ ImmutableList.of(),
586-
0, // MIREGO: multiple offline DRM keys
596+
"", // MIREGO: multiple offline DRM keys
587597
/* isPlaceholderSession= */ true,
588598
/* eventDispatcher= */ null,
589599
shouldReleasePreacquiredSessionsBeforeRetrying);
@@ -649,18 +659,18 @@ private void maybeCreateMediaDrmHandler(Looper playbackLooper) {
649659

650660
private DefaultDrmSession createAndAcquireSessionWithRetry(
651661
@Nullable List<SchemeData> schemeDatas,
652-
int drmInitDataHash, // MIREGO: multiple offline DRM keys
662+
String drmInitDataUid, // MIREGO: multiple offline DRM keys
653663
boolean isPlaceholderSession,
654664
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher,
655665
boolean shouldReleasePreacquiredSessionsBeforeRetrying) {
656666
DefaultDrmSession session =
657-
createAndAcquireSession(schemeDatas, drmInitDataHash, isPlaceholderSession, eventDispatcher); // MIREGO: multiple offline DRM keys
667+
createAndAcquireSession(schemeDatas, drmInitDataUid, isPlaceholderSession, eventDispatcher); // MIREGO: multiple offline DRM keys
658668
// If we're short on DRM session resources, first try eagerly releasing all our keepalive
659669
// sessions and then retry the acquisition.
660670
if (acquisitionFailedIndicatingResourceShortage(session) && !keepaliveSessions.isEmpty()) {
661671
releaseAllKeepaliveSessions();
662672
undoAcquisition(session, eventDispatcher);
663-
session = createAndAcquireSession(schemeDatas, drmInitDataHash, isPlaceholderSession, eventDispatcher); // MIREGO: multiple offline DRM keys
673+
session = createAndAcquireSession(schemeDatas, drmInitDataUid, isPlaceholderSession, eventDispatcher); // MIREGO: multiple offline DRM keys
664674
}
665675

666676
// If the acquisition failed again due to continued resource shortage, and
@@ -676,7 +686,7 @@ private DefaultDrmSession createAndAcquireSessionWithRetry(
676686
releaseAllKeepaliveSessions();
677687
}
678688
undoAcquisition(session, eventDispatcher);
679-
session = createAndAcquireSession(schemeDatas, drmInitDataHash, isPlaceholderSession, eventDispatcher); // MIREGO: multiple offline DRM keys
689+
session = createAndAcquireSession(schemeDatas, drmInitDataUid, isPlaceholderSession, eventDispatcher); // MIREGO: multiple offline DRM keys
680690
}
681691
return session;
682692
}
@@ -691,7 +701,7 @@ private static boolean acquisitionFailedIndicatingResourceShortage(DrmSession se
691701
}
692702

693703
/**
694-
* Undoes the acquisitions from {@link #createAndAcquireSession(List, boolean,
704+
* Undoes the acquisitions from {@link #createAndAcquireSession(List, int, boolean,
695705
* DrmSessionEventListener.EventDispatcher)}.
696706
*/
697707
private void undoAcquisition(
@@ -730,7 +740,7 @@ private void releaseAllPreacquiredSessions() {
730740
*/
731741
private DefaultDrmSession createAndAcquireSession(
732742
@Nullable List<SchemeData> schemeDatas,
733-
int drmInitDataHash, // MIREGO: multiple offline DRM keys
743+
String drmInitDataUid, // MIREGO: multiple offline DRM keys
734744
boolean isPlaceholderSession,
735745
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher) {
736746
checkNotNull(exoMediaDrm);
@@ -742,7 +752,7 @@ private DefaultDrmSession createAndAcquireSession(
742752
if (offlineLicenseKeySetIdList.size() == 1) { // Keep legacy behavior with single offline key (just use it)
743753
offlineLicenseKeySetId = offlineLicenseKeySetIdList.get(0);
744754
} else if (!offlineLicenseKeySetIdList.isEmpty()){ //multiple offline DRM keys. Find the right keyId from the drmInitData hash
745-
int index = drmInitDataHashList.indexOf(drmInitDataHash);
755+
int index = drmInitDataUidList.indexOf(drmInitDataUid);
746756
if (index >= 0) {
747757
offlineLicenseKeySetId = offlineLicenseKeySetIdList.get(index);
748758
} else { // oops, we haven't found the drmInitData hash. We might as well fallback to the first key.

0 commit comments

Comments
 (0)