diff --git a/index.d.ts b/index.d.ts index 38716dde55..075c5b56c3 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2989,46 +2989,6 @@ declare namespace dashjs { HTTP_REQUEST_DVB_REPORTING_TYPE: 'DVBReporting', } - export interface ProtectionConstants { - CLEARKEY_KEYSTEM_STRING: 'org.w3.clearkey', - WIDEVINE_KEYSTEM_STRING: 'com.widevine.alpha', - PLAYREADY_KEYSTEM_STRING: 'com.microsoft.playready', - PLAYREADY_RECOMMENDATION_KEYSTEM_STRING: 'com.microsoft.playready.recommendation', - WIDEVINE_UUID: 'edef8ba9-79d6-4ace-a3c8-27dcd51d21ed', - PLAYREADY_UUID: '9a04f079-9840-4286-ab92-e65be0885f95', - CLEARKEY_UUID: 'e2719d58-a985-b3c9-781a-b030af78d30e', - W3C_CLEARKEY_UUID: '1077efec-c0b2-4d02-ace3-3c1e52e2fb4b', - INITIALIZATION_DATA_TYPE_CENC: 'cenc', - INITIALIZATION_DATA_TYPE_KEYIDS: 'keyids', - INITIALIZATION_DATA_TYPE_WEBM: 'webm', - ENCRYPTION_SCHEME_CENC: 'cenc', - ENCRYPTION_SCHEME_CBCS: 'cbcs', - MEDIA_KEY_MESSAGE_TYPES: { - LICENSE_REQUEST: 'license-request', - LICENSE_RENEWAL: 'license-renewal', - LICENSE_RELEASE: 'license-release', - INDIVIDUALIZATION_REQUEST: 'individualization-request', - }, - ROBUSTNESS_STRINGS: { - WIDEVINE: { - SW_SECURE_CRYPTO: 'SW_SECURE_CRYPTO', - SW_SECURE_DECODE: 'SW_SECURE_DECODE', - HW_SECURE_CRYPTO: 'HW_SECURE_CRYPTO', - HW_SECURE_DECODE: 'HW_SECURE_DECODE', - HW_SECURE_ALL: 'HW_SECURE_ALL' - } - }, - MEDIA_KEY_STATUSES: { - USABLE: 'usable', - EXPIRED: 'expired', - RELEASED: 'released', - OUTPUT_RESTRICTED: 'output-restricted', - OUTPUT_DOWNSCALED: 'output-downscaled', - STATUS_PENDING: 'status-pending', - INTERNAL_ERROR: 'internal-error', - } - } - /** * Streaming - Controllers **/ @@ -4636,10 +4596,6 @@ declare namespace dashjs { VIDEO_ELEMENT_SELECTED: 'videoElementSelected'; } - export interface CommonEncryption { - // Does not export anything - } - export interface Protection { createProtectionSystem(config: object): void; } diff --git a/package-lock.json b/package-lock.json index 36f585f4d3..dae7e43306 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "dashjs", - "version": "5.0.0", + "version": "5.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dashjs", - "version": "5.0.0", + "version": "5.0.1", "license": "BSD-3-Clause", "dependencies": { "@svta/common-media-library": "^0.7.4", @@ -33,7 +33,7 @@ "chai": "^4.4.1", "chai-spies": "^1.1.0", "clean-jsdoc-theme": "^4.2.17", - "core-js": "^3.39.0", + "core-js": "^3.41.0", "eslint": "^9.13.0", "eslint-webpack-plugin": "^4.2.0", "globals": "^15.11.0", @@ -4190,9 +4190,9 @@ "dev": true }, "node_modules/core-js": { - "version": "3.39.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz", - "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", + "version": "3.41.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.41.0.tgz", + "integrity": "sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA==", "dev": true, "hasInstallScript": true, "funding": { diff --git a/package.json b/package.json index 2d0408dcf2..2fc92d1842 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "chai": "^4.4.1", "chai-spies": "^1.1.0", "clean-jsdoc-theme": "^4.2.17", - "core-js": "^3.39.0", + "core-js": "^3.41.0", "eslint": "^9.13.0", "eslint-webpack-plugin": "^4.2.0", "globals": "^15.11.0", diff --git a/src/mss/parser/MssParser.js b/src/mss/parser/MssParser.js index efcd799b02..fd818cf45f 100644 --- a/src/mss/parser/MssParser.js +++ b/src/mss/parser/MssParser.js @@ -37,7 +37,12 @@ import BigInt from '../../../externals/BigInteger.js'; import FactoryMaker from '../../core/FactoryMaker.js'; -import ProtectionConstants from '../../streaming/constants/ProtectionConstants.js'; + +// imports from common-media-library +import { PLAYREADY_UUID } from '@svta/common-media-library/drm/common/const/PLAYREADY_UUID.js'; +import { WIDEVINE_UUID } from '@svta/common-media-library/drm/common/const/WIDEVINE_UUID.js'; +import { WIDEVINE_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/WIDEVINE_KEY_SYSTEM.js'; +import { PLAYREADY_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/PLAYREADY_KEY_SYSTEM.js'; function MssParser(config) { config = config || {}; @@ -532,16 +537,16 @@ function MssParser(config) { __prefix: 'mspr' }; return { - schemeIdUri: 'urn:uuid:' + ProtectionConstants.PLAYREADY_UUID, - value: ProtectionConstants.PLAYREADY_KEYSTEM_STRING, + schemeIdUri: 'urn:uuid:' + PLAYREADY_UUID, + value: PLAYREADY_KEY_SYSTEM, pro: pro }; } function createWidevineContentProtection(KID) { let widevineCP = { - schemeIdUri: 'urn:uuid:' + ProtectionConstants.WIDEVINE_UUID, - value: ProtectionConstants.WIDEVINE_KEYSTEM_STRING + schemeIdUri: 'urn:uuid:' + WIDEVINE_UUID, + value: WIDEVINE_KEY_SYSTEM }; if (!KID) { return widevineCP; diff --git a/src/streaming/constants/ProtectionConstants.js b/src/streaming/constants/ProtectionConstants.js deleted file mode 100644 index dd9838286b..0000000000 --- a/src/streaming/constants/ProtectionConstants.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * 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 - * @ignore - */ -export default { - CLEARKEY_KEYSTEM_STRING: 'org.w3.clearkey', - WIDEVINE_KEYSTEM_STRING: 'com.widevine.alpha', - PLAYREADY_KEYSTEM_STRING: 'com.microsoft.playready', - PLAYREADY_RECOMMENDATION_KEYSTEM_STRING: 'com.microsoft.playready.recommendation', - WIDEVINE_UUID: 'edef8ba9-79d6-4ace-a3c8-27dcd51d21ed', - PLAYREADY_UUID: '9a04f079-9840-4286-ab92-e65be0885f95', - CLEARKEY_UUID: 'e2719d58-a985-b3c9-781a-b030af78d30e', - W3C_CLEARKEY_UUID: '1077efec-c0b2-4d02-ace3-3c1e52e2fb4b', - INITIALIZATION_DATA_TYPE_CENC: 'cenc', - INITIALIZATION_DATA_TYPE_KEYIDS: 'keyids', - INITIALIZATION_DATA_TYPE_WEBM: 'webm', - ENCRYPTION_SCHEME_CENC: 'cenc', - ENCRYPTION_SCHEME_CBCS: 'cbcs', - MEDIA_KEY_MESSAGE_TYPES: { - LICENSE_REQUEST: 'license-request', - LICENSE_RENEWAL: 'license-renewal', - LICENSE_RELEASE: 'license-release', - INDIVIDUALIZATION_REQUEST: 'individualization-request', - }, - ROBUSTNESS_STRINGS: { - WIDEVINE: { - SW_SECURE_CRYPTO: 'SW_SECURE_CRYPTO', - SW_SECURE_DECODE: 'SW_SECURE_DECODE', - HW_SECURE_CRYPTO: 'HW_SECURE_CRYPTO', - HW_SECURE_DECODE: 'HW_SECURE_DECODE', - HW_SECURE_ALL: 'HW_SECURE_ALL' - } - }, - MEDIA_KEY_STATUSES: { - USABLE: 'usable', - EXPIRED: 'expired', - RELEASED: 'released', - OUTPUT_RESTRICTED: 'output-restricted', - OUTPUT_DOWNSCALED: 'output-downscaled', - STATUS_PENDING: 'status-pending', - INTERNAL_ERROR: 'internal-error', - } -} - - diff --git a/src/streaming/protection/CommonEncryption.js b/src/streaming/protection/CommonEncryption.js deleted file mode 100644 index c6bbc22f68..0000000000 --- a/src/streaming/protection/CommonEncryption.js +++ /dev/null @@ -1,275 +0,0 @@ -/** - * 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. - */ -import DashConstants from '../../dash/constants/DashConstants.js'; -import ProtectionConstants from '../constants/ProtectionConstants.js'; - -const LICENSE_SERVER_MANIFEST_CONFIGURATIONS = { - prefixes: ['clearkey', 'dashif', 'ck'] -}; - -/** - * @class - * @ignore - */ -class CommonEncryption { - /** - * Find and return the ContentProtection element in the given array - * that indicates support for MP4 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 - */ - static findMp4ProtectionElement(cpArray) { - let retVal = null; - for (let i = 0; i < cpArray.length; ++i) { - let cp = cpArray[i]; - if (cp.schemeIdUri && cp.schemeIdUri.toLowerCase() === DashConstants.MP4_PROTECTION_SCHEME && cp.value && - (cp.value.toLowerCase() === ProtectionConstants.ENCRYPTION_SCHEME_CENC || cp.value.toLowerCase() === ProtectionConstants.ENCRYPTION_SCHEME_CBCS)) { - 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 - */ - static getPSSHData(pssh) { - let offset = 8; // Box size and type fields - let view = new DataView(pssh); - - // Read version - let 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. - */ - static getPSSHForKeySystem(keySystem, initData) { - let psshList = CommonEncryption.parsePSSHList(initData); - if (keySystem && 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 - */ - static parseInitDataFromContentProtection(cpData, BASE64) { - if ('pssh' in cpData && cpData.pssh) { - - // Remove whitespaces and newlines from pssh text - cpData.pssh.__text = cpData.pssh.__text.replace(/\r?\n|\r/g, '').replace(/\s+/g, ''); - - 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 - */ - static parsePSSHList(data) { - - if (data === null || data === undefined) { - return []; - } - - let dv = new DataView(data.buffer || data); // data.buffer first for Uint8Array support - let done = false; - let pssh = {}; - - // TODO: Need to check every data read for end of buffer - let byteCursor = 0; - while (!done) { - - let size, - nextBox, - version, - systemID; - let 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 = ''; - let i, val; - 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 */ - byteCursor += 4; - - /* PSSH Data */ - pssh[systemID] = dv.buffer.slice(boxStart, nextBox); - byteCursor = nextBox; - } - - return pssh; - } - - static getLicenseServerUrlFromMediaInfo(mediaInfoArr, schemeIdUri) { - try { - - if (!mediaInfoArr || mediaInfoArr.length === 0) { - return null; - } - - let i = 0; - let licenseServer = null; - - while (i < mediaInfoArr.length && !licenseServer) { - const mediaInfo = mediaInfoArr[i]; - - if (mediaInfo && mediaInfo.contentProtection && mediaInfo.contentProtection.length > 0) { - const targetProtectionData = mediaInfo.contentProtection.filter((cp) => { - return cp.schemeIdUri && cp.schemeIdUri === schemeIdUri; - }); - - if (targetProtectionData && targetProtectionData.length > 0) { - let j = 0; - while (j < targetProtectionData.length && !licenseServer) { - const contentProtection = targetProtectionData[j]; - if (contentProtection.laUrl - && contentProtection.laUrl.__prefix - && LICENSE_SERVER_MANIFEST_CONFIGURATIONS.prefixes.includes(contentProtection.laUrl.__prefix) - && contentProtection.laUrl.__text) { - licenseServer = contentProtection.laUrl.__text; - } - j += 1; - } - } - } - i += 1; - } - return licenseServer; - } catch (e) { - return null; - } - } - - static hexKidToBufferSource(hexKid) { - const cleanedHexKid = hexKid.replace(/-/g, ''); - - const typedArray = new Uint8Array(cleanedHexKid.match(/[\da-f]{2}/gi).map(function (h) { - return parseInt(h, 16) - })) - - return typedArray.buffer - } -} - -export default CommonEncryption; diff --git a/src/streaming/protection/controllers/ProtectionController.js b/src/streaming/protection/controllers/ProtectionController.js index 64dd9f656a..f9a7135e0c 100644 --- a/src/streaming/protection/controllers/ProtectionController.js +++ b/src/streaming/protection/controllers/ProtectionController.js @@ -29,7 +29,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -import CommonEncryption from '../CommonEncryption.js'; import MediaCapability from '../vo/MediaCapability.js'; import KeySystemConfiguration from '../vo/KeySystemConfiguration.js'; import ProtectionErrors from '../errors/ProtectionErrors.js'; @@ -40,7 +39,14 @@ import {HTTPRequest} from '../../vo/metrics/HTTPRequest.js'; import Utils from '../../../core/Utils.js'; import Constants from '../../constants/Constants.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; -import ProtectionConstants from '../../constants/ProtectionConstants.js'; + +import { getPSSHData } from '@svta/common-media-library/drm/common-encryption/getPSSHData.js'; +import { getPSSHForKeySystem } from '@svta/common-media-library/drm/common-encryption/getPSSHForKeySystem.js'; +import { getLicenseServerUrlFromContentProtection } from '@svta/common-media-library/drm/common-encryption/getLicenseServerUrlFromContentProtection.js'; +import { MEDIA_KEY_MESSAGE_TYPES } from '@svta/common-media-library/drm/common/const/MEDIA_KEY_MESSAGE_TYPES.js'; +import { INITIALIZATION_DATA_TYPE } from '@svta/common-media-library/drm/common/const/INITIALIZATION_DATA_TYPE.js'; +import { PLAYREADY_UUID } from '@svta/common-media-library/drm/common/const/PLAYREADY_UUID.js'; +import { MEDIA_KEY_STATUSES } from '@svta/common-media-library/drm/common/const/MEDIA_KEY_STATUSES.js'; const NEEDKEY_BEFORE_INITIALIZE_RETRIES = 5; const NEEDKEY_BEFORE_INITIALIZE_TIMEOUT = 500; @@ -303,7 +309,7 @@ function ProtectionController(config) { const protData = keySystemData.protData; const audioCapabilities = []; const videoCapabilities = []; - const initDataTypes = (protData && protData.initDataTypes && protData.initDataTypes.length > 0) ? protData.initDataTypes : [ProtectionConstants.INITIALIZATION_DATA_TYPE_CENC]; + const initDataTypes = (protData && protData.initDataTypes && protData.initDataTypes.length > 0) ? protData.initDataTypes : [INITIALIZATION_DATA_TYPE.CENC]; const audioRobustness = (protData && protData.audioRobustness && protData.audioRobustness.length > 0) ? protData.audioRobustness : robustnessLevel; const videoRobustness = (protData && protData.videoRobustness && protData.videoRobustness.length > 0) ? protData.videoRobustness : robustnessLevel; const ksSessionType = keySystemData.sessionType; @@ -384,7 +390,9 @@ function ProtectionController(config) { return; } - const initDataForKS = CommonEncryption.getPSSHForKeySystem(selectedKeySystem, keySystemMetadata ? keySystemMetadata.initData : null); + const initDataForKS = getPSSHForKeySystem(selectedKeySystem, keySystemMetadata ? keySystemMetadata.initData : null); + console.log('XXX - initDataForKS from createKeySession: ', initDataForKS); + if (initDataForKS) { // Check for duplicate initData @@ -676,7 +684,7 @@ function ProtectionController(config) { // Dispatch event to applications indicating we received a key message const keyMessage = e.data; eventBus.trigger(events.KEY_MESSAGE, { data: keyMessage }); - const messageType = (keyMessage.messageType) ? keyMessage.messageType : ProtectionConstants.MEDIA_KEY_MESSAGE_TYPES.LICENSE_REQUEST; + const messageType = (keyMessage.messageType) ? keyMessage.messageType : MEDIA_KEY_MESSAGE_TYPES.LICENSE_REQUEST; const message = keyMessage.message; const sessionToken = keyMessage.sessionToken; const protData = _getProtDataForKeySystem(selectedKeySystem); @@ -730,7 +738,7 @@ function ProtectionController(config) { */ function _issueLicenseRequest(keyMessage, licenseServerData, protData) { const sessionToken = keyMessage.sessionToken; - const messageType = (keyMessage.messageType) ? keyMessage.messageType : ProtectionConstants.MEDIA_KEY_MESSAGE_TYPES.LICENSE_REQUEST; + const messageType = (keyMessage.messageType) ? keyMessage.messageType : MEDIA_KEY_MESSAGE_TYPES.LICENSE_REQUEST; const eventData = { sessionToken: sessionToken, messageType: messageType }; const keySystemString = selectedKeySystem ? selectedKeySystem.systemString : null; @@ -966,11 +974,22 @@ function ProtectionController(config) { // No url provided by the app. Check the manifest and the pssh else { // Check for url defined in the manifest - url = CommonEncryption.getLicenseServerUrlFromMediaInfo(mediaInfoArr, selectedKeySystem.schemeIdURI); + if (Array.isArray(mediaInfoArr) && mediaInfoArr.length > 0) { + for (const mediaInfo of mediaInfoArr) { + const contentProtection = mediaInfo.contentProtection; + + if (Array.isArray(contentProtection)) { + url = getLicenseServerUrlFromContentProtection(contentProtection, selectedKeySystem.schemeIdURI); + if (url) { + break; + } + } + } + } // In case we are not using Clearky we can still get a url from the pssh. if (!url && !protectionKeyController.isClearKey(selectedKeySystem)) { - const psshData = CommonEncryption.getPSSHData(sessionToken.initData); + const psshData = getPSSHData(sessionToken.initData); url = selectedKeySystem.getLicenseServerURLFromInitData(psshData); // Still no url, check the keymessage @@ -1057,7 +1076,7 @@ function ProtectionController(config) { logger.debug('DRM: onNeedKey'); // Ignore non-cenc initData - if (event.key.initDataType !== ProtectionConstants.INITIALIZATION_DATA_TYPE_CENC) { + if (event.key.initDataType !== INITIALIZATION_DATA_TYPE.CENC) { logger.warn('DRM: Only \'cenc\' initData is supported! Ignoring initData of type: ' + event.key.initDataType); return; } @@ -1082,7 +1101,8 @@ function ProtectionController(config) { // If key system has already been selected and initData already seen, then do nothing if (selectedKeySystem) { - const initDataForKS = CommonEncryption.getPSSHForKeySystem(selectedKeySystem, abInitData); + const initDataForKS = getPSSHForKeySystem(selectedKeySystem, abInitData); + console.log('XXX - initDataForKS from _onNeedKey: ', initDataForKS); if (initDataForKS) { // Check for duplicate initData if (_isInitDataDuplicate(initDataForKS)) { @@ -1133,7 +1153,7 @@ function ProtectionController(config) { const isEdgeBrowser = ua && ua.browser && ua.browser.name && ua.browser.name.toLowerCase() === 'edge'; parsedKeyStatuses.forEach((keyStatus) => { if (isEdgeBrowser - && selectedKeySystem.uuid === ProtectionConstants.PLAYREADY_UUID + && selectedKeySystem.uuid === PLAYREADY_UUID && keyStatus.keyId && keyStatus.keyId.byteLength === 16) { _handlePlayreadyKeyId(keyStatus.keyId); } @@ -1168,7 +1188,7 @@ function ProtectionController(config) { return [...normalizedKeyIds].some((normalizedKeyId) => { const keyStatus = keyStatusMap.get(normalizedKeyId); - return keyStatus && keyStatus !== ProtectionConstants.MEDIA_KEY_STATUSES.INTERNAL_ERROR && keyStatus !== ProtectionConstants.MEDIA_KEY_STATUSES.OUTPUT_RESTRICTED; + return keyStatus && keyStatus !== MEDIA_KEY_STATUSES.INTERNAL_ERROR && keyStatus !== MEDIA_KEY_STATUSES.OUTPUT_RESTRICTED; }); } catch (error) { logger.error(error); @@ -1184,7 +1204,7 @@ function ProtectionController(config) { return [...normalizedKeyIds].every((normalizedKeyId) => { const keyStatus = keyStatusMap.get(normalizedKeyId); - return keyStatus === ProtectionConstants.MEDIA_KEY_STATUSES.EXPIRED; + return keyStatus === MEDIA_KEY_STATUSES.EXPIRED; }) } catch (error) { logger.error(error); diff --git a/src/streaming/protection/controllers/ProtectionKeyController.js b/src/streaming/protection/controllers/ProtectionKeyController.js index 2d06c7a4ff..1ec0ce9863 100644 --- a/src/streaming/protection/controllers/ProtectionKeyController.js +++ b/src/streaming/protection/controllers/ProtectionKeyController.js @@ -28,7 +28,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -import CommonEncryption from './../CommonEncryption.js'; import KeySystemClearKey from './../drm/KeySystemClearKey.js'; import KeySystemW3CClearKey from './../drm/KeySystemW3CClearKey.js'; import KeySystemWidevine from './../drm/KeySystemWidevine.js'; @@ -37,10 +36,17 @@ import DRMToday from './../servers/DRMToday.js'; import PlayReady from './../servers/PlayReady.js'; import Widevine from './../servers/Widevine.js'; import ClearKey from './../servers/ClearKey.js'; -import ProtectionConstants from '../../constants/ProtectionConstants.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; import KeySystemMetadata from '../vo/KeySystemMetadata.js'; +// imports from common-media-library +import { findCencContentProtection } from '@svta/common-media-library/drm/common-encryption/findCencContentProtection.js'; +import { parsePSSHList } from '@svta/common-media-library/drm/common-encryption/parsePSSHList.js'; +import { MEDIA_KEY_MESSAGE_TYPES } from '@svta/common-media-library/drm/common/const/MEDIA_KEY_MESSAGE_TYPES.js'; +import { WIDEVINE_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/WIDEVINE_KEY_SYSTEM.js'; +import { PLAYREADY_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/PLAYREADY_KEY_SYSTEM.js'; +import { CLEAR_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/CLEAR_KEY_SYSTEM.js'; + /** * @module ProtectionKeyController * @ignore @@ -216,7 +222,7 @@ function ProtectionKeyController() { return supportedKS } - const mp4ProtectionElement = CommonEncryption.findMp4ProtectionElement(contentProtectionElements); + const mp4ProtectionElement = findCencContentProtection(contentProtectionElements); for (ksIdx = 0; ksIdx < keySystems.length; ksIdx++) { keySystem = keySystems[ksIdx]; @@ -268,7 +274,9 @@ function ProtectionKeyController() { */ function getSupportedKeySystemsFromSegmentPssh(initData, protDataSet, sessionType) { let supportedKS = []; - let pssh = CommonEncryption.parsePSSHList(initData); + console.log('XXX - getSupportedKeySystemsFromSegmentPssh', initData); + let pssh = parsePSSHList(initData); + console.log('XXX - pssh', pssh); let ks, keySystemString; for (let ksIdx = 0; ksIdx < keySystems.length; ++ksIdx) { @@ -313,18 +321,18 @@ function ProtectionKeyController() { // Our default server implementations do not do anything with "license-release" or // "individualization-request" messages, so we just send a success event - if (messageType === ProtectionConstants.MEDIA_KEY_MESSAGE_TYPES.LICENSE_RELEASE || messageType === ProtectionConstants.MEDIA_KEY_MESSAGE_TYPES.INDIVIDUALIZATION_REQUEST) { + if (messageType === MEDIA_KEY_MESSAGE_TYPES.LICENSE_RELEASE || messageType === MEDIA_KEY_MESSAGE_TYPES.INDIVIDUALIZATION_REQUEST) { return null; } let licenseServerData = null; if (protData && protData.hasOwnProperty('drmtoday')) { licenseServerData = DRMToday(context).getInstance({BASE64: BASE64}); - } else if (keySystem.systemString === ProtectionConstants.WIDEVINE_KEYSTEM_STRING) { + } else if (keySystem.systemString === WIDEVINE_KEY_SYSTEM) { licenseServerData = Widevine(context).getInstance(); - } else if (keySystem.systemString === ProtectionConstants.PLAYREADY_KEYSTEM_STRING) { + } else if (keySystem.systemString === PLAYREADY_KEY_SYSTEM) { licenseServerData = PlayReady(context).getInstance(); - } else if (keySystem.systemString === ProtectionConstants.CLEARKEY_KEYSTEM_STRING) { + } else if (keySystem.systemString === CLEAR_KEY_SYSTEM) { licenseServerData = ClearKey(context).getInstance(); } diff --git a/src/streaming/protection/drm/KeySystemClearKey.js b/src/streaming/protection/drm/KeySystemClearKey.js index d0bb323ec6..52b5a878d1 100644 --- a/src/streaming/protection/drm/KeySystemClearKey.js +++ b/src/streaming/protection/drm/KeySystemClearKey.js @@ -31,14 +31,18 @@ import KeyPair from '../vo/KeyPair.js'; import ClearKeyKeySet from '../vo/ClearKeyKeySet.js'; -import CommonEncryption from '../CommonEncryption.js'; -import ProtectionConstants from '../../constants/ProtectionConstants.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; -const uuid = ProtectionConstants.CLEARKEY_UUID; -const systemString = ProtectionConstants.CLEARKEY_KEYSTEM_STRING; +// imports from common-media-library +import { CLEAR_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/CLEAR_KEY_SYSTEM.js'; +import { CLEAR_KEY_UUID } from '@svta/common-media-library/drm/common/const/CLEAR_KEY_UUID.js'; + +const uuid = CLEAR_KEY_UUID; +const systemString = CLEAR_KEY_SYSTEM; const schemeIdURI = 'urn:uuid:' + uuid; +import { parseInitDataFromContentProtection } from '@svta/common-media-library/drm/common-encryption/parseInitDataFromContentProtection.js'; + function KeySystemClearKey(config) { config = config || {}; @@ -78,7 +82,7 @@ function KeySystemClearKey(config) { function getInitData(cp, cencContentProtection) { try { - let initData = CommonEncryption.parseInitDataFromContentProtection(cp, BASE64); + let initData = parseInitDataFromContentProtection(cp, BASE64); if (!initData && cencContentProtection) { const cencDefaultKid = cencDefaultKidToBase64Representation(cencContentProtection.cencDefaultKid); diff --git a/src/streaming/protection/drm/KeySystemPlayReady.js b/src/streaming/protection/drm/KeySystemPlayReady.js index 62f6a58805..cf8e96c5b6 100644 --- a/src/streaming/protection/drm/KeySystemPlayReady.js +++ b/src/streaming/protection/drm/KeySystemPlayReady.js @@ -35,12 +35,14 @@ * @class * @implements KeySystem */ -import CommonEncryption from '../CommonEncryption.js'; -import ProtectionConstants from '../../constants/ProtectionConstants.js'; + import FactoryMaker from '../../../core/FactoryMaker.js'; +import { parseInitDataFromContentProtection } from '@svta/common-media-library/drm/common-encryption/parseInitDataFromContentProtection.js'; +import { PLAYREADY_UUID } from '@svta/common-media-library/drm/common/const/PLAYREADY_UUID.js'; +import { PLAYREADY_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/PLAYREADY_KEY_SYSTEM.js'; -const uuid = ProtectionConstants.PLAYREADY_UUID; -const systemString = ProtectionConstants.PLAYREADY_KEYSTEM_STRING; +const uuid = PLAYREADY_UUID; +const systemString = PLAYREADY_KEY_SYSTEM; const schemeIdURI = 'urn:uuid:' + uuid; const PRCDMData = '%CUSTOMDATA%'; @@ -199,7 +201,7 @@ function KeySystemPlayReady(config) { } // Handle common encryption PSSH if ('pssh' in cpData && cpData.pssh) { - return CommonEncryption.parseInitDataFromContentProtection(cpData, BASE64); + return parseInitDataFromContentProtection(cpData, BASE64); } // Handle native MS PlayReady ContentProtection elements if ('pro' in cpData && cpData.pro) { diff --git a/src/streaming/protection/drm/KeySystemW3CClearKey.js b/src/streaming/protection/drm/KeySystemW3CClearKey.js index c4b8780bcd..e1692b3ca6 100644 --- a/src/streaming/protection/drm/KeySystemW3CClearKey.js +++ b/src/streaming/protection/drm/KeySystemW3CClearKey.js @@ -31,12 +31,15 @@ import KeyPair from '../vo/KeyPair.js'; import ClearKeyKeySet from '../vo/ClearKeyKeySet.js'; -import CommonEncryption from '../CommonEncryption.js'; -import ProtectionConstants from '../../constants/ProtectionConstants.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; +import { parseInitDataFromContentProtection } from '@svta/common-media-library/drm/common-encryption/parseInitDataFromContentProtection.js'; -const uuid = ProtectionConstants.W3C_CLEARKEY_UUID; -const systemString = ProtectionConstants.CLEARKEY_KEYSTEM_STRING; +// imports from common-media-library +import { CLEAR_KEY_UUID } from '@svta/common-media-library/drm/common/const/CLEAR_KEY_UUID.js'; +import { CLEAR_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/CLEAR_KEY_SYSTEM.js'; + +const uuid = CLEAR_KEY_UUID; +const systemString = CLEAR_KEY_SYSTEM; const schemeIdURI = 'urn:uuid:' + uuid; function KeySystemW3CClearKey(config) { @@ -77,7 +80,7 @@ function KeySystemW3CClearKey(config) { } function getInitData(cp) { - return CommonEncryption.parseInitDataFromContentProtection(cp, BASE64); + return parseInitDataFromContentProtection(cp, BASE64); } function getRequestHeadersFromMessage(/*message*/) { diff --git a/src/streaming/protection/drm/KeySystemWidevine.js b/src/streaming/protection/drm/KeySystemWidevine.js index 0bc77ec49f..23f5b8c64c 100644 --- a/src/streaming/protection/drm/KeySystemWidevine.js +++ b/src/streaming/protection/drm/KeySystemWidevine.js @@ -36,12 +36,15 @@ * @implements MediaPlayer.dependencies.protection.KeySystem */ -import CommonEncryption from '../CommonEncryption.js'; -import ProtectionConstants from '../../constants/ProtectionConstants.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; +import { parseInitDataFromContentProtection } from '@svta/common-media-library/drm/common-encryption/parseInitDataFromContentProtection.js'; -const uuid = ProtectionConstants.WIDEVINE_UUID; -const systemString = ProtectionConstants.WIDEVINE_KEYSTEM_STRING; +// imports from common-media-library +import { WIDEVINE_UUID } from '@svta/common-media-library/drm/common/const/WIDEVINE_UUID.js'; +import { WIDEVINE_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/WIDEVINE_KEY_SYSTEM.js'; + +const uuid = WIDEVINE_UUID; +const systemString = WIDEVINE_KEY_SYSTEM; const schemeIdURI = 'urn:uuid:' + uuid; function KeySystemWidevine(config) { @@ -51,7 +54,7 @@ function KeySystemWidevine(config) { const BASE64 = config.BASE64; function getInitData(cp) { - return CommonEncryption.parseInitDataFromContentProtection(cp, BASE64); + return parseInitDataFromContentProtection(cp, BASE64); } function getRequestHeadersFromMessage( /*message*/ ) { diff --git a/src/streaming/protection/models/DefaultProtectionModel.js b/src/streaming/protection/models/DefaultProtectionModel.js index 2c6f673df1..d67a1208a9 100644 --- a/src/streaming/protection/models/DefaultProtectionModel.js +++ b/src/streaming/protection/models/DefaultProtectionModel.js @@ -41,15 +41,22 @@ import ProtectionKeyController from '../controllers/ProtectionKeyController.js'; import NeedKey from '../vo/NeedKey.js'; import ProtectionErrors from '../errors/ProtectionErrors.js'; import DashJSError from '../../vo/DashJSError.js'; -import KeyMessage from '../vo/KeyMessage.js'; import KeySystemAccess from '../vo/KeySystemAccess.js'; -import ProtectionConstants from '../../constants/ProtectionConstants.js'; +import KeyMessage from '../vo/KeyMessage.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; +// imports from common-media-library +import { PLAYREADY_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/PLAYREADY_KEY_SYSTEM.js'; +import { PLAYREADY_RECOMMENDATION_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/PLAYREADY_RECOMMENDATION_KEY_SYSTEM.js'; +import { WIDEVINE_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/WIDEVINE_KEY_SYSTEM.js'; +import { CLEAR_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/CLEAR_KEY_SYSTEM.js'; +import { INITIALIZATION_DATA_TYPE } from '@svta/common-media-library/drm/common/const/INITIALIZATION_DATA_TYPE.js'; +import { MEDIA_KEY_STATUSES } from '@svta/common-media-library/drm/common/const/MEDIA_KEY_STATUSES.js'; + const SYSTEM_STRING_PRIORITY = {}; -SYSTEM_STRING_PRIORITY[ProtectionConstants.PLAYREADY_KEYSTEM_STRING] = [ProtectionConstants.PLAYREADY_KEYSTEM_STRING, ProtectionConstants.PLAYREADY_RECOMMENDATION_KEYSTEM_STRING]; -SYSTEM_STRING_PRIORITY[ProtectionConstants.WIDEVINE_KEYSTEM_STRING] = [ProtectionConstants.WIDEVINE_KEYSTEM_STRING]; -SYSTEM_STRING_PRIORITY[ProtectionConstants.CLEARKEY_KEYSTEM_STRING] = [ProtectionConstants.CLEARKEY_KEYSTEM_STRING]; +SYSTEM_STRING_PRIORITY[PLAYREADY_KEY_SYSTEM] = [PLAYREADY_KEY_SYSTEM, PLAYREADY_RECOMMENDATION_KEY_SYSTEM]; +SYSTEM_STRING_PRIORITY[WIDEVINE_KEY_SYSTEM] = [WIDEVINE_KEY_SYSTEM]; +SYSTEM_STRING_PRIORITY[CLEAR_KEY_SYSTEM] = [CLEAR_KEY_SYSTEM]; function DefaultProtectionModel(config) { @@ -310,7 +317,7 @@ function DefaultProtectionModel(config) { const sessionToken = _createSessionToken(mediaKeySession, keySystemMetadata); // The "keyids" type is used for Clearkey when keys are provided directly in the protection data and a request to a license server is not needed - const dataType = keySystem.systemString === ProtectionConstants.CLEARKEY_KEYSTEM_STRING && (keySystemMetadata.initData || (keySystemMetadata.protData && keySystemMetadata.protData.clearkeys)) ? ProtectionConstants.INITIALIZATION_DATA_TYPE_KEYIDS : ProtectionConstants.INITIALIZATION_DATA_TYPE_CENC; + const dataType = keySystem.systemString === CLEAR_KEY_SYSTEM && (keySystemMetadata.initData || (keySystemMetadata.protData && keySystemMetadata.protData.clearkeys)) ? INITIALIZATION_DATA_TYPE.KEYIDS : INITIALIZATION_DATA_TYPE.CENC; mediaKeySession.generateRequest(dataType, keySystemMetadata.initData) .then(function () { @@ -520,7 +527,7 @@ function DefaultProtectionModel(config) { let usable = false; session.keyStatuses.forEach(function () { let keyStatus = _parseKeyStatus(arguments); - if (keyStatus.status === ProtectionConstants.MEDIA_KEY_STATUSES.USABLE) { + if (keyStatus.status === MEDIA_KEY_STATUSES.USABLE) { usable = true; } }); diff --git a/src/streaming/protection/models/ProtectionModel_01b.js b/src/streaming/protection/models/ProtectionModel_01b.js index 7529573e81..b4502bf608 100644 --- a/src/streaming/protection/models/ProtectionModel_01b.js +++ b/src/streaming/protection/models/ProtectionModel_01b.js @@ -45,7 +45,9 @@ import KeySystemConfiguration from '../vo/KeySystemConfiguration.js'; import KeySystemAccess from '../vo/KeySystemAccess.js'; import ProtectionErrors from '../errors/ProtectionErrors.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; -import ProtectionConstants from '../../constants/ProtectionConstants.js'; + +// imports from common-media-library +import { INITIALIZATION_DATA_TYPE } from '@svta/common-media-library/drm/common/const/INITIALIZATION_DATA_TYPE.js'; function ProtectionModel_01b(config) { @@ -311,7 +313,7 @@ function ProtectionModel_01b(config) { switch (event.type) { case api.needkey: let initData = ArrayBuffer.isView(event.initData) ? event.initData.buffer : event.initData; - eventBus.trigger(events.NEED_KEY, { key: new NeedKey(initData, ProtectionConstants.INITIALIZATION_DATA_TYPE_CENC) }); + eventBus.trigger(events.NEED_KEY, { key: new NeedKey(initData, INITIALIZATION_DATA_TYPE.CENC) }); break; case api.keyerror: diff --git a/src/streaming/protection/models/ProtectionModel_3Feb2014.js b/src/streaming/protection/models/ProtectionModel_3Feb2014.js index a4b8afcf36..5e9acf9ac8 100644 --- a/src/streaming/protection/models/ProtectionModel_3Feb2014.js +++ b/src/streaming/protection/models/ProtectionModel_3Feb2014.js @@ -43,10 +43,11 @@ import NeedKey from '../vo/NeedKey.js'; import DashJSError from '../../vo/DashJSError.js'; import ProtectionErrors from '../errors/ProtectionErrors.js'; import KeyMessage from '../vo/KeyMessage.js'; -import KeySystemConfiguration from '../vo/KeySystemConfiguration.js'; -import KeySystemAccess from '../vo/KeySystemAccess.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; -import ProtectionConstants from '../../constants/ProtectionConstants.js'; + +// imports from common-media-library +import { getCompatibleKeySystemAccess } from '@svta/common-media-library/drm/key-system/getCompatibleKeySystemAccess.js'; +import { INITIALIZATION_DATA_TYPE } from '@svta/common-media-library/drm/common/const/INITIALIZATION_DATA_TYPE.js'; function ProtectionModel_3Feb2014(config) { @@ -105,68 +106,82 @@ function ProtectionModel_3Feb2014(config) { } function requestKeySystemAccess(ksConfigurations) { - return new Promise((resolve, reject) => { - // Try key systems in order, first one with supported key system configuration - // is used - let found = false; - for (let ksIdx = 0; ksIdx < ksConfigurations.length; ksIdx++) { - const systemString = ksConfigurations[ksIdx].ks.systemString; - const configs = ksConfigurations[ksIdx].configs; - let supportedAudio = null; - let supportedVideo = null; - - // Try key system configs in order, first one with supported audio/video - // is used - for (let configIdx = 0; configIdx < configs.length; configIdx++) { - const audios = configs[configIdx].audioCapabilities; - const videos = configs[configIdx].videoCapabilities; - - // Look for supported audio container/codecs - if (audios && audios.length !== 0) { - supportedAudio = []; // Indicates that we have a requested audio config - for (let audioIdx = 0; audioIdx < audios.length; audioIdx++) { - if (window[api.MediaKeys].isTypeSupported(systemString, audios[audioIdx].contentType)) { - supportedAudio.push(audios[audioIdx]); - } - } - } - - // Look for supported video container/codecs - if (videos && videos.length !== 0) { - supportedVideo = []; // Indicates that we have a requested video config - for (let videoIdx = 0; videoIdx < videos.length; videoIdx++) { - if (window[api.MediaKeys].isTypeSupported(systemString, videos[videoIdx].contentType)) { - supportedVideo.push(videos[videoIdx]); - } - } - } - - // No supported audio or video in this configuration OR we have - // requested audio or video configuration that is not supported - if ((!supportedAudio && !supportedVideo) || - (supportedAudio && supportedAudio.length === 0) || - (supportedVideo && supportedVideo.length === 0)) { - continue; - } - - // This configuration is supported - found = true; - const ksConfig = new KeySystemConfiguration(supportedAudio, supportedVideo); - const ks = protectionKeyController.getKeySystemBySystemString(systemString); - const keySystemAccess = new KeySystemAccess(ks, ksConfig); - eventBus.trigger(events.KEY_SYSTEM_ACCESS_COMPLETE, { data: keySystemAccess }); - resolve({ data: keySystemAccess }); - break; - } - } - if (!found) { + return getCompatibleKeySystemAccess(ksConfigurations).then((keySystemAccess) => { + if (keySystemAccess) { + eventBus.trigger(events.KEY_SYSTEM_ACCESS_COMPLETE, { data: keySystemAccess }); + return { data: keySystemAccess }; + } + else { const errorMessage = 'Key system access denied! -- No valid audio/video content configurations detected!'; eventBus.trigger(events.KEY_SYSTEM_ACCESS_COMPLETE, { error: errorMessage }); - reject({ error: errorMessage }); + throw { error: errorMessage }; } - }) + }); } + // function requestKeySystemAccess(ksConfigurations) { + // return new Promise((resolve, reject) => { + // // Try key systems in order, first one with supported key system configuration + // // is used + // let found = false; + // for (let ksIdx = 0; ksIdx < ksConfigurations.length; ksIdx++) { + // const systemString = ksConfigurations[ksIdx].ks.systemString; + // const configs = ksConfigurations[ksIdx].configs; + // let supportedAudio = null; + // let supportedVideo = null; + + // // Try key system configs in order, first one with supported audio/video + // // is used + // for (let configIdx = 0; configIdx < configs.length; configIdx++) { + // const audios = configs[configIdx].audioCapabilities; + // const videos = configs[configIdx].videoCapabilities; + + // // Look for supported audio container/codecs + // if (audios && audios.length !== 0) { + // supportedAudio = []; // Indicates that we have a requested audio config + // for (let audioIdx = 0; audioIdx < audios.length; audioIdx++) { + // if (window[api.MediaKeys].isTypeSupported(systemString, audios[audioIdx].contentType)) { + // supportedAudio.push(audios[audioIdx]); + // } + // } + // } + + // // Look for supported video container/codecs + // if (videos && videos.length !== 0) { + // supportedVideo = []; // Indicates that we have a requested video config + // for (let videoIdx = 0; videoIdx < videos.length; videoIdx++) { + // if (window[api.MediaKeys].isTypeSupported(systemString, videos[videoIdx].contentType)) { + // supportedVideo.push(videos[videoIdx]); + // } + // } + // } + + // // No supported audio or video in this configuration OR we have + // // requested audio or video configuration that is not supported + // if ((!supportedAudio && !supportedVideo) || + // (supportedAudio && supportedAudio.length === 0) || + // (supportedVideo && supportedVideo.length === 0)) { + // continue; + // } + + // // This configuration is supported + // found = true; + // const ksConfig = new KeySystemConfiguration(supportedAudio, supportedVideo); + // const ks = protectionKeyController.getKeySystemBySystemString(systemString); + // const keySystemAccess = new KeySystemAccess(ks, ksConfig); + // eventBus.trigger(events.KEY_SYSTEM_ACCESS_COMPLETE, { data: keySystemAccess }); + // resolve({ data: keySystemAccess }); + // break; + // } + // } + // if (!found) { + // const errorMessage = 'Key system access denied! -- No valid audio/video content configurations detected!'; + // eventBus.trigger(events.KEY_SYSTEM_ACCESS_COMPLETE, { error: errorMessage }); + // reject({ error: errorMessage }); + // } + // }) + // } + function selectKeySystem(ksAccess) { return new Promise((resolve, reject) => { try { @@ -301,7 +316,7 @@ function ProtectionModel_3Feb2014(config) { case api.needkey: if (event.initData) { const initData = ArrayBuffer.isView(event.initData) ? event.initData.buffer : event.initData; - eventBus.trigger(events.NEED_KEY, { key: new NeedKey(initData, ProtectionConstants.INITIALIZATION_DATA_TYPE_CENC) }); + eventBus.trigger(events.NEED_KEY, { key: new NeedKey(initData, INITIALIZATION_DATA_TYPE.CENC) }); } break; } diff --git a/src/streaming/protection/servers/DRMToday.js b/src/streaming/protection/servers/DRMToday.js index 9c28e19afe..9fc9a38be0 100644 --- a/src/streaming/protection/servers/DRMToday.js +++ b/src/streaming/protection/servers/DRMToday.js @@ -36,16 +36,19 @@ * @class */ -import ProtectionConstants from '../../constants/ProtectionConstants.js'; import FactoryMaker from '../../../core/FactoryMaker.js'; +// imports from common-media-library +import { WIDEVINE_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/WIDEVINE_KEY_SYSTEM.js'; +import { PLAYREADY_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/PLAYREADY_KEY_SYSTEM.js'; + function DRMToday(config) { config = config || {}; const BASE64 = config.BASE64; const keySystems = {}; - keySystems[ProtectionConstants.WIDEVINE_KEYSTEM_STRING] = { + keySystems[WIDEVINE_KEY_SYSTEM] = { responseType: 'json', getLicenseMessage: function (response) { return BASE64.decodeArray(response.license); @@ -54,7 +57,7 @@ function DRMToday(config) { return response; } }; - keySystems[ProtectionConstants.PLAYREADY_KEYSTEM_STRING] = { + keySystems[PLAYREADY_KEY_SYSTEM] = { responseType: 'arraybuffer', getLicenseMessage: function (response) { return response; diff --git a/src/streaming/protection/vo/KeyMessage.js b/src/streaming/protection/vo/KeyMessage.js index ae3baa6931..9f8c4dfa50 100644 --- a/src/streaming/protection/vo/KeyMessage.js +++ b/src/streaming/protection/vo/KeyMessage.js @@ -28,7 +28,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -import ProtectionConstants from '../../constants/ProtectionConstants.js'; +import { MEDIA_KEY_MESSAGE_TYPES } from '@svta/common-media-library/drm/common/const/MEDIA_KEY_MESSAGE_TYPES.js'; /** * @classdesc EME-independent KeyMessage @@ -48,7 +48,7 @@ class KeyMessage { this.sessionToken = sessionToken; this.message = message; this.defaultURL = defaultURL; - this.messageType = messageType ? messageType : ProtectionConstants.MEDIA_KEY_MESSAGE_TYPES.LICENSE_REQUEST; + this.messageType = messageType ? messageType : MEDIA_KEY_MESSAGE_TYPES.LICENSE_REQUEST; } } diff --git a/src/streaming/protection/vo/KeySystemConfiguration.js b/src/streaming/protection/vo/KeySystemConfiguration.js index 523180f0ae..4b9737bb51 100644 --- a/src/streaming/protection/vo/KeySystemConfiguration.js +++ b/src/streaming/protection/vo/KeySystemConfiguration.js @@ -29,7 +29,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -import ProtectionConstants from '../../constants/ProtectionConstants.js'; +import { INITIALIZATION_DATA_TYPE } from '@svta/common-media-library/drm/common/const/INITIALIZATION_DATA_TYPE.js'; /** * @classdesc Represents a set of configurations that describe the capabilities desired for @@ -53,7 +53,7 @@ class KeySystemConfiguration { * @class */ constructor(audioCapabilities, videoCapabilities, distinctiveIdentifier, persistentState, sessionTypes, initDataTypes) { - this.initDataTypes = initDataTypes && initDataTypes.length > 0 ? initDataTypes : [ProtectionConstants.INITIALIZATION_DATA_TYPE_CENC]; + this.initDataTypes = initDataTypes && initDataTypes.length > 0 ? initDataTypes : [INITIALIZATION_DATA_TYPE.CENC]; if (audioCapabilities && audioCapabilities.length) { this.audioCapabilities = audioCapabilities; } diff --git a/src/streaming/protection/vo/LicenseRequestComplete.js b/src/streaming/protection/vo/LicenseRequestComplete.js index 869aee8235..3984860755 100644 --- a/src/streaming/protection/vo/LicenseRequestComplete.js +++ b/src/streaming/protection/vo/LicenseRequestComplete.js @@ -28,7 +28,9 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -import ProtectionConstants from '../../constants/ProtectionConstants.js'; + +// imports from common-media-library +import { MEDIA_KEY_MESSAGE_TYPES } from '@svta/common-media-library/drm/common/const/MEDIA_KEY_MESSAGE_TYPES.js'; /** * @classdesc Event indicating the receipt of a response from a license server @@ -49,7 +51,7 @@ class LicenseRequestComplete { constructor(message, sessionToken, messageType) { this.message = message; this.sessionToken = sessionToken; - this.messageType = messageType ? messageType : ProtectionConstants.MEDIA_KEY_MESSAGE_TYPES.LICENSE_REQUEST; + this.messageType = messageType ? messageType : MEDIA_KEY_MESSAGE_TYPES.LICENSE_REQUEST; } } diff --git a/src/streaming/utils/Capabilities.js b/src/streaming/utils/Capabilities.js index df5bdb9f9f..c57bc12b2f 100644 --- a/src/streaming/utils/Capabilities.js +++ b/src/streaming/utils/Capabilities.js @@ -30,10 +30,13 @@ */ import FactoryMaker from '../../core/FactoryMaker.js'; import Constants from '../constants/Constants.js'; -import ProtectionConstants from '../constants/ProtectionConstants.js'; import ObjectUtils from './ObjectUtils.js'; import Debug from '../../core/Debug.js'; +// imports from common-media-library +import { SW_SECURE_CRYPTO } from '@svta/common-media-library/drm/common/const/SW_SECURE_CRYPTO.js'; +import { WIDEVINE_KEY_SYSTEM } from '@svta/common-media-library/drm/common/const/WIDEVINE_KEY_SYSTEM.js'; + export function supportsMediaSource() { let hasManagedMediaSource = ('ManagedMediaSource' in window) let hasWebKit = ('WebKitMediaSource' in window); @@ -292,8 +295,8 @@ function Capabilities() { } let robustnessLevel = '' - if (keySystemMetadata.ks.systemString === ProtectionConstants.WIDEVINE_KEYSTEM_STRING) { - robustnessLevel = ProtectionConstants.ROBUSTNESS_STRINGS.WIDEVINE.SW_SECURE_CRYPTO; + if (keySystemMetadata.ks.systemString === WIDEVINE_KEY_SYSTEM) { + robustnessLevel = SW_SECURE_CRYPTO; } const protData = keySystemMetadata.protData const audioRobustness = (protData && protData.audioRobustness && protData.audioRobustness.length > 0) ? protData.audioRobustness : robustnessLevel;