-
Notifications
You must be signed in to change notification settings - Fork 615
Description
I'm working on a DRM-protected video playback application using ExoPlayer where I have multiple videos, and I'm trying to enforce L3 security level for certain Widevine DRM media. My initial setup was using the L1 security level through and through without modifying the security_level
, which was working fine. The issue I'm facing now with the new implementation is that when I play an L1 media (where shouldForceL3
is false), and then an L3 media (where shouldForceL3
is true), the second playback fails with the "Error decrypting data: ERROR_DRM_CANNOT_HANDLE" error. However, when I play the second media again after failure, it works fine. Moreover L1 -> L1, L3 -> L1 and L3 ->L3 playbacks work fine too. It's just L1 -> L3 playback that fails with the given error
I found a solution that if I stop the ExoPlayer (using player.stop()) before moving to the next media, it all works as expected. However, I wonder if there is a better solution that I am missing out (maybe release DRM session manager? but how?)
Here's the relevant code I'm using to create the media source and configure the DRM:
private fun createMediaSource(
mediaItem: MediaItem,
mimeType: Int,
licenseUri: String?,
forceL3: Boolean
): MediaSource {
val drmCallback = HttpMediaDrmCallback(
licenseUri ?: "",
DefaultHttpDataSource.Factory().setUserAgent(USER_AGENT).setTransferListener(
DefaultBandwidthMeter.Builder(context).setResetOnNetworkTypeChange(false).build()
)
)
val drmSessionManager = DefaultDrmSessionManager.Builder()
.setUuidAndExoMediaDrmProvider(C.WIDEVINE_UUID) { uuid ->
try {
FrameworkMediaDrm.newInstance(uuid).apply {
if (forceL3) {
Log.i(TAG, "Forcing Widevine security level L3. Previous security level = ${getPropertyString("securityLevel")}")
setPropertyString("securityLevel", "L3")
Log.i(TAG, "Actual enforced Widevine security level = ${getPropertyString("securityLevel")}")
}
}
} catch (e: UnsupportedDrmException) {
DummyExoMediaDrm()
}
}
.setMultiSession(false)
.build(drmCallback)
return when (mimeType) {
C.CONTENT_TYPE_DASH -> {
val dataSourceFactory = DefaultHttpDataSource.Factory().setUserAgent(USER_AGENT)
val dashChunkSourceFactory = DefaultDashChunkSource.Factory(dataSourceFactory)
val manifestFactory = DefaultHttpDataSource.Factory().setUserAgent(USER_AGENT)
DashMediaSource.Factory(dashChunkSourceFactory, manifestFactory)
.setDrmSessionManagerProvider { drmSessionManager }
.createMediaSource(mediaItem)
}
C.CONTENT_TYPE_HLS -> {
HlsMediaSource.Factory(DefaultHttpDataSource.Factory().setUserAgent(USER_AGENT))
.setDrmSessionManagerProvider { drmSessionManager }
.createMediaSource(mediaItem)
}
C.CONTENT_TYPE_SS -> {
SsMediaSource.Factory(DefaultHttpDataSource.Factory().setUserAgent(USER_AGENT))
.setDrmSessionManagerProvider { drmSessionManager }
.createMediaSource(mediaItem)
}
C.CONTENT_TYPE_RTSP -> {
throw IllegalStateException("Unsupported type: $mimeType")
}
else -> {
val dataSourceFactory = DefaultDataSource.Factory(context, DefaultHttpDataSource.Factory())
ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItem)
}
}
}
Here are the failure logs:
playerFailed [eventTime=685.62, mediaPos=0.00, window=0, period=0, errorCode=ERROR_CODE_DRM_SYSTEM_ERROR
androidx.media3.exoplayer.ExoPlaybackException: MediaCodecVideoRenderer error, index=0, format=Format(3, null, null, video/avc, avc1.4D4028, 7760004, null, [1280, 674, 24.0, ColorInfo(Unset color space, Unset color range, Unset color transfer, false, 8bit Luma, 8bit Chroma)], [-1, -1]), format_supported=YES
at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:641)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: android.media.MediaCodec$CryptoException: Error decrypting data: unspecified error: ERROR_DRM_CANNOT_HANDLE
cdm err: 178, oem err: 28, ctx: 23
============================== Beginning of DRM Plugin Log ==============================
09-22 10:27:30.733 I No hidl drm factories found
09-22 10:27:30.733 E Failed to find passthrough drm factories
09-22 10:27:32.975 I No hidl drm factories found
09-22 10:27:32.975 E Failed to find passthrough drm factories
09-22 10:27:33.931 I [cdm_engine.cpp(382):AddKey] session_id = sid24, key_set_id =
09-22 10:27:36.824 I No hidl drm factories found
09-22 10:27:36.827 E Failed to find passthrough drm factories
09-22 10:27:37.225 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:27:37.225 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:27:37.225 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:27:37.225 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:27:37.232 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:27:37.233 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:27:37.233 I [cdm_engine.cpp(216):OpenSession] New session: session_id = sid25
09-22 10:27:37.233 I [cdm_engine.cpp(1050):QueryOemCryptoSessionId] session_id = sid25
09-22 10:27:37.233 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:27:37.234 I [cdm_engine.cpp(955):QuerySessionStatus] session_id = sid25
09-22 10:27:37.234 I [cdm_engine.cpp(2264):SetPlaybackId] session_id = sid25, playback_id = nrL3oBu34d7yQ4-u
09-22 10:27:37.235 I [cdm_engine.cpp(303):GenerateKeyRequest] session_id = sid25, key_set_id = , license_type = Streaming
09-22 10:27:37.236 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:27:37.236 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:27:37.297 I [cdm_engine.cpp(955):QuerySessionStatus] session_id = sid25
09-22 10:27:37.297 I [cdm_engine.cpp(261):CloseSession] session_id = sid24
09-22 10:27:37.796 I [cdm_engine.cpp(382):AddKey] session_id = sid25, key_set_id =
09-22 10:27:38.302 E [cdm_session.cpp(734):Decrypt] Decryption failed: sid = sid25, status = 178
09-22 10:27:38.302 E [crypto_session.cpp(1976):Decrypt] OEMCrypto_DecryptCENC failed: oec_session_id = 0, security_level = L3, status = 28
09-22 10:27:38.471 I [cdm_engine.cpp(261):CloseSession] session_id = sid25
09-22 10:27:38.477 I [oemcrypto_adapter_dynamic.cpp(897):Level1Terminate] L1 Terminate
09-22 10:27:38.477 I [(0):] L3 Terminate.
09-22 10:38:46.049 I No hidl drm factories found
09-22 10:38:46.052 E Failed to find passthrough drm factories
09-22 10:38:46.054 I [(0):] Level3 Library 28613 May 1 2023 06:32:58
09-22 10:38:46.054 I [oemcrypto_adapter_dynamic.cpp(837):Initialize] Level 3 Build Info (v18): {"soc_vendor":"L3_28613","soc_model":"ARM 64 bit","ta_ver":"18.1.0+May 1 2023_06:32:58_","uses_opk":false,"tee_os":"none","tee_os_ver":"0.0.0","form_factor":"L3","implementer":"Widevine","fused":false}
09-22 10:38:46.054 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:46.060 I [oemcrypto_adapter_dynamic.cpp(851):Initialize] L3 Initialized. Trying L1.
2025-09-22 12:38:53.190 16039-16039 MediaPlatformTestSuite com...pinext.mediaframework.testapp E 09-22 10:38:46.263 W [oemcrypto_adapter_dynamic.cpp(1084):LoadLevel1] Could not load L1 _oecc140.
09-22 10:38:46.263 I [oemcrypto_adapter_dynamic.cpp(885):Initialize] Level 1 Build Info (v18): {"soc_vendor":"SEC","soc_model":"Exynosautov9","ta_ver":"1.0","uses_opk":false,"tee_os":"","tee_os_ver":"1.0","is_debug":false}
09-22 10:38:46.263 W [oemcrypto_adapter_dynamic.cpp(1083):LoadLevel1] Could not load L1 _oecc139.
09-22 10:38:46.263 W [oemcrypto_adapter_dynamic.cpp(1076):LoadLevel1] Could not load L1 _oecc141.
09-22 10:38:46.263 W [oemcrypto_adapter_dynamic.cpp(1013):LoadLevel1] Could not load L1 _oecc90.
09-22 10:38:46.263 W [oemcrypto_adapter_dynamic.cpp(1039):LoadLevel1] Could not load L1 _oecc23.
09-22 10:38:46.263 W [oemcrypto_adapter_dynamic.cpp(1059):LoadLevel1] Could not load L1 _oecc116.
09-22 10:38:46.263 W [oemcrypto_adapter_dynamic.cpp(1060):LoadLevel1] Could not load L1 _oecc117.
09-22 10:38:46.263 W [oemcrypto_adapter_dynamic.cpp(1061):LoadLevel1] Could not load L1 _oecc118.
09-22 10:38:46.263 W [oemcrypto_adapter_dynamic.cpp(1065):LoadLevel1] Could not load L1 _oecc113.
09-22 10:38:46.263 W [oemcrypto_adapter_dynamic.cpp(1066):LoadLevel1] Could not load L1 _oecc114.
09-22 10:38:46.263 W [oemcrypto_adapter_dynamic.cpp(1075):LoadLevel1] Could not load L1 _oecc131.
09-22 10:38:46.271 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:46.272 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:46.604 I [cdm_usage_table.cpp(203):RestoreTable] Found usage table to restore: entry_count = 0
09-22 10:38:46.605 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:46.605 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:46.605 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:46.614 I [cdm_usage_table.cpp(203):RestoreTable] Found usage table to restore: entry_count = 0
09-22 10:38:46.627 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:46.638 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:46.638 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:46.638 I [cdm_engine.cpp(216):OpenSession] New session: session_id = sid26
09-22 10:38:46.638 I [cdm_engine.cpp(1050):QueryOemCryptoSessionId] session_id = sid26
09-22 10:38:46.638 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:46.639 I [cdm_engine.cpp(955):QuerySessionStatus] session_id = sid26
09-22 10:38:46.640 I [cdm_engine.cpp(2264):SetPlaybackId] session_id = sid26, playback_id = nrL3oBu34d7yQ4-u
09-22 10:38:46.648 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:46.648 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:46.648 I [cdm_engine.cpp(303):GenerateKeyRequest] session_id = sid26, key_set_id = , license_type = Streaming
09-22 10:38:46.690 I [cdm_engine.cpp(1089):IsSecurityLevelSupported] level = L1
09-22 10:38:46.691 I [cdm_engine.cpp(955):QuerySessionStatus] session_id = sid26
09-22 10:38:46.737 I [cdm_engine.cpp(1089):IsSecurityLevelSupported] level = L1
09-22 10:38:46.738 I [cdm_engine.cpp(955):QuerySessionStatus] session_id = sid26
09-22 10:38:47.086 I [cdm_engine.cpp(382):AddKey] session_id = sid26, key_set_id =
09-22 10:38:49.626 I No hidl drm factories found
09-22 10:38:49.626 E Failed to find passthrough drm factories
09-22 10:38:49.954 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:49.965 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:49.965 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:49.965 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:49.966 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:49.972 I [cdm_engine.cpp(1050):QueryOemCryptoSessionId] session_id = sid27
09-22 10:38:49.972 I [file_utils.cpp(38):Exists] stat failed: ENOENT
2025-09-22 12:38:53.190 16039-16039 MediaPlatformTestSuite com...pinext.mediaframework.testapp E 09-22 10:38:49.972 I [cdm_engine.cpp(216):OpenSession] New session: session_id = sid27
09-22 10:38:49.973 I [cdm_engine.cpp(2264):SetPlaybackId] session_id = sid27, playback_id = nrL3oBu34d7yQ4-u
09-22 10:38:49.973 I [cdm_engine.cpp(955):QuerySessionStatus] session_id = sid27
09-22 10:38:49.977 I [cdm_engine.cpp(303):GenerateKeyRequest] session_id = sid27, key_set_id = , license_type = Streaming
09-22 10:38:49.977 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:49.977 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:50.361 I [cdm_engine.cpp(955):QuerySessionStatus] session_id = sid27
09-22 10:38:50.374 I [cdm_engine.cpp(955):QuerySessionStatus] session_id = sid27
09-22 10:38:50.383 I [cdm_engine.cpp(261):CloseSession] session_id = sid26
09-22 10:38:50.390 I [cdm_engine.cpp(1089):IsSecurityLevelSupported] level = L1
09-22 10:38:50.392 I [cdm_engine.cpp(955):QuerySessionStatus] session_id = sid27
09-22 10:38:50.622 I [cdm_engine.cpp(382):AddKey] session_id = sid27, key_set_id =
09-22 10:38:52.113 I No hidl drm factories found
09-22 10:38:52.113 E Failed to find passthrough drm factories
09-22 10:38:52.645 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:52.645 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:52.645 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:52.650 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:52.662 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:52.663 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:52.663 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:52.663 I [cdm_engine.cpp(216):OpenSession] New session: session_id = sid28
09-22 10:38:52.663 I [cdm_engine.cpp(1050):QueryOemCryptoSessionId] session_id = sid28
09-22 10:38:52.663 I [cdm_engine.cpp(955):QuerySessionStatus] session_id = sid28
09-22 10:38:52.664 I [cdm_engine.cpp(2264):SetPlaybackId] session_id = sid28, playback_id = nrL3oBu34d7yQ4-u
09-22 10:38:52.666 I [cdm_engine.cpp(303):GenerateKeyRequest] session_id = sid28, key_set_id = , license_type = Streaming
09-22 10:38:52.666 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:52.666 I [file_utils.cpp(38):Exists] stat failed: ENOENT
09-22 10:38:52.729 I [cdm_engine.cpp(955):QuerySessionStatus] session_id = sid28
09-22 10:38:52.729 I [cdm_engine.cpp(261):CloseSession] session_id = sid27
09-22 10:38:52.969 I [cdm_engine.cpp(382):AddKey] session_id = sid28, key_set_id =
09-22 10:38:53.012 E [crypto_session.cpp(1976):Decrypt] OEMCrypto_DecryptCENC failed: oec_session_id = 0, security_level = L3, status = 28
09-22 10:38:53.012 E [cdm_session.cpp(734):Decrypt] Decryption failed: sid = sid28, status = 178
============================== End of DRM Plugin Log ==============================
at android.media.MediaCodec.native_queueSecureInputBuffer(Native Method)
at android.media.MediaCodec.queueSecureInputBuffer(MediaCodec.java:3105)
at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecBufferEnqueuer.doQueueSecureInputBuffer(AsynchronousMediaCodecBufferEnqueuer.java:233)
at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecBufferEnqueuer.doHandleMessage(AsynchronousMediaCodecBufferEnqueuer.java:194)
at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecBufferEnqueuer.access$000(AsynchronousMediaCodecBufferEnqueuer.java:45)
at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecBufferEnqueuer$1.handleMessage(AsynchronousMediaCodecBufferEnqueuer.java:91)
at android.os.Handler.dispatchMessage(Handler.java:106)
... 3 more
Any insights or suggestions would be greatly appreciated. Thank you