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

PlayReady message UTF16 or UTF8 - make versatile solution for all browsers #3899

Closed
jtrelak-vewd opened this issue Mar 4, 2022 · 7 comments
Milestone

Comments

@jtrelak-vewd
Copy link

Is your feature request related to a problem? Please describe.
Currently UTF16 is default setting. For purpose of UTF8, the web application must set expected format to utf-8 (by using setPlayReadyMessageFormat('utf-8')). But then it will not work on systems that use UTF-16. From JS side it is really hard to judge: on what operating system the browser is run? (Windows is based on widechar (utf16), but linux/android on utf8) .

Describe the solution you'd like
I believe it is really easy to determine if the message is utf-8 or utf-16, and I think it is the best way here to have code working on all browsers:
(I didn't test that code, this is just brief proposal of solution)

let dataview, msg, xmlDoc;
if (message.byteLength % 2 == 0) {
    dataview = new Uint16Array(message);
    msg = String.fromCharCode.apply(null, dataview);
    if (!msg.includes("PlayReady")) { // if it does not include "PlayReady" string, it means we had utf-8, and we have trash in msg variable
        dataview = new Uint8Array(message);
        msg = String.fromCharCode.apply(null, dataview);
    }
} else {
    // odd length of the message means utf-8
    dataview = new Uint8Array(message);
    msg = String.fromCharCode.apply(null, dataview);
}
xmlDoc = parser.parseFromString(msg, 'application/xml');

This is a proposition of change this part of the KeySystemPlayReady.js :

    function getRequestHeadersFromMessage(message) {
        let msg,
            xmlDoc;
        const headers = {};
        const parser = new DOMParser();
        const dataview = (messageFormat === 'utf-16') ? new Uint16Array(message) : new Uint8Array(message);

        msg = String.fromCharCode.apply(null, dataview);
        xmlDoc = parser.parseFromString(msg, 'application/xml');
@jtrelak-vewd
Copy link
Author

I'm not sure if "PlayReady" string will be always in that message:

if (!msg.includes("PlayReady")) { // if it does not include "PlayReady" string, it means we had utf-8, and we have trash in msg variable

Maybe it is better to just check it like that:

if (!msg.startsWith("<?xml")) { // if it does not start with "<?xml" string, it means we had utf-8, and we have trash in msg variable

@Murmur
Copy link

Murmur commented Mar 8, 2022

Discussion about the same issue utf16|utf8 message format.
#3896

@vodlogic
Copy link
Contributor

Hi All,

It would be great if we could progress this issue in time for the dash.js 4.4 release?
Does anyone have any strong opinions on the approach proposed in #3899 (comment) or #3896 (reply in thread)? We have successfully tested the latter with several different devices and streams

@dsilhavy
Copy link
Collaborator

I would like to understand why we assume that an odd length of the message means we need to use utf-8. Is this documented somewhere?

@markriley9999
Copy link

markriley9999 commented Apr 12, 2022

Hi @dsilhavy

tbh, i'm finding it hard to find this actually documented anywhere! :(

I have discussed this with various device manufacturers (who port the PlayReady client) and Browser providers and there seems to be a general consensus that the 'js player' can and should be agnostic to the CDM message format - simply passing it through untouched...

However, there is a notable exception to this, this being Microsoft's own implementation of the PlayReady CDM for the Edge browser, where the message is wrapped within an xml element. So in this case, the DASH.JS does the correct thing and unwraps and passes on the message.

However, the player also needs to handle the other scenarios eg:

  • utf16 raw/unwrapped (which dash.js handles)
  • utf8 raw/unwrapped (dash.js exception fired when converting - an odd length message - to Uint16Array, in the getLicenseRequestFromMessage function)*

*Based on my testing so far a large number of devices (TVs) return this format - i have created a proof of concept and previously failing devices now work.

so the bottomline is we need the solution to avoid attempting to convert a message to utf-16** for an odd number of bytes (or catch the exception).
**(Assertion: utf-16 is 16 bits, an therefore valid utf-16 formatted messages will always be an even number of bytes)

does that sound reasonable?

@dsilhavy
Copy link
Collaborator

Thanks @markriley9999 . We can go with this solution but it should be configurable in the settings. @vodlogic created a PR for that in case you did not see it yet #3926

@dsilhavy dsilhavy added this to the 4.4.0 milestone May 3, 2022
@dsilhavy
Copy link
Collaborator

dsilhavy commented May 3, 2022

A potential fix for this was implemented in #3926 and is activated per default. In order to deactivate use the setting detectPlayreadyMessageFormat: false

@dsilhavy dsilhavy closed this as completed May 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants