@l5i/dashjs
Version:
A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers.
204 lines (203 loc) • 28.2 kB
JavaScript
/**
* 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=require('../CommonEncryption');var _CommonEncryption2=_interopRequireDefault(_CommonEncryption);var _voMediaCapability=require('../vo/MediaCapability');var _voMediaCapability2=_interopRequireDefault(_voMediaCapability);var _voKeySystemConfiguration=require('../vo/KeySystemConfiguration');var _voKeySystemConfiguration2=_interopRequireDefault(_voKeySystemConfiguration);var _errorsProtectionErrors=require('../errors/ProtectionErrors');var _errorsProtectionErrors2=_interopRequireDefault(_errorsProtectionErrors);var _voDashJSError=require('../../vo/DashJSError');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);eventBus.off(events.NEED_KEY,onNeedKey,this);}} /**
* Sets the session type to use when creating key sessions. Either "temporary" or
* "persistent-license". Default is "temporary".
*
* @param {string} value the session type
* @memberof module:ProtectionController
* @instance
*/function setSessionType(value){sessionType = value;} /**
* Sets the robustness level for video and audio capabilities. Optional to remove Chrome warnings.
* Possible values are SW_SECURE_CRYPTO, SW_SECURE_DECODE, HW_SECURE_CRYPTO, HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL.
*
* @param {string} level the robustness level
* @memberof module:ProtectionController
* @instance
*/function setRobustnessLevel(level){robustnessLevel = level;} /**
* Attach KeySystem-specific data to use for license acquisition with EME
*
* @param {Object} data an object containing property names corresponding to
* key system name strings (e.g. "org.w3.clearkey") and associated values
* being instances of {@link ProtectionData}
* @memberof module:ProtectionController
* @instance
*/function setProtectionData(data){protDataSet = data;protectionKeyController.setProtectionData(data);} /**
* Stop method is called when current playback is stopped/resetted.
*
* @memberof module:ProtectionController
* @instance
*/function stop(){if(protectionModel){protectionModel.stop();}} /**
* Destroys all protection data associated with this protection set. This includes
* deleting all key sessions. In the case of persistent key sessions, the sessions
* will simply be unloaded and not deleted. Additionally, if this protection set is
* associated with a HTMLMediaElement, it will be detached from that element.
*
* @memberof module:ProtectionController
* @instance
*/function reset(){eventBus.off(events.INTERNAL_KEY_MESSAGE,onKeyMessage,this);eventBus.off(events.INTERNAL_KEY_STATUS_CHANGED,onKeyStatusChanged,this);setMediaElement(null);keySystem = undefined; //TODO-Refactor look at why undefined is needed for this. refactor
if(protectionModel){protectionModel.reset();protectionModel = null;}needkeyRetries.forEach(function(retryTimeout){return clearTimeout(retryTimeout);});needkeyRetries = [];mediaInfoArr = [];} ///////////////
// Private
///////////////
function getProtData(keySystem){var protData=null;if(keySystem){var keySystemString=keySystem.systemString;if(protDataSet){protData = keySystemString in protDataSet?protDataSet[keySystemString]:null;}}return protData;}function getKeySystemConfiguration(keySystem){var protData=getProtData(keySystem);var audioCapabilities=[];var videoCapabilities=[];var audioRobustness=protData && protData.audioRobustness && protData.audioRobustness.length > 0?protData.audioRobustness:robustnessLevel;var videoRobustness=protData && protData.videoRobustness && protData.videoRobustness.length > 0?protData.videoRobustness:robustnessLevel;var ksSessionType=getSessionType(keySystem);var distinctiveIdentifier=protData && protData.distinctiveIdentifier?protData.distinctiveIdentifier:'optional';var persistentState=protData && protData.persistentState?protData.persistentState:ksSessionType === 'temporary'?'optional':'required';mediaInfoArr.forEach(function(media){if(media.type === constants.AUDIO){audioCapabilities.push(new _voMediaCapability2['default'](media.codec,audioRobustness));}else if(media.type === constants.VIDEO){videoCapabilities.push(new _voMediaCapability2['default'](media.codec,videoRobustness));}});return new _voKeySystemConfiguration2['default'](audioCapabilities,videoCapabilities,distinctiveIdentifier,persistentState,[ksSessionType]);}function getSessionType(keySystem){var protData=getProtData(keySystem);var ksSessionType=protData && protData.sessionType?protData.sessionType:sessionType;return ksSessionType;}function selectKeySystem(supportedKS,fromManifest){var self=this;var requestedKeySystems=[];var ksIdx=undefined;if(keySystem){ // We have a key system
for(ksIdx = 0;ksIdx < supportedKS.length;ksIdx++) {if(keySystem === supportedKS[ksIdx].ks){var _ret=(function(){requestedKeySystems.push({ks:supportedKS[ksIdx].ks,configs:[getKeySystemConfiguration(keySystem)]}); // Ensure that we would be granted key system access using the key
// system and codec information
var onKeySystemAccessComplete=function onKeySystemAccessComplete(event){eventBus.off(events.KEY_SYSTEM_ACCESS_COMPLETE,onKeySystemAccessComplete,self);if(event.error){if(!fromManifest){eventBus.trigger(events.KEY_SYSTEM_SELECTED,{error:new _voDashJSError2['default'](_errorsProtectionErrors2['default'].KEY_SYSTEM_ACCESS_DENIED_ERROR_CODE,_errorsProtectionErrors2['default'].KEY_SYSTEM_ACCESS_DENIED_ERROR_MESSAGE + event.error)});}}else {logger.info('DRM: KeySystem Access Granted');eventBus.trigger(events.KEY_SYSTEM_SELECTED,{data:event.data});if(supportedKS[ksIdx].sessionId){ // Load MediaKeySession with sessionId
loadKeySession(supportedKS[ksIdx].sessionId,supportedKS[ksIdx].initData);}else if(supportedKS[ksIdx].initData){ // Create new MediaKeySession with initData
createKeySession(supportedKS[ksIdx].initData,supportedKS[ksIdx].cdmData);}}};eventBus.on(events.KEY_SYSTEM_ACCESS_COMPLETE,onKeySystemAccessComplete,self);protectionModel.requestKeySystemAccess(requestedKeySystems);return 'break';})();if(_ret === 'break')break;}}}else if(keySystem === undefined){var onKeySystemSelected;(function(){ // First time through, so we need to select a key system
keySystem = null;pendingNeedKeyData.push(supportedKS); // Add all key systems to our request list since we have yet to select a key system
for(var i=0;i < supportedKS.length;i++) {requestedKeySystems.push({ks:supportedKS[i].ks,configs:[getKeySystemConfiguration(supportedKS[i].ks)]});}var keySystemAccess=undefined;var onKeySystemAccessComplete=function onKeySystemAccessComplete(event){eventBus.off(events.KEY_SYSTEM_ACCESS_COMPLETE,onKeySystemAccessComplete,self);if(event.error){keySystem = undefined;eventBus.off(events.INTERNAL_KEY_SYSTEM_SELECTED,onKeySystemSelected,self);if(!fromManifest){eventBus.trigger(events.KEY_SYSTEM_SELECTED,{data:null,error:new _voDashJSError2['default'](_errorsProtectionErrors2['default'].KEY_SYSTEM_ACCESS_DENIED_ERROR_CODE,_errorsProtectionErrors2['default'].KEY_SYSTEM_ACCESS_DENIED_ERROR_MESSAGE + event.error)});}}else {keySystemAccess = event.data;logger.info('DRM: KeySystem Access Granted (' + keySystemAccess.keySystem.systemString + ')! Selecting key system...');protectionModel.selectKeySystem(keySystemAccess);}};onKeySystemSelected = function onKeySystemSelected(event){eventBus.off(events.INTERNAL_KEY_SYSTEM_SELECTED,onKeySystemSelected,self);eventBus.off(events.KEY_SYSTEM_ACCESS_COMPLETE,onKeySystemAccessComplete,self);if(!event.error){if(!protectionModel){return;}keySystem = protectionModel.getKeySystem();eventBus.trigger(events.KEY_SYSTEM_SELECTED,{data:keySystemAccess}); // Set server certificate from protData
var protData=getProtData(keySystem);if(protData && protData.serverCertificate && protData.serverCertificate.length > 0){protectionModel.setServerCertificate(BASE64.decodeArray(protData.serverCertificate).buffer);}for(var i=0;i < pendingNeedKeyData.length;i++) {for(ksIdx = 0;ksIdx < pendingNeedKeyData[i].length;ksIdx++) {if(keySystem === pendingNeedKeyData[i][ksIdx].ks){ // For Clearkey: if parameters for generating init data was provided by the user, use them for generating
// initData and overwrite possible initData indicated in encrypted event (EME)
if(protectionKeyController.isClearKey(keySystem) && protData && protData.hasOwnProperty('clearkeys')){var initData={kids:Object.keys(protData.clearkeys)};pendingNeedKeyData[i][ksIdx].initData = new TextEncoder().encode(JSON.stringify(initData));}if(pendingNeedKeyData[i][ksIdx].sessionId){ // Load MediaKeySession with sessionId
loadKeySession(pendingNeedKeyData[i][ksIdx].sessionId,pendingNeedKeyData[i][ksIdx].initData);}else if(pendingNeedKeyData[i][ksIdx].initData !== null){ // Create new MediaKeySession with initData
createKeySession(pendingNeedKeyData[i][ksIdx].initData,pendingNeedKeyData[i][ksIdx].cdmData);}break;}}}}else {keySystem = undefined;if(!fromManifest){eventBus.trigger(events.KEY_SYSTEM_SELECTED,{data:null,error:new _voDashJSError2['default'](_errorsProtectionErrors2['default'].KEY_SYSTEM_ACCESS_DENIED_ERROR_CODE,_errorsProtectionErrors2['default'].KEY_SYSTEM_ACCESS_DENIED_ERROR_MESSAGE + 'Error selecting key system! -- ' + event.error)});}}};eventBus.on(events.INTERNAL_KEY_SYSTEM_SELECTED,onKeySystemSelected,self);eventBus.on(events.KEY_SYSTEM_ACCESS_COMPLETE,onKeySystemAccessComplete,self);protectionModel.requestKeySystemAccess(requestedKeySystems);})();}else { // We are in the process of selecting a key system, so just save the data
pendingNeedKeyData.push(supportedKS);}}function sendLicenseRequestCompleteEvent(data,error){eventBus.trigger(events.LICENSE_REQUEST_COMPLETE,{data:data,error:error});}function onKeyStatusChanged(e){if(e.error){eventBus.trigger(events.KEY_STATUSES_CHANGED,{data:null,error:e.error});}else {logger.debug('DRM: key status = ' + e.status);}}function onKeyMessage(e){logger.debug('DRM: onKeyMessage'); // Dispatch event to applications indicating we received a key message
var keyMessage=e.data;eventBus.trigger(events.KEY_MESSAGE,{data:keyMessage});var messageType=keyMessage.messageType?keyMessage.messageType:'license-request';var message=keyMessage.message;var sessionToken=keyMessage.sessionToken;var protData=getProtData(keySystem);var keySystemString=keySystem?keySystem.systemString:null;var licenseServerData=protectionKeyController.getLicenseServer(keySystem,protData,messageType);var eventData={sessionToken:sessionToken,messageType:messageType}; // Ensure message from CDM is not empty
if(!message || message.byteLength === 0){sendLicenseRequestCompleteEvent(eventData,new _voDashJSError2['default'](_errorsProtectionErrors2['default'].MEDIA_KEY_MESSAGE_NO_CHALLENGE_ERROR_CODE,_errorsProtectionErrors2['default'].MEDIA_KEY_MESSAGE_NO_CHALLENGE_ERROR_MESSAGE));return;} // Message not destined for license server
if(!licenseServerData){logger.debug('DRM: License server request not required for this message (type = ' + e.data.messageType + '). Session ID = ' + sessionToken.getSessionID());sendLicenseRequestCompleteEvent(eventData);return;} // Perform any special handling for ClearKey
if(protectionKeyController.isClearKey(keySystem)){var clearkeys=protectionKeyController.processClearKeyLicenseRequest(keySystem,protData,message);if(clearkeys){logger.debug('DRM: ClearKey license request handled by application!');sendLicenseRequestCompleteEvent(eventData);protectionModel.updateKeySession(sessionToken,clearkeys);return;}} // All remaining key system scenarios require a request to a remote license server
var xhr=new XMLHttpRequest(); // Determine license server URL
var url=null;if(protData && protData.serverURL){var serverURL=protData.serverURL;if(typeof serverURL === 'string' && serverURL !== ''){url = serverURL;}else if(typeof serverURL === 'object' && serverURL.hasOwnProperty(messageType)){url = serverURL[messageType];}}else if(protData && protData.laURL && protData.laURL !== ''){ // TODO: Deprecated!
url = protData.laURL;}else {url = keySystem.getLicenseServerURLFromInitData(_CommonEncryption2['default'].getPSSHData(sessionToken.initData));if(!url){url = e.data.laURL;}} // Possibly update or override the URL based on the message
//url = licenseServerData.getServerURLFromMessage(url, message, messageType);
// Ensure valid license server URL
if(!url){sendLicenseRequestCompleteEvent(eventData,new _voDashJSError2['default'](_errorsProtectionErrors2['default'].MEDIA_KEY_MESSAGE_NO_LICENSE_SERVER_URL_ERROR_CODE,_errorsProtectionErrors2['default'].MEDIA_KEY_MESSAGE_NO_LICENSE_SERVER_URL_ERROR_MESSAGE));return;}var reportError=function reportError(xhr,eventData,keySystemString,messageType){var errorMsg=xhr.response?licenseServerData.getErrorResponse(xhr.response,keySystemString,messageType):'NONE';sendLicenseRequestCompleteEvent(eventData,new _voDashJSError2['default'](_errorsProtectionErrors2['default'].MEDIA_KEY_MESSAGE_LICENSER_ERROR_CODE,_errorsProtectionErrors2['default'].MEDIA_KEY_MESSAGE_LICENSER_ERROR_MESSAGE + keySystemString + ' update, XHR complete. status is "' + xhr.statusText + '" (' + xhr.status + '), readyState is ' + xhr.readyState + '. Response is ' + errorMsg));};xhr.open(licenseServerData.getHTTPMethod(messageType),url,true);xhr.responseType = licenseServerData.getResponseType(keySystemString,messageType);xhr.onload = function(){if(!protectionModel){return;}if(this.status == 200){var licenseMessage=licenseServerData.getLicenseMessage(this.response,keySystemString,messageType);if(licenseMessage !== null){sendLicenseRequestCompleteEvent(eventData);protectionModel.updateKeySession(sessionToken,licenseMessage);}else {reportError(this,eventData,keySystemString,messageType);}}else {reportError(this,eventData,keySystemString,messageType);}};xhr.onabort = function(){sendLicenseRequestCompleteEvent(eventData,new _voDashJSError2['default'](_errorsProtectionErrors2['default'].MEDIA_KEY_MESSAGE_LICENSER_ERROR_CODE,_errorsProtectionErrors2['default'].MEDIA_KEY_MESSAGE_LICENSER_ERROR_MESSAGE + keySystemString + ' update, XHR aborted. status is "' + this.statusText + '" (' + this.status + '), readyState is ' + this.readyState));};xhr.onerror = function(){sendLicenseRequestCompleteEvent(eventData,new _voDashJSError2['default'](_errorsProtectionErrors2['default'].MEDIA_KEY_MESSAGE_LICENSER_ERROR_CODE,_errorsProtectionErrors2['default'].MEDIA_KEY_MESSAGE_LICENSER_ERROR_MESSAGE + keySystemString + ' update, XHR error. status is "' + this.statusText + '" (' + this.status + '), readyState is ' + this.readyState));}; // Set optional XMLHttpRequest headers from protection data and message
var updateHeaders=function updateHeaders(headers){if(headers){for(var key in headers) {if('authorization' === key.toLowerCase()){xhr.withCredentials = true;}xhr.setRequestHeader(key,headers[key]);}}};if(protData){updateHeaders(protData.httpRequestHeaders);}updateHeaders(keySystem.getRequestHeadersFromMessage(message)); // Overwrite withCredentials property from protData if present
if(protData && typeof protData.withCredentials == 'boolean'){xhr.withCredentials = protData.withCredentials;}xhr.send(keySystem.getLicenseRequestFromMessage(message));}function onNeedKey(event,retry){logger.debug('DRM: onNeedKey'); // Ignore non-cenc initData
if(event.key.initDataType !== 'cenc'){logger.warn('DRM: Only \'cenc\' initData is supported! Ignoring initData of type: ' + event.key.initDataType);return;}if(mediaInfoArr.length === 0){logger.warn('DRM: onNeedKey called before initializeForMedia, wait until initialized');retry = typeof retry === 'undefined'?1:retry + 1;if(retry < NEEDKEY_BEFORE_INITIALIZE_RETRIES){needkeyRetries.push(setTimeout(function(){onNeedKey(event,retry);},NEEDKEY_BEFORE_INITIALIZE_TIMEOUT));return;}} // Some browsers return initData as Uint8Array (IE), some as ArrayBuffer (Chrome).
// Convert to ArrayBuffer
var abInitData=event.key.initData;if(ArrayBuffer.isView(abInitData)){abInitData = abInitData.buffer;} // If key system has already been selected and initData already seen, then do nothing
if(keySystem){var initDataForKS=_CommonEncryption2['default'].getPSSHForKeySystem(keySystem,abInitData);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;}}}}logger.debug('DRM: initData:',String.fromCharCode.apply(null,new Uint8Array(abInitData)));var supportedKS=protectionKeyController.getSupportedKeySystems(abInitData,protDataSet);if(supportedKS.length === 0){logger.debug('DRM: Received needkey event with initData, but we don\'t support any of the key systems!');return;}selectKeySystem(supportedKS,false);}function getKeySystems(){return protectionKeyController?protectionKeyController.getKeySystems():[];}instance = {initializeForMedia:initializeForMedia,createKeySession:createKeySession,loadKeySession:loadKeySession,removeKeySession:removeKeySession,closeKeySession:closeKeySession,setServerCertificate:setServerCertificate,setMediaElement:setMediaElement,setSessionType:setSessionType,setRobustnessLevel:setRobustnessLevel,setProtectionData:setProtectionData,getSupportedKeySystemsFromContentProtection:getSupportedKeySystemsFromContentProtection,getKeySystems:getKeySystems,stop:stop,reset:reset};setup();return instance;}ProtectionController.__dashjs_factory_name = 'ProtectionController';exports['default'] = dashjs.FactoryMaker.getClassFactory(ProtectionController); /* jshint ignore:line */module.exports = exports['default'];
//# sourceMappingURL=ProtectionController.js.map