hls.js 1.6.3-0.canary.11253 → 1.6.3-0.canary.11255

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.3-0.canary.11253"}`);
526
+ newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.3-0.canary.11255"}`);
527
527
  } catch (e) {
528
528
  /* log fn threw an exception. All logger methods are no-ops. */
529
529
  return createLogger();
@@ -4113,7 +4113,6 @@ function findFragmentByPDT(fragments, PDTValue, maxFragLookUpTolerance) {
4113
4113
  if (PDTValue >= (endPDT || 0)) {
4114
4114
  return null;
4115
4115
  }
4116
- maxFragLookUpTolerance = maxFragLookUpTolerance || 0;
4117
4116
  for (let seg = 0; seg < fragments.length; ++seg) {
4118
4117
  const frag = fragments[seg];
4119
4118
  if (pdtWithinToleranceTest(PDTValue, maxFragLookUpTolerance, frag)) {
@@ -4224,40 +4223,34 @@ function pdtWithinToleranceTest(pdtBufferEnd, maxFragLookUpTolerance, candidate)
4224
4223
  const endProgramDateTime = candidate.endProgramDateTime || 0;
4225
4224
  return endProgramDateTime - candidateLookupTolerance > pdtBufferEnd;
4226
4225
  }
4227
- function findFragWithCC(fragments, cc) {
4228
- return BinarySearch.search(fragments, candidate => {
4229
- if (candidate.cc < cc) {
4230
- return 1;
4231
- } else if (candidate.cc > cc) {
4232
- return -1;
4233
- } else {
4234
- return 0;
4235
- }
4236
- });
4237
- }
4238
- function findNearestWithCC(details, cc, fragment) {
4226
+ function findNearestWithCC(details, cc, pos) {
4239
4227
  if (details) {
4240
4228
  if (details.startCC <= cc && details.endCC >= cc) {
4241
- const start = fragment.start;
4242
- const end = fragment.end;
4243
4229
  let fragments = details.fragments;
4244
- if (!fragment.relurl) {
4245
- const {
4246
- fragmentHint
4247
- } = details;
4248
- if (fragmentHint) {
4249
- fragments = fragments.concat(fragmentHint);
4230
+ const {
4231
+ fragmentHint
4232
+ } = details;
4233
+ if (fragmentHint) {
4234
+ fragments = fragments.concat(fragmentHint);
4235
+ }
4236
+ let closest;
4237
+ BinarySearch.search(fragments, candidate => {
4238
+ if (candidate.cc < cc) {
4239
+ return 1;
4250
4240
  }
4251
- }
4252
- return BinarySearch.search(fragments, candidate => {
4253
- if (candidate.cc < cc || candidate.end <= start) {
4241
+ if (candidate.cc > cc) {
4242
+ return -1;
4243
+ }
4244
+ closest = candidate;
4245
+ if (candidate.end <= pos) {
4254
4246
  return 1;
4255
- } else if (candidate.cc > cc || candidate.start >= end) {
4247
+ }
4248
+ if (candidate.start > pos) {
4256
4249
  return -1;
4257
- } else {
4258
- return 0;
4259
4250
  }
4251
+ return 0;
4260
4252
  });
4253
+ return closest || null;
4261
4254
  }
4262
4255
  }
4263
4256
  return null;
@@ -8908,8 +8901,11 @@ class BaseStreamController extends TaskLoop {
8908
8901
  if (this.fragCurrent === null) {
8909
8902
  keyLoadingPromise = Promise.reject(new Error(`frag load aborted, context changed in KEY_LOADING`));
8910
8903
  }
8911
- } else if (!frag.encrypted && details.encryptedFragments.length) {
8912
- this.keyLoader.loadClear(frag, details.encryptedFragments);
8904
+ } else if (!frag.encrypted) {
8905
+ keyLoadingPromise = this.keyLoader.loadClear(frag, details.encryptedFragments);
8906
+ if (keyLoadingPromise) {
8907
+ this.log(`[eme] blocking frag load until media-keys acquired`);
8908
+ }
8913
8909
  }
8914
8910
  const fragPrevious = this.fragPrevious;
8915
8911
  if (isMediaFragment(frag) && (!fragPrevious || frag.sn !== fragPrevious.sn)) {
@@ -9264,7 +9260,7 @@ class BaseStreamController extends TaskLoop {
9264
9260
  this.log(`LL-Part loading ON for initial live fragment`);
9265
9261
  this.loadingParts = true;
9266
9262
  }
9267
- frag = this.getInitialLiveFragment(levelDetails, fragments);
9263
+ frag = this.getInitialLiveFragment(levelDetails);
9268
9264
  const mainStart = this.hls.startPosition;
9269
9265
  const liveSyncPosition = this.hls.liveSyncPosition;
9270
9266
  const startPosition = frag ? (mainStart !== -1 && mainStart >= start ? mainStart : liveSyncPosition) || frag.start : pos;
@@ -9404,7 +9400,8 @@ class BaseStreamController extends TaskLoop {
9404
9400
  "sliding" of the playlist, which is its offset from the start of playback. After sliding we can compute the real
9405
9401
  start and end times for each fragment in the playlist (after which this method will not need to be called).
9406
9402
  */
9407
- getInitialLiveFragment(levelDetails, fragments) {
9403
+ getInitialLiveFragment(levelDetails) {
9404
+ const fragments = levelDetails.fragments;
9408
9405
  const fragPrevious = this.fragPrevious;
9409
9406
  let frag = null;
9410
9407
  if (fragPrevious) {
@@ -9427,7 +9424,7 @@ class BaseStreamController extends TaskLoop {
9427
9424
  // It's important to stay within the continuity range if available; otherwise the fragments in the playlist
9428
9425
  // will have the wrong start times
9429
9426
  if (!frag) {
9430
- frag = findFragWithCC(fragments, fragPrevious.cc);
9427
+ frag = findNearestWithCC(levelDetails, fragPrevious.cc, fragPrevious.end);
9431
9428
  if (frag) {
9432
9429
  this.log(`Live playlist, switching playlist, load frag with same CC: ${frag.sn}`);
9433
9430
  }
@@ -10237,7 +10234,7 @@ function requireEventemitter3 () {
10237
10234
  var eventemitter3Exports = requireEventemitter3();
10238
10235
  var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
10239
10236
 
10240
- const version = "1.6.3-0.canary.11253";
10237
+ const version = "1.6.3-0.canary.11255";
10241
10238
 
10242
10239
  // ensure the worker ends up in the bundle
10243
10240
  // If the worker should not be included this gets aliased to empty.js
@@ -16528,23 +16525,46 @@ class AudioStreamController extends BaseStreamController {
16528
16525
  if (this.state === State.WAITING_INIT_PTS) {
16529
16526
  const waitingData = this.waitingData;
16530
16527
  if (!waitingData && !this.loadingParts || waitingData && waitingData.frag.cc !== cc) {
16531
- this.nextLoadPosition = this.findSyncFrag(frag).start;
16528
+ this.syncWithAnchor(frag, waitingData == null ? void 0 : waitingData.frag);
16532
16529
  }
16533
- this.tick();
16534
16530
  } else if (!this.hls.hasEnoughToStart && inFlightFrag && inFlightFrag.cc !== cc) {
16535
- this.startFragRequested = false;
16536
- this.nextLoadPosition = this.findSyncFrag(frag).start;
16537
16531
  inFlightFrag.abortRequests();
16538
- this.resetLoadingState();
16532
+ this.syncWithAnchor(frag, inFlightFrag);
16539
16533
  } else if (this.state === State.IDLE) {
16540
16534
  this.tick();
16541
16535
  }
16542
16536
  }
16543
16537
  }
16544
- findSyncFrag(mainFrag) {
16538
+ getLoadPosition() {
16539
+ if (!this.startFragRequested && this.nextLoadPosition >= 0) {
16540
+ return this.nextLoadPosition;
16541
+ }
16542
+ return super.getLoadPosition();
16543
+ }
16544
+ syncWithAnchor(mainAnchor, waitingToAppend) {
16545
+ var _this$mainFragLoading;
16546
+ // Drop waiting fragment if videoTrackCC has changed since waitingFragment was set and initPTS was not found
16547
+ const mainFragLoading = ((_this$mainFragLoading = this.mainFragLoading) == null ? void 0 : _this$mainFragLoading.frag) || null;
16548
+ if (waitingToAppend) {
16549
+ if ((mainFragLoading == null ? void 0 : mainFragLoading.cc) === waitingToAppend.cc) {
16550
+ // Wait for loading frag to complete and INIT_PTS_FOUND
16551
+ return;
16552
+ }
16553
+ }
16554
+ const targetDiscontinuity = (mainFragLoading || mainAnchor).cc;
16545
16555
  const trackDetails = this.getLevelDetails();
16546
- const cc = mainFrag.cc;
16547
- return findNearestWithCC(trackDetails, cc, mainFrag) || trackDetails && findFragWithCC(trackDetails.fragments, cc) || mainFrag;
16556
+ const pos = this.getLoadPosition();
16557
+ const syncFrag = findNearestWithCC(trackDetails, targetDiscontinuity, pos);
16558
+ // Only stop waiting for audioFrag.cc if an audio segment of the same discontinuity domain (cc) is found
16559
+ if (syncFrag) {
16560
+ this.log(`Waiting fragment cc (${waitingToAppend == null ? void 0 : waitingToAppend.cc}) cancelled because video is at cc ${mainAnchor.cc}`);
16561
+ this.startFragRequested = false;
16562
+ this.nextLoadPosition = syncFrag.start;
16563
+ this.resetLoadingState();
16564
+ if (this.state === State.IDLE) {
16565
+ this.doTickIdle();
16566
+ }
16567
+ }
16548
16568
  }
16549
16569
  startLoad(startPosition, skipSeekToStartPosition) {
16550
16570
  if (!this.levels) {
@@ -16631,10 +16651,7 @@ class AudioStreamController extends BaseStreamController {
16631
16651
  super._handleFragmentLoadComplete(data);
16632
16652
  }
16633
16653
  } else if (mainAnchor && mainAnchor.cc !== waitingData.frag.cc) {
16634
- // Drop waiting fragment if videoTrackCC has changed since waitingFragment was set and initPTS was not found
16635
- this.log(`Waiting fragment cc (${frag.cc}) cancelled because video is at cc ${mainAnchor.cc}`);
16636
- this.nextLoadPosition = this.findSyncFrag(mainAnchor).start;
16637
- this.clearWaitingFragment();
16654
+ this.syncWithAnchor(mainAnchor, waitingData.frag);
16638
16655
  }
16639
16656
  } else {
16640
16657
  this.state = State.IDLE;
@@ -16643,22 +16660,12 @@ class AudioStreamController extends BaseStreamController {
16643
16660
  }
16644
16661
  this.onTickEnd();
16645
16662
  }
16646
- clearWaitingFragment() {
16663
+ resetLoadingState() {
16647
16664
  const waitingData = this.waitingData;
16648
16665
  if (waitingData) {
16649
- if (!this.hls.hasEnoughToStart) {
16650
- // Load overlapping fragment on start when discontinuity start times are not aligned
16651
- this.startFragRequested = false;
16652
- }
16653
16666
  this.fragmentTracker.removeFragment(waitingData.frag);
16654
16667
  this.waitingData = null;
16655
- if (this.state !== State.STOPPED) {
16656
- this.state = State.IDLE;
16657
- }
16658
16668
  }
16659
- }
16660
- resetLoadingState() {
16661
- this.clearWaitingFragment();
16662
16669
  super.resetLoadingState();
16663
16670
  }
16664
16671
  onTickEnd() {
@@ -16672,7 +16679,7 @@ class AudioStreamController extends BaseStreamController {
16672
16679
  this.lastCurrentTime = media.currentTime;
16673
16680
  }
16674
16681
  doTickIdle() {
16675
- var _this$mainFragLoading;
16682
+ var _this$mainFragLoading2;
16676
16683
  const {
16677
16684
  hls,
16678
16685
  levels,
@@ -16746,7 +16753,7 @@ class AudioStreamController extends BaseStreamController {
16746
16753
  }
16747
16754
 
16748
16755
  // Request audio segments up to one fragment ahead of main stream-controller
16749
- let mainFragLoading = ((_this$mainFragLoading = this.mainFragLoading) == null ? void 0 : _this$mainFragLoading.frag) || null;
16756
+ let mainFragLoading = ((_this$mainFragLoading2 = this.mainFragLoading) == null ? void 0 : _this$mainFragLoading2.frag) || null;
16750
16757
  if (!this.audioOnly && this.startFragRequested && mainFragLoading && isMediaFragment(frag) && !frag.endList && (!trackDetails.live || !this.loadingParts && targetBufferTime < this.hls.liveSyncPosition)) {
16751
16758
  if (this.fragmentTracker.getState(mainFragLoading) === FragmentState.OK) {
16752
16759
  this.mainFragLoading = mainFragLoading = null;
@@ -21828,6 +21835,7 @@ class EMEController extends Logger {
21828
21835
  this.log(`Create media-keys for "${keySystem}"`);
21829
21836
  _keySystemAccessPromises.mediaKeys = mediaKeySystemAccess.createMediaKeys().then(mediaKeys => {
21830
21837
  this.log(`Media-keys created for "${keySystem}"`);
21838
+ _keySystemAccessPromises.hasMediaKeys = true;
21831
21839
  return certificateRequest.then(certificate => {
21832
21840
  if (certificate) {
21833
21841
  return this.setMediaKeysServerCertificate(mediaKeys, keySystem, certificate);
@@ -21888,18 +21896,26 @@ class EMEController extends Logger {
21888
21896
  } (data length: ${data ? data.byteLength : data})`);
21889
21897
  return keySession.update(data);
21890
21898
  }
21891
- selectKeySystemFormat(frag) {
21892
- const keyFormats = Object.keys(frag.levelkeys || {});
21893
- if (!this.keyFormatPromise) {
21894
- this.log(`Selecting key-system from fragment (sn: ${frag.sn} ${frag.type}: ${frag.level}) key formats ${keyFormats.join(', ')}`);
21895
- this.keyFormatPromise = this.getKeyFormatPromise(keyFormats);
21896
- }
21897
- return this.keyFormatPromise;
21899
+ getSelectedKeySystemFormats() {
21900
+ return Object.keys(this.keySystemAccessPromises).map(keySystem => ({
21901
+ keySystem,
21902
+ hasMediaKeys: this.keySystemAccessPromises[keySystem].hasMediaKeys
21903
+ })).filter(({
21904
+ hasMediaKeys
21905
+ }) => !!hasMediaKeys).map(({
21906
+ keySystem
21907
+ }) => keySystemDomainToKeySystemFormat(keySystem)).filter(keySystem => !!keySystem);
21908
+ }
21909
+ getKeySystemAccess(keySystemsToAttempt) {
21910
+ return this.getKeySystemSelectionPromise(keySystemsToAttempt).then(({
21911
+ keySystem,
21912
+ mediaKeys
21913
+ }) => {
21914
+ return this.attemptSetMediaKeys(keySystem, mediaKeys);
21915
+ });
21898
21916
  }
21899
- getKeyFormatPromise(keyFormats) {
21917
+ selectKeySystem(keySystemsToAttempt) {
21900
21918
  return new Promise((resolve, reject) => {
21901
- const keySystemsInConfig = getKeySystemsForConfig(this.config);
21902
- const keySystemsToAttempt = keyFormats.map(keySystemFormatToKeySystemDomain).filter(value => !!value && keySystemsInConfig.indexOf(value) !== -1);
21903
21919
  return this.getKeySystemSelectionPromise(keySystemsToAttempt).then(({
21904
21920
  keySystem
21905
21921
  }) => {
@@ -21912,6 +21928,19 @@ class EMEController extends Logger {
21912
21928
  }).catch(reject);
21913
21929
  });
21914
21930
  }
21931
+ selectKeySystemFormat(frag) {
21932
+ const keyFormats = Object.keys(frag.levelkeys || {});
21933
+ if (!this.keyFormatPromise) {
21934
+ this.log(`Selecting key-system from fragment (sn: ${frag.sn} ${frag.type}: ${frag.level}) key formats ${keyFormats.join(', ')}`);
21935
+ this.keyFormatPromise = this.getKeyFormatPromise(keyFormats);
21936
+ }
21937
+ return this.keyFormatPromise;
21938
+ }
21939
+ getKeyFormatPromise(keyFormats) {
21940
+ const keySystemsInConfig = getKeySystemsForConfig(this.config);
21941
+ const keySystemsToAttempt = keyFormats.map(keySystemFormatToKeySystemDomain).filter(value => !!value && keySystemsInConfig.indexOf(value) !== -1);
21942
+ return this.selectKeySystem(keySystemsToAttempt);
21943
+ }
21915
21944
  loadKey(data) {
21916
21945
  const decryptdata = data.keyInfo.decryptdata;
21917
21946
  const keyId = this.getKeyIdString(decryptdata);
@@ -26061,8 +26090,7 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))} pos: ${this.timeline
26061
26090
  var _this$schedule$items4, _this$detachedData5;
26062
26091
  const {
26063
26092
  interstitial,
26064
- assetItem,
26065
- assetId
26093
+ assetItem
26066
26094
  } = player;
26067
26095
  const scheduleIndex = this.schedule.findEventIndex(interstitial.identifier);
26068
26096
  const item = (_this$schedule$items4 = this.schedule.items) == null ? void 0 : _this$schedule$items4[scheduleIndex];
@@ -30293,6 +30321,8 @@ const hlsDefaultConfig = _objectSpread2(_objectSpread2({
30293
30321
  // used by eme-controller
30294
30322
  requestMediaKeySystemAccessFunc: requestMediaKeySystemAccess ,
30295
30323
  // used by eme-controller
30324
+ requireKeySystemAccessOnStart: false,
30325
+ // used by eme-controller
30296
30326
  testBandwidth: true,
30297
30327
  progressive: false,
30298
30328
  lowLatencyMode: true,
@@ -33683,22 +33713,35 @@ class KeyLoader {
33683
33713
  });
33684
33714
  }
33685
33715
  loadClear(loadingFrag, encryptedFragments) {
33686
- if (this.emeController && this.config.emeEnabled) {
33687
- // access key-system with nearest key on start (loaidng frag is unencrypted)
33688
- const {
33689
- sn,
33690
- cc
33691
- } = loadingFrag;
33692
- for (let i = 0; i < encryptedFragments.length; i++) {
33693
- const frag = encryptedFragments[i];
33694
- if (cc <= frag.cc && (sn === 'initSegment' || frag.sn === 'initSegment' || sn < frag.sn)) {
33695
- this.emeController.selectKeySystemFormat(frag).then(keySystemFormat => {
33696
- frag.setKeyFormat(keySystemFormat);
33697
- });
33698
- break;
33716
+ if (this.emeController && this.config.emeEnabled && !this.emeController.getSelectedKeySystemFormats().length) {
33717
+ // access key-system with nearest key on start (loading frag is unencrypted)
33718
+ if (encryptedFragments.length) {
33719
+ const {
33720
+ sn,
33721
+ cc
33722
+ } = loadingFrag;
33723
+ for (let i = 0; i < encryptedFragments.length; i++) {
33724
+ const frag = encryptedFragments[i];
33725
+ if (cc <= frag.cc && (sn === 'initSegment' || frag.sn === 'initSegment' || sn < frag.sn)) {
33726
+ return this.emeController.selectKeySystemFormat(frag).then(keySystemFormat => {
33727
+ frag.setKeyFormat(keySystemFormat);
33728
+ if (this.emeController && this.config.requireKeySystemAccessOnStart) {
33729
+ const keySystem = keySystemFormatToKeySystemDomain(keySystemFormat);
33730
+ if (keySystem) {
33731
+ return this.emeController.getKeySystemAccess([keySystem]);
33732
+ }
33733
+ }
33734
+ });
33735
+ }
33736
+ }
33737
+ } else if (this.config.requireKeySystemAccessOnStart) {
33738
+ const keySystemsInConfig = getKeySystemsForConfig(this.config);
33739
+ if (keySystemsInConfig.length) {
33740
+ return this.emeController.getKeySystemAccess(keySystemsInConfig);
33699
33741
  }
33700
33742
  }
33701
33743
  }
33744
+ return null;
33702
33745
  }
33703
33746
  load(frag) {
33704
33747
  if (!frag.decryptdata && frag.encrypted && this.emeController && this.config.emeEnabled) {