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

Pass EME options to each user specified method #3

Merged
merged 1 commit into from
Sep 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 65 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,16 @@ Below is an example of videojs-contrib-eme options when only using FairPlay:
{
keySystems: {
"com.apple.fps.1_0": {
getCertificate: (options, callback) => {
getCertificate: (emeOptions, callback) => {
// request certificate
// if err, callback(err)
// if success, callback(null, certificate)
},
getContentId: (initData) => {
getContentId: (emeOptions, initData) => {
// return content ID
},
getLicense: (options, callback) => {
let { contentId, webKitKeyMessage } = options;

// request key using options
getLicense: (emeOptions, contentId, keyMessage, callback) => {
// request key
// if err, callback(err)
// if success, callback(null, key) as arraybuffer
}
Expand Down Expand Up @@ -104,15 +102,13 @@ systems:
"org.w3.clearkey": {
videoContentType: 'audio/webm; codecs="vorbis"',
audioContentType: 'video/webm; codecs="vp9"',
getCertificate: (options, callback) => {
getCertificate: (emeOptions, callback) => {
// request certificate
// if err, callback(err)
// if success, callback(null, certificate)
},
getLicense: (options, callback) => {
let keyMessage = options.keyMessage;

// request license using mediaKeyMessage
getLicense: (emeOptions, keyMessage, callback) => {
// request license
// if err, callback(err)
// if success, callback(null, license)
}
Expand Down Expand Up @@ -140,15 +136,13 @@ player.src({
'org.w3.clearkey': {
videoContentType: 'audio/webm; codecs="vorbis"',
audioContentType: 'video/webm; codecs="vp9"',
getCertificate: (options, callback) => {
getCertificate: (emeOptions, callback) => {
// request certificate
// if err, callback(err)
// if success, callback(null, certificate)
},
getLicense: (options, callback) => {
let keyMessage = options.keyMessage;

// request license using mediaKeyMessage
getLicense: (emeOptions, keyMessage, callback) => {
// request license
// if err, callback(err)
// if success, callback(null, license)
}
Expand All @@ -157,6 +151,61 @@ player.src({
});
```

### `emeOptions`

`emeOptions` are provided for all methods. This is a reference to the plugin options
merged with (overwritten by) the source options for the current source. It is available to
make it easier to access options so that you don't have to maintain them yourself.

For example. If you need to use a userId for the getCertificate request, you can pass in
plugin options that have:

```javascript
{
keySystems: {
"org.w3.clearkey": {
getCertificate: (emeOptions, callback) => {
let userId = emeOptions.userId; // 'user-id'
// ...
},
getLicense: (emeOptions, keyMessage, callback) => {
let userId = emeOptions.userId; // 'user-id'
// ...
}
}
},
userId: 'user-id'
}
```

Or, if you need a source-specific userId, you can overwrite it via the source options:

```javascript
// plugin options
{
keySystems: {
"org.w3.clearkey": {
getCertificate: (emeOptions, callback) => {
let userId = emeOptions.userId; // 'source-specific-user-id'
// ...
},
getLicense: (emeOptions, keyMessage, callback) => {
let userId = emeOptions.userId; // 'source-specific-user-id'
// ...
}
}
},
userId: 'user-id'
}

// source options
player.src({
src: '<URL>',
type: 'video/webm',
userId: 'source-specific-user-id'
});
```

### Passing methods seems complicated

If you're wondering why there are so many methods to implement, and why the options can't
Expand Down
3 changes: 1 addition & 2 deletions index-player-options.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@
eme: {
keySystems: {
'org.w3.clearkey': {
getLicense: (options, callback) => {
let keyMessage = options.keyMessage;
getLicense: (emeOptions, keyMessage, callback) => {
// Parse the clearkey license request.
let request = JSON.parse(new TextDecoder().decode(keyMessage));
// We only know one key, so there should only be one key ID.
Expand Down
3 changes: 1 addition & 2 deletions index-source-options.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@
type: 'video/webm',
keySystems: {
'org.w3.clearkey': {
getLicense: (options, callback) => {
let keyMessage = options.keyMessage;
getLicense: (emeOptions, keyMessage, callback) => {
// Parse the clearkey license request.
let request = JSON.parse(new TextDecoder().decode(keyMessage));
// We only know one key, so there should only be one key ID.
Expand Down
18 changes: 11 additions & 7 deletions src/eme.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ const getSupportedKeySystem = ({video, keySystems}) => {
return promise;
};

const makeNewRequest = ({mediaKeys, initDataType, initData, getLicense}) => {
const makeNewRequest = ({mediaKeys, initDataType, initData, options, getLicense}) => {
let keySession = mediaKeys.createSession();

keySession.addEventListener('message', (event) => {
getLicense(event.message)
getLicense(options, event.message)
.then((license) => {
return keySession.update(license);
})
Expand All @@ -52,20 +52,21 @@ const makeNewRequest = ({mediaKeys, initDataType, initData, getLicense}) => {
);
};

const addSession = ({video, initDataType, initData, getLicense}) => {
const addSession = ({video, initDataType, initData, options, getLicense}) => {
if (video.mediaKeysObject) {
makeNewRequest({
mediaKeys: video.mediaKeysObject,
initDataType,
initData,
options,
getLicense
});
} else {
video.pendingSessionData.push({initDataType, initData});
}
};

const setMediaKeys = ({video, certificate, createdMediaKeys, getLicense}) => {
const setMediaKeys = ({video, certificate, createdMediaKeys, options, getLicense}) => {
video.mediaKeysObject = createdMediaKeys;

if (certificate) {
Expand All @@ -79,6 +80,7 @@ const setMediaKeys = ({video, certificate, createdMediaKeys, getLicense}) => {
mediaKeys: video.mediaKeysObject,
initDataType: data.initDataType,
initData: data.initData,
options,
getLicense
});
}
Expand All @@ -89,9 +91,9 @@ const setMediaKeys = ({video, certificate, createdMediaKeys, getLicense}) => {
};

const promisifyGetLicense = (getLicenseFn) => {
return (keyMessage) => {
return (emeOptions, keyMessage) => {
return new Promise((resolve, reject) => {
getLicenseFn({ keyMessage }, (err, license) => {
getLicenseFn(emeOptions, keyMessage, (err, license) => {
if (err) {
reject(err);
}
Expand Down Expand Up @@ -127,7 +129,7 @@ export const standard5July2016 = ({video, initDataType, initData, options}) => {
resolve(keySystemAccess);
}

keySystemOptions.getCertificate({}, (err, cert) => {
keySystemOptions.getCertificate(options, (err, cert) => {
if (err) {
reject(err);
return;
Expand All @@ -145,6 +147,7 @@ export const standard5July2016 = ({video, initDataType, initData, options}) => {
video,
certificate,
createdMediaKeys,
options,
getLicense: promisifyGetLicense(keySystemOptions.getLicense)
});
}).catch(
Expand All @@ -157,6 +160,7 @@ export const standard5July2016 = ({video, initDataType, initData, options}) => {
video,
initDataType,
initData,
options,
// if key system has not been determined then addSession doesn't need getLicense
getLicense: video.keySystem ?
promisifyGetLicense(options.keySystems[video.keySystem].getLicense) :
Expand Down
20 changes: 9 additions & 11 deletions src/fairplay.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const concatInitDataIdAndCertificate = ({initData, id, cert}) => {
return new Uint8Array(buffer, 0, buffer.byteLength);
};

const addKey = ({video, contentId, initData, cert, getLicense}) => {
const addKey = ({video, contentId, initData, cert, options, getLicense}) => {
return new Promise((resolve, reject) => {
if (!video.webkitKeys) {
video.webkitSetMediaKeys(new window.WebKitMediaKeys(FAIRPLAY_KEY_SYSTEM));
Expand All @@ -65,10 +65,7 @@ const addKey = ({video, contentId, initData, cert, getLicense}) => {
keySession.contentId = contentId;

keySession.addEventListener('webkitkeymessage', (event) => {
getLicense({
contentId,
webKitKeyMessage: event.message
}, (err, license) => {
getLicense(options, contentId, event.message, (err, license) => {
if (err) {
reject(err);
return;
Expand All @@ -90,7 +87,7 @@ const addKey = ({video, contentId, initData, cert, getLicense}) => {
};

const defaultGetCertificate = (certificateUri) => {
return (options, callback) => {
return (emeOptions, callback) => {
videojs.xhr({
uri: certificateUri,
responseType: 'arraybuffer'
Expand All @@ -105,17 +102,17 @@ const defaultGetCertificate = (certificateUri) => {
};
};

const defaultGetContentId = (initData) => {
const defaultGetContentId = (emeOptions, initData) => {
return getHostnameFromUri(uint8ArrayToString(initData));
};

const defaultGetLicense = (licenseUri) => {
return (options, callback) => {
return (emeOptions, contentId, keyMessage, callback) => {
videojs.xhr({
uri: licenseUri,
method: 'POST',
responseType: 'arraybuffer',
body: options.webKitKeyMessage,
body: keyMessage,
headers: {
'Content-type': 'application/octet-stream'
}
Expand All @@ -139,7 +136,7 @@ const fairplay = ({video, initData, options}) => {
defaultGetLicense(fairplayOptions.licenseUri);

return new Promise((resolve, reject) => {
getCertificate({}, (err, cert) => {
getCertificate(options, (err, cert) => {
if (err) {
reject(err);
return;
Expand All @@ -153,7 +150,8 @@ const fairplay = ({video, initData, options}) => {
cert,
initData,
getLicense,
contentId: getContentId(initData)
options,
contentId: getContentId(options, initData)
});
}).catch(videojs.log.error.bind(videojs.log.error));
};
Expand Down
4 changes: 2 additions & 2 deletions test/eme.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ QUnit.test('5 July 2016 lifecycle', function(assert) {
});
};

let getCertificate = (options, callback) => {
let getCertificate = (emeOptions, callback) => {
callCounts.getCertificate++;
callbacks.getCertificate = callback;
};
let getLicense = (options, callback) => {
let getLicense = (emeOptions, keyMessage, callback) => {
callCounts.getLicense++;
callbacks.getLicense = callback;
};
Expand Down
4 changes: 2 additions & 2 deletions test/fairplay.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ QUnit.test('lifecycle', function(assert) {
createSession: 0
};

let getCertificate = (options, callback) => {
let getCertificate = (emeOptions, callback) => {
callCounts.getCertificate++;
callbacks.getCertificate = callback;
};
let getLicense = (options, callback) => {
let getLicense = (emeOptions, contentId, keyMessage, callback) => {
callCounts.getLicense++;
callbacks.getLicense = callback;
};
Expand Down