hls.js 1.5.10-0.canary.10320 → 1.5.10-0.canary.10326

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
@@ -501,7 +501,7 @@ function enableLogs(debugConfig, context, id) {
501
501
  // Some browsers don't allow to use bind on console object anyway
502
502
  // fallback to default if needed
503
503
  try {
504
- newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.10-0.canary.10320"}`);
504
+ newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.10-0.canary.10326"}`);
505
505
  } catch (e) {
506
506
  /* log fn threw an exception. All logger methods are no-ops. */
507
507
  return createLogger();
@@ -5851,7 +5851,7 @@ function findFragmentByPDT(fragments, PDTValue, maxFragLookUpTolerance) {
5851
5851
  * @param maxFragLookUpTolerance - The amount of time that a fragment's start/end can be within in order to be considered contiguous
5852
5852
  * @returns a matching fragment or null
5853
5853
  */
5854
- function findFragmentByPTS(fragPrevious, fragments, bufferEnd = 0, maxFragLookUpTolerance = 0) {
5854
+ function findFragmentByPTS(fragPrevious, fragments, bufferEnd = 0, maxFragLookUpTolerance = 0, nextFragLookupTolerance = 0.005) {
5855
5855
  let fragNext = null;
5856
5856
  if (fragPrevious) {
5857
5857
  fragNext = fragments[fragPrevious.sn - fragments[0].sn + 1] || null;
@@ -5864,7 +5864,7 @@ function findFragmentByPTS(fragPrevious, fragments, bufferEnd = 0, maxFragLookUp
5864
5864
  fragNext = fragments[0];
5865
5865
  }
5866
5866
  // Prefer the next fragment if it's within tolerance
5867
- if (fragNext && (!fragPrevious || fragPrevious.level === fragNext.level) && fragmentWithinToleranceTest(bufferEnd, maxFragLookUpTolerance, fragNext) === 0) {
5867
+ if (fragNext && ((!fragPrevious || fragPrevious.level === fragNext.level) && fragmentWithinToleranceTest(bufferEnd, maxFragLookUpTolerance, fragNext) === 0 || fragmentWithinFastStartSwitch(fragNext, fragPrevious, Math.min(nextFragLookupTolerance, maxFragLookUpTolerance)))) {
5868
5868
  return fragNext;
5869
5869
  }
5870
5870
  // We might be seeking past the tolerance so find the best match
@@ -5875,6 +5875,18 @@ function findFragmentByPTS(fragPrevious, fragments, bufferEnd = 0, maxFragLookUp
5875
5875
  // If no match was found return the next fragment after fragPrevious, or null
5876
5876
  return fragNext;
5877
5877
  }
5878
+ function fragmentWithinFastStartSwitch(fragNext, fragPrevious, nextFragLookupTolerance) {
5879
+ if (fragPrevious && fragPrevious.start === 0 && fragPrevious.level < fragNext.level && (fragPrevious.endPTS || 0) > 0) {
5880
+ const firstDuration = fragPrevious.tagList.reduce((duration, tag) => {
5881
+ if (tag[0] === 'INF') {
5882
+ duration += parseFloat(tag[1]);
5883
+ }
5884
+ return duration;
5885
+ }, nextFragLookupTolerance);
5886
+ return fragNext.start <= firstDuration;
5887
+ }
5888
+ return false;
5889
+ }
5878
5890
 
5879
5891
  /**
5880
5892
  * The test function used by the findFragmentBySn's BinarySearch to look for the best match to the current buffer conditions.
@@ -9668,7 +9680,7 @@ class BaseStreamController extends TaskLoop {
9668
9680
  if (this.state === State.STOPPED || this.state === State.ERROR) {
9669
9681
  return;
9670
9682
  }
9671
- this.warn(reason);
9683
+ this.warn(`Frag error: ${(reason == null ? void 0 : reason.message) || reason}`);
9672
9684
  this.resetFragmentLoading(frag);
9673
9685
  });
9674
9686
  }
@@ -10365,7 +10377,9 @@ class BaseStreamController extends TaskLoop {
10365
10377
  const {
10366
10378
  fragmentHint
10367
10379
  } = levelDetails;
10368
- const tolerance = config.maxFragLookUpTolerance;
10380
+ const {
10381
+ maxFragLookUpTolerance
10382
+ } = config;
10369
10383
  const partList = levelDetails.partList;
10370
10384
  const loadingParts = !!(this.loadingParts && partList != null && partList.length && fragmentHint);
10371
10385
  if (loadingParts && fragmentHint && !this.bitrateTest) {
@@ -10375,7 +10389,7 @@ class BaseStreamController extends TaskLoop {
10375
10389
  }
10376
10390
  let frag;
10377
10391
  if (bufferEnd < end) {
10378
- const lookupTolerance = bufferEnd > end - tolerance ? 0 : tolerance;
10392
+ const lookupTolerance = bufferEnd > end - maxFragLookUpTolerance ? 0 : maxFragLookUpTolerance;
10379
10393
  // Remove the tolerance if it would put the bufferEnd past the actual end of stream
10380
10394
  // Uses buffer and sequence number to calculate switch segment (required if using EXT-X-DISCONTINUITY-SEQUENCE)
10381
10395
  frag = findFragmentByPTS(fragPrevious, fragments, bufferEnd, lookupTolerance);
@@ -13374,7 +13388,7 @@ class TSDemuxer {
13374
13388
  if (stt) {
13375
13389
  offset += data[offset] + 1;
13376
13390
  }
13377
- const parsedPIDs = parsePMT(data, offset, this.typeSupported, isSampleAes);
13391
+ const parsedPIDs = parsePMT(data, offset, this.typeSupported, isSampleAes, this.observer);
13378
13392
 
13379
13393
  // only update track id if track PID found while parsing PMT
13380
13394
  // this is to avoid resetting the PID to -1 in case
@@ -13417,14 +13431,7 @@ class TSDemuxer {
13417
13431
  }
13418
13432
  }
13419
13433
  if (tsPacketErrors > 0) {
13420
- const error = new Error(`Found ${tsPacketErrors} TS packet/s that do not start with 0x47`);
13421
- this.observer.emit(Events.ERROR, Events.ERROR, {
13422
- type: ErrorTypes.MEDIA_ERROR,
13423
- details: ErrorDetails.FRAG_PARSING_ERROR,
13424
- fatal: false,
13425
- error,
13426
- reason: error.message
13427
- });
13434
+ emitParsingError(this.observer, new Error(`Found ${tsPacketErrors} TS packet/s that do not start with 0x47`));
13428
13435
  }
13429
13436
  videoTrack.pesData = videoData;
13430
13437
  audioTrack.pesData = audioData;
@@ -13592,16 +13599,7 @@ class TSDemuxer {
13592
13599
  } else {
13593
13600
  reason = 'No ADTS header found in AAC PES';
13594
13601
  }
13595
- const error = new Error(reason);
13596
- logger.warn(`parsing error: ${reason}`);
13597
- this.observer.emit(Events.ERROR, Events.ERROR, {
13598
- type: ErrorTypes.MEDIA_ERROR,
13599
- details: ErrorDetails.FRAG_PARSING_ERROR,
13600
- fatal: false,
13601
- levelRetry: recoverable,
13602
- error,
13603
- reason
13604
- });
13602
+ emitParsingError(this.observer, new Error(reason), recoverable);
13605
13603
  if (!recoverable) {
13606
13604
  return;
13607
13605
  }
@@ -13702,7 +13700,7 @@ function parsePAT(data, offset) {
13702
13700
  // skip the PSI header and parse the first PMT entry
13703
13701
  return (data[offset + 10] & 0x1f) << 8 | data[offset + 11];
13704
13702
  }
13705
- function parsePMT(data, offset, typeSupported, isSampleAes) {
13703
+ function parsePMT(data, offset, typeSupported, isSampleAes, observer) {
13706
13704
  const result = {
13707
13705
  audioPid: -1,
13708
13706
  videoPid: -1,
@@ -13820,7 +13818,8 @@ function parsePMT(data, offset, typeSupported, isSampleAes) {
13820
13818
  case 0xc2: // SAMPLE-AES EC3
13821
13819
  /* falls through */
13822
13820
  case 0x87:
13823
- throw new Error('Unsupported EC-3 in M2TS found');
13821
+ emitParsingError(observer, new Error('Unsupported EC-3 in M2TS found'));
13822
+ return result;
13824
13823
  case 0x24:
13825
13824
  // ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
13826
13825
  {
@@ -13838,6 +13837,17 @@ function parsePMT(data, offset, typeSupported, isSampleAes) {
13838
13837
  }
13839
13838
  return result;
13840
13839
  }
13840
+ function emitParsingError(observer, error, levelRetry) {
13841
+ logger.warn(`parsing error: ${error.message}`);
13842
+ observer.emit(Events.ERROR, Events.ERROR, {
13843
+ type: ErrorTypes.MEDIA_ERROR,
13844
+ details: ErrorDetails.FRAG_PARSING_ERROR,
13845
+ fatal: false,
13846
+ levelRetry,
13847
+ error,
13848
+ reason: error.message
13849
+ });
13850
+ }
13841
13851
  function logEncryptedSamplesFoundInUnencryptedStream(type) {
13842
13852
  logger.log(`${type} with AES-128-CBC encryption found in unencrypted stream`);
13843
13853
  }
@@ -16584,10 +16594,6 @@ class TransmuxerInterface {
16584
16594
  this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
16585
16595
  this.observer.on(Events.ERROR, forwardMessage);
16586
16596
  const m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
16587
-
16588
- // navigator.vendor is not always available in Web Worker
16589
- // refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
16590
- const vendor = navigator.vendor;
16591
16597
  if (this.useWorker && typeof Worker !== 'undefined') {
16592
16598
  const canCreateWorker = config.workerPath || hasUMDWorker();
16593
16599
  if (canCreateWorker) {
@@ -16599,7 +16605,7 @@ class TransmuxerInterface {
16599
16605
  logger.log(`injecting Web Worker for "${id}"`);
16600
16606
  this.workerContext = injectWorker();
16601
16607
  }
16602
- this.onwmsg = ev => this.onWorkerMessage(ev);
16608
+ this.onwmsg = event => this.onWorkerMessage(event);
16603
16609
  const {
16604
16610
  worker
16605
16611
  } = this.workerContext;
@@ -16619,7 +16625,7 @@ class TransmuxerInterface {
16619
16625
  worker.postMessage({
16620
16626
  cmd: 'init',
16621
16627
  typeSupported: m2tsTypeSupported,
16622
- vendor: vendor,
16628
+ vendor: '',
16623
16629
  id: id,
16624
16630
  config: JSON.stringify(config)
16625
16631
  });
@@ -16627,12 +16633,12 @@ class TransmuxerInterface {
16627
16633
  logger.warn(`Error setting up "${id}" Web Worker, fallback to inline`, err);
16628
16634
  this.resetWorker();
16629
16635
  this.error = null;
16630
- this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, vendor, id);
16636
+ this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, '', id);
16631
16637
  }
16632
16638
  return;
16633
16639
  }
16634
16640
  }
16635
- this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, vendor, id);
16641
+ this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, '', id);
16636
16642
  }
16637
16643
  resetWorker() {
16638
16644
  if (this.workerContext) {
@@ -16784,9 +16790,16 @@ class TransmuxerInterface {
16784
16790
  });
16785
16791
  this.onFlush(chunkMeta);
16786
16792
  }
16787
- onWorkerMessage(ev) {
16788
- const data = ev.data;
16793
+ onWorkerMessage(event) {
16794
+ const data = event.data;
16795
+ if (!(data != null && data.event)) {
16796
+ logger.warn(`worker message received with no ${data ? 'event name' : 'data'}`);
16797
+ return;
16798
+ }
16789
16799
  const hls = this.hls;
16800
+ if (!this.hls) {
16801
+ return;
16802
+ }
16790
16803
  switch (data.event) {
16791
16804
  case 'init':
16792
16805
  {
@@ -25765,8 +25778,6 @@ class XhrLoader {
25765
25778
  this.config = null;
25766
25779
  this.context = null;
25767
25780
  this.xhrSetup = null;
25768
- // @ts-ignore
25769
- this.stats = null;
25770
25781
  }
25771
25782
  abortInternal() {
25772
25783
  const loader = this.loader;
@@ -25814,13 +25825,14 @@ class XhrLoader {
25814
25825
  const xhrSetup = this.xhrSetup;
25815
25826
  if (xhrSetup) {
25816
25827
  Promise.resolve().then(() => {
25817
- if (this.stats.aborted) return;
25828
+ if (this.loader !== xhr || this.stats.aborted) return;
25818
25829
  return xhrSetup(xhr, context.url);
25819
25830
  }).catch(error => {
25831
+ if (this.loader !== xhr || this.stats.aborted) return;
25820
25832
  xhr.open('GET', context.url, true);
25821
25833
  return xhrSetup(xhr, context.url);
25822
25834
  }).then(() => {
25823
- if (this.stats.aborted) return;
25835
+ if (this.loader !== xhr || this.stats.aborted) return;
25824
25836
  this.openAndSendXhr(xhr, context, config);
25825
25837
  }).catch(error => {
25826
25838
  // IE11 throws an exception on xhr.open if attempting to access an HTTP resource over HTTPS
@@ -25940,8 +25952,8 @@ class XhrLoader {
25940
25952
  }
25941
25953
  }
25942
25954
  loadtimeout() {
25943
- var _this$config;
25944
- const retryConfig = (_this$config = this.config) == null ? void 0 : _this$config.loadPolicy.timeoutRetry;
25955
+ if (!this.config) return;
25956
+ const retryConfig = this.config.loadPolicy.timeoutRetry;
25945
25957
  const retryCount = this.stats.retry;
25946
25958
  if (shouldRetry(retryConfig, retryCount, true)) {
25947
25959
  this.retry(retryConfig);
@@ -28843,7 +28855,8 @@ class StreamController extends BaseStreamController {
28843
28855
  // In the case that AAC and HE-AAC audio codecs are signalled in manifest,
28844
28856
  // force HE-AAC, as it seems that most browsers prefers it.
28845
28857
  // don't force HE-AAC if mono stream, or in Firefox
28846
- if (audio.metadata.channelCount !== 1 && ua.indexOf('firefox') === -1) {
28858
+ const audioMetadata = audio.metadata;
28859
+ if (audioMetadata && 'channelCount' in audioMetadata && (audioMetadata.channelCount || 1) !== 1 && ua.indexOf('firefox') === -1) {
28847
28860
  audioCodec = 'mp4a.40.5';
28848
28861
  }
28849
28862
  }
@@ -29006,7 +29019,7 @@ class Hls {
29006
29019
  * Get the video-dev/hls.js package version.
29007
29020
  */
29008
29021
  static get version() {
29009
- return "1.5.10-0.canary.10320";
29022
+ return "1.5.10-0.canary.10326";
29010
29023
  }
29011
29024
 
29012
29025
  /**