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

feat: added API to set media keys directly #61

Merged
merged 15 commits into from
Oct 24, 2018
35 changes: 31 additions & 4 deletions src/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,18 +231,45 @@ const onPlayerReady = (player) => {
* to you; if not, remove the wait for "ready"!
*
* @function eme
* @param {Object} [player]
* A playerobject.
Copy link
Contributor

Choose a reason for hiding this comment

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

player object

* @param {Object} [options={}]
* An object of options left to the plugin author to define.
*/
const eme = function(options = {}) {

Choose a reason for hiding this comment

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

This worked for me:

const eme = function(options = {}) {
  const player = this;

  this.ready(() => onPlayerReady(this));

  this.eme = {
    initializeMediaKeys(emeOptions = {}) {
      const mergedEmeOptions = videojs.mergeOptions(
        player.currentSource(),
        options,
        emeOptions
      );

      return initializeMediaKeys(player, mergedEmeOptions);
    },
    options
  };
};

// Register the plugin with video.js.
const registerPlugin = videojs.registerPlugin || videojs.plugin;

registerPlugin('eme', eme);

to be clear, I'm trying to avoid an anonymous function being the plugin factory here

this.eme.options = options;
const eme = function(player, options = {}) {
const initializeMediaKeys = (emeOptions = {}) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be easier to read (and potentially test) if we make this a top level function.

const e = {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should use a more descriptive variable name. Maybe something like mockEncryptedEvent or something alongside a comment.

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));

this.ready(() => onPlayerReady(this));
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;
67 changes: 67 additions & 0 deletions test/plugin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this testing a rejection?

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 = {
Expand Down