videojs / videojs-contrib-eme

Supports Encrypted Media Extensions for playback of encrypted content in Video.js
Other
199 stars 71 forks source link

getLicense function is not called for DRM content in case of fairplay #159

Open shubham-wynk opened 2 years ago

shubham-wynk commented 2 years ago

player.ready(function () { player.eme(); player.src({ src: config?.playurl, type: "application/x-mpegURL", keySystems: config.keySystems, withCredentials: true, }); });

getLicense: function( emeOptions, contentId, keyMessage, callback, keyId ){ console.log("GET LICENECE"); },

evanluu commented 2 years ago

I have the same issue with DRM content when AirPlay on Safari

cfra commented 1 year ago

I believe this is related to this early return in handleEncryptedEvent:

https://github.com/videojs/videojs-contrib-eme/blob/c8ca31a2c9e49a4ea76b3801763ddace66cfbdb4/src/plugin.js#L79

When FairPlay protected content is played back via AirPlay, the key request of the player is proxies through the users browser.

So after the initial encrypted event that was received when playback was started, another encrypted event will be received when switching to AirPlay.

I could not find a lot of documentation on this process out there, however there is a brief description on page 9 of this PDF by Apple.

Either way, it seems like this second encrypted event has exactly the same initialData like the first event, so the event gets ignored by videojs-contrib-eme, so the AirPlay target never receives the necessary key information and cannot start playback.

I resolved this problem by changing the code like this, however I am not sure if this really is a clean solution, or if it should be resolved differently:

diff --git a/src/plugin.js b/src/plugin.js
index 53cb8e9..41b4c54 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -71,11 +71,11 @@ export const handleEncryptedEvent = (player, event, options, sessions, eventBus)
     // set of stream(s) or media data."
     // eslint-disable-next-line max-len
     // @see [Initialization Data Spec]{@link https://www.w3.org/TR/encrypted-media/#initialization-data}
-    if (hasSession(sessions, initData) || !initData) {
+    if (!initData) {
       // TODO convert to videojs.log.debug and add back in
       // https://github.com/videojs/video.js/pull/4780
       // videojs.log('eme',
-      //             'Already have a configured session for init data, ignoring event.');
+      //             'Empty init data, ignoring event.');
       return Promise.resolve();
     } 

For reference, it seems like Shaka Player was running in the same issue as well.

The issue can be found here https://github.com/shaka-project/shaka-player/issues/2177 and their resolution can be found here https://github.com/shaka-project/shaka-player/pull/2257

It seems they opted to clear the session store when switching beween AirPlay playback and regular playback, but I neither have the experience nor the testing resources available to come up with a solution like this for videojs-contrib-eme without further guidance.

cfra commented 1 year ago

The solution I described in the previous comment turns out to be a bad idea:

It leads to lots of duplicate license requests and high time to first frame in the best case, and playback failure in other cases where license requests are guarded by a nonce.

Clearing the list of existing sessions when switching beween regular and AirPlay playback similar to https://github.com/shaka-project/shaka-player/pull/2257 seems like a better approach.

I have opened #180 with an implementation of this approach.

As the PR will only have any effect if AirPlay is used, and AirPlay was broken before, it should definitely be an improvement. :smiley: