2019/lib/eme/emeManager.js (101 lines of code) (raw):

/** * @license * Copyright 2018 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict'; var EMEHandler = function() {}; EMEHandler.prototype.init = function(video, licenseManager) { this.video = video; this.licenseManager = licenseManager; this.keySystem = licenseManager.keySystem; this.keyUnusable = false; this.keyCount = 0; this.keySessions = []; this.licenseDelay = 10; // In milliseconds. video.addEventListener('encrypted', this.onEncrypted.bind(this)); return this; }; EMEHandler.prototype.addEventSpies = function(eventSpies) { for (var spy in eventSpies) { this['_' + spy] = this[spy]; this[spy] = eventSpies[spy]; } }; /** * Default callback for onEncrypted event from EME system. * @param {Event} e Event passed in by the EME system. */ EMEHandler.prototype.onEncrypted = function(event) { if (!this.keySystem) { throw 'Not initialized! Bad manifest parse?'; } dlog(2, 'onEncrypted()'); var self = this; var initData = this.licenseManager.getExternalPSSH(); if (!initData) { initData = event.initData; } var initDataType = event.initDataType var video = event.target; var config = this.licenseManager.makeKeySystemConfig(); var promise = navigator.requestMediaKeySystemAccess(this.keySystem, config); promise.then(function(keySystemAccess) { keySystemAccess.createMediaKeys().then( function(createdMediaKeys) { var mediaKeys = video.mediaKeys; if (!mediaKeys) { video.setMediaKeys(createdMediaKeys); mediaKeys = createdMediaKeys; } var keySession = mediaKeys.createSession(); keySession.addEventListener( 'message', self.onMessage.bind(self), false); keySession.addEventListener( 'keystatuseschange', self.onKeyStatusesChange.bind(self), false); keySession.generateRequest(initDataType, initData); self.keySessions.push(keySession); } ); }).catch(function(error) { dlog(2, 'error requesting media keys system access'); }); }; /** * Default callback for onMessage event from EME system. * @param {Event} e Event passed in by the EME system. */ EMEHandler.prototype.onMessage = function(event) { dlog(2, 'onMessage()'); var keySession = event.target; var message = event.message; var messageType = event.messageType; var licenseDelay = this.licenseDelay; var updateSession = function(response) { setTimeout(function() { keySession.update(response).catch(dlog(2, 'keySession.update failed')) }, licenseDelay); } if (messageType == 'individualization-request') { this.licenseManager.requestIndividualization(message, updateSession); } else if (messageType == 'license-request') { this.licenseManager.acquireLicense(message, updateSession); } else { dlog(2, 'Unknown message:' + messageType); } }; /** * Default callback for keystatuseschange event from EME system. * @param {Event} event Event passed in by the EME system. */ EMEHandler.prototype.onKeyStatusesChange = function(event) { dlog(2, 'onKeyStatusesChange()'); var self = this; event.target.keyStatuses.forEach(function(status, kid) { self.keyCount++; if (status != 'usable') { self.keyUnusable = true; } }); }; EMEHandler.prototype.closeAllKeySessions = function (cb) { if (this.keySessions === undefined) { cb(); return; } var self = this; var closeAllSessions = function() { if (self.keySessions.length == 0) { cb(); return; } dlog(2, 'Closing key session'); var keySession = self.keySessions.pop(); var promise = keySession.close(); promise.then(closeAllSessions); }; closeAllSessions(); };