Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRM & ClearKey 1.4.X Unexpected runtime error on FireTV Stick 4K #1732

Closed
1 task done
KingLucius opened this issue Sep 16, 2024 · 35 comments
Closed
1 task done

DRM & ClearKey 1.4.X Unexpected runtime error on FireTV Stick 4K #1732

KingLucius opened this issue Sep 16, 2024 · 35 comments
Assignees
Labels

Comments

@KingLucius
Copy link

KingLucius commented Sep 16, 2024

Version

Media3 1.4.0

More version details

From 1.4.0 and up has this issue, downgrading to 1.3.1 fixes it

Devices that reproduce the issue

Amazon FireTV Stick 4K (Mantis)

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

Not tested

Reproduction steps

I can provide sample ClearKey link in private to test

Expected result

Media working like in 1.3.1

Actual result

09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal: Playback error
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:   androidx.media3.exoplayer.ExoPlaybackException: Unexpected runtime error
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:720)
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:       at android.os.Handler.dispatchMessage(Handler.java:98)
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:       at android.os.Looper.loop(Looper.java:154)
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:       at android.os.HandlerThread.run(HandlerThread.java:61)
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:   Caused by: android.media.MediaCodec$CryptoException: Operation not supported in this configuration
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:       at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:       at android.media.MediaCodec.dequeueOutputBuffer(MediaCodec.java:2584)
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.mediacodec.SynchronousMediaCodecAdapter.dequeueOutputBufferIndex(SynchronousMediaCodecAdapter.java:108)
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.drainOutputBuffer(MediaCodecRenderer.java:1994)
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:873)
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.render(MediaCodecVideoRenderer.java:1018)
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1136)
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:561)
09-13 07:39:36.096 18108 18297 E ExoPlayerImplInternal:       ... 3 more
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal: Disable failed.
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:   android.media.MediaCodec$CryptoException: Operation not supported in this configuration
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at android.media.MediaCodec.native_flush(Native Method)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at android.media.MediaCodec.flush(MediaCodec.java:2068)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.mediacodec.SynchronousMediaCodecAdapter.flush(SynchronousMediaCodecAdapter.java:168)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.flushCodec(MediaCodecRenderer.java:960)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.flushOrReleaseCodec(MediaCodecRenderer.java:953)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.onDisabled(MediaCodecRenderer.java:780)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.onDisabled(MediaCodecVideoRenderer.java:794)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.BaseRenderer.disable(BaseRenderer.java:220)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.ExoPlayerImplInternal.disableRenderer(ExoPlayerImplInternal.java:1846)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.ExoPlayerImplInternal.resetInternal(ExoPlayerImplInternal.java:1566)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.ExoPlayerImplInternal.stopInternal(ExoPlayerImplInternal.java:1523)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:722)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at android.os.Handler.dispatchMessage(Handler.java:98)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at android.os.Looper.loop(Looper.java:154)
09-13 07:39:36.097 18108 18297 E ExoPlayerImplInternal:       at android.os.HandlerThread.run(HandlerThread.java:61)

Media

Will send to [email protected]

Bug Report

  • You will email the zip file produced by adb bugreport to [email protected] after filing this issue.
@icbaker
Copy link
Collaborator

icbaker commented Sep 17, 2024

  • You will email the zip file produced by adb bugreport to [email protected] after filing this issue.

We didn't receive this. Please re-send it with subject Issue #1732. Thanks!

@KingLucius
Copy link
Author

  • You will email the zip file produced by adb bugreport to [email protected] after filing this issue.

We didn't receive this. Please re-send it with subject Issue #1732. Thanks!

Done

@icbaker
Copy link
Collaborator

icbaker commented Sep 20, 2024

The email contains a logcat snippet, not the zip file produced by adb bugreport. The full bugreport often contains additional info which can help to understand issues. Please run adb bugreport after reproducing the issue, and email us the resulting zip file, then update this issue.

@KingLucius
Copy link
Author

The email contains a logcat snippet, not the zip file produced by adb bugreport. The full bugreport often contains additional info which can help to understand issues. Please run adb bugreport after reproducing the issue, and email us the resulting zip file, then update this issue.

Updated the email with adb bugreport zip file result

@icbaker
Copy link
Collaborator

icbaker commented Sep 20, 2024

Thanks - please can you add an EventLogger (https://developer.android.com/media/media3/exoplayer/debug-logging) and reproduce and take a new BR.

Please can you also provide a BR of a successful playback using 1.3.1, so we can understand what might be behaving differently.

@KingLucius
Copy link
Author

Thanks - please can you add an EventLogger (https://developer.android.com/media/media3/exoplayer/debug-logging) and reproduce and take a new BR.

Please can you also provide a BR of a successful playback using 1.3.1, so we can understand what might be behaving differently.

Updated, please check

@icbaker
Copy link
Collaborator

icbaker commented Sep 23, 2024

Thanks - I can't see any EventLogger output in the BR, so I'm not sure if you added it correctly (you need to add a line like player.addAnalyticsListener(new EventLogger())).

However I can see a difference between the two BRs without this, that I suspect is responsible for the error you're seeing.

At 1.3.1 we are instantiating an "insecure" (i.e. not HW-secure) video decoder:

OMXMaster: makeComponentInstance(OMX.MTK.VIDEO.DECODER.AVC) in mediacodec process

At 1.4.0 we are instantiating a HW-secure one (note the .secure suffix):

OMXMaster: makeComponentInstance(OMX.MTK.VIDEO.DECODER.AVC.secure) in mediacodec process

ClearKey doesn't support HW-secure playback.

At a guess, I suspect the change in behaviour might have been introduced by c872af4 where we switched from using MediaCrypto.requiresSecureDecoderComponent(String) to MediaDrm.requiresSecureDecoder(String).

We made a related follow-up fix/workaround that was included in 1.4.1 where MediaDrm.requiresSecureDecoder(String) was returning false when it should have been returning true (and MediaCrypto.requiresSecureDecoderComponent(String) was returning true): b184677 (and then a follow-up fix to this for an edge-case that will be in 1.5.0-beta01: 0b86f89).

In your case, my hypothesis would suggest that MediaDrm.requiresSecureDecoder(String) is incorrectly returning true while MediaCrypto.requiresSecureDecoderComponent(String) is returning false. Would you be able to test this hypothesis?

If you have a local dependency on ExoPlayer this is quite easy, because you can just add some logging here in MediaCodecRenderer:

boolean mediaCryptoRequiresSecureDecoder =
codecDrmSession != null
&& (codecDrmSession.getState() == DrmSession.STATE_OPENED
|| codecDrmSession.getState() == DrmSession.STATE_OPENED_WITH_KEYS)
&& codecDrmSession.requiresSecureDecoder(
checkStateNotNull(inputFormat.sampleMimeType));

Something like:

if (codecDrmSession != null 
    && (codecDrmSession.getState() == DrmSession.STATE_OPENED
        || codecDrmSession.getState() == DrmSession.STATE_OPENED_WITH_KEYS)) {
  Log.w(
    "issue-1732",
    "drmSession.requiresSecureDecoder()="
        + codecDrmSession.requiresSecureDecoder(checkStateNotNull(inputFormat.sampleMimeType));
}
if (mediaCrypto != null) {
  Log.w(
    "issue-1732",
    "mediaCrypto.requiresSecureDecoderComponent()="
        + mediaCrypto.requiresSecureDecoderComponent(checkStateNotNull(mimeType));
}

@google-oss-bot
Copy link
Collaborator

Hey @KingLucius. We need more information to resolve this issue but there hasn't been an update in 14 weekdays. I'm marking the issue as stale and if there are no new updates in the next 7 days I will close it automatically.

If you have more information that will help us get to the bottom of this, just add a comment!

@google-oss-bot
Copy link
Collaborator

Since there haven't been any recent updates here, I am going to close this issue.

@KingLucius if you're still experiencing this problem and want to continue the discussion just leave a comment here and we are happy to re-open this.

@icbaker icbaker changed the title DRM & ClearKey 1.4.X Unexpected runtime error DRM & ClearKey 1.4.X Unexpected runtime error on FireTV Stick 4K Dec 16, 2024
@KingLucius
Copy link
Author

KingLucius commented Dec 16, 2024

These commits are on different branches, so it's not very meaningful to compare the code state between them.

Both on release

And what does MediaCrypto.requiresSecureDecoderComponent(String) return in each case? See #1732 (comment).

drmSession.requiresSecureDecoder()=true for both emulator (media works) & real Amazon stick (media doesn't work)

@icbaker
Copy link
Collaborator

icbaker commented Dec 16, 2024

And what does MediaCrypto.requiresSecureDecoderComponent(String) return in each case? See #1732 (comment).

drmSession.requiresSecureDecoder()=true for both emulator (media works) & real Amazon stick (media doesn't work)

OK - but that's only half of what I asked, in either my original comment and my follow-up. The other half is: MediaCrypto.requiresSecureDecoderComponent (not drmSession.requiresSecureDecoder)

@KingLucius
Copy link
Author

Ah sorry missed those part

for MediaCrypto.requiresSecureDecoderComponent there was no logging at all

@KingLucius
Copy link
Author

KingLucius commented Dec 16, 2024

mediaCrypto is always null even on the emulator though the media is working with no issue, please find the below full logcat from the device
Amazon-AFTMM-Android-7.1.2_2024-12-16_195057.zip

@icbaker
Copy link
Collaborator

icbaker commented Dec 17, 2024

mediaCrypto is always null even on the emulator though the media is working with no issue, please find the below full logcat from the device

Thanks for clarifying - it looks like I asked you to add the MediaCrypto part of the logging in the wrong place. Can you try putting it back closer to where it was before c872af4 - concretely here, at the bottom of (but inside) this else if:

} else if (cryptoConfig instanceof FrameworkCryptoConfig) {
FrameworkCryptoConfig frameworkCryptoConfig = (FrameworkCryptoConfig) cryptoConfig;
try {
mediaCrypto = new MediaCrypto(frameworkCryptoConfig.uuid, frameworkCryptoConfig.sessionId);
} catch (MediaCryptoException e) {
throw createRendererException(
e, inputFormat, PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR);
}
}

So it looks like:

  } else if (cryptoConfig instanceof FrameworkCryptoConfig) {
    FrameworkCryptoConfig frameworkCryptoConfig = (FrameworkCryptoConfig) cryptoConfig;
    try {
      mediaCrypto = new MediaCrypto(frameworkCryptoConfig.uuid, frameworkCryptoConfig.sessionId);
    } catch (MediaCryptoException e) {
      throw createRendererException(
          e, inputFormat, PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR);
    }
    Log.w(
        "issue-1732",
        "mime="
            + inputFormat.sampleMimeType
            + ", mediaCrypto.requiresSecureDecoderComponent()="
            + mediaCrypto.requiresSecureDecoderComponent(
                checkStateNotNull(inputFormat.sampleMimeType)));
  }
  return true;
}

When testing I also realised the duplicate logging is due to one for audio and one for video, so it might be clearer to log the MIME type in each case too (as I've added to the code snippet above).

@KingLucius
Copy link
Author

KingLucius commented Dec 17, 2024

API 25 on Emulator

drmSession.requiresSecureDecoder()=true
mime=video/avc, mediaCrypto.requiresSecureDecoderComponent()=false
drmSession.requiresSecureDecoder()=true
mime=video/avc, mediaCrypto.requiresSecureDecoderComponent()=false
drmSession.requiresSecureDecoder()=true
mime=audio/mp4a-latm, mediaCrypto.requiresSecureDecoderComponent()=false

API 25 on Fire Stick

drmSession.requiresSecureDecoder()=true
mime=video/avc, mediaCrypto.requiresSecureDecoderComponent()=false
drmSession.requiresSecureDecoder()=true
mime=video/avc, mediaCrypto.requiresSecureDecoderComponent()=false

Amazon-AFTMM-Android-7.1.2_2024-12-17_154730.zip

@icbaker
Copy link
Collaborator

icbaker commented Dec 17, 2024

Thanks, those logs seem to confirm my hypothesis from above in #1732 (comment):

In your case, my hypothesis would suggest that MediaDrm.requiresSecureDecoder(String) is incorrectly returning true while MediaCrypto.requiresSecureDecoderComponent(String) is returning false.

@KingLucius
Copy link
Author

KingLucius commented Dec 17, 2024

Have you noticed that the log repeated 3 times for the emulator (2 video / 1 audio), while on Fire stick no audio mime logging
Please notice that media is working on emulator while not working on real fire stick

@icbaker
Copy link
Collaborator

icbaker commented Dec 17, 2024

Have you noticed that the log repeated 3 times for the emulator (2 video / 1 audio), while on Fire stick no audio mime logging

I'm not sure if this is relevant? Given your exception in #1732 (comment) is from the video decoder.

Please notice that media is working on emulator while not working on real fire stick

This may be because the emulator isn't able to provide a secure decoder, so we never end up incorrectly playing content on a secure decoder.

@KingLucius
Copy link
Author

I'm not sure if this is relevant? Given your exception in #1732 (comment) is from the video decoder.

I think you're right, I have tried the same build on Android 14 smart phone and the result is media is working and the log as the below:

drmSession.requiresSecureDecoder()=false
mime=video/avc, mediaCrypto.requiresSecureDecoderComponent()=false
drmSession.requiresSecureDecoder()=false
mime=audio/mp4a-latm, mediaCrypto.requiresSecureDecoderComponent()=false

@KingLucius
Copy link
Author

As a double-check, I have hardcoded mediaCryptoRequiresSecureDecoder as false and media worked on Fire stick

maybeInitCodecWithFallback(mediaCrypto, mediaCryptoRequiresSecureDecoder);

@KingLucius
Copy link
Author

Any ETA when this issue can be resolved ?

@KingLucius
Copy link
Author

Any update?

@icbaker icbaker marked this as a duplicate of #2088 Feb 17, 2025
@icbaker
Copy link
Collaborator

icbaker commented Feb 18, 2025

Looking into this again - my hypothesis from #1732 (comment) can't be correct because in the FireTV BR provided by @KingLucius the device reports its API level as 25 ([ro.build.version.sdk]: [25]) and the Xiaomi TV looks like it's API 23 (based on the screenshot provided in #2088). Both of these are lower than 31, which is when the framework MediaDrm.requiresSecureDecoder method was added. So this bug can't be about a discrepancy between the return values of the framework MediaCrypto and MediaDrm methods.

New, related, hypothesis: We're entering this catch block:

try {
mediaCrypto = new MediaCrypto(uuid, sessionId);
result = mediaCrypto.requiresSecureDecoderComponent(mimeType);
} catch (MediaCryptoException e) {
// This shouldn't happen, but if it does then assume that a secure decoder may be required.
result = true;
} finally {

@KingLucius Would you be able to add a bit of logging to confirm that?

@KingLucius
Copy link
Author

Image

Image

FrameworkMediaDrm.requiresSecureDecoder() Exception Exception Details =>android.media.MediaCryptoException: Failed to instantiate crypto object. drmSession.requiresSecureDecoder()=true FrameworkMediaDrm.requiresSecureDecoder() Exception Exception Details =>android.media.MediaCryptoException: Failed to instantiate crypto object.

@FongMi
Copy link

FongMi commented Feb 21, 2025

Finally, I make result = fasle when catch expection, it's works.

@Tangsan99999
Copy link

wow, its work. thanks @FongMi

copybara-service bot pushed a commit that referenced this issue Feb 25, 2025
Before API 27, the platform DRM components incorrectly expected
`C.COMMON_PSSH_UUID` instead of `C.CLEARKEY_UUID` in order to perform
ClearKey decryption. `FrameworkMediaDrm` is responsible for doing this
adjustment on these API levels, but this call was missed when
refactoring some DRM code in
c872af4.

This led to `MediaCodec$CryptoException: Operation not supported in this
configuration` errors when doing ClearKey playback on devices with
API < 27. This was because the earlier, clearer error from the
`MediaCrypto` constructor was being swallowed and transformed to
`requiresSecureDecoder = true` by the `catch` logic in
`FrameworkMediaDrm.requiresSecureDecoder`.

This change also makes the error handling in
`FrameworkMediaDrm.requiresSecureDecoder` more robust by assuming
`requiresSecure = false` for ClearKey (and true for all other DRM
schemes), since we know that ClearKey never supports secure decoding.
This will help avoid more ClearKey playback failures if we see other,
unrelated, errors at this point.

Issue: #1732

#cherrypick

PiperOrigin-RevId: 730882278
@icbaker
Copy link
Collaborator

icbaker commented Feb 25, 2025

While looking to make the change to set result = false for ClearKey in that catch block I spotted the probable cause for the exception in the first place - and fixed that too. The fix is in the commit linked above.

@icbaker icbaker closed this as completed Feb 25, 2025
oceanjules pushed a commit that referenced this issue Mar 3, 2025
Before API 27, the platform DRM components incorrectly expected
`C.COMMON_PSSH_UUID` instead of `C.CLEARKEY_UUID` in order to perform
ClearKey decryption. `FrameworkMediaDrm` is responsible for doing this
adjustment on these API levels, but this call was missed when
refactoring some DRM code in
c872af4.

This led to `MediaCodec$CryptoException: Operation not supported in this
configuration` errors when doing ClearKey playback on devices with
API < 27. This was because the earlier, clearer error from the
`MediaCrypto` constructor was being swallowed and transformed to
`requiresSecureDecoder = true` by the `catch` logic in
`FrameworkMediaDrm.requiresSecureDecoder`.

This change also makes the error handling in
`FrameworkMediaDrm.requiresSecureDecoder` more robust by assuming
`requiresSecure = false` for ClearKey (and true for all other DRM
schemes), since we know that ClearKey never supports secure decoding.
This will help avoid more ClearKey playback failures if we see other,
unrelated, errors at this point.

Issue: #1732

#cherrypick

PiperOrigin-RevId: 730882278
(cherry picked from commit ecb83f3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants