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

Parse multiple pssh from "encrypted" init data and fix Widevine key I… #6640

Merged
merged 3 commits into from
Aug 22, 2024

Conversation

robwalch
Copy link
Collaborator

This PR will...

Parse multiple pssh from "encrypted" init data and fix Widevine key ID extraction for playlist match

Why is this Pull Request needed?

With Widevine, HLS.js generates key sessions and license requests using key IDs from pssh data found in playlist KEY URIs or "encrypted" events - whichever it encounters first. The parsing of pssh data in "encrypted" event init data did not parse all payloads for all key-systems present. It also did not pull the key ID for the correct offset and as a result was not matching the playlist key which could result in a second session and set of license requests being made when the first payload was a Widevine PSSH. If it was for another key-system then the "encrypted" event was ignored.

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

Resolves issues:

Fixes #6636

Checklist

  • changes have been done against master branch, and PR does not conflict
  • new unit / functional tests have been added (whenever applicable)
  • API or design changes are documented in API.md

@robwalch robwalch added this to the 1.5.15 milestone Aug 21, 2024
cjpillsbury
cjpillsbury previously approved these changes Aug 21, 2024
Copy link
Collaborator

@cjpillsbury cjpillsbury left a comment

Choose a reason for hiding this comment

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

Have a couple of non-blocking suggestions, one semi-blocking question wrt the change in getting the key id from pssh data, and a few other callouts (mostly praise). Pre-approving for expediency. All in all, these look like positive improvements 👌

src/controller/eme-controller.ts Outdated Show resolved Hide resolved
function parsePssh(view: DataView): PsshData | { size: number } {
const size = view.getUint32(0);
const length = view.byteLength;
if (view.byteLength < size) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

praise: 😎 shouldn't happen, but good cheap validation.

if (result.version > 1) {
return null;
const version = view.getUint32(8) >>> 24;
if (version !== 0 && version !== 1) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

praise: probably a better check than prior impl 👌

size: number;
};

export function parseMultiPssh(initData: ArrayBuffer): PsshData[] {
Copy link
Collaborator

Choose a reason for hiding this comment

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

praise: 👌

while (offset + 32 < length) {
const view = new DataView(initData, offset);
const pssh = parsePssh(view);
if ('systemId' in pssh) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

suggestion(non-blocking): should we consider signaling somehow when a pssh box was invalid and thus dropped (would say a dum dum console.warn but that wouldn't get control from hls logger)? We could check this "from the outside" by doing a sum of psshInfo.sizes and comparing to byteLength

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Dealing with this outside of helper functions would be preferred so that we keep logging in the controller instances for log messages to have access to player and component context (v1.6 will include logger enhancements including #6131, #6198, #6242).

What do you think about returning all results including the invalid ones and typing them PsshInvalidData. Adding offset to the results might help too.

I expect the most common issue to be incomplete data, but we might also run into bad boundaries/data without the type sync value (0x70737368). I'm not sure how granular we need to be here.

It would help if you could comment on the logging for the "encrypted" event and let me know what elements you'd like to see like selected key-system or pssh system ids found.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Cool about to hop on a wall of meetings but will try to circle back after. 👌

} else if (result.version === 1) {
result.kids = [];
data = new Uint8Array(buffer, view.byteOffset + 32, dataSizeOrKidCount);
} else if (version === 1) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

question(non-blocking): Since this was already status quo before the changes, it doesn't need to be included in this PR, but is there any reason why we "leave the data on the floor" for the parsed pssh for version 1?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's all present in the split kids isn't it?

psshInfo.systemId === KeySystemIds.WIDEVINE &&
psshInfo.data
psshInfo.data &&
psshInfo.data.length >= 30
Copy link
Collaborator

Choose a reason for hiding this comment

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

question: Where did 30 bytes come from/why the change in keyId, below? Couldn't figure it out from various specs/"specs" (i.e. example code in various languages in the wild for creating and/or parsing widevine pssh data). Phrased differently, what was wrong with:

keyId = psshInfo.data.subarray(8, 24);

Copy link
Collaborator Author

@robwalch robwalch Aug 21, 2024

Choose a reason for hiding this comment

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

Phrased differently, what was wrong with: Phrased differently, what was wrong with:

The key ID ends at an offset from the end of the data. Not 8 bytes from the start.

question: Where did 30 bytes come from

That was incorrect. The length check has been moved into the helper. The key bytes start 22 bytes from the end of the PSSH data matching how we extract the playlist key ID in level-key.ts.

tests/unit/controller/eme-controller.ts Outdated Show resolved Hide resolved
@robwalch robwalch merged commit a960251 into master Aug 22, 2024
16 checks passed
@robwalch robwalch deleted the bugfix/resolve-widevine-keys-in-multi-drm branch August 22, 2024 01:05
robwalch added a commit that referenced this pull request Aug 22, 2024
#6640)

* Parse multiple pssh from "encrypted" init data and fix Widevine key ID extraction for playlist match
Fixes #6636

* Logging and assertion improvements per @cjpillsbury's review

* Logging and assertion improvements per @cjpillsbury's review

(cherry picked from commit a960251)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging this pull request may close these issues.

Widevine DRM Requests are sent twice
2 participants