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

fix: assumptions in multi-drm cases where only playready is available for playback. #6946

Merged

Conversation

cjpillsbury
Copy link
Collaborator

@cjpillsbury cjpillsbury commented Jan 6, 2025

This PR will...

Clean up some assumptions on key request logic in multi-drm scenarios, particularly around PlayReady usage.

Why is this Pull Request needed?

There were

Are there any points in the code the reviewer needs to double check?

Everything was localized to EmeController::onMediaEncrypted() and much of the core logic stayed the same, but definitely want some attention while reviewing the implementation decisions, particularly the callout questions/comments (including in github comments) before 👍.

Smoke tested multi-drm case (on demand stream with FairPlay, Widevine, and PlayReady advertised via EXT-X-KEY tags and sinf/pssh mp4 boxes) on:

  1. macOS
    1. Safari (for FairPlay usage regression testing)
    2. Chrome (for Widevine usage regression testing)
  2. Windows
    1. Edge ("Edgium") with Widevine Enabled and Widevine Disabled (See: https://learn.microsoft.com/en-us/legal/microsoft-edge/privacy#digital-rights-management-and-media-licenses for disabling flag)

Also tested using both the repo-provided demo application* and local linking to Mux Elements ("Mux Player") using the repo-provided next.js application.

NOTE: For my testing, where my dev machine is macOS but I needed to test on a Windows machine on my LAN, this required updating the server script (http-server) to use https (based on security constraints). If needed for review, see https://www.npmjs.com/package/http-server#tlsssl or reach out to me directly.

NOTE: I do not have any publicly-shareable test assets + corresponding service requests, however, if needed for review, reach out to me directly and I can provide one out of band.

Resolves issues:

fixes #6947

Checklist

  • changes have been done against master branch, and PR does not conflict
  • new unit / functional tests have been added (whenever applicable) (N/A from what I could tell with existing unit tests)
  • API or design changes are documented in API.md (N/A)

const keySystem = pssh.systemId
? keySystemIdToKeySystemDomain(pssh.systemId)
: null;
return keySystem ? keySystems.indexOf(keySystem) > -1 : false;
})[0];
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

NOTE: Here's an example where we're presumptuously assuming that the 0th key system will work in a multi-drm scenario, which may or may not be true.

}
} else if (this.getLicenseServerUrl(KeySystems.WIDEVINE)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

here's an example where we're tying ourselves explicitly to the availability of a Widevine DRM server for PSSH cases, when it may be widevine, playready, or both.

break;
}
}
/** @TODO errors? */
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

NOTE: If we early bail here, this means we didn't find any matches for playback between the intersection of our config + what was signaled from EME in the init data. We plausibly should construct an error here, and potentially earlier in the newly created getKeyIdInfos() function (if we want more context clues in our error as to what specifically failed)

);

try {
// Use the first successful key session context promise.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

NOTE: In order to strike a balance between non-blocking async behavior and not requesting keys for multiple key systems in parallel, the balance I struck in this implementation is to keep everything for a single key system roughly as it was in the old implementation, but then block on a 👍 / 👎 for that key system. If that key system fails to be usable, we proceed to the next (in cases where that applies).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Would you mind using then/catch (as we do in other parts of the code) rather than await keySessionContextPromise?

@cjpillsbury cjpillsbury changed the title fix: assumptions in multi-drm cases where only playready is available… fix: assumptions in multi-drm cases where only playready is available for playback. Jan 6, 2025
@robwalch robwalch added this to the 1.6.0 milestone Jan 6, 2025
@robwalch
Copy link
Collaborator

robwalch commented Jan 6, 2025

After confirming the bug and verifying the fix these changes will go into v1.6.0 (beta.3). If you'd like a patch for v1.5 we can follow up after that by cherry-picking the changes in the patch/v1.5.x branch. Thanks for the detailed report and fix!

@@ -525,7 +525,7 @@ class EMEController extends Logger implements ComponentAPI {
return this.attemptKeySystemAccess(keySystemsToAttempt);
}

private onMediaEncrypted = (event: MediaEncryptedEvent) => {
private onMediaEncrypted = async (event: MediaEncryptedEvent) => {
Copy link
Collaborator

@robwalch robwalch Jan 7, 2025

Choose a reason for hiding this comment

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

Making this method async for the await at the bottom of the method adds a lot of boiler plate (regenerator runtime) to the UMD build. Would you mind using then/catch (as we do in other parts of the code) rather than await keySessionContextPromise?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Rather than suggest changes without verifying that they work, I put together this draft:

Besides avoiding the use of async/await which adds regenerator-runtime boilerplate to our es5 output, I wanted to avoid the additional looping through found pssh and config, by resolving the selected key-system first. This is closer to how playlist keys are selected. onMediaEncrypted will always run after a playlist key has been selected unless the encrypted event is for a clear segment that signals upcoming encrypted keys ("clear-lead").

);

try {
// Use the first successful key session context promise.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would you mind using then/catch (as we do in other parts of the code) rather than await keySessionContextPromise?

robwalch
robwalch previously approved these changes Jan 10, 2025
src/controller/eme-controller.ts Outdated Show resolved Hide resolved
@robwalch robwalch merged commit d602e36 into video-dev:master Jan 10, 2025
12 checks passed
robwalch added a commit that referenced this pull request Jan 10, 2025
…for playback (#6946)

cherry-picked d602e36
Author: Christian Pillsbury <[email protected]> (+1 squashed commit)
Squashed commits:
[4522cb0] Only use selected key-system in EME "mediaencrypted" event handler
Changes picked from #6644 and #6948 with changes for feedback from @cjpillsbury
robwalch added a commit that referenced this pull request Jan 10, 2025
…for playback (#6946)

cherry-picked d602e36
Author: Christian Pillsbury <[email protected]> (+1 squashed commit)
Squashed commits:
[4522cb0] Only use selected key-system in EME "mediaencrypted" event handler
Changes picked from #6644 and #6948 with changes for feedback from @cjpillsbury
cjpillsbury added a commit to muxinc/elements that referenced this pull request Jan 13, 2025
…bug. (#1060)

For details on the bug and fix, see:
- video-dev/hls.js#6947
- video-dev/hls.js#6946

Full smoke testing of the issue requires a Windows machine with Edgeium
and Widevine DRM disabled. If available, please reach out for details on
playback ids + tokens to test.
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

Successfully merging this pull request may close these issues.

PlayReady+Widevine MultiDRM error cases
2 participants