So basically, when a license request fails (eg. network Error, server
down whatever), apps can now retry from scratch by calling
`player.retryLicensing()`. This was tricky to implement because of EME
spec limitations: `generateRequest()` can only be called once per
session. So if it fails, it would be stuck.
So I close the old session and create a brand new one with the same
`initData`
> Will Video element throw an error during this process?
we were worried that closing the session would leave the video without
keys for a brief moment, potentially triggering errors. But in practice,
the transition is fast enough( I added a 0.1s delay for CDM clean up)
and the video element handles it gracefully
> Will new encrypted event fire? If not, will it limit this feature?
The encrypted event only fires when the browser first encounters
encrypted content. When we close and recreate a session, the content is
already loaded, so no new event
Solutions: In `CreateSession()` metadata store `initData` and
`initDataType` in the session metadata when the session is first
created. So when `retryLicensing()`is called, we just grab the stored
data and pass it to `generateRequest()` on the new session. No need to
wait for an `encrypted` event at all.
---------
Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
Co-authored-by: Wojciech Tyczyński <tykus160@gmail.com>
Widevine's CDM handles renewal automatically, but FairPlay and PlayReady
require manual
`session.update()` calls to renew licenses before they expire.
Previously, developers had to access internal APIs like
`getDrmEngine().activeSessions_` which only works in debug builds - not
ideal for production use.
Based on the discussion in #9505, this PR implements both Option A and
Option C:
**Option A - Manual renewal API:**
```js
player.renewLicense(); // all sessions
player.renewLicense(sessionId); // specific session
```
**Option C - Automatic renewal with config:**
```js
player.configure({
drm: {
renewalIntervalSec: 600
}
});
player.addEventListener('licenserenewal', (event) => {
console.log('License renewed:', event.newSessionMetadata,
event.oldSessionMetadata);
});
```
This way, developers can choose automatic renewal, manual control, or
both depending on their use case.
Under the hood, FairPlay sends a 'renew' message via session.update(),
while PlayReady re-creates the session. Widevine just dispatches the
event since the CDM already handles everything.
Added polyfills for `Map.getOrInsert()` and
`Map.getOrInsertComputed()` from the TC39 upsert proposal and refactor
the codebase to use them.
These methods replace the common "check if key exists, then set default"
pattern with a single atomic operation. This improves code readability
and eliminates redundant map lookups throughout the player.
---------
Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
When a MediaKeySession is closed by the CDM, the engine now utilizes the
MediaKeySessionClosedReason to determine the appropriate recovery path.
For critical reasons like hardware-context-reset, the engine
automatically recreates the session using its original initialization
data. We also addressed a race condition where keystatuseschange events
arriving for already-closed sessions would cause an engine crash.
This implementation is specific to the new EME closed promise resolution
logic and handles CDM-initiated closures. It ensures robustness on
platforms where hardware events, such as device sleep or GPU switches,
would otherwise lead to permanent playback failure.
Correctly handling these closure reasons prevents orphaned sessions and
allows playback to resume seamlessly after a hardware reset. The
additional safety check in the key status path ensures that asynchronous
notifications from the CDM do not interfere with the engine's session
management.
---------
Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
Before this, DRM engine would dedup using the old initData, then
transform it via callback, then create sessions. So if the
transformation creates duplicate initData, we get more DRM sessions than
we should have otherwise.
This changes the order from "1. dedup, 2. transform, 3. create" to "1.
transform, 2. dedup, 3. create", so that deduplication can also work on
transformed init data.
DRM license is always fetched prior to play when there is no video
element. It was done like that to support offline scenario. But on
preload, we should delay license request if that was specified in
configuration.
Speed up execution of `shaka.Player.probeSupport()` which tends to be
super slow on Windows with HW DRM. Changes include several tweaks in DRM
probing:
- test only using `navigator.requestMediaKeySystemAccess()`, using
MediaCapabilities as well was redundant
- test HDCP only once
- drop HDCP tests once we know some version is unsupported
On Windows it speeds up execution from 20s to 0.7-1s.
`queryMediaKeys()` was able to work both with variants and key system
configs. The latter option was needed only for `initForRemoval()`
method. By removing it we are able to make the logic more easy to
follow.
Additionally, compiled build is now 2 KB smaller.
The goal is to simplify and abstract feature logic detection. Currently
lots of places depend on various calls to `shaka.util.Platform` and
mainteinance of this is hard & not easy to read.
By introducing device API ideally rest of the player logic would look
into device features instead of directly checking platform. Additionally
we can more easily cache needed values, so we won't have to parse user
agent several times anymore.
---------
Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
Fixes https://github.com/shaka-project/shaka-player/issues/8576
Browser on this Sony TV returns little-endian, which results in
false-positive unsupported key system. Looks like this is a known issue
impacting couple of other platforms as well. I need to add this TV as
well.
Without this change, `expandRobustness` ended up running 480 times for
the stream `Angel One (multicodec, multilingual, Widevine)` with
`SW_SECURE_CRYPTO,SW_SECURE_CRYPTO,SW_SECURE_CRYPTO` set up as the
multiple robustness. With it, it only runs 44 times, which is expected
because there are 22 unique streams, and it expands `videoRobustness`
and `audioRobustness` on each.
Fixes#8408
Firefox 136 running on Windows in our lab seems to crash when accessing
the CDM. This happens in our background Windows service, but not in the
foreground when run as a regular user. We don't really understand the
nature of it, so we have to disable this in lab tests.
This reverts commit eda85d6607 (#8173),
but then goes a bit further:
- Add a flag to we know if we're running in the lab
- Narrow the workaround to lab test runs, not local runs or GitHub
Actions VM workflows
My previous change, #8109, didn't go far enough. In a full test run,
some ClearKey tests still crash Firefox in the lab. By removing it from
the support dictionary used to gate DRM tests, we ensure all ClearKey
tests are skipped.
Our automated test lab runs Windows browsers under a headless service.
In this environment, Firefox's ClearKey CDM seems to crash when we
create the CDM in probeSupport().
To avoid this, we check for a debug or uncompiled build running in
Firefox on Windows, and if this combination is found, we skip
createMediaKeys() in probeSupport().
Because the check uses the compile-time constant goog.DEBUG, we avoid
any penalty in a production build.
Fixes#7770
Webkit DRM heavily relies on video element, so it needs to be provided
in proper order to avoid any issues.
---------
Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
Adds a replacement for removed JSDoc checks from ESLint v9.
Additionally fixes lots of issues found in the JSDoc, such as:
- missing `@param`/`@return` annotations
- bad formatting
- params order
- param name in the same line as type definition (tried to disable it,
but it was causing other issues and we didn't have lots of places with
such formatting)
Minor fixes in code found by Closure Compiler after fixing JSDoc are
also included.