canalplus / rx-player

DASH/Smooth HTML5 Video Player
https://developers.canal-plus.com/rx-player/
Apache License 2.0
853 stars 130 forks source link

PIPELINE_ERROR_INVALID_STATE error when using Playready/Dash stream (mixed encrypted/unecrypted content) #1403

Open adamtatur opened 5 months ago

adamtatur commented 5 months ago

Hi,

We noticed an issue when integrating avod functionality with Playready/DASH streams. When provided manifest contains both encrypted and unencrypted periods player doesn't work properly.

We checked both scenarios using Widevine/DASH configuration and everything works fine. The only thing that caught my eye was that the license fetching logic runs a few seconds before going to the encrypted parts than is the case with Playready/DASH.

Issue is presented using:

Is there any know solution to circumvent this problem using the appropriate player configuration?

peaBerberian commented 5 months ago

Hi,

Interesting, we've heard by looking around some time ago of this type of problem when going from encrypted to unencrypted and vice-versa on PlayReady devices, but we've never really were able to reliably reproduce it (maybe it's also content-dependent?)

We have some old work we still maintain (we last rebased it last week) that create fake encryption metadata for initialization segments of clear Representation (https://github.com/canalplus/rx-player/commit/408191eb346e562e587a1ce097ba1112daf5c5d3#diff-5182788b34332efc49b4a47fcd7ffa0af9e5698d8da035c5e8cade8e95b920ce) which is a trick we've for example seen on the shaka-player (we've never merged that development on our side as we've never really been able to reproduce the issue).

With a little work, I can make an RxPlayer version including it to see if that fixes the issue, then if it fixes this issue and seen as non-problematic with enough testing we might be able to include it in a future version.

adamtatur commented 5 months ago

Hi,

Thanks. If this is not a problem we could check it on our side with provided RxPlayer version.

peaBerberian commented 4 months ago

Hi,

If it's still possible for you I updated and tested the fix/create-fake-encryption-init-segment branch. You can depend on its latest commit (which includes our build to simplify dependency on it), you can set in your package.json something like:

    "rx-player": "https://github.com/canalplus/rx-player.git#a74239e129904970c5b6497020b3f7dc38b0cb0a",

This will depend on the commit a74239e129904970c5b6497020b3f7dc38b0cb0a, which is currently the last commit of the fix/create-fake-encryption-init-segment branch

Can you test it to see if unencrypted/encrypted transitions (and vice-versa) works with it?

m-scheepers commented 2 months ago

@adamtatur are we able to plan this on our side (with rxpalyer 4) or the custom branch for testing purposes.

peaBerberian commented 1 month ago

Following our conversation, I just re-checked, we have two builds made, both for the RxPlayer v3 and v4.

When relying on v3, you can put on your package.json:

    "rx-player": "https://github.com/canalplus/rx-player.git#
fd615528986ef67d4dc5e22d87670296d7180b48",

When relying on v4, set instead:

    "rx-player": "https://github.com/canalplus/rx-player.git#a74239e129904970c5b6497020b3f7dc38b0cb0a",

Those commits contain built RxPlayer, so you just need to perform a npm install / yarn following this edit.

Let me know if it fixes things.

adamtatur commented 1 month ago

Hi,

Unfortunately, the error still occurs when it comes to the case of transition from unencrypted to encrypted periods. Player throws an error: "PIPELINE_ERROR_INVALID_STATE: MediaFoundationRenderer error: kCdmProxyReceivedInInvalidState (Error (0x13D) while retrieving error. (0x8004FA03))" In case transition from encrypted to unencrypted periods streams works fine this time.

Checked for both rxplayer fix versions.

peaBerberian commented 1 month ago

OK so if I get this correctly, there is an improvement for encrypted -> clear (the video does not turn green anymore), but there's still a fatal error for clear -> encrypted

peaBerberian commented 1 month ago

If you're calling rxPlayer.reload() as this error happens, does it plays the encrypted part? It will lead to a temporary black screen on clear->encrypted transitions, but it could be a last resort just in case we don't find any work-around for the issue nor can we fix this content-side.

adamtatur commented 1 month ago

Unfortunately, using reload didn't fix an issue for clear -> encrypted transitions

peaBerberian commented 1 month ago

Just to keep track of the attempts of work-arounds I've made, now only for clear -> encrypted transitions:

  1. "regular" case where we're creating the MediaKeys and attaching the HTMLMediaElement before any data is buffered and then creating session lazily as we begin to consider encrypted content:

    Result: we obtain a MEDIA_ERR_DECODE on Edge PlayReady if there was clear content in the buffer as soon as we call the generateRequest EME API, even if the encrypted data is not yet pushed to a SourceBuffer.

    -> This looks to me as if it fails if the CDM starts its encryption-related logic during playback of clear content, so I've tried many work-arounds which tries to communicate to PlayReady that we're gonna push encrypted content

  2. Relying on Widevine instead

    Result: it works without issue.

    -> This looks to be a PlayReady-specific issue

  3. adding a tenc ISOBMFF box with a 0x0 key id on initialization segment for clear content (reasoning: the CDM/browser is going to see it and start some encryption-related logic)

    Result: no effect

    I also tested that work-around with most of the other described below (a test without then a test with, it seems to never have an effect for clear -> encrypted transitions)

  4. Changing the clear portion of the stream with a random one from our demo page

    Result: no effect (same MEDIA_ERR_DECODE issue)

  5. calling the createSession + generateRequest EME API with dummy data (e.g. an inexistant key id for which we'll never do the license request anyway) BEFORE ANY data (clear or encrypted) is pushed to a SourceBuffer

    Result: It buffers indefinitely when encountering encrypted media, even after reload, and even if starting directly by the encrypted media data (no clear->encrypted transition, just encrypted). Because Edge+PlayReady is like it is, this may seemingly randomly lead or not lead (read: just keep being infinitely buffering instead) to a MEDIA_ERR_SRC_NOT_SUPPORTED after many seconds in that condition

    I also closed the fake session immediately after the generateRequest call, but no change

  6. Just calling the createSession EME API and let it dangling BEFORE ANY data (clear or encrypted) is pushed to a SourceBuffer

    Result: It seems to succeed to "transition" from the clear to the encrypted content when looking at metrics, but visually and audibly this is just visual green noise and audio noise (as if it's trying to decrypt with the wrong key? That's weird because we didn't ask for any key for the first session). Same result when directly beginning with the encrypted content. Note: calling the reload RxPlayer API (basically reloading the content at the same position it was before) while it reads that noise lead to actual real playback of the encrypted media.

    I also closed the fake session immediately after the createSession call, but no change

  7. calling the createSession + generateRequest EME API with a real key id that is not the one used later BEFORE ANY data (clear or encrypted) is pushed to a SourceBuffer.

    Result: Same visual green noise and audio noise than in the preceding check