UNPKG

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