diff --git a/src/eme.js b/src/eme.js index 8c70c7a..6ed0665 100644 --- a/src/eme.js +++ b/src/eme.js @@ -117,8 +117,13 @@ export const makeNewRequest = (requestOptions) => { } getLicense(options, event.message, contentId) - .then((license) => { - resolve(keySession.update(license)); + .then((licenses) => { + if (!Array.isArray(licenses)) { + licenses = [licenses]; + } + return Promise.all(licenses.map(function(license) { + return keySession.update(license); + })).then(resolve); }) .catch((err) => { reject(err); @@ -294,6 +299,17 @@ const defaultPlayreadyGetLicense = (keySystemOptions) => (emeOptions, keyMessage requestPlayreadyLicense(keySystemOptions, keyMessage, emeOptions, callback); }; +const requestLicense = function(options) { + return new Promise(function(resolve, reject) { + videojs.xhr(options, httpResponseHandler(function(err, body) { + if (err) { + return reject(err); + } + resolve(body); + }, true)); + }); +}; + export const defaultGetLicense = (keySystemOptions) => (emeOptions, keyMessage, callback) => { const headers = mergeAndRemoveNull( {'Content-type': 'application/octet-stream'}, @@ -301,13 +317,33 @@ export const defaultGetLicense = (keySystemOptions) => (emeOptions, keyMessage, keySystemOptions.licenseHeaders ); - videojs.xhr({ - uri: keySystemOptions.url, - method: 'POST', - responseType: 'arraybuffer', - body: keyMessage, - headers - }, httpResponseHandler(callback, true)); + const promises = []; + + if (keySystemOptions.url) { + promises.push(requestLicense({ + uri: keySystemOptions.url, + method: 'POST', + responseType: 'arraybuffer', + body: keyMessage, + headers + })); + } else if (keySystemOptions.urls) { + keySystemOptions.urls.forEach(function(url) { + promises.push(requestLicense({ + uri: url, + method: 'POST', + responseType: 'arraybuffer', + body: keyMessage, + headers + })); + }); + } + + Promise.all(promises).then(function(results) { + callback(null, results); + }).catch(function(error) { + callback(error, null); + }); }; const promisifyGetLicense = (keySystem, getLicenseFn, eventBus) => { @@ -343,8 +379,8 @@ const standardizeKeySystemOptions = (keySystem, keySystemOptions) => { keySystemOptions.url = keySystemOptions.licenseUri; } - if (!keySystemOptions.url && !keySystemOptions.getLicense) { - throw new Error(`Missing url/licenseUri or getLicense in ${keySystem} keySystem configuration.`); + if (!keySystemOptions.url && !keySystemOptions.urls && !keySystemOptions.getLicense) { + throw new Error(`Missing url/urls/licenseUri or getLicense in ${keySystem} keySystem configuration.`); } const isFairplay = isFairplayKeySystem(keySystem); @@ -361,7 +397,7 @@ const standardizeKeySystemOptions = (keySystem, keySystemOptions) => { keySystemOptions.getContentId = defaultFairplayGetContentId; } - if (keySystemOptions.url && !keySystemOptions.getLicense) { + if ((keySystemOptions.url || keySystemOptions.urls) && !keySystemOptions.getLicense) { if (keySystem === 'com.microsoft.playready') { keySystemOptions.getLicense = defaultPlayreadyGetLicense(keySystemOptions); } else if (isFairplay) { diff --git a/src/fairplay.js b/src/fairplay.js index 591b902..c97de1a 100644 --- a/src/fairplay.js +++ b/src/fairplay.js @@ -124,7 +124,7 @@ export const defaultGetCertificate = (fairplayOptions) => { // (we don't want httpResponseHandler to decode it) // convert it into Uint8Array as expected callback(null, new Uint8Array(license)); - })); + }, true)); }; }; diff --git a/test/eme.test.js b/test/eme.test.js index d1be434..ab54e88 100644 --- a/test/eme.test.js +++ b/test/eme.test.js @@ -11,7 +11,6 @@ import { getSupportedConfigurations } from '../src/eme'; import { getMockEventBus } from './utils'; -import sinon from 'sinon'; // mock session to make testing easier (so we can trigger events) const getMockSession = () => { @@ -600,7 +599,7 @@ QUnit.test('errors when missing url/licenseUri or getLicense', function(assert) }).catch((err) => { assert.equal( err, - 'Error: Missing url/licenseUri or getLicense in com.widevine.alpha keySystem configuration.', + 'Error: Missing url/urls/licenseUri or getLicense in com.widevine.alpha keySystem configuration.', 'correct error message' ); done(); @@ -879,8 +878,14 @@ QUnit.test('getLicense promise rejection', function(assert) { }); QUnit.test('getLicense calls back with error for 400 and 500 status codes', function(assert) { - const getLicenseCallback = sinon.spy(); - const getLicense = defaultGetLicense({}); + assert.expect(9); + const done = assert.async(3); + const getLicenseCallback = function(error, result) { + assert.deepEqual(error, {cause: '{"body":"some-body"}'}, 'expected error'); + assert.notOk(result, 'no result'); + done(); + }; + const getLicense = defaultGetLicense({url: 'foo'}); function toArrayBuffer(obj) { const json = JSON.stringify(obj); @@ -894,53 +899,59 @@ QUnit.test('getLicense calls back with error for 400 and 500 status codes', func } videojs.xhr = (params, callback) => { + assert.ok(true, 'sent statusCode 400'); return callback(null, {statusCode: 400}, toArrayBuffer({body: 'some-body'})); }; getLicense({}, null, getLicenseCallback); videojs.xhr = (params, callback) => { + assert.ok(true, 'sent statusCode 500'); return callback(null, {statusCode: 500}, toArrayBuffer({body: 'some-body'})); }; getLicense({}, null, getLicenseCallback); videojs.xhr = (params, callback) => { + assert.ok(true, 'sent statusCode 599'); return callback(null, {statusCode: 599}, toArrayBuffer({body: 'some-body'})); }; getLicense({}, null, getLicenseCallback); - assert.equal(getLicenseCallback.callCount, 3, 'correct callcount'); - assert.ok(getLicenseCallback.alwaysCalledWith({ - cause: JSON.stringify({body: 'some-body'}) - }), 'getLicense callback called with correct error'); }); QUnit.test('getLicense calls back with response body for non-400/500 status codes', function(assert) { - const getLicenseCallback = sinon.spy(); - const getLicense = defaultGetLicense({}); + assert.expect(9); + const done = assert.async(3); + const getLicenseCallback = function(error, result) { + assert.notOk(error, 'no error'); + assert.deepEqual(result, [{body: 'some-body'}], 'expected result'); + done(); + }; + const getLicense = defaultGetLicense({url: 'foo'}); videojs.xhr = (params, callback) => { + assert.ok(true, '200 statuscode'); return callback(null, {statusCode: 200}, {body: 'some-body'}); }; getLicense({}, null, getLicenseCallback); videojs.xhr = (params, callback) => { + assert.ok(true, '399 statuscode'); return callback(null, {statusCode: 399}, {body: 'some-body'}); }; getLicense({}, null, getLicenseCallback); videojs.xhr = (params, callback) => { + assert.ok(true, '600 statuscode'); return callback(null, {statusCode: 600}, {body: 'some-body'}); }; getLicense({}, null, getLicenseCallback); - assert.equal(getLicenseCallback.callCount, 3, 'correct callcount'); - assert.equal(getLicenseCallback.alwaysCalledWith(null, {body: 'some-body'}), true, 'getLicense callback called with correct args'); }); QUnit.test('keySession.update promise rejection', function(assert) {