download
raw
6.54 kB
import { optionalSelf } from './global';
import { changeEndianness } from './keysystem-util';
import { base64Decode } from './numeric-encoding-utils';
import type { DRMSystemOptions, EMEControllerConfig } from '../config';
/**
* @see https://developer.mozilla.org/en-US/docs/Web/API/Navigator/requestMediaKeySystemAccess
*/
export const enum KeySystems {
CLEARKEY = 'org.w3.clearkey',
FAIRPLAY = 'com.apple.fps',
PLAYREADY = 'com.microsoft.playready',
WIDEVINE = 'com.widevine.alpha',
}
// Playlist #EXT-X-KEY KEYFORMAT values
export const enum KeySystemFormats {
CLEARKEY = 'org.w3.clearkey',
FAIRPLAY = 'com.apple.streamingkeydelivery',
PLAYREADY = 'com.microsoft.playready',
WIDEVINE = 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed',
}
export function keySystemFormatToKeySystemDomain(
format: KeySystemFormats,
): KeySystems | undefined {
switch (format) {
case KeySystemFormats.FAIRPLAY:
return KeySystems.FAIRPLAY;
case KeySystemFormats.PLAYREADY:
return KeySystems.PLAYREADY;
case KeySystemFormats.WIDEVINE:
return KeySystems.WIDEVINE;
case KeySystemFormats.CLEARKEY:
return KeySystems.CLEARKEY;
}
}
// System IDs for which we can extract a key ID from "encrypted" event PSSH
export const enum KeySystemIds {
CENC = '1077efecc0b24d02ace33c1e52e2fb4b',
CLEARKEY = 'e2719d58a985b3c9781ab030af78d30e',
FAIRPLAY = '94ce86fb07ff4f43adb893d2fa968ca2',
PLAYREADY = '9a04f07998404286ab92e65be0885f95',
WIDEVINE = 'edef8ba979d64acea3c827dcd51d21ed',
}
export function keySystemIdToKeySystemDomain(
systemId: KeySystemIds,
): KeySystems | undefined {
if (systemId === KeySystemIds.WIDEVINE) {
return KeySystems.WIDEVINE;
} else if (systemId === KeySystemIds.PLAYREADY) {
return KeySystems.PLAYREADY;
} else if (
systemId === KeySystemIds.CENC ||
systemId === KeySystemIds.CLEARKEY
) {
return KeySystems.CLEARKEY;
}
}
export function keySystemDomainToKeySystemFormat(
keySystem: KeySystems,
): KeySystemFormats | undefined {
switch (keySystem) {
case KeySystems.FAIRPLAY:
return KeySystemFormats.FAIRPLAY;
case KeySystems.PLAYREADY:
return KeySystemFormats.PLAYREADY;
case KeySystems.WIDEVINE:
return KeySystemFormats.WIDEVINE;
case KeySystems.CLEARKEY:
return KeySystemFormats.CLEARKEY;
}
}
export function getKeySystemsForConfig(
config: EMEControllerConfig,
): KeySystems[] {
const { drmSystems, widevineLicenseUrl } = config;
const keySystemsToAttempt: KeySystems[] = drmSystems
? [
KeySystems.FAIRPLAY,
KeySystems.WIDEVINE,
KeySystems.PLAYREADY,
KeySystems.CLEARKEY,
].filter((keySystem) => !!drmSystems[keySystem])
: [];
if (!keySystemsToAttempt[KeySystems.WIDEVINE] && widevineLicenseUrl) {
keySystemsToAttempt.push(KeySystems.WIDEVINE);
}
return keySystemsToAttempt;
}
export type MediaKeyFunc = (
keySystem: KeySystems,
supportedConfigurations: MediaKeySystemConfiguration[],
) => Promise<MediaKeySystemAccess>;
export const requestMediaKeySystemAccess = (function (): MediaKeyFunc | null {
if (optionalSelf?.navigator?.requestMediaKeySystemAccess) {
return self.navigator.requestMediaKeySystemAccess.bind(self.navigator);
} else {
return null;
}
})();
/**
* @see https://developer.mozilla.org/en-US/docs/Web/API/MediaKeySystemConfiguration
*/
export function getSupportedMediaKeySystemConfigurations(
keySystem: KeySystems,
audioCodecs: string[],
videoCodecs: string[],
drmSystemOptions: DRMSystemOptions,
): MediaKeySystemConfiguration[] {
let initDataTypes: string[];
switch (keySystem) {
case KeySystems.FAIRPLAY:
initDataTypes = ['cenc', 'sinf'];
break;
case KeySystems.WIDEVINE:
case KeySystems.PLAYREADY:
initDataTypes = ['cenc'];
break;
case KeySystems.CLEARKEY:
initDataTypes = ['cenc', 'keyids'];
break;
default:
throw new Error(`Unknown key-system: ${keySystem}`);
}
return createMediaKeySystemConfigurations(
initDataTypes,
audioCodecs,
videoCodecs,
drmSystemOptions,
);
}
function createMediaKeySystemConfigurations(
initDataTypes: string[],
audioCodecs: string[],
videoCodecs: string[],
drmSystemOptions: DRMSystemOptions,
): MediaKeySystemConfiguration[] {
const baseConfig: MediaKeySystemConfiguration = {
initDataTypes: initDataTypes,
persistentState: drmSystemOptions.persistentState || 'optional',
distinctiveIdentifier: drmSystemOptions.distinctiveIdentifier || 'optional',
sessionTypes: drmSystemOptions.sessionTypes || [
drmSystemOptions.sessionType || 'temporary',
],
audioCapabilities: audioCodecs.map((codec) => ({
contentType: `audio/mp4; codecs=${codec}`,
robustness: drmSystemOptions.audioRobustness || '',
encryptionScheme: drmSystemOptions.audioEncryptionScheme || null,
})),
videoCapabilities: videoCodecs.map((codec) => ({
contentType: `video/mp4; codecs=${codec}`,
robustness: drmSystemOptions.videoRobustness || '',
encryptionScheme: drmSystemOptions.videoEncryptionScheme || null,
})),
};
return [baseConfig];
}
export function isPersistentSessionType(
drmSystemOptions: DRMSystemOptions | undefined,
): boolean {
return (
!!drmSystemOptions &&
(drmSystemOptions.sessionType === 'persistent-license' ||
!!drmSystemOptions.sessionTypes?.some(
(type) => type === 'persistent-license',
))
);
}
export function parsePlayReadyWRM(keyBytes: Uint8Array<ArrayBuffer>) {
const keyBytesUtf16 = new Uint16Array(
keyBytes.buffer,
keyBytes.byteOffset,
keyBytes.byteLength / 2,
);
const keyByteStr = String.fromCharCode.apply(null, Array.from(keyBytesUtf16));
// Parse Playready WRMHeader XML
const xmlKeyBytes = keyByteStr.substring(
keyByteStr.indexOf('<'),
keyByteStr.length,
);
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlKeyBytes, 'text/xml');
const keyData = xmlDoc.getElementsByTagName('KID')[0];
if (keyData) {
const keyId = keyData.childNodes[0]
? keyData.childNodes[0].nodeValue
: keyData.getAttribute('VALUE');
if (keyId) {
const keyIdArray = base64Decode(keyId).subarray(0, 16);
// KID value in PRO is a base64-encoded little endian GUID interpretation of UUID
// KID value in ‘tenc’ is a big endian UUID GUID interpretation of UUID
changeEndianness(keyIdArray);
return keyIdArray;
}
}
return null;
}

Xet Storage Details

Size:
6.54 kB
·
Xet hash:
4e094362d6b0ebf7a805aa1566f2e599abf9f526d9adc75b862584feb3a50f54

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.