hls.js 1.5.18 → 1.5.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hls.js +250 -203
- package/dist/hls.js.d.ts +3 -4
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +24 -29
- package/dist/hls.light.js.map +1 -1
- package/dist/hls.light.min.js +1 -1
- package/dist/hls.light.min.js.map +1 -1
- package/dist/hls.light.mjs +23 -28
- package/dist/hls.light.mjs.map +1 -1
- package/dist/hls.min.js +1 -1
- package/dist/hls.min.js.map +1 -1
- package/dist/hls.mjs +200 -157
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/package.json +1 -1
- package/src/controller/eme-controller.ts +184 -124
- package/src/loader/key-loader.ts +6 -1
- package/src/loader/level-key.ts +6 -30
- package/src/utils/level-helper.ts +37 -38
- package/src/utils/mediakeys-helper.ts +34 -1
package/dist/hls.mjs
CHANGED
@@ -411,7 +411,7 @@ function enableLogs(debugConfig, id) {
|
|
411
411
|
// Some browsers don't allow to use bind on console object anyway
|
412
412
|
// fallback to default if needed
|
413
413
|
try {
|
414
|
-
exportedLogger.log(`Debug logs enabled for "${id}" in hls.js version ${"1.5.
|
414
|
+
exportedLogger.log(`Debug logs enabled for "${id}" in hls.js version ${"1.5.19"}`);
|
415
415
|
} catch (e) {
|
416
416
|
exportedLogger = fakeLogger;
|
417
417
|
}
|
@@ -1157,6 +1157,27 @@ function createMediaKeySystemConfigurations(initDataTypes, audioCodecs, videoCod
|
|
1157
1157
|
};
|
1158
1158
|
return [baseConfig];
|
1159
1159
|
}
|
1160
|
+
function parsePlayReadyWRM(keyBytes) {
|
1161
|
+
const keyBytesUtf16 = new Uint16Array(keyBytes.buffer, keyBytes.byteOffset, keyBytes.byteLength / 2);
|
1162
|
+
const keyByteStr = String.fromCharCode.apply(null, Array.from(keyBytesUtf16));
|
1163
|
+
|
1164
|
+
// Parse Playready WRMHeader XML
|
1165
|
+
const xmlKeyBytes = keyByteStr.substring(keyByteStr.indexOf('<'), keyByteStr.length);
|
1166
|
+
const parser = new DOMParser();
|
1167
|
+
const xmlDoc = parser.parseFromString(xmlKeyBytes, 'text/xml');
|
1168
|
+
const keyData = xmlDoc.getElementsByTagName('KID')[0];
|
1169
|
+
if (keyData) {
|
1170
|
+
const keyId = keyData.childNodes[0] ? keyData.childNodes[0].nodeValue : keyData.getAttribute('VALUE');
|
1171
|
+
if (keyId) {
|
1172
|
+
const keyIdArray = base64Decode(keyId).subarray(0, 16);
|
1173
|
+
// KID value in PRO is a base64-encoded little endian GUID interpretation of UUID
|
1174
|
+
// KID value in ‘tenc’ is a big endian UUID GUID interpretation of UUID
|
1175
|
+
changeEndianness(keyIdArray);
|
1176
|
+
return keyIdArray;
|
1177
|
+
}
|
1178
|
+
}
|
1179
|
+
return null;
|
1180
|
+
}
|
1160
1181
|
|
1161
1182
|
function sliceUint8(array, start, end) {
|
1162
1183
|
// @ts-expect-error This polyfills IE11 usage of Uint8Array slice.
|
@@ -2773,6 +2794,8 @@ class LevelKey {
|
|
2773
2794
|
if (keyBytes) {
|
2774
2795
|
switch (this.keyFormat) {
|
2775
2796
|
case KeySystemFormats.WIDEVINE:
|
2797
|
+
// Setting `pssh` on this LevelKey/DecryptData allows HLS.js to generate a session using
|
2798
|
+
// the playlist-key before the "encrypted" event. (Comment out to only use "encrypted" path.)
|
2776
2799
|
this.pssh = keyBytes;
|
2777
2800
|
// In case of widevine keyID is embedded in PSSH box. Read Key ID.
|
2778
2801
|
if (keyBytes.length >= 22) {
|
@@ -2782,25 +2805,11 @@ class LevelKey {
|
|
2782
2805
|
case KeySystemFormats.PLAYREADY:
|
2783
2806
|
{
|
2784
2807
|
const PlayReadyKeySystemUUID = new Uint8Array([0x9a, 0x04, 0xf0, 0x79, 0x98, 0x40, 0x42, 0x86, 0xab, 0x92, 0xe6, 0x5b, 0xe0, 0x88, 0x5f, 0x95]);
|
2808
|
+
|
2809
|
+
// Setting `pssh` on this LevelKey/DecryptData allows HLS.js to generate a session using
|
2810
|
+
// the playlist-key before the "encrypted" event. (Comment out to only use "encrypted" path.)
|
2785
2811
|
this.pssh = mp4pssh(PlayReadyKeySystemUUID, null, keyBytes);
|
2786
|
-
|
2787
|
-
const keyByteStr = String.fromCharCode.apply(null, Array.from(keyBytesUtf16));
|
2788
|
-
|
2789
|
-
// Parse Playready WRMHeader XML
|
2790
|
-
const xmlKeyBytes = keyByteStr.substring(keyByteStr.indexOf('<'), keyByteStr.length);
|
2791
|
-
const parser = new DOMParser();
|
2792
|
-
const xmlDoc = parser.parseFromString(xmlKeyBytes, 'text/xml');
|
2793
|
-
const keyData = xmlDoc.getElementsByTagName('KID')[0];
|
2794
|
-
if (keyData) {
|
2795
|
-
const keyId = keyData.childNodes[0] ? keyData.childNodes[0].nodeValue : keyData.getAttribute('VALUE');
|
2796
|
-
if (keyId) {
|
2797
|
-
const keyIdArray = base64Decode(keyId).subarray(0, 16);
|
2798
|
-
// KID value in PRO is a base64-encoded little endian GUID interpretation of UUID
|
2799
|
-
// KID value in ‘tenc’ is a big endian UUID GUID interpretation of UUID
|
2800
|
-
changeEndianness(keyIdArray);
|
2801
|
-
this.keyId = keyIdArray;
|
2802
|
-
}
|
2803
|
-
}
|
2812
|
+
this.keyId = parsePlayReadyWRM(keyBytes);
|
2804
2813
|
break;
|
2805
2814
|
}
|
2806
2815
|
default:
|
@@ -5250,15 +5259,16 @@ function mergeDetails(oldDetails, newDetails) {
|
|
5250
5259
|
delete oldDetails.fragmentHint.endPTS;
|
5251
5260
|
}
|
5252
5261
|
// check if old/new playlists have fragments in common
|
5253
|
-
// loop through overlapping SN and update startPTS
|
5254
|
-
let ccOffset = 0;
|
5262
|
+
// loop through overlapping SN and update startPTS, cc, and duration if any found
|
5255
5263
|
let PTSFrag;
|
5256
|
-
mapFragmentIntersection(oldDetails, newDetails, (oldFrag, newFrag) => {
|
5257
|
-
if (
|
5258
|
-
|
5259
|
-
|
5260
|
-
|
5261
|
-
|
5264
|
+
mapFragmentIntersection(oldDetails, newDetails, (oldFrag, newFrag, newFragIndex, newFragments) => {
|
5265
|
+
if (newDetails.skippedSegments) {
|
5266
|
+
if (newFrag.cc !== oldFrag.cc) {
|
5267
|
+
const ccOffset = oldFrag.cc - newFrag.cc;
|
5268
|
+
for (let i = newFragIndex; i < newFragments.length; i++) {
|
5269
|
+
newFragments[i].cc += ccOffset;
|
5270
|
+
}
|
5271
|
+
}
|
5262
5272
|
}
|
5263
5273
|
if (isFiniteNumber(oldFrag.startPTS) && isFiniteNumber(oldFrag.endPTS)) {
|
5264
5274
|
newFrag.start = newFrag.startPTS = oldFrag.startPTS;
|
@@ -5283,8 +5293,9 @@ function mergeDetails(oldDetails, newDetails) {
|
|
5283
5293
|
currentInitSegment = oldFrag.initSegment;
|
5284
5294
|
}
|
5285
5295
|
});
|
5296
|
+
const newFragments = newDetails.fragments;
|
5286
5297
|
if (currentInitSegment) {
|
5287
|
-
const fragmentsToCheck = newDetails.fragmentHint ?
|
5298
|
+
const fragmentsToCheck = newDetails.fragmentHint ? newFragments.concat(newDetails.fragmentHint) : newFragments;
|
5288
5299
|
fragmentsToCheck.forEach(frag => {
|
5289
5300
|
var _currentInitSegment;
|
5290
5301
|
if (frag && (!frag.initSegment || frag.initSegment.relurl === ((_currentInitSegment = currentInitSegment) == null ? void 0 : _currentInitSegment.relurl))) {
|
@@ -5293,27 +5304,20 @@ function mergeDetails(oldDetails, newDetails) {
|
|
5293
5304
|
});
|
5294
5305
|
}
|
5295
5306
|
if (newDetails.skippedSegments) {
|
5296
|
-
newDetails.deltaUpdateFailed =
|
5307
|
+
newDetails.deltaUpdateFailed = newFragments.some(frag => !frag);
|
5297
5308
|
if (newDetails.deltaUpdateFailed) {
|
5298
5309
|
logger.warn('[level-helper] Previous playlist missing segments skipped in delta playlist');
|
5299
5310
|
for (let i = newDetails.skippedSegments; i--;) {
|
5300
|
-
|
5311
|
+
newFragments.shift();
|
5312
|
+
}
|
5313
|
+
newDetails.startSN = newFragments[0].sn;
|
5314
|
+
} else {
|
5315
|
+
if (newDetails.canSkipDateRanges) {
|
5316
|
+
newDetails.dateRanges = mergeDateRanges(oldDetails.dateRanges, newDetails.dateRanges, newDetails.recentlyRemovedDateranges);
|
5301
5317
|
}
|
5302
|
-
newDetails.startSN = newDetails.fragments[0].sn;
|
5303
|
-
newDetails.startCC = newDetails.fragments[0].cc;
|
5304
|
-
} else if (newDetails.canSkipDateRanges) {
|
5305
|
-
newDetails.dateRanges = mergeDateRanges(oldDetails.dateRanges, newDetails.dateRanges, newDetails.recentlyRemovedDateranges);
|
5306
|
-
}
|
5307
|
-
}
|
5308
|
-
const newFragments = newDetails.fragments;
|
5309
|
-
if (ccOffset) {
|
5310
|
-
logger.warn('discontinuity sliding from playlist, take drift into account');
|
5311
|
-
for (let i = 0; i < newFragments.length; i++) {
|
5312
|
-
newFragments[i].cc += ccOffset;
|
5313
5318
|
}
|
5314
|
-
}
|
5315
|
-
if (newDetails.skippedSegments) {
|
5316
5319
|
newDetails.startCC = newDetails.fragments[0].cc;
|
5320
|
+
newDetails.endCC = newFragments[newFragments.length - 1].cc;
|
5317
5321
|
}
|
5318
5322
|
|
5319
5323
|
// Merge parts
|
@@ -5397,7 +5401,7 @@ function mapFragmentIntersection(oldDetails, newDetails, intersectionFn) {
|
|
5397
5401
|
newFrag = newDetails.fragments[i] = oldFrag;
|
5398
5402
|
}
|
5399
5403
|
if (oldFrag && newFrag) {
|
5400
|
-
intersectionFn(oldFrag, newFrag);
|
5404
|
+
intersectionFn(oldFrag, newFrag, i, newFrags);
|
5401
5405
|
}
|
5402
5406
|
}
|
5403
5407
|
}
|
@@ -22012,12 +22016,148 @@ class EMEController {
|
|
22012
22016
|
this.mediaKeySessions = [];
|
22013
22017
|
this.keyIdToKeySessionPromise = {};
|
22014
22018
|
this.setMediaKeysQueue = EMEController.CDMCleanupPromise ? [EMEController.CDMCleanupPromise] : [];
|
22015
|
-
this.onMediaEncrypted = this._onMediaEncrypted.bind(this);
|
22016
|
-
this.onWaitingForKey = this._onWaitingForKey.bind(this);
|
22017
22019
|
this.debug = logger.debug.bind(logger, LOGGER_PREFIX);
|
22018
22020
|
this.log = logger.log.bind(logger, LOGGER_PREFIX);
|
22019
22021
|
this.warn = logger.warn.bind(logger, LOGGER_PREFIX);
|
22020
22022
|
this.error = logger.error.bind(logger, LOGGER_PREFIX);
|
22023
|
+
this.onMediaEncrypted = event => {
|
22024
|
+
const {
|
22025
|
+
initDataType,
|
22026
|
+
initData
|
22027
|
+
} = event;
|
22028
|
+
const logMessage = `"${event.type}" event: init data type: "${initDataType}"`;
|
22029
|
+
this.debug(logMessage);
|
22030
|
+
|
22031
|
+
// Ignore event when initData is null
|
22032
|
+
if (initData === null) {
|
22033
|
+
return;
|
22034
|
+
}
|
22035
|
+
if (!this.keyFormatPromise) {
|
22036
|
+
let keySystems = Object.keys(this.keySystemAccessPromises);
|
22037
|
+
if (!keySystems.length) {
|
22038
|
+
keySystems = getKeySystemsForConfig(this.config);
|
22039
|
+
}
|
22040
|
+
const keyFormats = keySystems.map(keySystemDomainToKeySystemFormat).filter(k => !!k);
|
22041
|
+
this.keyFormatPromise = this.getKeyFormatPromise(keyFormats);
|
22042
|
+
}
|
22043
|
+
this.keyFormatPromise.then(keySystemFormat => {
|
22044
|
+
const keySystem = keySystemFormatToKeySystemDomain(keySystemFormat);
|
22045
|
+
let keyId;
|
22046
|
+
let keySystemDomain;
|
22047
|
+
if (initDataType === 'sinf') {
|
22048
|
+
if (keySystem !== KeySystems.FAIRPLAY) {
|
22049
|
+
this.warn(`Ignoring unexpected "${event.type}" event with init data type: "${initDataType}" for selected key-system ${keySystem}`);
|
22050
|
+
return;
|
22051
|
+
}
|
22052
|
+
// Match sinf keyId to playlist skd://keyId=
|
22053
|
+
const json = bin2str(new Uint8Array(initData));
|
22054
|
+
try {
|
22055
|
+
const sinf = base64Decode(JSON.parse(json).sinf);
|
22056
|
+
const tenc = parseSinf(sinf);
|
22057
|
+
if (!tenc) {
|
22058
|
+
throw new Error(`'schm' box missing or not cbcs/cenc with schi > tenc`);
|
22059
|
+
}
|
22060
|
+
keyId = tenc.subarray(8, 24);
|
22061
|
+
keySystemDomain = KeySystems.FAIRPLAY;
|
22062
|
+
} catch (error) {
|
22063
|
+
this.warn(`${logMessage} Failed to parse sinf: ${error}`);
|
22064
|
+
return;
|
22065
|
+
}
|
22066
|
+
} else {
|
22067
|
+
if (keySystem !== KeySystems.WIDEVINE && keySystem !== KeySystems.PLAYREADY) {
|
22068
|
+
this.warn(`Ignoring unexpected "${event.type}" event with init data type: "${initDataType}" for selected key-system ${keySystem}`);
|
22069
|
+
return;
|
22070
|
+
}
|
22071
|
+
// Support Widevine/PlayReady clear-lead key-session creation (otherwise depend on playlist keys)
|
22072
|
+
const psshResults = parseMultiPssh(initData);
|
22073
|
+
const psshInfos = psshResults.filter(pssh => !!pssh.systemId && keySystemIdToKeySystemDomain(pssh.systemId) === keySystem);
|
22074
|
+
if (psshInfos.length > 1) {
|
22075
|
+
this.warn(`${logMessage} Using first of ${psshInfos.length} pssh found for selected key-system ${keySystem}`);
|
22076
|
+
}
|
22077
|
+
const psshInfo = psshInfos[0];
|
22078
|
+
if (!psshInfo) {
|
22079
|
+
if (psshResults.length === 0 || psshResults.some(pssh => !pssh.systemId)) {
|
22080
|
+
this.warn(`${logMessage} contains incomplete or invalid pssh data`);
|
22081
|
+
} else {
|
22082
|
+
this.log(`ignoring ${logMessage} for ${psshResults.map(pssh => keySystemIdToKeySystemDomain(pssh.systemId)).join(',')} pssh data in favor of playlist keys`);
|
22083
|
+
}
|
22084
|
+
return;
|
22085
|
+
}
|
22086
|
+
keySystemDomain = keySystemIdToKeySystemDomain(psshInfo.systemId);
|
22087
|
+
if (psshInfo.version === 0 && psshInfo.data) {
|
22088
|
+
if (keySystemDomain === KeySystems.WIDEVINE) {
|
22089
|
+
const offset = psshInfo.data.length - 22;
|
22090
|
+
keyId = psshInfo.data.subarray(offset, offset + 16);
|
22091
|
+
} else if (keySystemDomain === KeySystems.PLAYREADY) {
|
22092
|
+
keyId = parsePlayReadyWRM(psshInfo.data);
|
22093
|
+
}
|
22094
|
+
}
|
22095
|
+
}
|
22096
|
+
if (!keySystemDomain || !keyId) {
|
22097
|
+
this.log(`Unable to handle ${logMessage} with key-system ${keySystem}`);
|
22098
|
+
return;
|
22099
|
+
}
|
22100
|
+
const keyIdHex = Hex.hexDump(keyId);
|
22101
|
+
const {
|
22102
|
+
keyIdToKeySessionPromise,
|
22103
|
+
mediaKeySessions
|
22104
|
+
} = this;
|
22105
|
+
let keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex];
|
22106
|
+
for (let i = 0; i < mediaKeySessions.length; i++) {
|
22107
|
+
// Match playlist key
|
22108
|
+
const keyContext = mediaKeySessions[i];
|
22109
|
+
const decryptdata = keyContext.decryptdata;
|
22110
|
+
if (!decryptdata.keyId) {
|
22111
|
+
continue;
|
22112
|
+
}
|
22113
|
+
const oldKeyIdHex = Hex.hexDump(decryptdata.keyId);
|
22114
|
+
if (keyIdHex === oldKeyIdHex || decryptdata.uri.replace(/-/g, '').indexOf(keyIdHex) !== -1) {
|
22115
|
+
keySessionContextPromise = keyIdToKeySessionPromise[oldKeyIdHex];
|
22116
|
+
if (decryptdata.pssh) {
|
22117
|
+
break;
|
22118
|
+
}
|
22119
|
+
delete keyIdToKeySessionPromise[oldKeyIdHex];
|
22120
|
+
decryptdata.pssh = new Uint8Array(initData);
|
22121
|
+
decryptdata.keyId = keyId;
|
22122
|
+
keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex] = keySessionContextPromise.then(() => {
|
22123
|
+
return this.generateRequestWithPreferredKeySession(keyContext, initDataType, initData, 'encrypted-event-key-match');
|
22124
|
+
});
|
22125
|
+
keySessionContextPromise.catch(error => this.handleError(error));
|
22126
|
+
break;
|
22127
|
+
}
|
22128
|
+
}
|
22129
|
+
if (!keySessionContextPromise) {
|
22130
|
+
if (keySystemDomain !== keySystem) {
|
22131
|
+
this.log(`Ignoring "${logMessage}" with ${keySystemDomain} init data for selected key-system ${keySystem}`);
|
22132
|
+
return;
|
22133
|
+
}
|
22134
|
+
// "Clear-lead" (misc key not encountered in playlist)
|
22135
|
+
keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex] = this.getKeySystemSelectionPromise([keySystemDomain]).then(({
|
22136
|
+
keySystem,
|
22137
|
+
mediaKeys
|
22138
|
+
}) => {
|
22139
|
+
var _keySystemToKeySystem;
|
22140
|
+
this.throwIfDestroyed();
|
22141
|
+
const decryptdata = new LevelKey('ISO-23001-7', keyIdHex, (_keySystemToKeySystem = keySystemDomainToKeySystemFormat(keySystem)) != null ? _keySystemToKeySystem : '');
|
22142
|
+
decryptdata.pssh = new Uint8Array(initData);
|
22143
|
+
decryptdata.keyId = keyId;
|
22144
|
+
return this.attemptSetMediaKeys(keySystem, mediaKeys).then(() => {
|
22145
|
+
this.throwIfDestroyed();
|
22146
|
+
const keySessionContext = this.createMediaKeySessionContext({
|
22147
|
+
decryptdata,
|
22148
|
+
keySystem,
|
22149
|
+
mediaKeys
|
22150
|
+
});
|
22151
|
+
return this.generateRequestWithPreferredKeySession(keySessionContext, initDataType, initData, 'encrypted-event-no-match');
|
22152
|
+
});
|
22153
|
+
});
|
22154
|
+
keySessionContextPromise.catch(error => this.handleError(error));
|
22155
|
+
}
|
22156
|
+
});
|
22157
|
+
};
|
22158
|
+
this.onWaitingForKey = event => {
|
22159
|
+
this.log(`"${event.type}" event`);
|
22160
|
+
};
|
22021
22161
|
this.hls = hls;
|
22022
22162
|
this.config = hls.config;
|
22023
22163
|
this.registerListeners();
|
@@ -22031,9 +22171,9 @@ class EMEController {
|
|
22031
22171
|
config.licenseXhrSetup = config.licenseResponseCallback = undefined;
|
22032
22172
|
config.drmSystems = config.drmSystemOptions = {};
|
22033
22173
|
// @ts-ignore
|
22034
|
-
this.hls = this.
|
22174
|
+
this.hls = this.config = this.keyIdToKeySessionPromise = null;
|
22035
22175
|
// @ts-ignore
|
22036
|
-
this.
|
22176
|
+
this.onMediaEncrypted = this.onWaitingForKey = null;
|
22037
22177
|
}
|
22038
22178
|
registerListeners() {
|
22039
22179
|
this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
@@ -22061,7 +22201,13 @@ class EMEController {
|
|
22061
22201
|
if (keySystem === KeySystems.WIDEVINE && widevineLicenseUrl) {
|
22062
22202
|
return widevineLicenseUrl;
|
22063
22203
|
}
|
22064
|
-
|
22204
|
+
}
|
22205
|
+
getLicenseServerUrlOrThrow(keySystem) {
|
22206
|
+
const url = this.getLicenseServerUrl(keySystem);
|
22207
|
+
if (url === undefined) {
|
22208
|
+
throw new Error(`no license server URL configured for key-system "${keySystem}"`);
|
22209
|
+
}
|
22210
|
+
return url;
|
22065
22211
|
}
|
22066
22212
|
getServerCertificateUrl(keySystem) {
|
22067
22213
|
const {
|
@@ -22297,111 +22443,6 @@ class EMEController {
|
|
22297
22443
|
}
|
22298
22444
|
return this.attemptKeySystemAccess(keySystemsToAttempt);
|
22299
22445
|
}
|
22300
|
-
_onMediaEncrypted(event) {
|
22301
|
-
const {
|
22302
|
-
initDataType,
|
22303
|
-
initData
|
22304
|
-
} = event;
|
22305
|
-
const logMessage = `"${event.type}" event: init data type: "${initDataType}"`;
|
22306
|
-
this.debug(logMessage);
|
22307
|
-
|
22308
|
-
// Ignore event when initData is null
|
22309
|
-
if (initData === null) {
|
22310
|
-
return;
|
22311
|
-
}
|
22312
|
-
let keyId;
|
22313
|
-
let keySystemDomain;
|
22314
|
-
if (initDataType === 'sinf' && this.config.drmSystems[KeySystems.FAIRPLAY]) {
|
22315
|
-
// Match sinf keyId to playlist skd://keyId=
|
22316
|
-
const json = bin2str(new Uint8Array(initData));
|
22317
|
-
try {
|
22318
|
-
const sinf = base64Decode(JSON.parse(json).sinf);
|
22319
|
-
const tenc = parseSinf(new Uint8Array(sinf));
|
22320
|
-
if (!tenc) {
|
22321
|
-
throw new Error(`'schm' box missing or not cbcs/cenc with schi > tenc`);
|
22322
|
-
}
|
22323
|
-
keyId = tenc.subarray(8, 24);
|
22324
|
-
keySystemDomain = KeySystems.FAIRPLAY;
|
22325
|
-
} catch (error) {
|
22326
|
-
this.warn(`${logMessage} Failed to parse sinf: ${error}`);
|
22327
|
-
return;
|
22328
|
-
}
|
22329
|
-
} else {
|
22330
|
-
// Support Widevine clear-lead key-session creation (otherwise depend on playlist keys)
|
22331
|
-
const psshResults = parseMultiPssh(initData);
|
22332
|
-
const psshInfo = psshResults.filter(pssh => pssh.systemId === KeySystemIds.WIDEVINE)[0];
|
22333
|
-
if (!psshInfo) {
|
22334
|
-
if (psshResults.length === 0 || psshResults.some(pssh => !pssh.systemId)) {
|
22335
|
-
this.warn(`${logMessage} contains incomplete or invalid pssh data`);
|
22336
|
-
} else {
|
22337
|
-
this.log(`ignoring ${logMessage} for ${psshResults.map(pssh => keySystemIdToKeySystemDomain(pssh.systemId)).join(',')} pssh data in favor of playlist keys`);
|
22338
|
-
}
|
22339
|
-
return;
|
22340
|
-
}
|
22341
|
-
keySystemDomain = keySystemIdToKeySystemDomain(psshInfo.systemId);
|
22342
|
-
if (psshInfo.version === 0 && psshInfo.data) {
|
22343
|
-
const offset = psshInfo.data.length - 22;
|
22344
|
-
keyId = psshInfo.data.subarray(offset, offset + 16);
|
22345
|
-
}
|
22346
|
-
}
|
22347
|
-
if (!keySystemDomain || !keyId) {
|
22348
|
-
return;
|
22349
|
-
}
|
22350
|
-
const keyIdHex = Hex.hexDump(keyId);
|
22351
|
-
const {
|
22352
|
-
keyIdToKeySessionPromise,
|
22353
|
-
mediaKeySessions
|
22354
|
-
} = this;
|
22355
|
-
let keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex];
|
22356
|
-
for (let i = 0; i < mediaKeySessions.length; i++) {
|
22357
|
-
// Match playlist key
|
22358
|
-
const keyContext = mediaKeySessions[i];
|
22359
|
-
const decryptdata = keyContext.decryptdata;
|
22360
|
-
if (!decryptdata.keyId) {
|
22361
|
-
continue;
|
22362
|
-
}
|
22363
|
-
const oldKeyIdHex = Hex.hexDump(decryptdata.keyId);
|
22364
|
-
if (keyIdHex === oldKeyIdHex || decryptdata.uri.replace(/-/g, '').indexOf(keyIdHex) !== -1) {
|
22365
|
-
keySessionContextPromise = keyIdToKeySessionPromise[oldKeyIdHex];
|
22366
|
-
if (decryptdata.pssh) {
|
22367
|
-
break;
|
22368
|
-
}
|
22369
|
-
delete keyIdToKeySessionPromise[oldKeyIdHex];
|
22370
|
-
decryptdata.pssh = new Uint8Array(initData);
|
22371
|
-
decryptdata.keyId = keyId;
|
22372
|
-
keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex] = keySessionContextPromise.then(() => {
|
22373
|
-
return this.generateRequestWithPreferredKeySession(keyContext, initDataType, initData, 'encrypted-event-key-match');
|
22374
|
-
});
|
22375
|
-
break;
|
22376
|
-
}
|
22377
|
-
}
|
22378
|
-
if (!keySessionContextPromise) {
|
22379
|
-
// Clear-lead key (not encountered in playlist)
|
22380
|
-
keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex] = this.getKeySystemSelectionPromise([keySystemDomain]).then(({
|
22381
|
-
keySystem,
|
22382
|
-
mediaKeys
|
22383
|
-
}) => {
|
22384
|
-
var _keySystemToKeySystem;
|
22385
|
-
this.throwIfDestroyed();
|
22386
|
-
const decryptdata = new LevelKey('ISO-23001-7', keyIdHex, (_keySystemToKeySystem = keySystemDomainToKeySystemFormat(keySystem)) != null ? _keySystemToKeySystem : '');
|
22387
|
-
decryptdata.pssh = new Uint8Array(initData);
|
22388
|
-
decryptdata.keyId = keyId;
|
22389
|
-
return this.attemptSetMediaKeys(keySystem, mediaKeys).then(() => {
|
22390
|
-
this.throwIfDestroyed();
|
22391
|
-
const keySessionContext = this.createMediaKeySessionContext({
|
22392
|
-
decryptdata,
|
22393
|
-
keySystem,
|
22394
|
-
mediaKeys
|
22395
|
-
});
|
22396
|
-
return this.generateRequestWithPreferredKeySession(keySessionContext, initDataType, initData, 'encrypted-event-no-match');
|
22397
|
-
});
|
22398
|
-
});
|
22399
|
-
}
|
22400
|
-
keySessionContextPromise.catch(error => this.handleError(error));
|
22401
|
-
}
|
22402
|
-
_onWaitingForKey(event) {
|
22403
|
-
this.log(`"${event.type}" event`);
|
22404
|
-
}
|
22405
22446
|
attemptSetMediaKeys(keySystem, mediaKeys) {
|
22406
22447
|
const queue = this.setMediaKeysQueue.slice();
|
22407
22448
|
this.log(`Setting media-keys for "${keySystem}"`);
|
@@ -22694,7 +22735,7 @@ class EMEController {
|
|
22694
22735
|
requestLicense(keySessionContext, licenseChallenge) {
|
22695
22736
|
const keyLoadPolicy = this.config.keyLoadPolicy.default;
|
22696
22737
|
return new Promise((resolve, reject) => {
|
22697
|
-
const url = this.
|
22738
|
+
const url = this.getLicenseServerUrlOrThrow(keySessionContext.keySystem);
|
22698
22739
|
this.log(`Sending license request to URL: ${url}`);
|
22699
22740
|
const xhr = new XMLHttpRequest();
|
22700
22741
|
xhr.responseType = 'arraybuffer';
|
@@ -22764,6 +22805,8 @@ class EMEController {
|
|
22764
22805
|
|
22765
22806
|
// keep reference of media
|
22766
22807
|
this.media = media;
|
22808
|
+
media.removeEventListener('encrypted', this.onMediaEncrypted);
|
22809
|
+
media.removeEventListener('waitingforkey', this.onWaitingForKey);
|
22767
22810
|
media.addEventListener('encrypted', this.onMediaEncrypted);
|
22768
22811
|
media.addEventListener('waitingforkey', this.onWaitingForKey);
|
22769
22812
|
}
|
@@ -26113,7 +26156,7 @@ class KeyLoader {
|
|
26113
26156
|
}
|
26114
26157
|
}
|
26115
26158
|
load(frag) {
|
26116
|
-
if (!frag.decryptdata && frag.encrypted && this.emeController) {
|
26159
|
+
if (!frag.decryptdata && frag.encrypted && this.emeController && this.config.emeEnabled) {
|
26117
26160
|
// Multiple keys, but none selected, resolve in eme-controller
|
26118
26161
|
return this.emeController.selectKeySystemFormat(frag).then(keySystemFormat => {
|
26119
26162
|
return this.loadInternal(frag, keySystemFormat);
|
@@ -27801,7 +27844,7 @@ class Hls {
|
|
27801
27844
|
* Get the video-dev/hls.js package version.
|
27802
27845
|
*/
|
27803
27846
|
static get version() {
|
27804
|
-
return "1.5.
|
27847
|
+
return "1.5.19";
|
27805
27848
|
}
|
27806
27849
|
|
27807
27850
|
/**
|