androidx / androidx/media

Motorola Moto G20 bug: Offline Widevine DRM playback error gives "Crypto key not available"

Open
#1,307 3 comments 0 reactions 1 assignee View on GitHub

@tianyif is already working on this.

Since May 2, 2024.

needs triage question
Dominant language
Java
Stars
3k
Forks
955
Avg merge
12d 14h
Merged PRs (30d)
2

Description

I'm trying to play a downloaded DASH stream protected by Widevine DRM. Player shows the expected duration but playback won't start, I get this error:

androidx.media3.exoplayer.ExoPlaybackException: MediaCodecVideoRenderer error, index=0, format=Format(2, null, null, video/avc, avc1.42C028, 1007100, null, [852, 480, 25.00036, ColorInfo(BT709, Limited range, SDR SMPTE 170M, false, 8bit Luma, 8bit Chroma)], [-1, -1]), format_supported=YES
    at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:620)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:240)
    at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: android.media.MediaCodec$CryptoException: Crypto key not available
    at android.media.MediaCodec.native_queueSecureInputBuffer(Native Method)
    at android.media.MediaCodec.queueSecureInputBuffer(MediaCodec.java:2821)
    at androidx.media3.exoplayer.mediacodec.SynchronousMediaCodecAdapter.queueSecureInputBuffer(SynchronousMediaCodecAdapter.java:151)
    at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.feedInputBuffer(MediaCodecRenderer.java:1448)
    at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:829)
    at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.render(MediaCodecVideoRenderer.java:940)
    at androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1102)
    at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:541)
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:240) 
    at android.os.HandlerThread.run(HandlerThread.java:67) 

I suppose the issue is in the way I configure the DRM session? Here is my code:

val cacheDataSourceFactory: DataSource.Factory =
    CacheDataSource.Factory()
        .setCache(downloadCache)
        .setUpstreamDataSourceFactory(DefaultHttpDataSource.Factory())
        .setCacheWriteDataSinkFactory(null)

val player =
    ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory),
        )
        .build()

var downloads =
    downloadManager.downloadIndex.getDownloads(Download.STATE_COMPLETED)
downloads.moveToFirst()

var mediaItem = downloads.download.request.toMediaItem()

val drmSessionManager = DefaultDrmSessionManager.Builder()
    .build(
        HttpMediaDrmCallback(
            null,
            false,
            DefaultHttpDataSource.Factory()
        )
    )

drmSessionManager.setMode(DefaultDrmSessionManager.MODE_PLAYBACK, keySetId);

val mediaSource =
    DashMediaSource.Factory(cacheDataSourceFactory)
        .setDrmSessionManagerProvider { drmSessionManager }
        .createMediaSource(mediaItem)

player?.setMediaSource(mediaSource, 0, true)

I think the code to download the DRM key is correct because after downloading it, I can print the license expiration and it matches my expectation. Here is my code just in case:

val dataSourceFactory =
    getDataSourceFactory(context, playerDependencies)
val dataSource = dataSourceFactory.createDataSource()
val dashManifest = DashUtil.loadManifest(dataSource, Uri.parse(mainStream.url))
val drmInitData =
    DashUtil.loadFormatWithDrmInitData(dataSource, dashManifest.getPeriod(0))

drmInitData?.let {
val offlineLicenseHelper = OfflineLicenseHelper.newWidevineInstance(
    drmLicenseUrl.url,
    dataSourceFactory as HttpDataSource.Factory,
    DrmSessionEventListener.EventDispatcher(),
)
val keySetId = offlineLicenseHelper.downloadLicense(it)

// validation license expiration is ok
// val licenseExpiration = System.currentTimeMillis() + (offlineLicenseHelper.getLicenseDurationRemainingSec(keySetId).first * 1000)

val downloadRequest = DownloadRequest.Builder(mediaResource.id, Uri.parse(mainStream.url))
    .setKeySetId(keySetId)
    .build()

DownloadService.sendAddDownload(
    context,
    MyDownloadService::class.java,
    downloadRequest,
    /* foreground= */ false
)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.