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

KEY_GENERATE_REQUEST_ERROR - The initDataType parameter is empty (observed on Tizen 2017) #1259

Open
peijkelhardt opened this issue Jul 5, 2023 · 7 comments

Comments

@peijkelhardt
Copy link

Issue observed on Tizen 2017, unclear which models might be affected as well.

After updating the RxPlayer from 3.29 to 3.30, some of our streams result in a EncryptedMediaError. This happens with streams which use DASH/Widevine. When checking the behaviour of 3.29 I noticed that these warnings are identical:

DRM: mediaKeys.setServerCertificate returned an error DOMException: Set server certificate failed.

Additionally, the 3.30 version throws this exception a bit later:

API: The player stopped because of an error Error: EncryptedMediaError (KEY_GENERATE_REQUEST_ERROR) InvalidAccessError: The initDataType parameter is empty.

Has something changed between these versions which might cause this behaviour?

@peaBerberian
Copy link
Collaborator

Hi @peijkelhardt,

I don't really now why it would appear in the v3.30.0 but anyway that second error's message seems clear enough (the first warning just tells that we were unable to set a server certificate which is an optimization to prevent a potential round-trip to the license server to obtain it - but this should not block anything).

The issue's source should be on session.generateRequest calls, which are performed here:
https://github.com/canalplus/rx-player/blob/v3.30.0/src/compat/eme/generate_key_request.ts#L146-L161

There's actually a work-around for when the initDataType parameter (the one they talk about in the error) - the first parameter of the function - is empty, as it is a known compatibility issue we encountered. But at https://github.com/canalplus/rx-player/blob/v3.30.0/src/compat/eme/generate_key_request.ts#L148 , we check for a TypeError and here the type of error actually thrown is the - normally inexistant - InvalidAccessError (I still saw some reference to it linked to Tizen here).

So maybe, when on Tizen 2017 and when InvalidAccessError exists, we should also check for that type?
Can you make a quick check, by like replacing:

!(error instanceof TypeError)

By something like:

 (!(error instanceof TypeError) && (typeof InvalidStateError === "undefined" || !(error instanceof InvalidStateError))) 

(hard to reason about so maybe not the final code but it should not pass that condition if the error is an InvalidStateError anymore)

?


NOTE:
What we usually do for quick and dirty debugging like this is to directly update the node_modules/rx-player directory and then rebuild the application (most bundlers re-read node_modules on each build so this usually works):

  • if you rely on the complete build of the RxPlayer (e.g. import player from "rx-player"), you'll have to find and replace the code in dist/rx-player.js
  • if you rely on the minimal build of the RxPlayer (e.g. import player from "rx-player/minimal"), you can update the dist/_esm5.processed/compat/eme/generate_key_request.js file

@peijkelhardt
Copy link
Author

Hi @peaBerberian,

I did a quick test by modifying the source code, but unfortunately, without success.

You've mentioned both InvalidAccessError & InvalidStateError, so I did a test with these 2 types. What seems weird is that both Error types checks result in undefined:

typeof InvalidAccessError
typeof InvalidStateError

When commenting the entire check:

if (initDataType !== "" || !(error instanceof TypeError)) {
throw error;
}

This exception pops up:

Rx Player error error: EncryptedMediaError (KEY_GENERATE_REQUEST_ERROR) InvalidStateError: The session is already initialized

@peaBerberian
Copy link
Collaborator

This exception pops up:

OK, so it seems to consider the failed generateRequest like an initialization...

Can you directly replace the line:

return session.generateRequest(initDataType, patchedInit)

By the work-around:

  return session.generateRequest(initDataType, patchedInit)

?

@peaBerberian
Copy link
Collaborator

You've mentioned both InvalidAccessError & InvalidStateError, so I did a test with these 2 types.

Ah yes, sorry I mixed them up, we needed just to check for InvalidAccessError.

@peijkelhardt
Copy link
Author

This exception pops up:

OK, so it seems to consider the failed generateRequest like an initialization...

Can you directly replace the line:

return session.generateRequest(initDataType, patchedInit)

By the work-around:

  return session.generateRequest(initDataType, patchedInit)

?

Hmm, those lines are identical. Can you please check again for the 'work-around' code?

@peaBerberian
Copy link
Collaborator

Oops yes sorry :D I meant the work-around of the following line:

      return session.generateRequest("cenc", patchedInit);

To explain what we're doing:

Basically generateRequest is the method which allows to generate a challenge, a necessary payload of data to make a license request.

It has two parameters:

Here the "The initDataType parameter is empty" message seems to tell us that the initDataType part is an empty string - which is kind of weird because we do fill it automatically when found in the MPD or when found in the initialization segments (so either there's a small bug in our logic, either we relying here on an encrypted event with no initDataType property).

Why the initDataType is not set is a secondary issue, for which we have a work-around anyway. That work-around is not triggered because for whatever reason the error doesn't seem to be a TypeError.

To just check if the work-around would work, I propose to directly force the initDataType to "cenc" (as that's probably what we're relying on here), just to test if with this, it works.

@peijkelhardt
Copy link
Author

  return session.generateRequest("cenc", patchedInit);

This has a positive effect! The stream is able to play.

When testting the setup I also added a small console.log to check the value of initDataType and I noticed something (which might help hopefully). This generateRequest is called twice. The first time, the initDataType does contain cenc, but the second time it's empty.

I've collected the logs (the generateRequest (initDataType): log is my custom log):

DRM: Creating a new temporary session
DRM-LSS: Add MediaKeySession temporary
DRM: Binding session events 
DRM: Init data already processed. Skipping it.
Compat: Calling generateRequest on the MediaKeySession
Compat: Trying to move CENC PSSH from init data at the end of it.
generateRequest (initDataType): cenc
AVSB: receiving order to push data to the SourceBuffer video 
AVSB: updating codec video/mp4;codecs="avc1.4d001f"
AVSB: could not update codec video/mp4;codecs="avc1.4d001f" video/mp4;codecs="avc1.4d0015"
AVSB: pushing segment video 
Stream: no more init segment to request. Cancelling queue. video
SF: Segment request cancelled video P: 1688977240 A: 2 R: tracks-v2 S: init
SF: Segment request ended with success video P: 1688977240 A: 2 R: tracks-v2 S: init
AVSB: receiving order for validating end of segment video video P: 1688977240 A: 2 R: tracks-v2 S: init
API: current media element state tick event timeupdate position 0 seeking false internalSeek null rebuffering false freezing false ended false paused true playbackRate 1 readyState 0
API: current playback timeline:

^0 
timeupdate
ABR: Choosing representation with bandwidth estimation. 2408000 tracks-v2
observers
SF: Segment request ended with success audio P: 1688977240 A: 1 R: tracks-a1 S: 34164.79-6
AVSB: receiving order to push data to the SourceBuffer audio 
AVSB: pushing segment audio 
Stream: no more init segment to request. Cancelling queue. audio
SF: Segment request cancelled audio P: 1688977240 A: 1 R: tracks-a1 S: init
ABR: New last stable representation 99000
AVSB: receiving order to push data to the SourceBuffer audio audio P: 1688977240 A: 1 R: tracks-a1 S: 34164.79-6
AVSB: receiving order for validating end of segment audio audio P: 1688977240 A: 1 R: tracks-a1 S: 34164.79-6
SF: Beginning request audio P: 1688977240 A: 1 R: tracks-a1 S: 34170.79-6
SF: Segment request ended with success audio P: 1688977240 A: 1 R: tracks-a1 S: init
AVSB: receiving order for validating end of segment audio audio P: 1688977240 A: 1 R: tracks-a1 S: init
AVSB: Acknowledging complete segment video P: 1688977240 A: 2 R: tracks-v2 S: init
ABR: Choosing representation with bandwidth estimation. 2408000 tracks-v2
AVSB: receiving order to push data to the SourceBuffer audio audio P: 1688977240 A: 1 R: tracks-a1 S: 34170.79-6
SF: Segment request ended with success audio P: 1688977240 A: 1 R: tracks-a1 S: 34170.79-6
AVSB: receiving order for validating end of segment audio audio P: 1688977240 A: 1 R: tracks-a1 S: 34170.79-6
AVSB: pushing segment audio audio P: 1688977240 A: 1 R: tracks-a1 S: 34164.79-6
DRM: Received message event, type license-request sid4
DRM: Calling `getLicense` license-request
AVSB: receiving order to push data to the SourceBuffer video video P: 1688977240 A: 2 R: tracks-v2 S: 34164.79-6
AVSB: updating codec video/mp4;codecs="avc1.4d001f"
AVSB: could not update codec video/mp4;codecs="avc1.4d001f" video/mp4;codecs="avc1.4d0015"
AVSB: pushing segment video video P: 1688977240 A: 2 R: tracks-v2 S: 34164.79-6
SF: Segment request ended with success video P: 1688977240 A: 2 R: tracks-v2 S: 34164.79-6
AVSB: receiving order for validating end of segment video video P: 1688977240 A: 2 R: tracks-v2 S: 34164.79-6
ABR: New last stable representation 2408000
SF: Beginning request video P: 1688977240 A: 2 R: tracks-v2 S: 34170.79-6
SI: first segment pushed audio 34164.808666666664 34170.80333333333
AVSB: Acknowledging complete segment audio P: 1688977240 A: 1 R: tracks-a1 S: 34164.79-6
SI: found true buffered start audio 34164.808 34164.808666666664
SI: found true buffered end audio 34170.803 34170.80333333333
AVSB: Acknowledging complete segment audio P: 1688977240 A: 1 R: tracks-a1 S: init
AVSB: pushing segment audio audio P: 1688977240 A: 1 R: tracks-a1 S: 34170.79-6
DRM: Updating MediaKeySession with message
DRM: Encrypted event received from media element.
DRM: Init data already processed. Skipping it.
DRM: Encrypted event received from media element.
DRM: Creating a new temporary session
DRM-LSS: Add MediaKeySession temporary
DRM: Binding session events 
Compat: Calling generateRequest on the MediaKeySession
Compat: Trying to move CENC PSSH from init data at the end of it.
generateRequest (initDataType): 
API: current media element state tick event loadedmetadata position 0 seeking false internalSeek null rebuffering false freezing false ended false paused true playbackRate 1 readyState 1
API: current playback timeline:
34164.81|==0.18==|34164.99
             ^0 
loadedmetadata
ABR: Choosing representation with bandwidth estimation. 4004000 tracks-v1
Stream: new video bitrate estimate 13739498.296271862
Stream: slow Representation switch video
Init: Set initial time 34169.438164711
Init: Can begin to play content
DRM: MediaKeySession update succeeded.

Also note that this behaviour occurs on a subset of our streams. We have different 3rd parties which serve the streams, and the ones which were not affected have the generateRequest (initDataType): cenc logged twice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants