hls.js 1.6.7-0.canary.11366 → 1.6.7-0.canary.11369

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.mjs CHANGED
@@ -523,7 +523,7 @@ function enableLogs(debugConfig, context, id) {
523
523
  // Some browsers don't allow to use bind on console object anyway
524
524
  // fallback to default if needed
525
525
  try {
526
- newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.7-0.canary.11366"}`);
526
+ newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.7-0.canary.11369"}`);
527
527
  } catch (e) {
528
528
  /* log fn threw an exception. All logger methods are no-ops. */
529
529
  return createLogger();
@@ -648,6 +648,9 @@ const Hex = {
648
648
  return str;
649
649
  }
650
650
  };
651
+ function hexToArrayBuffer(str) {
652
+ return Uint8Array.from(str.replace(/^0x/, '').replace(/([\da-fA-F]{2}) ?/g, '0x$1 ').replace(/ +$/, '').split(' ')).buffer;
653
+ }
651
654
 
652
655
  function getDefaultExportFromCjs (x) {
653
656
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
@@ -2298,88 +2301,6 @@ function mp4pssh(systemId, keyids, data) {
2298
2301
  // 16 bytes
2299
2302
  kidCount, kids, dataSize, data || new Uint8Array());
2300
2303
  }
2301
- function parseMultiPssh(initData) {
2302
- const results = [];
2303
- if (initData instanceof ArrayBuffer) {
2304
- const length = initData.byteLength;
2305
- let offset = 0;
2306
- while (offset + 32 < length) {
2307
- const view = new DataView(initData, offset);
2308
- const pssh = parsePssh(view);
2309
- results.push(pssh);
2310
- offset += pssh.size;
2311
- }
2312
- }
2313
- return results;
2314
- }
2315
- function parsePssh(view) {
2316
- const size = view.getUint32(0);
2317
- const offset = view.byteOffset;
2318
- const length = view.byteLength;
2319
- if (length < size) {
2320
- return {
2321
- offset,
2322
- size: length
2323
- };
2324
- }
2325
- const type = view.getUint32(4);
2326
- if (type !== 0x70737368) {
2327
- return {
2328
- offset,
2329
- size
2330
- };
2331
- }
2332
- const version = view.getUint32(8) >>> 24;
2333
- if (version !== 0 && version !== 1) {
2334
- return {
2335
- offset,
2336
- size
2337
- };
2338
- }
2339
- const buffer = view.buffer;
2340
- const systemId = Hex.hexDump(new Uint8Array(buffer, offset + 12, 16));
2341
- let kids = null;
2342
- let data = null;
2343
- let dataSizeOffset = 0;
2344
- if (version === 0) {
2345
- dataSizeOffset = 28;
2346
- } else if (version === 1) {
2347
- const kidCounts = view.getUint32(28);
2348
- if (!kidCounts || length < 32 + kidCounts * 16) {
2349
- return {
2350
- offset,
2351
- size
2352
- };
2353
- }
2354
- kids = [];
2355
- for (let i = 0; i < kidCounts; i++) {
2356
- kids.push(new Uint8Array(buffer, offset + 32 + i * 16, 16));
2357
- }
2358
- dataSizeOffset = 32 + kidCounts * 16;
2359
- }
2360
- if (!dataSizeOffset) {
2361
- return {
2362
- offset,
2363
- size
2364
- };
2365
- }
2366
- const dataSizeOrKidCount = view.getUint32(dataSizeOffset);
2367
- if (size - 32 < dataSizeOrKidCount) {
2368
- return {
2369
- offset,
2370
- size
2371
- };
2372
- }
2373
- data = new Uint8Array(buffer, offset + dataSizeOffset + 4, dataSizeOrKidCount);
2374
- return {
2375
- version,
2376
- systemId,
2377
- kids,
2378
- data,
2379
- offset,
2380
- size
2381
- };
2382
- }
2383
2304
 
2384
2305
  const userAgentHevcSupportIsInaccurate = () => {
2385
2306
  return /\(Windows.+Firefox\//i.test(navigator.userAgent);
@@ -6825,23 +6746,6 @@ function keySystemFormatToKeySystemDomain(format) {
6825
6746
  return KeySystems.CLEARKEY;
6826
6747
  }
6827
6748
  }
6828
-
6829
- // System IDs for which we can extract a key ID from "encrypted" event PSSH
6830
- var KeySystemIds = {
6831
- CENC: "1077efecc0b24d02ace33c1e52e2fb4b",
6832
- CLEARKEY: "e2719d58a985b3c9781ab030af78d30e",
6833
- PLAYREADY: "9a04f07998404286ab92e65be0885f95",
6834
- WIDEVINE: "edef8ba979d64acea3c827dcd51d21ed"
6835
- };
6836
- function keySystemIdToKeySystemDomain(systemId) {
6837
- if (systemId === KeySystemIds.WIDEVINE) {
6838
- return KeySystems.WIDEVINE;
6839
- } else if (systemId === KeySystemIds.PLAYREADY) {
6840
- return KeySystems.PLAYREADY;
6841
- } else if (systemId === KeySystemIds.CENC || systemId === KeySystemIds.CLEARKEY) {
6842
- return KeySystems.CLEARKEY;
6843
- }
6844
- }
6845
6749
  function keySystemDomainToKeySystemFormat(keySystem) {
6846
6750
  switch (keySystem) {
6847
6751
  case KeySystems.FAIRPLAY:
@@ -6944,7 +6848,7 @@ class LevelKey {
6944
6848
  static clearKeyUriToKeyIdMap() {
6945
6849
  keyUriToKeyIdMap = {};
6946
6850
  }
6947
- constructor(method, uri, format, formatversions = [1], iv = null) {
6851
+ constructor(method, uri, format, formatversions = [1], iv = null, keyId) {
6948
6852
  this.uri = void 0;
6949
6853
  this.method = void 0;
6950
6854
  this.keyFormat = void 0;
@@ -6962,6 +6866,13 @@ class LevelKey {
6962
6866
  this.iv = iv;
6963
6867
  this.encrypted = method ? method !== 'NONE' : false;
6964
6868
  this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
6869
+ if (keyId != null && keyId.startsWith('0x')) {
6870
+ this.keyId = new Uint8Array(hexToArrayBuffer(keyId));
6871
+ }
6872
+ }
6873
+ matches(key) {
6874
+ var _key$iv, _this$iv;
6875
+ return key.uri === this.uri && key.method === this.method && key.encrypted === this.encrypted && key.keyFormat === this.keyFormat && key.keyFormatVersions.join(',') === this.keyFormatVersions.join(',') && ((_key$iv = key.iv) == null ? void 0 : _key$iv.join(',')) === ((_this$iv = this.iv) == null ? void 0 : _this$iv.join(','));
6965
6876
  }
6966
6877
  isSupported() {
6967
6878
  // If it's Segment encryption or No encryption, just select that key system
@@ -7002,6 +6913,9 @@ class LevelKey {
7002
6913
  const decryptdata = new LevelKey(this.method, this.uri, 'identity', this.keyFormatVersions, iv);
7003
6914
  return decryptdata;
7004
6915
  }
6916
+ if (this.pssh && this.keyId) {
6917
+ return this;
6918
+ }
7005
6919
 
7006
6920
  // Initialize keyId if possible
7007
6921
  const keyBytes = convertDataUriToArrayBytes(this.uri);
@@ -7011,9 +6925,10 @@ class LevelKey {
7011
6925
  // Setting `pssh` on this LevelKey/DecryptData allows HLS.js to generate a session using
7012
6926
  // the playlist-key before the "encrypted" event. (Comment out to only use "encrypted" path.)
7013
6927
  this.pssh = keyBytes;
7014
- // In case of widevine keyID is embedded in PSSH box. Read Key ID.
7015
- if (keyBytes.length >= 22) {
7016
- this.keyId = keyBytes.subarray(keyBytes.length - 22, keyBytes.length - 6);
6928
+ // In case of Widevine, if KEYID is not in the playlist, assume only two fields in the pssh KEY tag URI.
6929
+ if (!this.keyId && keyBytes.length >= 22) {
6930
+ const offset = keyBytes.length - 22;
6931
+ this.keyId = keyBytes.subarray(offset, offset + 16);
7017
6932
  }
7018
6933
  break;
7019
6934
  case KeySystemFormats.PLAYREADY:
@@ -7507,10 +7422,14 @@ class M3U8Parser {
7507
7422
  if (!levelkeys) {
7508
7423
  levelkeys = {};
7509
7424
  }
7510
- if (levelkeys[levelKey.keyFormat]) {
7511
- levelkeys = _extends({}, levelkeys);
7425
+ const currentKey = levelkeys[levelKey.keyFormat];
7426
+ // Ignore duplicate playlist KEY tags
7427
+ if (!(currentKey != null && currentKey.matches(levelKey))) {
7428
+ if (currentKey) {
7429
+ levelkeys = _extends({}, levelkeys);
7430
+ }
7431
+ levelkeys[levelKey.keyFormat] = levelKey;
7512
7432
  }
7513
- levelkeys[levelKey.keyFormat] = levelKey;
7514
7433
  } else {
7515
7434
  logger.warn(`[Keys] Ignoring invalid EXT-X-KEY tag: "${value1}"`);
7516
7435
  }
@@ -7733,7 +7652,7 @@ function parseKey(keyTagAttributes, baseurl, parsed) {
7733
7652
  // No uri is allowed when METHOD is NONE
7734
7653
  const resolvedUri = decrypturi ? M3U8Parser.resolve(decrypturi, baseurl) : '';
7735
7654
  const keyFormatVersions = (decryptkeyformatversions ? decryptkeyformatversions : '1').split('/').map(Number).filter(Number.isFinite);
7736
- return new LevelKey(decryptmethod, resolvedUri, decryptkeyformat, keyFormatVersions, decryptiv);
7655
+ return new LevelKey(decryptmethod, resolvedUri, decryptkeyformat, keyFormatVersions, decryptiv, keyAttrs.KEYID);
7737
7656
  }
7738
7657
  function parseStartTimeOffset(startAttributes) {
7739
7658
  const startAttrs = new AttrList(startAttributes);
@@ -10267,7 +10186,7 @@ function requireEventemitter3 () {
10267
10186
  var eventemitter3Exports = requireEventemitter3();
10268
10187
  var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
10269
10188
 
10270
- const version = "1.6.7-0.canary.11366";
10189
+ const version = "1.6.7-0.canary.11369";
10271
10190
 
10272
10191
  // ensure the worker ends up in the bundle
10273
10192
  // If the worker should not be included this gets aliased to empty.js
@@ -16597,7 +16516,7 @@ class AudioStreamController extends BaseStreamController {
16597
16516
  const syncFrag = findNearestWithCC(trackDetails, targetDiscontinuity, pos);
16598
16517
  // Only stop waiting for audioFrag.cc if an audio segment of the same discontinuity domain (cc) is found
16599
16518
  if (syncFrag) {
16600
- this.log(`Waiting fragment cc (${waitingToAppend == null ? void 0 : waitingToAppend.cc}) cancelled because video is at cc ${mainAnchor.cc}`);
16519
+ this.log(`Syncing with main frag at ${syncFrag.start} cc ${syncFrag.cc}`);
16601
16520
  this.startFragRequested = false;
16602
16521
  this.nextLoadPosition = syncFrag.start;
16603
16522
  this.resetLoadingState();
@@ -21633,140 +21552,6 @@ class EMEController extends Logger {
21633
21552
  this.keyIdToKeySessionPromise = {};
21634
21553
  this.mediaKeys = null;
21635
21554
  this.setMediaKeysQueue = EMEController.CDMCleanupPromise ? [EMEController.CDMCleanupPromise] : [];
21636
- this.onMediaEncrypted = event => {
21637
- const {
21638
- initDataType,
21639
- initData
21640
- } = event;
21641
- const logMessage = `"${event.type}" event: init data type: "${initDataType}"`;
21642
- this.debug(logMessage);
21643
-
21644
- // Ignore event when initData is null
21645
- if (initData === null) {
21646
- return;
21647
- }
21648
- if (!this.keyFormatPromise) {
21649
- let keySystems = Object.keys(this.keySystemAccessPromises);
21650
- if (!keySystems.length) {
21651
- keySystems = getKeySystemsForConfig(this.config);
21652
- }
21653
- const keyFormats = keySystems.map(keySystemDomainToKeySystemFormat).filter(k => !!k);
21654
- this.keyFormatPromise = this.getKeyFormatPromise(keyFormats);
21655
- }
21656
- this.keyFormatPromise.then(keySystemFormat => {
21657
- const keySystem = keySystemFormatToKeySystemDomain(keySystemFormat);
21658
- let keyId;
21659
- let keySystemDomain;
21660
- if (initDataType === 'sinf') {
21661
- if (keySystem !== KeySystems.FAIRPLAY) {
21662
- this.warn(`Ignoring unexpected "${event.type}" event with init data type: "${initDataType}" for selected key-system ${keySystem}`);
21663
- return;
21664
- }
21665
- // Match sinf keyId to playlist skd://keyId=
21666
- const json = bin2str(new Uint8Array(initData));
21667
- try {
21668
- const sinf = base64Decode(JSON.parse(json).sinf);
21669
- const tenc = parseSinf(sinf);
21670
- if (!tenc) {
21671
- throw new Error(`'schm' box missing or not cbcs/cenc with schi > tenc`);
21672
- }
21673
- keyId = new Uint8Array(tenc.subarray(8, 24));
21674
- keySystemDomain = KeySystems.FAIRPLAY;
21675
- } catch (error) {
21676
- this.warn(`${logMessage} Failed to parse sinf: ${error}`);
21677
- return;
21678
- }
21679
- } else {
21680
- if (keySystem !== KeySystems.WIDEVINE && keySystem !== KeySystems.PLAYREADY) {
21681
- this.warn(`Ignoring unexpected "${event.type}" event with init data type: "${initDataType}" for selected key-system ${keySystem}`);
21682
- return;
21683
- }
21684
- // Support Widevine/PlayReady clear-lead key-session creation (otherwise depend on playlist keys)
21685
- const psshResults = parseMultiPssh(initData);
21686
- const psshInfos = psshResults.filter(pssh => !!pssh.systemId && keySystemIdToKeySystemDomain(pssh.systemId) === keySystem);
21687
- if (psshInfos.length > 1) {
21688
- this.warn(`${logMessage} Using first of ${psshInfos.length} pssh found for selected key-system ${keySystem}`);
21689
- }
21690
- const psshInfo = psshInfos[0];
21691
- if (!psshInfo) {
21692
- if (psshResults.length === 0 || psshResults.some(pssh => !pssh.systemId)) {
21693
- this.warn(`${logMessage} contains incomplete or invalid pssh data`);
21694
- } else {
21695
- this.log(`ignoring ${logMessage} for ${psshResults.map(pssh => keySystemIdToKeySystemDomain(pssh.systemId)).join(',')} pssh data in favor of playlist keys`);
21696
- }
21697
- return;
21698
- }
21699
- keySystemDomain = keySystemIdToKeySystemDomain(psshInfo.systemId);
21700
- if (psshInfo.version === 0 && psshInfo.data) {
21701
- if (keySystemDomain === KeySystems.WIDEVINE) {
21702
- const offset = psshInfo.data.length - 22;
21703
- keyId = new Uint8Array(psshInfo.data.subarray(offset, offset + 16));
21704
- } else if (keySystemDomain === KeySystems.PLAYREADY) {
21705
- keyId = parsePlayReadyWRM(psshInfo.data);
21706
- }
21707
- }
21708
- }
21709
- if (!keySystemDomain || !keyId) {
21710
- return;
21711
- }
21712
- const keyIdHex = Hex.hexDump(keyId);
21713
- const {
21714
- keyIdToKeySessionPromise,
21715
- mediaKeySessions
21716
- } = this;
21717
- let keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex];
21718
- for (let i = 0; i < mediaKeySessions.length; i++) {
21719
- // Match playlist key
21720
- const keyContext = mediaKeySessions[i];
21721
- const decryptdata = keyContext.decryptdata;
21722
- if (!decryptdata.keyId) {
21723
- continue;
21724
- }
21725
- const oldKeyIdHex = Hex.hexDump(decryptdata.keyId);
21726
- if (keyIdHex === oldKeyIdHex || decryptdata.uri.replace(/-/g, '').indexOf(keyIdHex) !== -1) {
21727
- keySessionContextPromise = keyIdToKeySessionPromise[oldKeyIdHex];
21728
- if (decryptdata.pssh) {
21729
- break;
21730
- }
21731
- delete keyIdToKeySessionPromise[oldKeyIdHex];
21732
- decryptdata.pssh = new Uint8Array(initData);
21733
- decryptdata.keyId = keyId;
21734
- keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex] = keySessionContextPromise.then(() => {
21735
- return this.generateRequestWithPreferredKeySession(keyContext, initDataType, initData, 'encrypted-event-key-match');
21736
- });
21737
- keySessionContextPromise.catch(error => this.handleError(error));
21738
- break;
21739
- }
21740
- }
21741
- if (!keySessionContextPromise) {
21742
- if (keySystemDomain !== keySystem) {
21743
- this.log(`Ignoring "${event.type}" event with ${keySystemDomain} init data for selected key-system ${keySystem}`);
21744
- return;
21745
- }
21746
- // "Clear-lead" (misc key not encountered in playlist)
21747
- keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex] = this.getKeySystemSelectionPromise([keySystemDomain]).then(({
21748
- keySystem,
21749
- mediaKeys
21750
- }) => {
21751
- var _keySystemToKeySystem;
21752
- this.throwIfDestroyed();
21753
- const decryptdata = new LevelKey('ISO-23001-7', keyIdHex, (_keySystemToKeySystem = keySystemDomainToKeySystemFormat(keySystem)) != null ? _keySystemToKeySystem : '');
21754
- decryptdata.pssh = new Uint8Array(initData);
21755
- decryptdata.keyId = keyId;
21756
- return this.attemptSetMediaKeys(keySystem, mediaKeys).then(() => {
21757
- this.throwIfDestroyed();
21758
- const keySessionContext = this.createMediaKeySessionContext({
21759
- decryptdata,
21760
- keySystem,
21761
- mediaKeys
21762
- });
21763
- return this.generateRequestWithPreferredKeySession(keySessionContext, initDataType, initData, 'encrypted-event-no-match');
21764
- });
21765
- });
21766
- keySessionContextPromise.catch(error => this.handleError(error));
21767
- }
21768
- });
21769
- };
21770
21555
  this.onWaitingForKey = event => {
21771
21556
  this.log(`"${event.type}" event`);
21772
21557
  };
@@ -21785,7 +21570,7 @@ class EMEController extends Logger {
21785
21570
  // @ts-ignore
21786
21571
  this.hls = this.config = this.keyIdToKeySessionPromise = null;
21787
21572
  // @ts-ignore
21788
- this.onMediaEncrypted = this.onWaitingForKey = null;
21573
+ this.onWaitingForKey = null;
21789
21574
  }
21790
21575
  registerListeners() {
21791
21576
  this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
@@ -22464,13 +22249,11 @@ class EMEController extends Logger {
22464
22249
 
22465
22250
  // keep reference of media
22466
22251
  this.media = media;
22467
- addEventListener(media, 'encrypted', this.onMediaEncrypted);
22468
22252
  addEventListener(media, 'waitingforkey', this.onWaitingForKey);
22469
22253
  }
22470
22254
  onMediaDetached() {
22471
22255
  const media = this.media;
22472
22256
  if (media) {
22473
- removeEventListener(media, 'encrypted', this.onMediaEncrypted);
22474
22257
  removeEventListener(media, 'waitingforkey', this.onWaitingForKey);
22475
22258
  this.media = null;
22476
22259
  this.mediaKeys = null;
@@ -31267,9 +31050,6 @@ const MAX_CUE_ENDTIME = (() => {
31267
31050
  }
31268
31051
  return Number.POSITIVE_INFINITY;
31269
31052
  })();
31270
- function hexToArrayBuffer(str) {
31271
- return Uint8Array.from(str.replace(/^0x/, '').replace(/([\da-fA-F]{2}) ?/g, '0x$1 ').replace(/ +$/, '').split(' ')).buffer;
31272
- }
31273
31053
  class ID3TrackController {
31274
31054
  constructor(hls) {
31275
31055
  this.hls = void 0;