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: Create new persistent MediaKeySession when load fails #1139

Merged
merged 1 commit into from
Aug 29, 2022

Conversation

peaBerberian
Copy link
Collaborator

@peaBerberian peaBerberian commented Aug 1, 2022

We noticed of an issue which led to the impossibility of playing an encrypted content in a "persistent-license" mode if its license had already been persisted in the past but it could not be retrieved by the browser through the MediaKeySession.load API.

This problematic situation only arises if the RxPlayer's persistent session storage, generally stored in localStorage by the application, is de-synchronized with the browser/CDM internal one, with the former having more items than the latter.
Arguably that situation is not frequent:

  • we reproduced it at a large scale when updating the browser of some devices on which the RxPlayer runs.

    That update was not a small step (the two versions were released years apart), leading us to believe that that browser internal representation of persisted MediaKeySession had changed, thus it being not able to re-load old persistent MediaKeySession.

    Because the application kept however the same store of old persisted MediaKeySession, such de-synchronization was created.

    (To note that the RxPlayer currently has a policy of being retro-compatible by default - unless opted-out for performance reasons - when it comes to old persisted MediaKeySession, so updating the RxPlayer should normally not invalidate old persisted MediaKeySession the way it did for the browser here.)

  • In any case, we suppose that a browser or CDM may decide at any time to evict old persisted MediaKeySession.

    The RxPlayer also has an eviction mechanism in its own store but as both logics are completely un-synchronized, differences may appear at any time.


The previous logic of the RxPlayer when failing to load an old persistent MediaKeySession's information on a newly created one (as that's how the EME API works), was to just abort trying to load it and continue doing the license request on the same MediaKeySession.

However, by re-reading the specification, it seems that this does not work. This is not indicated clearly however, but can be deduced by following the unitialized flag the EME specification brings up in some API's documentation.

Reading the different algorithms proposed for the load and generateRequest methods, it appears that neither can be called after the other was on the same MediaKeySession, because this unitialized flag is set to false, having previously been asserted to be true right before the actual implementation logic is done.

Even more implicit, it seems that it is not possible to close a MediaKeySession whose load call did not retrieve anything, by following this time an EME flag called callable.


The (simple) fix for that situation, which remain to be tested, is to just throw away, without closing it, a MediaKeySession whose load call resolved with false, and to create a new one so that generateRequest can be called on it.

Also, to prevent any issues (for now unseen) with that callable flag whose context appear more unclear, I chose to check if a sessionId is set on a persistent MediaKeySession whose closing operation failed, to ignore the failure if it wasn't and just continue the usual logic.
I did that check in such a way because there seem to be a relation between a set (i.e. different than the empty string) sessionId and the callable flag though this is never clearly stated.

Because all this is only interpretation of the EME specification, I left big comments in the corresponding code with my name on it :p (git blame becomes rapidly unreliable and complex after multiple code refacto)

@peaBerberian peaBerberian added bug This is an RxPlayer issue (unexpected result when comparing to the API) DRM Relative to DRM (EncryptedMediaExtensions) Priority: 1 (High) This issue or PR has a high priority. labels Aug 1, 2022
* @param {MediaKeySession} session
* @param {string} sessionId
* @returns {Observable}
* @returns {Promise.<boolean>}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All those modiications only concern the documentation.

I noticed it wasn't updated since we made the transition from Observable-based to Promise-based

// Thus, we're creating another `"persistent-license"` `MediaKeySession`
// in that specific case:
const newEntry = loadedSessionsStore.createSession(initData,
"persistent-license");
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main fix!

@peaBerberian peaBerberian force-pushed the fix/eme_create_new_session_when_load_fails branch 2 times, most recently from 2149c45 to 7cb1ce0 Compare August 1, 2022 14:20
We noticed of an issue which led to the impossibility of playing an
encrypted content in a "persistent-license" mode if its license had
already been persisted in the past but it could not be retrieved by
the browser through the `MediaKeySession.load` API.

This problematic situation only arises if the RxPlayer's persistent
session storage, generally stored in `localStorage` by the application,
is de-synchronized with the browser/CDM internal one, with the former
having more items than the latter.
Arguably that situation is not frequent:

  - we reproduced it at a large scale when updating the browser of some
    devices on which the RxPlayer runs.

    That update was not a small step (the two versions were released
    years apart), leading us to believe that that browser internal
    representation of persisted `MediaKeySession` had changed, thus it
    being not able to re-load old persistent `MediaKeySession`.

    Because the application kept however the same store of old persisted
    `MediaKeySession`, such de-synchronization was created.

    (To note that the RxPlayer currently has a policy of being
    retro-compatible by default - unless opted-out for performance
    reasons - when it comes to old persisted `MediaKeySession`, so
    updating the RxPlayer should normally not invalidate old persisted
    `MediaKeySession` the way it did for the browser here.)

  - In any case, we suppose that a browser or CDM may decide at any time
    to evict old persisted `MediaKeySession`.

    The RxPlayer also has an eviction mechanism in its own store but as
    both logics are completely un-synchronized, differences may appear
    in any time.

---

The previous logic of the RxPlayer when failing to load an old
persistent `MediaKeySession`'s information on a newly created one (as
that's how the EME API works), was to just abort trying to load it
and continue doing the license request on the same `MediaKeySession`.

However, by re-reading the specification, it seems that this does not
work. This is not indicated clearly however, but can be deduced by
following the `unitialized` flag the EME specification brings up in some
API's documentation.

Reading the different algorithms proposed for the `load` and
`generateRequest` methods, it appears that neither can be called after
the other was on the same `MediaKeySession`, because this `unitialized`
flag is set to `false`, having previously been asserted to be `true`
right before the actual implementation logic is done.

Even more implicit, it seems that it is not possible to `close` a
`MediaKeySession` whose `load` call did not retrieve anything, by
following this time an EME flag called `callable`.

---

The (simple) fix for that situation, which remain to be tested, is to
just throw away, without closing it, a `MediaKeySession` whose `load`
call resolved with false, and to create a new one so that
`generateRequest` can be called on it.

Also, to prevent any issues (for now unseen) with that `callable` flag
whose context appear more unclear, I chose to check if a `sessionId` is
set on a persistent `MediaKeySession` whose closing operation failed,
to ignore the failure if it wasn't and just continue the usual logic.
I did that check in such a way because there seem to be a relation
between a set (i.e. different than the empty string) `sessionId` and the
`callable` flag though this is never clearly stated.
@peaBerberian peaBerberian force-pushed the fix/eme_create_new_session_when_load_fails branch from 7cb1ce0 to 2baac94 Compare August 2, 2022 09:43
@peaBerberian peaBerberian added Priority: 0 (Very high) This issue or PR has a very high priority. Efforts should be concentrated on it first. and removed Priority: 1 (High) This issue or PR has a high priority. labels Aug 29, 2022
@peaBerberian peaBerberian merged commit a48e185 into master Aug 29, 2022
@peaBerberian peaBerberian added this to the 3.29.0 milestone Sep 5, 2022
@peaBerberian peaBerberian mentioned this pull request Nov 15, 2022
@peaBerberian peaBerberian deleted the fix/eme_create_new_session_when_load_fails branch November 17, 2022 13:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This is an RxPlayer issue (unexpected result when comparing to the API) DRM Relative to DRM (EncryptedMediaExtensions) Priority: 0 (Very high) This issue or PR has a very high priority. Efforts should be concentrated on it first.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant