From b184677b7b50652ea9a97d1504c80f171143d7d9 Mon Sep 17 00:00:00 2001 From: ibaker Date: Wed, 14 Aug 2024 03:24:51 -0700 Subject: [PATCH] Check WV version before relying on `MediaDrm.requiresSecureDecoder` This method was added in API 31 (S) but it's non-functional (incorrectly, silently, returns `false`) on the Widevine plugin version (`16.0`) from R (API 30), which some devices up to at least API 34 are still using. This results in ExoPlayer incorrectly selecting an insecure decoder for L1 secure content, and subsequently calling `MediaCodec.queueInputBuffer` instead of `queueSecureInputBuffer`, which is not supported and generates the following error: > Operation not supported in this configuration: ERROR_DRM_CANNOT_HANDLE Issue: androidx/media#1603 #cherrypick PiperOrigin-RevId: 662852176 (cherry picked from commit ca455ee8583938669179b30a686a894b353820eb) --- RELEASENOTES.md | 6 +++++ .../exoplayer/drm/FrameworkMediaDrm.java | 22 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 9aecd342b49..d5b14bed721 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -26,6 +26,12 @@ * Image: * DataSource: * DRM: + * Fix `android.media.MediaCodec$CryptoException: Operation not supported + in this configuration: ERROR_DRM_CANNOT_HANDLE` error on API 31+ devices + playing L1 Widevine content. This error is caused by an incomplete + implementation of the framework + [`MediaDrm.requiresSecureDecoder`](https://developer.android.com/reference/android/media/MediaDrm#requiresSecureDecoder\(java.lang.String\)) + method ([#1603](https://github.com/google/ExoPlayer/issues/1603)). * Effect: * Add a `release()` method to `GlObjectsProvider`. * Muxers: diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/drm/FrameworkMediaDrm.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/drm/FrameworkMediaDrm.java index 873fd2849a5..05f3f1171fe 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/drm/FrameworkMediaDrm.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/drm/FrameworkMediaDrm.java @@ -292,7 +292,7 @@ public Map queryKeyStatus(byte[] sessionId) { @Override public boolean requiresSecureDecoder(byte[] sessionId, String mimeType) { boolean result; - if (Util.SDK_INT >= 31) { + if (Util.SDK_INT >= 31 && isMediaDrmRequiresSecureDecoderImplemented()) { result = Api31.requiresSecureDecoder(mediaDrm, mimeType); } else { MediaCrypto mediaCrypto = null; @@ -408,6 +408,26 @@ private boolean shouldForceAllowInsecureDecoderComponents() { return C.CRYPTO_TYPE_FRAMEWORK; } + /** + * {@link MediaDrm#requiresSecureDecoder} is nominally available from API 31, but it's only + * functional for Widevine if the plugin version is greater than 16.0. See b/352419654#comment63. + */ + @RequiresApi(31) + private boolean isMediaDrmRequiresSecureDecoderImplemented() { + // TODO: b/359768062 - Add an SDK_INT guard clause once WV 16.0 is not permitted on any device. + if (uuid.equals(C.WIDEVINE_UUID)) { + String pluginVersion = getPropertyString(MediaDrm.PROPERTY_VERSION); + return !pluginVersion.startsWith("v5.") + && !pluginVersion.startsWith("14.") + && !pluginVersion.startsWith("15.") + && !pluginVersion.startsWith("16.0"); + } else { + // Assume that ClearKey plugin always supports this method, and no non-Google plugin does. See + // b/352419654#comment71. + return uuid.equals(C.CLEARKEY_UUID); + } + } + private static SchemeData getSchemeData(UUID uuid, List schemeDatas) { if (!C.WIDEVINE_UUID.equals(uuid)) { // For non-Widevine CDMs always use the first scheme data.