feat: allow reuse of persistent license sessions#4461
Conversation
| } | ||
| } | ||
|
|
||
| // TODO: We should get a key status change event. Remove once Chrome CDM |
There was a problem hiding this comment.
ℹ️ Worked like a charm on Chrome, I might need to test the full offline capabilities
There was a problem hiding this comment.
Downloaded Widevine DRM content worked great with Chrome ;)
There was a problem hiding this comment.
What happens in old TV browsers?
There was a problem hiding this comment.
Haven't tested yet the persistent licenses on TV but will do
There was a problem hiding this comment.
Tizen 6.5
It correctly starts the persistent-license session at first launch but fails on the session load at second launch, so my guess is that this isn't supported.
The sessionId is always the same initialdrmsessionid so I don't think it could work at all.
Shaka Error DRM.FAILED_TO_CREATE_SESSION (Failed to execute 'load' on 'MediaKeySession': Loading session failed. . (2))
webOS 5.0
It fails to request a media key system access when asking for a persistent-license with the error REQUESTED_KEY_SYSTEM_CONFIG_UNAVAILABLE, so it seems it doesn't support persistent license at all
So my overall conclusion is persistent license isn't supported on TV devices, so I don't think we need to go further into making this feature working on those devices.
Error Recoverability
It pointed me out on an issue with my code where fails to load a persistent license will stop the player, rather than trying to fetch a new one (intended behaviour).
I have two options for that, let me know what you prefer (my pref is option 1):
- Option 1: Send a RECOVERABLE error
this.onError_(new shaka.util.Error(
this.config_.persistentSessionOnlinePlayback ?
shaka.util.Error.Severity.RECOVERABLE : shaka.util.Error.Severity.CRITICAL;
shaka.util.Error.Category.DRM,
shaka.util.Error.Code.FAILED_TO_CREATE_SESSION,
error.message));
- Option 2: Bypass the error, only log something:
if (this.config_.persistentSessionOnlinePlayback) {
shaka.log.warning('Persistent session', sessionId, 'not available');
} else {
this.onError_(new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
shaka.util.Error.Category.DRM,
shaka.util.Error.Code.OFFLINE_SESSION_REMOVED));
return Promise.resolve();
}
|
Incremental code coverage: 90.85% |
|
Related to #1956 |
| */ | ||
| createOrLoad() { | ||
| // Create temp sessions. | ||
| async createOrLoad() { |
There was a problem hiding this comment.
I noticed that the attach(video) function calls createOrLoad() but does not wait for the returned promise to resolve. Should it wait?
There was a problem hiding this comment.
I think it was done on purpose so that creating / loading sessions could be done in parallel of fetching manifest information, segments and more.
avelad
left a comment
There was a problem hiding this comment.
In general, LGTM, but I think we should give the possibility (player configuration) that ShakaPlayer itself stores this information in localStorage for example.
|
@valotvince it seems that there are some conflict with the main branch, can you rebase? Thanks! |
da2d158 to
e00ec59
Compare
c1880a2 to
8ee4eba
Compare
|
👋 @avelad @joeyparrish I've rebased on main & added documentation about the feature, could you review it again ? Thanks :)
If that's possible I'd like it to be done in another PR, as localStorage (or Indexeddb) is not necessarily the best on some devices. It might take more reflexion on the whole storage capabilities of Shaka, like allowing to give a StorageManager like the ABRManager which would handle the storage, without Shaka's knowing what the storage is. |
|
Hi @avelad @joeyparrish, any comments to share on this PR ? Thanks ! |
| * }} | ||
| * | ||
| * @description | ||
| * DRM Session Metadata for as session |
There was a problem hiding this comment.
The JSDoc for this is the same as DrmSessionMetadata, but the two represent different types of data.
From what I gather, PersistentSessionMetadata is the type that the user passes in, representing an existing persistent session. Meanwhile, DrmSessionMetadata represents an active session, which may have come from this playback or have been loaded from a persistent session.
Correct?
There was a problem hiding this comment.
You are correct ! :)
| shaka.util.Error.Severity.CRITICAL, | ||
| severity, | ||
| shaka.util.Error.Category.DRM, | ||
| shaka.util.Error.Code.OFFLINE_SESSION_REMOVED)); |
There was a problem hiding this comment.
The JSDoc for OFFLINE_SESSION_REMOVED should probably be updated. Right now it specifically says "The content is not playable", which is no longer going to be true if this error will sometimes be recoverable.
There was a problem hiding this comment.
I'll change the description of the error to:
A required offline session was removed. The content might not be playable depending of the playback context.
| metadata.loaded = true; | ||
| if (this.areAllSessionsLoaded_()) { | ||
| this.allSessionsLoaded_.resolve(); | ||
| metadata.loaded = true; |
There was a problem hiding this comment.
Do we really need to set metadata.loaded to true here?
All that value does is determine when areAllSessionsLoaded_ returns true. So if we are manually setting this to true for each stream we call loadOfflineSession_ on, and we call createOrLoad on each session at once inside createOrLoad, doesn't that mean that we will just immediately resolve this.allSessionsLoaded_ when the last session begins to load? That seems like it defeats the purpose of waiting for the key status change event, if we're still resolving before the event fires.
There was a problem hiding this comment.
We only set metadata.loaded when the session is not present anymore (we will never receive a keystatuschange event), and send a OFFLINE_SESSION_REMOVED event.
If other sessions are present & correctly loaded, we wait for the keystatuschange to set the session as loaded.
| expect(session2.generateRequest).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it( |
There was a problem hiding this comment.
I think this would fit into one line. No need to do the weird indenting.
There was a problem hiding this comment.
The whole line
it('tries persistent session ids before requesting a license', async () => {
is 81 characters long 😞
avelad
left a comment
There was a problem hiding this comment.
LGTM, can you rebase and resolve the conflicts? Thanks!
f0e9fec to
5f8bf6f
Compare
|
@avelad 👋 Rebase done ! |
| }); | ||
| ``` | ||
|
|
||
| NB: Shaka doesn't provide a out-of-the-box storage mechanism for the sessions |
There was a problem hiding this comment.
There is such a mechanism in the offline/ codebase. We could discuss a follow-up PR to use that mechanism if/when offline support is included.
|
Failed tests look like unrelated flakiness, but I'm re-running them just to be sure. |
Add capability to re-use persistent license sessions across sessions.
DrmEngine will now always:
Given the flag
persistentSessionOnlinePlaybackis true, DrmEngine:For now, it needs Shaka's users to persist session information by themselves (localStorage, IndexDB, ...) before giving it back for the next session. Still, it lays foundation to develop the feature to fully handling it on Shaka's side.
TBD:
offlineSessionIds_in DrmEngine tostoredPersistentSessionIds_because we now use those in two different contexts, online / offline (and in comments too) (after full review to avoid noise over the feature)loadOfflineSession_in DrmEngine toloadStoredPersistentSession_(after full review to avoid noise over the feature)Related to #1956