From 312b04879171b0b8ede8c948d2f8d53e79609bce Mon Sep 17 00:00:00 2001 From: jforbes Date: Tue, 16 Oct 2018 13:59:25 -0400 Subject: [PATCH 01/15] feat: added API to set media keys directly --- src/plugin.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/plugin.js b/src/plugin.js index f0d5727..f408e15 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -237,6 +237,20 @@ const onPlayerReady = (player) => { const eme = function(options = {}) { this.eme.options = options; + this.eme.init = (config) => { + const e = { + initDataType: '', + initData: null, + target: this.tech_.el_ + }; + + if (this.tech_.el_.setMediaKeys) { + handleEncryptedEvent(e, config, this.eme.sessions, this.tech_); + } else if (this.tech_.el_.msSetMediaKeys) { + handleMsNeedKeyEvent(e, config, this.eme.sessions, this.tech_); + } + }; + this.ready(() => onPlayerReady(this)); }; From 3adb9958d2d27ed6d055826d53b9c2d786c1a589 Mon Sep 17 00:00:00 2001 From: jforbes Date: Tue, 16 Oct 2018 14:27:28 -0400 Subject: [PATCH 02/15] renamed method, merge options, added note --- src/plugin.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/plugin.js b/src/plugin.js index f408e15..ca5b16e 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -237,17 +237,24 @@ const onPlayerReady = (player) => { const eme = function(options = {}) { this.eme.options = options; - this.eme.init = (config) => { + this.eme.initializeMediaKeys = (emeOptions = {}) => { const e = { initDataType: '', initData: null, target: this.tech_.el_ }; + const mergedEmeOptions = videojs.mergeOptions( + this.currentSource(), + options, + emeOptions + ); + // TODO: this should be refactored and renamed to be less tied + // to encrypted events if (this.tech_.el_.setMediaKeys) { - handleEncryptedEvent(e, config, this.eme.sessions, this.tech_); + handleEncryptedEvent(e, mergedEmeOptions, this.eme.sessions, this.tech_); } else if (this.tech_.el_.msSetMediaKeys) { - handleMsNeedKeyEvent(e, config, this.eme.sessions, this.tech_); + handleMsNeedKeyEvent(e, mergedEmeOptions, this.eme.sessions, this.tech_); } }; From b93d9c2b1df0b620a0bda7dc405e5f2abfd7bf72 Mon Sep 17 00:00:00 2001 From: jforbes Date: Tue, 16 Oct 2018 16:00:27 -0400 Subject: [PATCH 03/15] added test, cleaned up reinit --- src/plugin.js | 30 ++++++++++++-------- test/plugin.test.js | 67 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 12 deletions(-) diff --git a/src/plugin.js b/src/plugin.js index ca5b16e..47a4ba0 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -231,39 +231,45 @@ const onPlayerReady = (player) => { * to you; if not, remove the wait for "ready"! * * @function eme + * @param {Object} [player] + * A playerobject. * @param {Object} [options={}] * An object of options left to the plugin author to define. */ -const eme = function(options = {}) { - this.eme.options = options; - - this.eme.initializeMediaKeys = (emeOptions = {}) => { +const eme = function(player, options = {}) { + const initializeMediaKeys = (emeOptions = {}) => { const e = { initDataType: '', initData: null, - target: this.tech_.el_ + target: player.tech_.el_ }; const mergedEmeOptions = videojs.mergeOptions( - this.currentSource(), + player.currentSource(), options, emeOptions ); + setupSessions(player); + // TODO: this should be refactored and renamed to be less tied // to encrypted events - if (this.tech_.el_.setMediaKeys) { - handleEncryptedEvent(e, mergedEmeOptions, this.eme.sessions, this.tech_); - } else if (this.tech_.el_.msSetMediaKeys) { - handleMsNeedKeyEvent(e, mergedEmeOptions, this.eme.sessions, this.tech_); + if (player.tech_.el_.setMediaKeys) { + return handleEncryptedEvent(e, mergedEmeOptions, player.eme.sessions, player.tech_); + } else if (player.tech_.el_.msSetMediaKeys) { + handleMsNeedKeyEvent(e, mergedEmeOptions, player.eme.sessions, player.tech_); } }; - this.ready(() => onPlayerReady(this)); + player.ready(() => onPlayerReady(player)); + + player.eme = { initializeMediaKeys, options }; }; // Register the plugin with video.js. const registerPlugin = videojs.registerPlugin || videojs.plugin; -registerPlugin('eme', eme); +registerPlugin('eme', function(options) { + eme(this, options); +}); export default eme; diff --git a/test/plugin.test.js b/test/plugin.test.js index cda62b5..1791b61 100644 --- a/test/plugin.test.js +++ b/test/plugin.test.js @@ -82,6 +82,73 @@ QUnit.test('exposes options', function(assert) { 'exposes publisherId'); }); +QUnit.test('initializeMediaKeys standard', function(assert) { + const done = assert.async(); + const initData1 = new Uint8Array([1, 2, 3]).buffer; + + // mock requestMediaKeySystemAccess + const oldRequestMediaKeySystemAccess = window.navigator.requestMediaKeySystemAccess; + + window.navigator.requestMediaKeySystemAccess = (keySystem, options) => { + return Promise.resolve({ + keySystem: 'org.w3.clearkey', + createMediaKeys: () => { + return { + createSession: () => new videojs.EventTarget() + }; + } + }); + }; + + this.player.eme(); + + // testing the rejection path because this isn't a real session + this.player.eme.initializeMediaKeys({ + keySystems: { + 'org.w3.clearkey': { + pssh: initData1 + } + } + }).then(() => { + const sessions = this.player.eme.sessions; + + assert.equal(sessions.length, 1, 'created a session when keySystems in options'); + assert.deepEqual(sessions[0].initData, initData1, 'captured initData in the session'); + done(); + }); + + // restore requestMediaKeySystemAccess + window.navigator.requestMediaKeySystemAccess = oldRequestMediaKeySystemAccess; +}); + +QUnit.test('initializeMediaKeys ms-prefix', function(assert) { + // stub setMediaKeys + const setMediaKeys = this.player.tech_.el_.setMediaKeys; + + this.player.tech_.el_.setMediaKeys = null; + this.player.tech_.el_.msSetMediaKeys = () => {}; + + const initData1 = new Uint8Array([1, 2, 3]).buffer; + + this.player.eme(); + + this.player.eme.initializeMediaKeys({ + keySystems: { + 'com.microsoft.playready': { + pssh: initData1 + } + } + }); + + const sessions = this.player.eme.sessions; + + assert.equal(sessions.length, 1, 'created a session when keySystems in options'); + assert.deepEqual(sessions[0].initData, initData1, 'captured initData in the session'); + + this.player.tech_.el_.msSetMediaKeys = null; + this.player.tech_.el_.setMediaKeys = setMediaKeys; +}); + QUnit.module('plugin guard functions', { beforeEach() { this.options = { From 1471c5f211e29a265c4192b2c121bb938b044686 Mon Sep 17 00:00:00 2001 From: jforbes Date: Tue, 16 Oct 2018 16:06:20 -0400 Subject: [PATCH 04/15] added initDataType --- src/plugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugin.js b/src/plugin.js index 47a4ba0..acee7de 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -239,7 +239,7 @@ const onPlayerReady = (player) => { const eme = function(player, options = {}) { const initializeMediaKeys = (emeOptions = {}) => { const e = { - initDataType: '', + initDataType: 'cenc', initData: null, target: player.tech_.el_ }; From fd383d9f8e319d9edd3df27268080491a2140dcf Mon Sep 17 00:00:00 2001 From: jforbes Date: Tue, 16 Oct 2018 16:41:36 -0400 Subject: [PATCH 05/15] review comments --- src/plugin.js | 67 ++++++++++++++++++++++++++++----------------- test/plugin.test.js | 2 +- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/plugin.js b/src/plugin.js index acee7de..f602578 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -222,6 +222,35 @@ const onPlayerReady = (player) => { }); }; +/** + * Sets up MediaKeys on demand + * + * @function initializeMediaKeys + * @param {Object} [player] + * A player object. + * @param {Object} [emeOptions={}] + * An object of eme plugin options. + */ +const initializeMediaKeys = (player, emeOptions = {}) => { + // TODO: this should be refactored + // fake an encrypted event for handleEncryptedEvent + const mockEncryptedEvent = { + initDataType: 'cenc', + initData: null, + target: player.tech_.el_ + }; + + setupSessions(player); + + // TODO: this should be refactored and renamed to be less tied + // to encrypted events + if (player.tech_.el_.setMediaKeys) { + return handleEncryptedEvent(mockEncryptedEvent, emeOptions, player.eme.sessions, player.tech_); + } else if (player.tech_.el_.msSetMediaKeys) { + handleMsNeedKeyEvent(mockEncryptedEvent, emeOptions, player.eme.sessions, player.tech_); + } +}; + /** * A video.js plugin. * @@ -232,37 +261,25 @@ const onPlayerReady = (player) => { * * @function eme * @param {Object} [player] - * A playerobject. + * A player object. * @param {Object} [options={}] * An object of options left to the plugin author to define. */ const eme = function(player, options = {}) { - const initializeMediaKeys = (emeOptions = {}) => { - const e = { - initDataType: 'cenc', - initData: null, - target: player.tech_.el_ - }; - const mergedEmeOptions = videojs.mergeOptions( - player.currentSource(), - options, - emeOptions - ); - - setupSessions(player); - - // TODO: this should be refactored and renamed to be less tied - // to encrypted events - if (player.tech_.el_.setMediaKeys) { - return handleEncryptedEvent(e, mergedEmeOptions, player.eme.sessions, player.tech_); - } else if (player.tech_.el_.msSetMediaKeys) { - handleMsNeedKeyEvent(e, mergedEmeOptions, player.eme.sessions, player.tech_); - } - }; - player.ready(() => onPlayerReady(player)); - player.eme = { initializeMediaKeys, options }; + player.eme = { + initializeMediaKeys(emeOptions = {}) { + const mergedEmeOptions = videojs.mergeOptions( + player.currentSource(), + options, + emeOptions + ); + + return initializeMediaKeys(player, mergedEmeOptions); + }, + options + }; }; // Register the plugin with video.js. diff --git a/test/plugin.test.js b/test/plugin.test.js index 1791b61..13acc22 100644 --- a/test/plugin.test.js +++ b/test/plugin.test.js @@ -109,7 +109,7 @@ QUnit.test('initializeMediaKeys standard', function(assert) { pssh: initData1 } } - }).then(() => { + }).catch(() => { const sessions = this.player.eme.sessions; assert.equal(sessions.length, 1, 'created a session when keySystems in options'); From 4f1109d3c020a18f84897cb1ae0db8e2b8abbae9 Mon Sep 17 00:00:00 2001 From: jforbes Date: Tue, 16 Oct 2018 18:15:50 -0400 Subject: [PATCH 06/15] added usage to readme --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index c2610a9..2d9e770 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Maintenance Status: Stable - [Source Options](#source-options) - [Plugin Options](#plugin-options) - [emeOptions](#emeoptions) + - [initializeMediaKeys](#initializemediakeys) - [Passing methods seems complicated](#passing-methods-seems-complicated) - [Special Events](#special-events) - [Getting Started](#getting-started) @@ -328,6 +329,23 @@ player.src({ }); ``` +### initializeMediaKeys +Type: `function` + +`player.eme.initializeMediaKeys()` sets up MediaKeys immediately on demand. This is useful for setting up the video element for DRM before loading any content. Otherwise the video element is set up for DRM on `encrypted` events. + +```javascript +// additional plugin options +var emeOptions = { + keySystems: { + 'org.w3.clearkey': {...}, + } + } +}; + +player.eme.initializeMediaKeys(emeOptions); +``` + ### Passing methods seems complicated While simple URLs are supported for many EME implementations, we wanted to provide as much From bd151fbca04a9a0356d1ca3e1d6df88a99f747bf Mon Sep 17 00:00:00 2001 From: jforbes Date: Tue, 16 Oct 2018 18:27:06 -0400 Subject: [PATCH 07/15] update tests --- test/plugin.test.js | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/test/plugin.test.js b/test/plugin.test.js index 13acc22..444fdb4 100644 --- a/test/plugin.test.js +++ b/test/plugin.test.js @@ -37,9 +37,23 @@ QUnit.module('videojs-contrib-eme', { this.video = document.createElement('video'); this.fixture.appendChild(this.video); this.player = videojs(this.video); + + this.origRequestMediaKeySystemAccess = window.navigator.requestMediaKeySystemAccess; + + window.navigator.requestMediaKeySystemAccess = (keySystem, options) => { + return Promise.resolve({ + keySystem: 'org.w3.clearkey', + createMediaKeys: () => { + return { + createSession: () => new videojs.EventTarget() + }; + } + }); + }; }, afterEach() { + window.navigator.requestMediaKeySystemAccess = this.origRequestMediaKeySystemAccess; this.player.dispose(); this.clock.restore(); } @@ -84,21 +98,7 @@ QUnit.test('exposes options', function(assert) { QUnit.test('initializeMediaKeys standard', function(assert) { const done = assert.async(); - const initData1 = new Uint8Array([1, 2, 3]).buffer; - - // mock requestMediaKeySystemAccess - const oldRequestMediaKeySystemAccess = window.navigator.requestMediaKeySystemAccess; - - window.navigator.requestMediaKeySystemAccess = (keySystem, options) => { - return Promise.resolve({ - keySystem: 'org.w3.clearkey', - createMediaKeys: () => { - return { - createSession: () => new videojs.EventTarget() - }; - } - }); - }; + const initData = new Uint8Array([1, 2, 3]).buffer; this.player.eme(); @@ -106,19 +106,16 @@ QUnit.test('initializeMediaKeys standard', function(assert) { this.player.eme.initializeMediaKeys({ keySystems: { 'org.w3.clearkey': { - pssh: initData1 + pssh: initData } } }).catch(() => { const sessions = this.player.eme.sessions; assert.equal(sessions.length, 1, 'created a session when keySystems in options'); - assert.deepEqual(sessions[0].initData, initData1, 'captured initData in the session'); + assert.deepEqual(sessions[0].initData, initData, 'captured initData in the session'); done(); }); - - // restore requestMediaKeySystemAccess - window.navigator.requestMediaKeySystemAccess = oldRequestMediaKeySystemAccess; }); QUnit.test('initializeMediaKeys ms-prefix', function(assert) { @@ -128,14 +125,14 @@ QUnit.test('initializeMediaKeys ms-prefix', function(assert) { this.player.tech_.el_.setMediaKeys = null; this.player.tech_.el_.msSetMediaKeys = () => {}; - const initData1 = new Uint8Array([1, 2, 3]).buffer; + const initData = new Uint8Array([1, 2, 3]).buffer; this.player.eme(); this.player.eme.initializeMediaKeys({ keySystems: { 'com.microsoft.playready': { - pssh: initData1 + pssh: initData } } }); @@ -143,7 +140,7 @@ QUnit.test('initializeMediaKeys ms-prefix', function(assert) { const sessions = this.player.eme.sessions; assert.equal(sessions.length, 1, 'created a session when keySystems in options'); - assert.deepEqual(sessions[0].initData, initData1, 'captured initData in the session'); + assert.deepEqual(sessions[0].initData, initData, 'captured initData in the session'); this.player.tech_.el_.msSetMediaKeys = null; this.player.tech_.el_.setMediaKeys = setMediaKeys; From fc14190f75edb07e4c6101211475d88b7d9c74c3 Mon Sep 17 00:00:00 2001 From: jforbes Date: Tue, 16 Oct 2018 18:27:57 -0400 Subject: [PATCH 08/15] typo --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 2d9e770..17514cb 100644 --- a/README.md +++ b/README.md @@ -338,8 +338,7 @@ Type: `function` // additional plugin options var emeOptions = { keySystems: { - 'org.w3.clearkey': {...}, - } + 'org.w3.clearkey': {...} } }; From e79cdff7a97c513e4bf0b40eb20fc79cd0c42121 Mon Sep 17 00:00:00 2001 From: jforbes Date: Mon, 22 Oct 2018 16:20:50 -0400 Subject: [PATCH 09/15] update comments --- src/plugin.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugin.js b/src/plugin.js index f602578..26a8e98 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -232,7 +232,9 @@ const onPlayerReady = (player) => { * An object of eme plugin options. */ const initializeMediaKeys = (player, emeOptions = {}) => { - // TODO: this should be refactored + // TODO: this should be refactored and renamed to be less tied + // to encrypted events + // fake an encrypted event for handleEncryptedEvent const mockEncryptedEvent = { initDataType: 'cenc', @@ -242,8 +244,6 @@ const initializeMediaKeys = (player, emeOptions = {}) => { setupSessions(player); - // TODO: this should be refactored and renamed to be less tied - // to encrypted events if (player.tech_.el_.setMediaKeys) { return handleEncryptedEvent(mockEncryptedEvent, emeOptions, player.eme.sessions, player.tech_); } else if (player.tech_.el_.msSetMediaKeys) { From 9c163e94fbc16f2c1bb175b135de86ce248c0222 Mon Sep 17 00:00:00 2001 From: jforbes Date: Mon, 22 Oct 2018 16:32:27 -0400 Subject: [PATCH 10/15] added chromium bug ticket note --- src/plugin.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugin.js b/src/plugin.js index 26a8e98..fb0764b 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -224,6 +224,7 @@ const onPlayerReady = (player) => { /** * Sets up MediaKeys on demand + * Works around https://bugs.chromium.org/p/chromium/issues/detail?id=895449 * * @function initializeMediaKeys * @param {Object} [player] From 68d5e2e1400747905d57f8642a6c29cd7b6d400c Mon Sep 17 00:00:00 2001 From: jforbes Date: Mon, 22 Oct 2018 17:23:27 -0400 Subject: [PATCH 11/15] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 17514cb..7377956 100644 --- a/README.md +++ b/README.md @@ -332,7 +332,7 @@ player.src({ ### initializeMediaKeys Type: `function` -`player.eme.initializeMediaKeys()` sets up MediaKeys immediately on demand. This is useful for setting up the video element for DRM before loading any content. Otherwise the video element is set up for DRM on `encrypted` events. +`player.eme.initializeMediaKeys()` sets up MediaKeys immediately on demand. This is useful for setting up the video element for DRM before loading any content. Otherwise the video element is set up for DRM on `encrypted` events. This is not supported in Safari. ```javascript // additional plugin options From a28a2e9892772ae042a1eafc3445ade0655aecbb Mon Sep 17 00:00:00 2001 From: jforbes Date: Tue, 23 Oct 2018 11:03:48 -0400 Subject: [PATCH 12/15] undo plugin function change --- src/plugin.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/plugin.js b/src/plugin.js index fb0764b..97a8e11 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -261,12 +261,12 @@ const initializeMediaKeys = (player, emeOptions = {}) => { * to you; if not, remove the wait for "ready"! * * @function eme - * @param {Object} [player] - * A player object. * @param {Object} [options={}] * An object of options left to the plugin author to define. */ -const eme = function(player, options = {}) { +const eme = function(options = {}) { + const player = this; + player.ready(() => onPlayerReady(player)); player.eme = { @@ -286,8 +286,6 @@ const eme = function(player, options = {}) { // Register the plugin with video.js. const registerPlugin = videojs.registerPlugin || videojs.plugin; -registerPlugin('eme', function(options) { - eme(this, options); -}); +registerPlugin('eme', eme); export default eme; From 619b03c5f99924e6fee9bed8998d6804b1400cea Mon Sep 17 00:00:00 2001 From: jforbes Date: Tue, 23 Oct 2018 13:59:33 -0400 Subject: [PATCH 13/15] skip test in Safari --- test/plugin.test.js | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/test/plugin.test.js b/test/plugin.test.js index 444fdb4..f38f6df 100644 --- a/test/plugin.test.js +++ b/test/plugin.test.js @@ -96,27 +96,30 @@ QUnit.test('exposes options', function(assert) { 'exposes publisherId'); }); -QUnit.test('initializeMediaKeys standard', function(assert) { - const done = assert.async(); - const initData = new Uint8Array([1, 2, 3]).buffer; +// skip test for Safari +if (!window.WebKitMediaKeys) { + QUnit.test('initializeMediaKeys standard', function(assert) { + const done = assert.async(); + const initData = new Uint8Array([1, 2, 3]).buffer; - this.player.eme(); + this.player.eme(); - // testing the rejection path because this isn't a real session - this.player.eme.initializeMediaKeys({ - keySystems: { - 'org.w3.clearkey': { - pssh: initData + // testing the rejection path because this isn't a real session + this.player.eme.initializeMediaKeys({ + keySystems: { + 'org.w3.clearkey': { + pssh: initData + } } - } - }).catch(() => { - const sessions = this.player.eme.sessions; + }).catch(() => { + const sessions = this.player.eme.sessions; - assert.equal(sessions.length, 1, 'created a session when keySystems in options'); - assert.deepEqual(sessions[0].initData, initData, 'captured initData in the session'); - done(); + assert.equal(sessions.length, 1, 'created a session when keySystems in options'); + assert.deepEqual(sessions[0].initData, initData, 'captured initData in the session'); + done(); + }); }); -}); +} QUnit.test('initializeMediaKeys ms-prefix', function(assert) { // stub setMediaKeys From e97b8958f674007eb44607290f0f823b36b0d67a Mon Sep 17 00:00:00 2001 From: jforbes Date: Tue, 23 Oct 2018 14:46:32 -0400 Subject: [PATCH 14/15] add callback to API --- README.md | 8 +++++- src/plugin.js | 62 ++++++++++++++++++++++----------------------- test/plugin.test.js | 13 ++++++---- 3 files changed, 45 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 7377956..705e9f4 100644 --- a/README.md +++ b/README.md @@ -342,7 +342,13 @@ var emeOptions = { } }; -player.eme.initializeMediaKeys(emeOptions); +player.eme.initializeMediaKeys(emeOptions, function(error) { + if (error) { + // do something with error + } + + // do something else +}); ``` ### Passing methods seems complicated diff --git a/src/plugin.js b/src/plugin.js index 97a8e11..5b474c0 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -222,36 +222,6 @@ const onPlayerReady = (player) => { }); }; -/** - * Sets up MediaKeys on demand - * Works around https://bugs.chromium.org/p/chromium/issues/detail?id=895449 - * - * @function initializeMediaKeys - * @param {Object} [player] - * A player object. - * @param {Object} [emeOptions={}] - * An object of eme plugin options. - */ -const initializeMediaKeys = (player, emeOptions = {}) => { - // TODO: this should be refactored and renamed to be less tied - // to encrypted events - - // fake an encrypted event for handleEncryptedEvent - const mockEncryptedEvent = { - initDataType: 'cenc', - initData: null, - target: player.tech_.el_ - }; - - setupSessions(player); - - if (player.tech_.el_.setMediaKeys) { - return handleEncryptedEvent(mockEncryptedEvent, emeOptions, player.eme.sessions, player.tech_); - } else if (player.tech_.el_.msSetMediaKeys) { - handleMsNeedKeyEvent(mockEncryptedEvent, emeOptions, player.eme.sessions, player.tech_); - } -}; - /** * A video.js plugin. * @@ -269,15 +239,43 @@ const eme = function(options = {}) { player.ready(() => onPlayerReady(player)); + // Plugin API player.eme = { - initializeMediaKeys(emeOptions = {}) { + /** + * Sets up MediaKeys on demand + * Works around https://bugs.chromium.org/p/chromium/issues/detail?id=895449 + * + * @function initializeMediaKeys + * @param {Object} [emeOptions={}] + * An object of eme plugin options. + * @param {Function} [callback=function(){}] + */ + initializeMediaKeys(emeOptions = {}, callback = function() {}) { + // TODO: this should be refactored and renamed to be less tied + // to encrypted events const mergedEmeOptions = videojs.mergeOptions( player.currentSource(), options, emeOptions ); - return initializeMediaKeys(player, mergedEmeOptions); + // fake an encrypted event for handleEncryptedEvent + const mockEncryptedEvent = { + initDataType: 'cenc', + initData: null, + target: player.tech_.el_ + }; + + setupSessions(player); + + if (player.tech_.el_.setMediaKeys) { + handleEncryptedEvent(mockEncryptedEvent, mergedEmeOptions, player.eme.sessions, player.tech_) + .then(() => callback()) + .catch((error) => callback(error)); + } else if (player.tech_.el_.msSetMediaKeys) { + handleMsNeedKeyEvent(mockEncryptedEvent, mergedEmeOptions, player.eme.sessions, player.tech_); + callback(); + } }, options }; diff --git a/test/plugin.test.js b/test/plugin.test.js index f38f6df..f5f888b 100644 --- a/test/plugin.test.js +++ b/test/plugin.test.js @@ -111,7 +111,7 @@ if (!window.WebKitMediaKeys) { pssh: initData } } - }).catch(() => { + }, () => { const sessions = this.player.eme.sessions; assert.equal(sessions.length, 1, 'created a session when keySystems in options'); @@ -122,6 +122,7 @@ if (!window.WebKitMediaKeys) { } QUnit.test('initializeMediaKeys ms-prefix', function(assert) { + const done = assert.async(); // stub setMediaKeys const setMediaKeys = this.player.tech_.el_.setMediaKeys; @@ -138,12 +139,14 @@ QUnit.test('initializeMediaKeys ms-prefix', function(assert) { pssh: initData } } - }); + }, () => { + const sessions = this.player.eme.sessions; - const sessions = this.player.eme.sessions; + assert.equal(sessions.length, 1, 'created a session when keySystems in options'); + assert.deepEqual(sessions[0].initData, initData, 'captured initData in the session'); - assert.equal(sessions.length, 1, 'created a session when keySystems in options'); - assert.deepEqual(sessions[0].initData, initData, 'captured initData in the session'); + done(); + }); this.player.tech_.el_.msSetMediaKeys = null; this.player.tech_.el_.setMediaKeys = setMediaKeys; From 771cc6bac375029e557a90facfdff5217cee34ae Mon Sep 17 00:00:00 2001 From: jforbes Date: Wed, 24 Oct 2018 10:36:47 -0400 Subject: [PATCH 15/15] remove comment --- test/plugin.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/plugin.test.js b/test/plugin.test.js index f5f888b..5a3bc73 100644 --- a/test/plugin.test.js +++ b/test/plugin.test.js @@ -104,7 +104,6 @@ if (!window.WebKitMediaKeys) { this.player.eme(); - // testing the rejection path because this isn't a real session this.player.eme.initializeMediaKeys({ keySystems: { 'org.w3.clearkey': {