androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

OfflineLicenseHelperdownloadLicense stuck

chladto1 opened this issue · comments

Version

Media3 1.2.1

More version details

No response

Devices that reproduce the issue

All, but only when minifyEnabled = true

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

No

Reproduction steps

We are using code below to download offline DRM license. Application is stuck on OfflineLicenseHelper.downloadLicense call. The issue is reproducible only in build with minifyEnabled = true.

        val httpDrmCallback = HttpMediaDrmCallback(drmData.licenseServerUrl, httpDataSourceFactory)
        httpDrmCallback.setKeyRequestProperty("X-AxDRM-Message", drmData.token)

        val drmCallback = CRaMediaDrmCallback(httpDrmCallback)
        val mediaDrm = FrameworkMediaDrm.newInstance(drmData.scheme.uuid)

        if (onKeyStatusListener != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
            mediaDrm.setOnKeyStatusChangeListener { _, _, exoKeyInformation, _ ->
                val info = exoKeyInformation.map { OnKeyStatusListener.KeyStatus(it.keyId, it.statusCode) }
                onKeyStatusListener.onKeyStatusChange(info)
            }

        val drmProvider = ExoMediaDrm.AppManagedProvider(mediaDrm)

        val drmSessionManager = DefaultDrmSessionManager.Builder()
            .setUuidAndExoMediaDrmProvider(drmData.scheme.uuid, drmProvider)
            .build(drmCallback)

        val eventDispatcher = DrmSessionEventListener.EventDispatcher()
        val offlineLicenseHelper = OfflineLicenseHelper(drmSessionManager, eventDispatcher)

            for (periodIndex in 0 until manifest.periodCount) {
                val period = manifest.getPeriod(periodIndex)

                for (adaptationSet in period.adaptationSets)
                    for (representation in adaptationSet.representations) {
                        if (representation.format.drmInitData != null) {
                            val format = DashUtil.loadSampleFormat(httpDataSourceFactory.createDataSource(), adaptationSet.type, representation) ?: continue
                            val drmInitData = format.withManifestFormatInfo(representation.format)

                            val licenseBytes = offlineLicenseHelper.downloadLicense(drmInitData) // Never returns
                            return DrmLicense(licenseBytes, drmData)
                        }
                    }
            }

            throw IllegalArgumentException("Not a DRM content")
        

Expected result

Method downloadLicense will return DRM license.

Actual result

Application is stuck on downloadLicense call.

Media

Media
https://prima-vod-prep-prot.ssl.cdn.cra.cz/0258/4917/cze-dash-s-axinom-sd1-sd2-sd3-sd4-hd1-hd2-uhd2-rMpw0DDl.ism/.mpd

licenseServerUrl
https://drm-widevine-licensing.axprod.net/AcquireLicense

token
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjb21fa2V5X2lkIjoiOUJDMDREREUtQzc4OC00MDUzLUJGMzQtQUUzNjAwQkY5RjdDIiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsInZlcnNpb24iOjIsImxpY2Vuc2UiOnsiYWxsb3dfcGVyc2lzdGVuY2UiOnRydWUsImZhaXJwbGF5Ijp7InJlYWxfdGltZV9leHBpcmF0aW9uIjpmYWxzZX0sInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6ZmFsc2V9LCJ3aWRldmluZSI6e319LCJjb250ZW50X2tleXNfc291cmNlIjp7ImlubGluZSI6W3siaWQiOiJhMWM3M2MwMS02MWNlLTRiNjQtZGVkNC0yMWZlNTNhM2Q4YWIifV19fSwidmVyc2lvbiI6MX0._wMOjnQbYufBLJNHQkQ96zdCwsjdcdqp33FlouO-EbY

Bug Report

Application is stuck on downloadLicense call.

If you're able to reproduce this, please can you investigate further (maybe depend on the library locally and add some logging inside OfflineLicenseHelper.downloadLicense) in order to understand exactly where the hang is happening. I suspect you'll find that it's blocked on drmSessionFuture.get() here:

In which case the question is then why the Runnable defined just above in that method hasn't made progress - i.e. work out whether we managed to complete the calls to drmSessionManager.prepare() and/or drmSessionManager.acquireSession().

All calls are completed (drmSessionManager.prepare(), drmSessionManager.acquireSession() and drmSessionFuture.set()), but drmSessionFuture.get() never returns a result. I tried to force guava v31.1-android, because this version was used in Exo v2.19.1 where this worked fine. Unfortunately, Media3 is using com.google.common.collect.Streams, which is missing in the older guava. Versions 32.1.2-android and 33.2.1-android are also broken. I rewrote OfflineLicenseHelper to our own barrier implementation, and it is working fine.

Could you please try to help the guava team fix the issue?

That does sound surprising. It sounds like some interaction between R8 and Guava is resulting in SettableFuture.set not unblocking SettableFuture.get.

This reminds me a bit of this other recent R8 issue #1407 (though that was more clearly related to shrinking, this one is harder to reason about)

I tried to force guava v31.1-android, because this version was used in Exo v2.19.1 where this worked fine. Unfortunately, Media3 is using com.google.common.collect.Streams, which is missing in the older guava

I couldn't find any usages of this symbol. I downgraded the Guava version in constants.gradle to 31.1-android on the tip of main and the demo app built and installed fine. I also checked on version 1.2.1 (which you reported in the original comment), and that's already/still using 31.1-android:

guavaVersion = '31.1-android'


You could try downgrading R8 in your local repro case to help further pin-point the problem here. There's some tips on printing the current version here: stackoverflow.com/q/65194964, and you can set an explicit version as described here: https://stackoverflow.com/a/62734492

You could also try adding some very broad keep R8 rules to retain all of com.google.common.util.concurrent, to see if that affects the problem.

If you identify a regression between R8 versions you can report it here: https://r8.googlesource.com/r8#getting-help

I couldn't find any usages of this symbol. I downgraded the Guava version in constants.gradle to 31.1-android on the tip of main and the demo app built and installed fine. I also checked on version 1.2.1 (which you reported in the original comment), and that's already/still using 31.1-android:

Oh, sorry, my mistake, the most likely I looked into master instead of 1.2.1 tag.

There's some tips on printing the current version here: stackoverflow.com/q/65194964

I'm using this version.

3.2.74 (build 5a007b90730be50a5cc54e7897d86312107f4984 from go/r8bot (luci-r8-custom-ci-xenial-2-tnjr))

You could also try adding some very broad keep R8 rules to retain all of com.google.common.util.concurrent, to see if that affects the problem.

A DRM content can be downloaded if I add the following rule.

-keep class com.google.common.util.concurrent.** { *; }

you can set an explicit version as described here: https://stackoverflow.com/a/62734492

I tried the latest version 8.3.37 and it works too.

Looks like it was a bug in the R8. Many thanks for your help in investigating the issue.

Thanks for letting us know, glad you got it resolved by upgrading R8.