@l5i/dashjs
Version:
A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers.
1,159 lines (995 loc) • 223 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}(g.dashjs || (g.dashjs = {})).Protection = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
/**
* The copyright in this software is being made available under the BSD License,
* included below. This software may be subject to other third party and contributor
* rights, including patent rights, and no such rights are granted under this license.
*
* Copyright (c) 2013, Dash Industry Forum.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* * Neither the name of Dash Industry Forum nor the names of its
* contributors may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @class
* @ignore
*/
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var ErrorsBase = (function () {
function ErrorsBase() {
_classCallCheck(this, ErrorsBase);
}
_createClass(ErrorsBase, [{
key: 'extend',
value: function extend(errors, config) {
if (!errors) return;
var override = config ? config.override : false;
var publicOnly = config ? config.publicOnly : false;
for (var err in errors) {
if (!errors.hasOwnProperty(err) || this[err] && !override) continue;
if (publicOnly && errors[err].indexOf('public_') === -1) continue;
this[err] = errors[err];
}
}
}]);
return ErrorsBase;
})();
exports['default'] = ErrorsBase;
module.exports = exports['default'];
},{}],2:[function(_dereq_,module,exports){
/**
* The copyright in this software is being made available under the BSD License,
* included below. This software may be subject to other third party and contributor
* rights, including patent rights, and no such rights are granted under this license.
*
* Copyright (c) 2013, Dash Industry Forum.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* * Neither the name of Dash Industry Forum nor the names of its
* contributors may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @class
* @ignore
*/
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var EventsBase = (function () {
function EventsBase() {
_classCallCheck(this, EventsBase);
}
_createClass(EventsBase, [{
key: 'extend',
value: function extend(events, config) {
if (!events) return;
var override = config ? config.override : false;
var publicOnly = config ? config.publicOnly : false;
for (var evt in events) {
if (!events.hasOwnProperty(evt) || this[evt] && !override) continue;
if (publicOnly && events[evt].indexOf('public_') === -1) continue;
this[evt] = events[evt];
}
}
}]);
return EventsBase;
})();
exports['default'] = EventsBase;
module.exports = exports['default'];
},{}],3:[function(_dereq_,module,exports){
/**
* The copyright in this software is being made available under the BSD License,
* included below. This software may be subject to other third party and contributor
* rights, including patent rights, and no such rights are granted under this license.
*
* Copyright (c) 2013, Dash Industry Forum.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* * Neither the name of Dash Industry Forum nor the names of its
* contributors may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Protection Constants declaration
* @class
* @ignore
*/
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var ProtectionConstants = (function () {
_createClass(ProtectionConstants, [{
key: 'init',
value: function init() {
this.CLEARKEY_KEYSTEM_STRING = 'org.w3.clearkey';
this.WIDEVINE_KEYSTEM_STRING = 'com.widevine.alpha';
this.PLAYREADY_KEYSTEM_STRING = 'com.microsoft.playready';
}
}]);
function ProtectionConstants() {
_classCallCheck(this, ProtectionConstants);
this.init();
}
return ProtectionConstants;
})();
var constants = new ProtectionConstants();
exports['default'] = constants;
module.exports = exports['default'];
},{}],4:[function(_dereq_,module,exports){
/**
* The copyright in this software is being made available under the BSD License,
* included below. This software may be subject to other third party and contributor
* rights, including patent rights, and no such rights are granted under this license.
*
* Copyright (c) 2013, Dash Industry Forum.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* * Neither the name of Dash Industry Forum nor the names of its
* contributors may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var CommonEncryption = (function () {
function CommonEncryption() {
_classCallCheck(this, CommonEncryption);
}
_createClass(CommonEncryption, null, [{
key: 'findCencContentProtection',
/**
* Find and return the ContentProtection element in the given array
* that indicates support for MPEG Common Encryption
*
* @param {Array} cpArray array of content protection elements
* @returns {Object|null} the Common Encryption content protection element or
* null if one was not found
*/
value: function findCencContentProtection(cpArray) {
var retVal = null;
for (var i = 0; i < cpArray.length; ++i) {
var cp = cpArray[i];
if (cp.schemeIdUri.toLowerCase() === 'urn:mpeg:dash:mp4protection:2011' && cp.value.toLowerCase() === 'cenc') retVal = cp;
}
return retVal;
}
/**
* Returns just the data portion of a single PSSH
*
* @param {ArrayBuffer} pssh - the PSSH
* @return {ArrayBuffer} data portion of the PSSH
*/
}, {
key: 'getPSSHData',
value: function getPSSHData(pssh) {
var offset = 8; // Box size and type fields
var view = new DataView(pssh);
// Read version
var version = view.getUint8(offset);
offset += 20; // Version (1), flags (3), system ID (16)
if (version > 0) {
offset += 4 + 16 * view.getUint32(offset); // Key ID count (4) and All key IDs (16*count)
}
offset += 4; // Data size
return pssh.slice(offset);
}
/**
* Returns the PSSH associated with the given key system from the concatenated
* list of PSSH boxes in the given initData
*
* @param {KeySystem} keySystem the desired
* key system
* @param {ArrayBuffer} initData 'cenc' initialization data. Concatenated list of PSSH.
* @returns {ArrayBuffer|null} The PSSH box data corresponding to the given key system, null if not found
* or null if a valid association could not be found.
*/
}, {
key: 'getPSSHForKeySystem',
value: function getPSSHForKeySystem(keySystem, initData) {
var psshList = CommonEncryption.parsePSSHList(initData);
if (psshList.hasOwnProperty(keySystem.uuid.toLowerCase())) {
return psshList[keySystem.uuid.toLowerCase()];
}
return null;
}
/**
* Parse a standard common encryption PSSH which contains a simple
* base64-encoding of the init data
*
* @param {Object} cpData the ContentProtection element
* @param {BASE64} BASE64 reference
* @returns {ArrayBuffer|null} the init data or null if not found
*/
}, {
key: 'parseInitDataFromContentProtection',
value: function parseInitDataFromContentProtection(cpData, BASE64) {
if ('pssh' in cpData) {
return BASE64.decodeArray(cpData.pssh.__text).buffer;
}
return null;
}
/**
* Parses list of PSSH boxes into keysystem-specific PSSH data
*
* @param {ArrayBuffer} data - the concatenated list of PSSH boxes as provided by
* CDM as initialization data when CommonEncryption content is detected
* @returns {Object|Array} an object that has a property named according to each of
* the detected key system UUIDs (e.g. 00000000-0000-0000-0000-0000000000)
* and a ArrayBuffer (the entire PSSH box) as the property value
*/
}, {
key: 'parsePSSHList',
value: function parsePSSHList(data) {
if (data === null) return [];
var dv = new DataView(data.buffer || data); // data.buffer first for Uint8Array support
var done = false;
var pssh = {};
// TODO: Need to check every data read for end of buffer
var byteCursor = 0;
while (!done) {
var size = undefined,
nextBox = undefined,
version = undefined,
systemID = undefined,
psshDataSize = undefined;
var boxStart = byteCursor;
if (byteCursor >= dv.buffer.byteLength) break;
/* Box size */
size = dv.getUint32(byteCursor);
nextBox = byteCursor + size;
byteCursor += 4;
/* Verify PSSH */
if (dv.getUint32(byteCursor) !== 0x70737368) {
byteCursor = nextBox;
continue;
}
byteCursor += 4;
/* Version must be 0 or 1 */
version = dv.getUint8(byteCursor);
if (version !== 0 && version !== 1) {
byteCursor = nextBox;
continue;
}
byteCursor++;
byteCursor += 3; /* skip flags */
// 16-byte UUID/SystemID
systemID = '';
var i = undefined,
val = undefined;
for (i = 0; i < 4; i++) {
val = dv.getUint8(byteCursor + i).toString(16);
systemID += val.length === 1 ? '0' + val : val;
}
byteCursor += 4;
systemID += '-';
for (i = 0; i < 2; i++) {
val = dv.getUint8(byteCursor + i).toString(16);
systemID += val.length === 1 ? '0' + val : val;
}
byteCursor += 2;
systemID += '-';
for (i = 0; i < 2; i++) {
val = dv.getUint8(byteCursor + i).toString(16);
systemID += val.length === 1 ? '0' + val : val;
}
byteCursor += 2;
systemID += '-';
for (i = 0; i < 2; i++) {
val = dv.getUint8(byteCursor + i).toString(16);
systemID += val.length === 1 ? '0' + val : val;
}
byteCursor += 2;
systemID += '-';
for (i = 0; i < 6; i++) {
val = dv.getUint8(byteCursor + i).toString(16);
systemID += val.length === 1 ? '0' + val : val;
}
byteCursor += 6;
systemID = systemID.toLowerCase();
/* PSSH Data Size */
psshDataSize = dv.getUint32(byteCursor);
byteCursor += 4;
/* PSSH Data */
pssh[systemID] = dv.buffer.slice(boxStart, nextBox);
byteCursor = nextBox;
}
return pssh;
}
}]);
return CommonEncryption;
})();
exports['default'] = CommonEncryption;
module.exports = exports['default'];
},{}],5:[function(_dereq_,module,exports){
/**
* The copyright in this software is being made available under the BSD License,
* included below. This software may be subject to other third party and contributor
* rights, including patent rights, and no such rights are granted under this license.
*
* Copyright (c) 2013, Dash Industry Forum.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* * Neither the name of Dash Industry Forum nor the names of its
* contributors may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _controllersProtectionController = _dereq_(7);
var _controllersProtectionController2 = _interopRequireDefault(_controllersProtectionController);
var _controllersProtectionKeyController = _dereq_(8);
var _controllersProtectionKeyController2 = _interopRequireDefault(_controllersProtectionKeyController);
var _ProtectionEvents = _dereq_(6);
var _ProtectionEvents2 = _interopRequireDefault(_ProtectionEvents);
var _errorsProtectionErrors = _dereq_(13);
var _errorsProtectionErrors2 = _interopRequireDefault(_errorsProtectionErrors);
var _modelsProtectionModel_21Jan2015 = _dereq_(15);
var _modelsProtectionModel_21Jan20152 = _interopRequireDefault(_modelsProtectionModel_21Jan2015);
var _modelsProtectionModel_3Feb2014 = _dereq_(16);
var _modelsProtectionModel_3Feb20142 = _interopRequireDefault(_modelsProtectionModel_3Feb2014);
var _modelsProtectionModel_01b = _dereq_(14);
var _modelsProtectionModel_01b2 = _interopRequireDefault(_modelsProtectionModel_01b);
var APIS_ProtectionModel_01b = [
// Un-prefixed as per spec
{
// Video Element
generateKeyRequest: 'generateKeyRequest',
addKey: 'addKey',
cancelKeyRequest: 'cancelKeyRequest',
// Events
needkey: 'needkey',
keyerror: 'keyerror',
keyadded: 'keyadded',
keymessage: 'keymessage'
},
// Webkit-prefixed (early Chrome versions and Chrome with EME disabled in chrome://flags)
{
// Video Element
generateKeyRequest: 'webkitGenerateKeyRequest',
addKey: 'webkitAddKey',
cancelKeyRequest: 'webkitCancelKeyRequest',
// Events
needkey: 'webkitneedkey',
keyerror: 'webkitkeyerror',
keyadded: 'webkitkeyadded',
keymessage: 'webkitkeymessage'
}];
var APIS_ProtectionModel_3Feb2014 = [
// Un-prefixed as per spec
// Chrome 38-39 (and some earlier versions) with chrome://flags -- Enable Encrypted Media Extensions
{
// Video Element
setMediaKeys: 'setMediaKeys',
// MediaKeys
MediaKeys: 'MediaKeys',
// MediaKeySession
release: 'close',
// Events
needkey: 'needkey',
error: 'keyerror',
message: 'keymessage',
ready: 'keyadded',
close: 'keyclose'
},
// MS-prefixed (IE11, Windows 8.1)
{
// Video Element
setMediaKeys: 'msSetMediaKeys',
// MediaKeys
MediaKeys: 'MSMediaKeys',
// MediaKeySession
release: 'close',
// Events
needkey: 'msneedkey',
error: 'mskeyerror',
message: 'mskeymessage',
ready: 'mskeyadded',
close: 'mskeyclose'
}];
function Protection() {
var instance = undefined;
var context = this.context;
/**
* Create a ProtectionController and associated ProtectionModel for use with
* a single piece of content.
*
* @param {Object} config
* @return {ProtectionController} protection controller
*
*/
function createProtectionSystem(config) {
var controller = null;
var protectionKeyController = (0, _controllersProtectionKeyController2['default'])(context).getInstance();
protectionKeyController.setConfig({ debug: config.debug, BASE64: config.BASE64 });
protectionKeyController.initialize();
var protectionModel = getProtectionModel(config);
if (!controller && protectionModel) {
//TODO add ability to set external controller if still needed at all?
controller = (0, _controllersProtectionController2['default'])(context).create({
protectionModel: protectionModel,
protectionKeyController: protectionKeyController,
eventBus: config.eventBus,
debug: config.debug,
events: config.events,
BASE64: config.BASE64,
constants: config.constants
});
config.capabilities.setEncryptedMediaSupported(true);
}
return controller;
}
function getProtectionModel(config) {
var debug = config.debug;
var logger = debug.getLogger(instance);
var eventBus = config.eventBus;
var errHandler = config.errHandler;
var videoElement = config.videoModel ? config.videoModel.getElement() : null;
if ((!videoElement || videoElement.onencrypted !== undefined) && (!videoElement || videoElement.mediaKeys !== undefined)) {
logger.info('EME detected on this user agent! (ProtectionModel_21Jan2015)');
return (0, _modelsProtectionModel_21Jan20152['default'])(context).create({ debug: debug, eventBus: eventBus, events: config.events });
} else if (getAPI(videoElement, APIS_ProtectionModel_3Feb2014)) {
logger.info('EME detected on this user agent! (ProtectionModel_3Feb2014)');
return (0, _modelsProtectionModel_3Feb20142['default'])(context).create({ debug: debug, eventBus: eventBus, events: config.events, api: getAPI(videoElement, APIS_ProtectionModel_3Feb2014) });
} else if (getAPI(videoElement, APIS_ProtectionModel_01b)) {
logger.info('EME detected on this user agent! (ProtectionModel_01b)');
return (0, _modelsProtectionModel_01b2['default'])(context).create({ debug: debug, eventBus: eventBus, errHandler: errHandler, events: config.events, api: getAPI(videoElement, APIS_ProtectionModel_01b) });
} else {
logger.warn('No supported version of EME detected on this user agent! - Attempts to play encrypted content will fail!');
return null;
}
}
function getAPI(videoElement, apis) {
for (var i = 0; i < apis.length; i++) {
var api = apis[i];
// detect if api is supported by browser
// check only first function in api -> should be fine
if (typeof videoElement[api[Object.keys(api)[0]]] !== 'function') {
continue;
}
return api;
}
return null;
}
instance = {
createProtectionSystem: createProtectionSystem
};
return instance;
}
Protection.__dashjs_factory_name = 'Protection';
var factory = dashjs.FactoryMaker.getClassFactory(Protection); /* jshint ignore:line */
factory.events = _ProtectionEvents2['default'];
factory.errors = _errorsProtectionErrors2['default'];
dashjs.FactoryMaker.updateClassFactory(Protection.__dashjs_factory_name, factory); /* jshint ignore:line */
exports['default'] = factory;
module.exports = exports['default'];
},{"13":13,"14":14,"15":15,"16":16,"6":6,"7":7,"8":8}],6:[function(_dereq_,module,exports){
/**
* The copyright in this software is being made available under the BSD License,
* included below. This software may be subject to other third party and contributor
* rights, including patent rights, and no such rights are granted under this license.
*
* Copyright (c) 2013, Dash Industry Forum.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* * Neither the name of Dash Industry Forum nor the names of its
* contributors may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _coreEventsEventsBase = _dereq_(2);
var _coreEventsEventsBase2 = _interopRequireDefault(_coreEventsEventsBase);
/**
* @class
*
*/
var ProtectionEvents = (function (_EventsBase) {
_inherits(ProtectionEvents, _EventsBase);
/**
* @description Public facing external events to be used when including protection package.
* All public events will be aggregated into the MediaPlayerEvents Class and can be accessed
* via MediaPlayer.events. public_ is the prefix that we use to move event names to MediaPlayerEvents.
*/
function ProtectionEvents() {
_classCallCheck(this, ProtectionEvents);
_get(Object.getPrototypeOf(ProtectionEvents.prototype), 'constructor', this).call(this);
/**
* Event ID for events delivered when the protection set receives
* a key message from the CDM
*
* @ignore
*/
this.INTERNAL_KEY_MESSAGE = 'internalKeyMessage';
/**
* Event ID for events delivered when a key system selection procedure
* completes
* @ignore
*/
this.INTERNAL_KEY_SYSTEM_SELECTED = 'internalKeySystemSelected';
/**
* Event ID for events delivered when the status of one decryption keys has changed
* @ignore
*/
this.INTERNAL_KEY_STATUS_CHANGED = 'internalkeyStatusChanged';
/**
* Event ID for events delivered when a new key has been added
*
* @constant
* @deprecated The latest versions of the EME specification no longer
* use this event. {@MediaPlayer.models.protectionModel.eventList.KEY_STATUSES_CHANGED}
* is preferred.
* @event ProtectionEvents#KEY_ADDED
*/
this.KEY_ADDED = 'public_keyAdded';
/**
* Event ID for events delivered when an error is encountered by the CDM
* while processing a license server response message
* @event ProtectionEvents#KEY_ERROR
*/
this.KEY_ERROR = 'public_keyError';
/**
* Event ID for events delivered when the protection set receives
* a key message from the CDM
* @event ProtectionEvents#KEY_MESSAGE
*/
this.KEY_MESSAGE = 'public_keyMessage';
/**
* Event ID for events delivered when a key session close
* process has completed
* @event ProtectionEvents#KEY_SESSION_CLOSED
*/
this.KEY_SESSION_CLOSED = 'public_keySessionClosed';
/**
* Event ID for events delivered when a new key sessions creation
* process has completed
* @event ProtectionEvents#KEY_SESSION_CREATED
*/
this.KEY_SESSION_CREATED = 'public_keySessionCreated';
/**
* Event ID for events delivered when a key session removal
* process has completed
* @event ProtectionEvents#KEY_SESSION_REMOVED
*/
this.KEY_SESSION_REMOVED = 'public_keySessionRemoved';
/**
* Event ID for events delivered when the status of one or more
* decryption keys has changed
* @event ProtectionEvents#KEY_STATUSES_CHANGED
*/
this.KEY_STATUSES_CHANGED = 'public_keyStatusesChanged';
/**
* Event ID for events delivered when a key system access procedure
* has completed
* @ignore
*/
this.KEY_SYSTEM_ACCESS_COMPLETE = 'public_keySystemAccessComplete';
/**
* Event ID for events delivered when a key system selection procedure
* completes
* @event ProtectionEvents#KEY_SYSTEM_SELECTED
*/
this.KEY_SYSTEM_SELECTED = 'public_keySystemSelected';
/**
* Event ID for events delivered when a license request procedure
* has completed
* @event ProtectionEvents#LICENSE_REQUEST_COMPLETE
*/
this.LICENSE_REQUEST_COMPLETE = 'public_licenseRequestComplete';
/**
* Event ID for needkey/encrypted events
* @ignore
*/
this.NEED_KEY = 'needkey';
/**
* Event ID for events delivered when the Protection system is detected and created.
* @event ProtectionEvents#PROTECTION_CREATED
*/
this.PROTECTION_CREATED = 'public_protectioncreated';
/**
* Event ID for events delivered when the Protection system is destroyed.
* @event ProtectionEvents#PROTECTION_DESTROYED
*/
this.PROTECTION_DESTROYED = 'public_protectiondestroyed';
/**
* Event ID for events delivered when a new server certificate has
* been delivered to the CDM
* @ignore
*/
this.SERVER_CERTIFICATE_UPDATED = 'serverCertificateUpdated';
/**
* Event ID for events delivered when the process of shutting down
* a protection set has completed
* @ignore
*/
this.TEARDOWN_COMPLETE = 'protectionTeardownComplete';
/**
* Event ID for events delivered when a HTMLMediaElement has been
* associated with the protection set
* @ignore
*/
this.VIDEO_ELEMENT_SELECTED = 'videoElementSelected';
}
return ProtectionEvents;
})(_coreEventsEventsBase2['default']);
var protectionEvents = new ProtectionEvents();
exports['default'] = protectionEvents;
module.exports = exports['default'];
},{"2":2}],7:[function(_dereq_,module,exports){
/**
* The copyright in this software is being made available under the BSD License,
* included below. This software may be subject to other third party and contributor
* rights, including patent rights, and no such rights are granted under this license.
*
* Copyright (c) 2013, Dash Industry Forum.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* * Neither the name of Dash Industry Forum nor the names of its
* contributors may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _CommonEncryption = _dereq_(4);
var _CommonEncryption2 = _interopRequireDefault(_CommonEncryption);
var _voMediaCapability = _dereq_(26);
var _voMediaCapability2 = _interopRequireDefault(_voMediaCapability);
var _voKeySystemConfiguration = _dereq_(25);
var _voKeySystemConfiguration2 = _interopRequireDefault(_voKeySystemConfiguration);
var _errorsProtectionErrors = _dereq_(13);
var _errorsProtectionErrors2 = _interopRequireDefault(_errorsProtectionErrors);
var _voDashJSError = _dereq_(28);
var _voDashJSError2 = _interopRequireDefault(_voDashJSError);
var NEEDKEY_BEFORE_INITIALIZE_RETRIES = 5;
var NEEDKEY_BEFORE_INITIALIZE_TIMEOUT = 500;
/**
* @module ProtectionController
* @description Provides access to media protection information and functionality. Each
* ProtectionController manages a single {@link MediaPlayer.models.ProtectionModel}
* which encapsulates a set of protection information (EME APIs, selected key system,
* key sessions). The APIs of ProtectionController mostly align with the latest EME
* APIs. Key system selection is mostly automated when combined with app-overrideable
* functionality provided in {@link ProtectionKeyController}.
* @todo ProtectionController does almost all of its tasks automatically after init() is
* called. Applications might want more control over this process and want to go through
* each step manually (key system selection, session creation, session maintenance).
* @param {Object} config
*/
function ProtectionController(config) {
config = config || {};
var protectionKeyController = config.protectionKeyController;
var protectionModel = config.protectionModel;
var eventBus = config.eventBus;
var events = config.events;
var debug = config.debug;
var BASE64 = config.BASE64;
var constants = config.constants;
var needkeyRetries = [];
var instance = undefined,
logger = undefined,
pendingNeedKeyData = undefined,
mediaInfoArr = undefined,
protDataSet = undefined,
sessionType = undefined,
robustnessLevel = undefined,
keySystem = undefined;
function setup() {
logger = debug.getLogger(instance);
pendingNeedKeyData = [];
mediaInfoArr = [];
sessionType = 'temporary';
robustnessLevel = '';
}
function checkConfig() {
if (!eventBus || !eventBus.hasOwnProperty('on') || !protectionKeyController || !protectionKeyController.hasOwnProperty('getSupportedKeySystemsFromContentProtection')) {
throw new Error('Missing config parameter(s)');
}
}
/**
* Initialize this protection system with a given audio
* or video stream information.
*
* @param {StreamInfo} [mediaInfo] Media information
* @memberof module:ProtectionController
* @instance
* @todo This API will change when we have better support for allowing applications
* to select different adaptation sets for playback. Right now it is clunky for
* applications to create {@link StreamInfo} with the right information,
*/
function initializeForMedia(mediaInfo) {
// Not checking here if a session for similar KS/KID combination is already created
// because still don't know which keysystem will be selected.
// Once Keysystem is selected and before creating the session, we will do that check
// so we create the strictly necessary DRM sessions
if (!mediaInfo) {
throw new Error('mediaInfo can not be null or undefined');
}
checkConfig();
eventBus.on(events.INTERNAL_KEY_MESSAGE, onKeyMessage, this);
eventBus.on(events.INTERNAL_KEY_STATUS_CHANGED, onKeyStatusChanged, this);
mediaInfoArr.push(mediaInfo);
// ContentProtection elements are specified at the AdaptationSet level, so the CP for audio
// and video will be the same. Just use one valid MediaInfo object
var supportedKS = protectionKeyController.getSupportedKeySystemsFromContentProtection(mediaInfo.contentProtection);
if (supportedKS && supportedKS.length > 0) {
selectKeySystem(supportedKS, true);
}
}
/**
* Returns a set of supported key systems and CENC initialization data
* from the given array of ContentProtection elements. Only
* key systems that are supported by this player will be returned.
* Key systems are returned in priority order (highest first).
*
* @param {Array.<Object>} cps - array of content protection elements parsed
* from the manifest
* @returns {Array.<Object>} array of objects indicating which supported key
* systems were found. Empty array is returned if no
* supported key systems were found
* @memberof module:ProtectionKeyController
* @instance
*/
function getSupportedKeySystemsFromContentProtection(cps) {
return protectionKeyController.getSupportedKeySystemsFromContentProtection(cps);
}
/**
* Create a new key session associated with the given initialization data from
* the MPD or from the PSSH box in the media
*
* @param {ArrayBuffer} initData the initialization data
* @param {Uint8Array} cdmData the custom data to provide to licenser
* @memberof module:ProtectionController
* @instance
* @fires ProtectionController#KeySessionCreated
* @todo In older versions of the EME spec, there was a one-to-one relationship between
* initialization data and key sessions. That is no longer true in the latest APIs. This
* API will need to modified (and a new "generateRequest(keySession, initData)" API created)
* to come up to speed with the latest EME standard
*/
function createKeySession(initData, cdmData) {
var initDataForKS = _CommonEncryption2['default'].getPSSHForKeySystem(keySystem, initData);
var protData = getProtData(keySystem);
if (initDataForKS) {
// Check for duplicate initData
var currentInitData = protectionModel.getAllInitData();
for (var i = 0; i < currentInitData.length; i++) {
if (protectionKeyController.initDataEquals(initDataForKS, currentInitData[i])) {
logger.warn('DRM: Ignoring initData because we have already seen it!');
return;
}
}
try {
protectionModel.createKeySession(initDataForKS, protData, getSessionType(keySystem), cdmData);
} catch (error) {
eventBus.trigger(events.KEY_SESSION_CREATED, { data: null, error: new _voDashJSError2['default'](_errorsProtectionErrors2['default'].KEY_SESSION_CREATED_ERROR_CODE, _errorsProtectionErrors2['default'].KEY_SESSION_CREATED_ERROR_MESSAGE + error.message) });
}
} else if (initData) {
protectionModel.createKeySession(initData, protData, getSessionType(keySystem), cdmData);
} else {
eventBus.trigger(events.KEY_SESSION_CREATED, { data: null, error: new _voDashJSError2['default'](_errorsProtectionErrors2['default'].KEY_SESSION_CREATED_ERROR_CODE, _errorsProtectionErrors2['default'].KEY_SESSION_CREATED_ERROR_MESSAGE + 'Selected key system is ' + keySystem.systemString + '. needkey/encrypted event contains no initData corresponding to that key system!') });
}
}
/**
* Loads a key session with the given session ID from persistent storage. This
* essentially creates a new key session
*
* @param {string} sessionID
* @param {string} initData
* @memberof module:ProtectionController
* @instance
* @fires ProtectionController#KeySessionCreated
*/
function loadKeySession(sessionID, initData) {
protectionModel.loadKeySession(sessionID, initData, getSessionType(keySystem));
}
/**
* Removes the given key session from persistent storage and closes the session
* as if {@link ProtectionController#closeKeySession}
* was called
*
* @param {SessionToken} sessionToken the session
* token
* @memberof module:ProtectionController
* @instance
* @fires ProtectionController#KeySessionRemoved
* @fires ProtectionController#KeySessionClosed
*/
function removeKeySession(sessionToken) {
protectionModel.removeKeySession(sessionToken);
}
/**
* Closes the key session and releases all associated decryption keys. These
* keys will no longer be available for decrypting media
*
* @param {SessionToken} sessionToken the session
* token
* @memberof module:ProtectionController
* @instance
* @fires ProtectionController#KeySessionClosed
*/
function closeKeySession(sessionToken) {
protectionModel.closeKeySession(sessionToken);
}
/**
* Sets a server certificate for use by the CDM when signing key messages
* intended for a particular license server. This will fire
* an error event if a key system has not yet been selected.
*
* @param {ArrayBuffer} serverCertificate a CDM-specific license server
* certificate
* @memberof module:ProtectionController
* @instance
* @fires ProtectionController#ServerCertificateUpdated
*/
function setServerCertificate(serverCertificate) {
protectionModel.setServerCertificate(serverCertificate);
}
/**
* Associate this protection system with the given HTMLMediaElement. This
* causes the system to register for needkey/encrypted events from the given
* element and provides a destination for setting of MediaKeys
*
* @param {HTMLMediaElement} element the media element to which the protection
* system should be associated
* @memberof module:ProtectionController
* @instance
*/
function setMediaElement(element) {
if (element) {
protectionModel.setMediaElement(element);
eventBus.on(events.NEED_KEY, onNeedKey, this);
} else if (element === null) {
protectionModel.setMediaElement(element);