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

Safari Fairplay MediaKeys Polyfill #382

Closed
sanbornhilland opened this issue May 17, 2016 · 79 comments
Closed

Safari Fairplay MediaKeys Polyfill #382

sanbornhilland opened this issue May 17, 2016 · 79 comments
Assignees
Labels
component: HLS The issue involves Apple's HLS manifest format flag: seeking PR We are actively seeking PRs for this; we do not currently expect the core team will resolve this status: archived Archived and locked; will not be updated type: enhancement New feature or request
Milestone

Comments

@sanbornhilland
Copy link
Contributor

In issue #279 it was mentioned that "The status of Fairplay through EME is unknown at this time." Can you elaborate on what you mean by this? We have some apple sample code that shows Fairplay playback in Safari. However trying to play the same content through Shaka with an HLS Parser plugin is not going so smoothly. I'm not sure the MediaKeys polyfill is working correctly on Safari. Have you tested in Safari?

I can get more detailed logs and specific failings in the next few days but I wanted to initially enquire about the compatibility of the MediaKeys polyfill and the Safari (9.1) EME implementation.

@joeyparrish joeyparrish added the type: question A question from the community label May 18, 2016
@joeyparrish
Copy link
Member

What I meant by that comment is that we have never seen any Fairplay-compatible DASH content we could try in Shaka, nor any EME-based Fairplay demos using HLS. So we can only assume Apple's EME works. Can you share a link to something of that sort?

A quick check shows that Safari 9's EME is the webkit-prefixed v0.1b API. The polyfill for that was originally developed against Chrome, but Chrome has long-since implemented the unprefixed working-draft EME API. If we need to modify the polyfill to better support Safari, I have no problems with that. Safari is, at the moment, the only known consumer of it.

@sanbornhilland
Copy link
Contributor Author

We have a server issue to resolve but then I should be able to provide you with a working Safari sample with HLS Fairplay content.

@sanbornhilland
Copy link
Contributor Author

I'm still working on getting you some HLS + Fairplay samples to give you. But there is sample client code from apple here: https://developer.apple.com/streaming/fps/ if you download the FairPlay Streaming Server SDK. If you haven't looked at this it would be useful for comparing to the v01b polyfill.

For instance, for FPS on Safari the init data is formed by concatenating the initData from the needkey event with a contentId and an Apple App Cert. I believe this is different from Chrome and other browsers that just require the init data? It looks to me like currently Shaka and the MediaKeys polyfill assumes the needkey event.initData is sufficient.

After that it looks like there are some other differences. The concatenated init data is passed in the createSession call and then there is no generateRequest call at all. This also appears to be different than how Shaka is handling it where the createSession call does not take any arguments and there is a generateRequest call that takes initData.

It appears to me that the flow on Safari is a bit different than on Chrome. I have tested that Apple sample code with HLS + Fairplay content and it does work in Safari.

I'm also having the following issue in Safari: In shaka.polyfill.PatchedMediaKeys.v01b.MediaKeys.prototype.onWebkitNeedKey_ it throws an error when trying to dispatch the shaka FakeEvent: UNSPECIFIED_EVENT_TYPE_ERR: DOM Events Exception 0: The Event's type was not specified by initializing the event before the method was called. The only way I can see to avoid that is to create a custom event instead like this:

var event2 = new CustomEvent('encrypted');
event2.initDataType = 'webm';
event2.initData = event.initData;

I'm not sure you'd want to handle it like this just for consistency reasons but this was how I could get around that error just for POC purposes.

@joeyparrish joeyparrish added type: enhancement New feature or request and removed type: question A question from the community labels Oct 4, 2016
@joeyparrish joeyparrish added this to the v2.1.0 milestone Oct 4, 2016
@joeyparrish joeyparrish modified the milestones: Backlog, v2.1.0 Mar 31, 2017
@joeyparrish joeyparrish added the component: HLS The issue involves Apple's HLS manifest format label Mar 31, 2017
@joeyparrish joeyparrish modified the milestones: Backlog, v2.2.0 Mar 31, 2017
@sarge
Copy link

sarge commented Apr 11, 2017

@joeyparrish would it help if I provide some test content to run against?

@joeyparrish
Copy link
Member

@sarge, it couldn't hurt! Thanks!

@joeyparrish joeyparrish self-assigned this Apr 26, 2017
@boredom2
Copy link

Hi there - we are now also finally under Pressure to run a DRM Solution for Safari asap.
I am really a little confused :) We have Assets in HLS and with FairPlay Protection ready.
Initially, I thought, that Safari will handle the Process itself, but looks, like if we have to do something here :) So Apple DRM also works on MSE Base?
And if yes, I suggest, this will only work with HLS (DASH with FairPlay is afaik not possible to create or at least never done and for sure not possible to create on MS Azure).
So can you maybe give me a little Hint on how to make this work?
Did someone ever made HLS+FairPlay+MSE work at all?
(and if you know that - how does this work on iOS, if this does not support MSE?)

@sarge
Copy link

sarge commented May 8, 2017

@joeyparrish I have uploaded a working sample of the fairplay drm.
https://s3.amazonaws.com/shift72-temp/hls_fps_bento4_sintel/master.m3u8

This file contains reference to the "Apple Developer Program License Agreement", so you can choose not to view it. Not sure what to do about worlds colliding here (shrug)
https://s3.amazonaws.com/shift72-temp/hls_fps_bento4_sintel/safari_hls.html

@boredom2 HLS + Fairplay works on Safari Desktop. But does not work on Safari iOS, an app is still required.
Dash + Fairplay + (Widevine + Playready) + MSE appears possible, implementations are rare from what I have seen. An additional pssh box with the fairplay id and some work generating the initData in the format [initData] = [initData] + [4 byte: idLength] + [idLength byte: id] + [4 byte:certLength] + [certLength byte: cert] should work.

@boredom2
Copy link

boredom2 commented May 8, 2017

Thanks for that Information - I will try once SHAKA can handle the slightly "crippled" HLS Manifest, that we get from MS Azure CDN. I will update then here :)

@joeyparrish
Copy link
Member

Here's an update on our progress.

The polyfill part is not that difficult. I have written a polyfill that builds a compliant MediaKeys API on top of Safari 10's WebKitMediaKeys.

Parsing the FairPlay tag in HLS to feed EME is trivial.

The challenge is that the key system com.apple.fps.1_0 seems to be usable only with video.src=foo.m3u8. When used with MediaSource, createSession() causes the page to crash and reload. And Shaka Player currently only works with MediaSource.

Judging from a WebKit commit log, they introduced com.apple.fps.2_0 for MediaSource:

(WebCore::keySystemIsSupported): Use "com.apple.fps.2_0" to distinguish from the not-media-source scheme.

I have not been able to find any working examples of that key system in use.

Creating a session with fps.2_0 results in a message that contains only the text "certificate". Looking at WebKit sources, this is unconditional and we are expected to call update() with the certificate after that.

Dealing with this certificate request is enough to do, and we can even hide it in the MediaKeys polyfill. However, the message we get after that is not a license request, either. It's completely empty.

WebKit sources also show support for com.apple.fps.3_0, but that also has no documentation and does not get us any further than fps.2_0 did.

@sarge
Copy link

sarge commented May 18, 2017

Thanks Joey for taking a look at this. You got further than I did. Would you mind pushing a branch?

fps.2_0 being for MSE is a good find - the apple forums note that NetFlix uses this scheme.

When you say after the certificate request you get a message that is empty do you mean that get a call to webkitkeymessage with no initdata?

@joeyparrish
Copy link
Member

I mean that the second webkitkeymessage event has message.length of zero.

@joeyparrish
Copy link
Member

I can't push anything until it's been through code review by the team, but I'll try to clean up what I've done so far and make it available in some form.

@joeyparrish joeyparrish modified the milestones: v2.2.0, v2.3.0 Jun 6, 2017
@senaev
Copy link

senaev commented Apr 25, 2019

Can someone with Mojave confirm or deny that window.MediaKeys shows up in the JS debugger on Safari 12.1?

yes, there is MediaKeys, but i did not find the way to detect fireplay anyway

Now we are using WebKitMediaKeys.isTypeSupported, and we are in search of unprefixed api to.

Google 2019-04-25 23-19-33

About This Mac 2019-04-25 23-23-30

@joeyparrish
Copy link
Member

isTypeSupported is not a part of the MediaKeys API. Instead, you are supposed to use navigator.requestMediaKeySystemAccess, which is much more complicated. Thankfully, Shaka Player handles that API for you.

Since this unprefixed API is dependent on a specific OS version, I think it's best if I continue developing the polyfill to support older OS versions. Then I'll perform the update to Mojave and test again. :-)

@senaev
Copy link

senaev commented Apr 25, 2019

isTypeSupported is not a part of the MediaKeys API. Instead, you are supposed to use navigator.requestMediaKeySystemAccess, which is much more complicated. Thankfully, Shaka Player handles that API for you.

Yeah, used to try, but there is also no way to detect fireplay with navigator.requestMediaKeySystemAccess api on 12.1 version. If you know how to do it, share it please!

@joeyparrish
Copy link
Member

If that's the case, we'll be stuck using prefixed until Apple implements the whole thing. I'll find out soon. Probably tomorrow.

@joeyparrish
Copy link
Member

A teammate has confirmed that requestMediaKeySystemAccess is available on Safari 12.1 on Mojave specifically. It's not on 12.1 on High Sierra.

shaka-bot pushed a commit that referenced this issue Apr 25, 2019
Using a custom server certificate, starting playback, then reloading
the demo app was resulting in the cert field being lost.  This ensures
that the server cert is always preserved across reloads.

Very useful while working on #382

Change-Id: If1b65b1f24e21ce27cb3a54b5862b2b700b23ac1
@joeyparrish
Copy link
Member

Thank you @avelad for the content. My changes are still in review, but I have your content working with Apple's HLS and fps.1_0!

If anyone else has sample content to contribute, please send them our way!

shaka-bot pushed a commit that referenced this issue Apr 25, 2019
This shouldn't depend on the load state.

Issue #382

Change-Id: Ia601c79404e074ec080c923f239533a8d04f6e64
shaka-bot pushed a commit that referenced this issue Apr 26, 2019
By fixing the definitions of isLive and seekRange for native HLS and
other src= playbacks, the UI for live streams with native HLS is now
working correctly on Safari.

Issue #382
Issue #997

Change-Id: I3d4f49ebe31a543c75f8607e7a194095ef198c0a
shaka-bot pushed a commit that referenced this issue Apr 26, 2019
There was a bug here that allowed the PIP button to be shown on any
track change event.  This bug only manifests on platforms without PIP,
such as Safari 12.

Found while working on #997 and #382

Change-Id: Iad51b2e9a5e86767a3ebf606c3e3b976d2d19ad7
shaka-bot pushed a commit that referenced this issue Apr 29, 2019
Allow indirect access to members (such as DRM engine, manifest, etc)
from Player methods as soon as they become available, instead of
waiting until the very end of the load process.

This fixes application access to several methods during the
"manifestparsed" event.  The point of the "manifestparsed" event was
to allow early access to manifest and other metadata before streaming
begins.

This also lays the foundations for improvements in native HLS support
in those same methods, including the ability to get track information.

Issue #382
Issue #997
Fixes b/131604508

Change-Id: Ifee7b06fc2ccdcf5bcdf1c44f2f851d1d7e67fa1
@osmestad
Copy link

I sent a link with some TIDAL sample content to [email protected] now, would be great if you can test that!

@joeyparrish
Copy link
Member

Will do! Thank you!

shaka-bot pushed a commit that referenced this issue Apr 30, 2019
If the resolution menu sees audio-only content, it should be hidden.
But it should come back as soon as the audio-video content is seen.

This came up during work on #997 and #382

Change-Id: I3297847c905c867bcdd14cf7e525a408890a273a
shaka-bot pushed a commit that referenced this issue Apr 30, 2019
Track methods are now implemented for native HLS and other src=
playbacks.  This will allow the UI to select text and audio languages.

This change adds best-effort methods to get track information for src=
playbacks, including native HLS on Safari.  In many cases, it relies
on the audioTracks and videoTracks members of HTMLVideoElement which
are only implemented on Safari.  They are in the spec, though, so
there's no harm in using them when they exist.

This is fully parallel to the manifest-based paradigm for MSE-based
playbacks.  Each of these top-level methods in Player has an "if" to
decide which way to supply the requested info, except for the language
methods, which now delegate to the track methods.

With this, Safari's native HLS can supply audio and text language
information to the UI/app, and the UI/app can have some control over
those things through the tracks API.  I believe this is important to
the success of our new iOS support.

Issue #997
Issue #382

Change-Id: Icc44a932927fafedda1b62a9d4c6e2ed3dc7db30
shaka-bot pushed a commit that referenced this issue Apr 30, 2019
This adds a polyfill for Apple's prefixed EME implementation.  This
will be used on all macOS versions prior to 10.14 (Mojave) and on
Safari versions prior to 12.1.

This also adds support for FairPlay license protocol eccentricities
in DrmEngine, so that the proper formatting is used for requests and
responses.

Issue #382

Change-Id: If1274d2f018a475f56c09df97645694f13acbde9
shaka-bot pushed a commit that referenced this issue Apr 30, 2019
The unprefixed EME launched with macOS 10.14 (Mojave) rejects requests
for the key system IDs we know how to use.  So until the bug we filed
against Apple is resolved, prefer the prefixed API.

Issue #382

Change-Id: I71313be2102af2da66a6389a9e9afdebd8ae033d
@avelad
Copy link
Member

avelad commented May 1, 2019

@joeyparrish Can you update README.md file with current Fairplay status?

@joeyparrish
Copy link
Member

Yes, thanks for reminding me!

shaka-bot pushed a commit that referenced this issue May 1, 2019
Issue #382

Change-Id: I85279100052c3eedd46912e74448cd29268e8632
@mathieuedet
Copy link

I'm trying to implement Fairplay with new shaka-player version (2.5) ? Can you update documentation to include configuration for Fairplay ?

@joeyparrish
Copy link
Member

joeyparrish commented May 9, 2019

Sure. In the mean time, here's what you need to know.

You use FairPlay just like any other DRM in terms of the license server config:

player.configure({
  drm: {
    servers: {
      'com.apple.fps.1_0': '/path/to/my/server',
    },
  },
});

// or

player.configure('drm.servers.com\\.apple\\.fps\\.1_0', '/path/to/my/server');

In addition, FairPlay requires you to provide a certificate through the "advanced" DRM config:

const response = await fetch('/path/to/my/cert.der');
if (!response.ok) {
  // handle error
}
const cert = await response.arrayBuffer();

player.configure({
  drm: {
    advanced: {
      'com.apple.fps.1_0': {
        serverCertificate: new Uint8Array(cert),
      },
    },
  },
});

// or

player.configure('drm.advanced.com\\.apple\\.fps\\.1_0.serverCertificate',
                 new Uint8Array(cert));

If your license server doesn't use the default formatting for FairPlay license requests/responses, you can use request and response filters to transform them. See the "License Wrapping" tutorials for generic examples of that.

I hope that helps you get started. We'll work on improving the docs around FairPlay so that these things are clearer.

@sandeep-mirpuri
Copy link

@joeyparrish I'm so excited about this. Been waiting for it for ages :). But I can't get it to work. I am setting the licenseUrl and certificate ArrayBuffer as described in your comment above. Then trying to load the corresponding m3u8 manifest. But I get a couple of different errors.

  1. invalid config, wrong type for .drm.advanced.com.apple.fps.1_0
  2. Error code: 6010 - Shaka Error DRM.ENCRYPTED_CONTENT_WITHOUT_DRM_INFO

I assumed that it might be an issue with getting the license key since we need to append a session key and ticket number to the request. I tried registering a request filter for this, but it seems its not even getting as far as the license, since the filter doesn't seem to be firing at all (fires fine on chrome using widevine). This is the line for the key info in the manifest.

#EXT-X-SESSION-KEY:METHOD=SAMPLE-AES,URI="skd://key-server-url",KEYFORMAT="com.apple.streamingkeydelivery",KEYFORMATVERSIONS="1"

I have also attached an image with the logs in my safari browser from shaka

Not sure what is happening here. I am working on getting permissions to share the manifest with you but until then, any pointers? (At the moment we are using a raw implementation using safari's webkit apis. This implementation works fine. Let me know if steps describing this implementation are of any use)

Screen Shot 2019-05-23 at 2 22 27 pm

@shaka-project shaka-project locked and limited conversation to collaborators Jun 30, 2019
@shaka-bot shaka-bot added the status: archived Archived and locked; will not be updated label Apr 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
component: HLS The issue involves Apple's HLS manifest format flag: seeking PR We are actively seeking PRs for this; we do not currently expect the core team will resolve this status: archived Archived and locked; will not be updated type: enhancement New feature or request
Projects
None yet
Development

No branches or pull requests