hls.js 1.5.7-0.canary.10015 → 1.5.7-0.canary.10016

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.light.js CHANGED
@@ -613,7 +613,7 @@
613
613
  // Some browsers don't allow to use bind on console object anyway
614
614
  // fallback to default if needed
615
615
  try {
616
- newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.7-0.canary.10015");
616
+ newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.7-0.canary.10016");
617
617
  } catch (e) {
618
618
  /* log fn threw an exception. All logger methods are no-ops. */
619
619
  return createLogger();
@@ -6813,6 +6813,9 @@
6813
6813
  var fragCurrent = this.fragCurrent,
6814
6814
  partCurrent = this.partCurrent,
6815
6815
  hls = this.hls;
6816
+ if (hls.levels.length <= 1) {
6817
+ return hls.loadLevel;
6818
+ }
6816
6819
  var maxAutoLevel = hls.maxAutoLevel,
6817
6820
  config = hls.config,
6818
6821
  minAutoLevel = hls.minAutoLevel;
@@ -7230,24 +7233,23 @@
7230
7233
  this.executeNext(type);
7231
7234
  }
7232
7235
  };
7233
- _proto.insertAbort = function insertAbort(operation, type) {
7234
- var queue = this.queues[type];
7235
- queue.unshift(operation);
7236
- this.executeNext(type);
7237
- };
7238
7236
  _proto.appendBlocker = function appendBlocker(type) {
7239
- var execute;
7240
- var promise = new Promise(function (resolve) {
7241
- execute = resolve;
7237
+ var _this = this;
7238
+ return new Promise(function (resolve) {
7239
+ var operation = {
7240
+ execute: resolve,
7241
+ onStart: function onStart() {},
7242
+ onComplete: function onComplete() {},
7243
+ onError: function onError() {}
7244
+ };
7245
+ _this.append(operation, type);
7242
7246
  });
7243
- var operation = {
7244
- execute: execute,
7245
- onStart: function onStart() {},
7246
- onComplete: function onComplete() {},
7247
- onError: function onError() {}
7248
- };
7249
- this.append(operation, type);
7250
- return promise;
7247
+ };
7248
+ _proto.unblockAudio = function unblockAudio(op) {
7249
+ var queue = this.queues.audio;
7250
+ if (queue[0] === op) {
7251
+ this.shiftAndExecuteNext('audio');
7252
+ }
7251
7253
  };
7252
7254
  _proto.executeNext = function executeNext(type) {
7253
7255
  var queue = this.queues[type];
@@ -7282,7 +7284,7 @@
7282
7284
  var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
7283
7285
  var BufferController = /*#__PURE__*/function (_Logger) {
7284
7286
  _inheritsLoose(BufferController, _Logger);
7285
- function BufferController(hls) {
7287
+ function BufferController(hls, fragmentTracker) {
7286
7288
  var _this;
7287
7289
  _this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
7288
7290
  // The level details used to determine duration, target-duration and live
@@ -7294,6 +7296,7 @@
7294
7296
  // References to event listeners for each SourceBuffer, so that they can be referenced for event removal
7295
7297
  _this.listeners = void 0;
7296
7298
  _this.hls = void 0;
7299
+ _this.fragmentTracker = void 0;
7297
7300
  // The number of BUFFER_CODEC events received before any sourceBuffers are created
7298
7301
  _this.bufferCodecEventsExpected = 0;
7299
7302
  // The total number of BUFFER_CODEC events received
@@ -7304,6 +7307,10 @@
7304
7307
  _this.mediaSource = null;
7305
7308
  // Last MP3 audio chunk appended
7306
7309
  _this.lastMpegAudioChunk = null;
7310
+ // Audio fragment blocked from appending until corresponding video appends or context changes
7311
+ _this.blockedAudioAppend = null;
7312
+ // Keep track of video append position for unblocking audio
7313
+ _this.lastVideoAppendEnd = 0;
7307
7314
  _this.appendSource = void 0;
7308
7315
  // counters
7309
7316
  _this.appendErrors = {
@@ -7334,7 +7341,10 @@
7334
7341
  _this.log('Media source opened');
7335
7342
  if (media) {
7336
7343
  media.removeEventListener('emptied', _this._onMediaEmptied);
7337
- _this.updateMediaElementDuration();
7344
+ var durationAndRange = _this.getDurationAndRange();
7345
+ if (durationAndRange) {
7346
+ _this.updateMediaSource(durationAndRange);
7347
+ }
7338
7348
  _this.hls.trigger(Events.MEDIA_ATTACHED, {
7339
7349
  media: media,
7340
7350
  mediaSource: mediaSource
@@ -7361,6 +7371,7 @@
7361
7371
  }
7362
7372
  };
7363
7373
  _this.hls = hls;
7374
+ _this.fragmentTracker = fragmentTracker;
7364
7375
  _this.appendSource = hls.config.preferManagedMediaSource;
7365
7376
  _this._initSourceBuffer();
7366
7377
  _this.registerListeners();
@@ -7375,7 +7386,7 @@
7375
7386
  this.details = null;
7376
7387
  this.lastMpegAudioChunk = null;
7377
7388
  // @ts-ignore
7378
- this.hls = null;
7389
+ this.hls = this.fragmentTracker = null;
7379
7390
  // @ts-ignore
7380
7391
  this._onMediaSourceOpen = this._onMediaSourceClose = null;
7381
7392
  // @ts-ignore
@@ -7427,6 +7438,8 @@
7427
7438
  audiovideo: 0
7428
7439
  };
7429
7440
  this.lastMpegAudioChunk = null;
7441
+ this.blockedAudioAppend = null;
7442
+ this.lastVideoAppendEnd = 0;
7430
7443
  };
7431
7444
  _proto.onManifestLoading = function onManifestLoading() {
7432
7445
  this.bufferCodecEventsExpected = this._bufferCodecEventsTotal = 0;
@@ -7564,9 +7577,10 @@
7564
7577
  var trackNames = Object.keys(data);
7565
7578
  trackNames.forEach(function (trackName) {
7566
7579
  if (sourceBufferCount) {
7580
+ var _track$buffer;
7567
7581
  // check if SourceBuffer codec needs to change
7568
7582
  var track = _this3.tracks[trackName];
7569
- if (track && typeof track.buffer.changeType === 'function') {
7583
+ if (track && typeof ((_track$buffer = track.buffer) == null ? void 0 : _track$buffer.changeType) === 'function') {
7570
7584
  var _trackCodec;
7571
7585
  var _data$trackName = data[trackName],
7572
7586
  id = _data$trackName.id,
@@ -7634,17 +7648,52 @@
7634
7648
  };
7635
7649
  operationQueue.append(operation, type, !!this.pendingTracks[type]);
7636
7650
  };
7651
+ _proto.blockAudio = function blockAudio(partOrFrag) {
7652
+ var _this$fragmentTracker,
7653
+ _this5 = this;
7654
+ var pStart = partOrFrag.start;
7655
+ var pTime = pStart + partOrFrag.duration * 0.05;
7656
+ var atGap = ((_this$fragmentTracker = this.fragmentTracker.getAppendedFrag(pStart, PlaylistLevelType.MAIN)) == null ? void 0 : _this$fragmentTracker.gap) === true;
7657
+ if (atGap) {
7658
+ return;
7659
+ }
7660
+ var op = {
7661
+ execute: function execute() {
7662
+ var _this5$fragmentTracke;
7663
+ if (_this5.lastVideoAppendEnd > pTime || _this5.sourceBuffer.video && BufferHelper.isBuffered(_this5.sourceBuffer.video, pTime) || ((_this5$fragmentTracke = _this5.fragmentTracker.getAppendedFrag(pTime, PlaylistLevelType.MAIN)) == null ? void 0 : _this5$fragmentTracke.gap) === true) {
7664
+ _this5.blockedAudioAppend = null;
7665
+ _this5.operationQueue.shiftAndExecuteNext('audio');
7666
+ }
7667
+ },
7668
+ onStart: function onStart() {},
7669
+ onComplete: function onComplete() {},
7670
+ onError: function onError() {}
7671
+ };
7672
+ this.blockedAudioAppend = {
7673
+ op: op,
7674
+ frag: partOrFrag
7675
+ };
7676
+ this.operationQueue.append(op, 'audio', true);
7677
+ };
7678
+ _proto.unblockAudio = function unblockAudio() {
7679
+ var blockedAudioAppend = this.blockedAudioAppend;
7680
+ if (blockedAudioAppend) {
7681
+ this.blockedAudioAppend = null;
7682
+ this.operationQueue.unblockAudio(blockedAudioAppend.op);
7683
+ }
7684
+ };
7637
7685
  _proto.onBufferAppending = function onBufferAppending(event, eventData) {
7638
- var _this5 = this;
7639
- var hls = this.hls,
7640
- operationQueue = this.operationQueue,
7686
+ var _this6 = this;
7687
+ var operationQueue = this.operationQueue,
7641
7688
  tracks = this.tracks;
7642
7689
  var data = eventData.data,
7643
7690
  type = eventData.type,
7691
+ parent = eventData.parent,
7644
7692
  frag = eventData.frag,
7645
7693
  part = eventData.part,
7646
7694
  chunkMeta = eventData.chunkMeta;
7647
7695
  var chunkStats = chunkMeta.buffering[type];
7696
+ var sn = frag.sn;
7648
7697
  var bufferAppendingStart = self.performance.now();
7649
7698
  chunkStats.start = bufferAppendingStart;
7650
7699
  var fragBuffering = frag.stats.buffering;
@@ -7667,21 +7716,50 @@
7667
7716
  checkTimestampOffset = !this.lastMpegAudioChunk || chunkMeta.id === 1 || this.lastMpegAudioChunk.sn !== chunkMeta.sn;
7668
7717
  this.lastMpegAudioChunk = chunkMeta;
7669
7718
  }
7670
- var fragStart = frag.start;
7719
+
7720
+ // Block audio append until overlapping video append
7721
+ var videoSb = this.sourceBuffer.video;
7722
+ if (videoSb && sn !== 'initSegment') {
7723
+ var partOrFrag = part || frag;
7724
+ var blockedAudioAppend = this.blockedAudioAppend;
7725
+ if (type === 'audio' && parent !== 'main' && !this.blockedAudioAppend) {
7726
+ var pStart = partOrFrag.start;
7727
+ var pTime = pStart + partOrFrag.duration * 0.05;
7728
+ var vbuffered = videoSb.buffered;
7729
+ var vappending = this.operationQueue.current('video');
7730
+ if (!vbuffered.length && !vappending) {
7731
+ // wait for video before appending audio
7732
+ this.blockAudio(partOrFrag);
7733
+ } else if (!vappending && !BufferHelper.isBuffered(videoSb, pTime) && this.lastVideoAppendEnd < pTime) {
7734
+ // audio is ahead of video
7735
+ this.blockAudio(partOrFrag);
7736
+ }
7737
+ } else if (type === 'video') {
7738
+ var videoAppendEnd = partOrFrag.end;
7739
+ if (blockedAudioAppend) {
7740
+ var audioStart = blockedAudioAppend.frag.start;
7741
+ if (videoAppendEnd > audioStart || videoAppendEnd < this.lastVideoAppendEnd || BufferHelper.isBuffered(videoSb, audioStart)) {
7742
+ this.unblockAudio();
7743
+ }
7744
+ }
7745
+ this.lastVideoAppendEnd = videoAppendEnd;
7746
+ }
7747
+ }
7748
+ var fragStart = (part || frag).start;
7671
7749
  var operation = {
7672
7750
  execute: function execute() {
7673
7751
  chunkStats.executeStart = self.performance.now();
7674
7752
  if (checkTimestampOffset) {
7675
- var sb = _this5.sourceBuffer[type];
7753
+ var sb = _this6.sourceBuffer[type];
7676
7754
  if (sb) {
7677
7755
  var delta = fragStart - sb.timestampOffset;
7678
7756
  if (Math.abs(delta) >= 0.1) {
7679
- _this5.log("Updating audio SourceBuffer timestampOffset to " + fragStart + " (delta: " + delta + ") sn: " + frag.sn + ")");
7757
+ _this6.log("Updating audio SourceBuffer timestampOffset to " + fragStart + " (delta: " + delta + ") sn: " + sn + ")");
7680
7758
  sb.timestampOffset = fragStart;
7681
7759
  }
7682
7760
  }
7683
7761
  }
7684
- _this5.appendExecutor(data, type);
7762
+ _this6.appendExecutor(data, type);
7685
7763
  },
7686
7764
  onStart: function onStart() {
7687
7765
  // logger.debug(`[buffer-controller]: ${type} SourceBuffer updatestart`);
@@ -7696,19 +7774,19 @@
7696
7774
  if (partBuffering && partBuffering.first === 0) {
7697
7775
  partBuffering.first = end;
7698
7776
  }
7699
- var sourceBuffer = _this5.sourceBuffer;
7777
+ var sourceBuffer = _this6.sourceBuffer;
7700
7778
  var timeRanges = {};
7701
7779
  for (var _type in sourceBuffer) {
7702
7780
  timeRanges[_type] = BufferHelper.getBuffered(sourceBuffer[_type]);
7703
7781
  }
7704
- _this5.appendErrors[type] = 0;
7782
+ _this6.appendErrors[type] = 0;
7705
7783
  if (type === 'audio' || type === 'video') {
7706
- _this5.appendErrors.audiovideo = 0;
7784
+ _this6.appendErrors.audiovideo = 0;
7707
7785
  } else {
7708
- _this5.appendErrors.audio = 0;
7709
- _this5.appendErrors.video = 0;
7786
+ _this6.appendErrors.audio = 0;
7787
+ _this6.appendErrors.video = 0;
7710
7788
  }
7711
- _this5.hls.trigger(Events.BUFFER_APPENDED, {
7789
+ _this6.hls.trigger(Events.BUFFER_APPENDED, {
7712
7790
  type: type,
7713
7791
  frag: frag,
7714
7792
  part: part,
@@ -7736,51 +7814,57 @@
7736
7814
  // let's stop appending any segments, and report BUFFER_FULL_ERROR error
7737
7815
  event.details = ErrorDetails.BUFFER_FULL_ERROR;
7738
7816
  } else {
7739
- var appendErrorCount = ++_this5.appendErrors[type];
7817
+ var appendErrorCount = ++_this6.appendErrors[type];
7740
7818
  event.details = ErrorDetails.BUFFER_APPEND_ERROR;
7741
7819
  /* with UHD content, we could get loop of quota exceeded error until
7742
7820
  browser is able to evict some data from sourcebuffer. Retrying can help recover.
7743
7821
  */
7744
- _this5.warn("Failed " + appendErrorCount + "/" + hls.config.appendErrorMaxRetry + " times to append segment in \"" + type + "\" sourceBuffer");
7745
- if (appendErrorCount >= hls.config.appendErrorMaxRetry) {
7822
+ _this6.warn("Failed " + appendErrorCount + "/" + _this6.hls.config.appendErrorMaxRetry + " times to append segment in \"" + type + "\" sourceBuffer");
7823
+ if (appendErrorCount >= _this6.hls.config.appendErrorMaxRetry) {
7746
7824
  event.fatal = true;
7747
7825
  }
7748
7826
  }
7749
- hls.trigger(Events.ERROR, event);
7827
+ _this6.hls.trigger(Events.ERROR, event);
7750
7828
  }
7751
7829
  };
7752
7830
  operationQueue.append(operation, type, !!this.pendingTracks[type]);
7753
7831
  };
7832
+ _proto.getFlushOp = function getFlushOp(type, start, end) {
7833
+ var _this7 = this;
7834
+ return {
7835
+ execute: function execute() {
7836
+ _this7.removeExecutor(type, start, end);
7837
+ },
7838
+ onStart: function onStart() {
7839
+ // logger.debug(`[buffer-controller]: Started flushing ${data.startOffset} -> ${data.endOffset} for ${type} Source Buffer`);
7840
+ },
7841
+ onComplete: function onComplete() {
7842
+ // logger.debug(`[buffer-controller]: Finished flushing ${data.startOffset} -> ${data.endOffset} for ${type} Source Buffer`);
7843
+ _this7.hls.trigger(Events.BUFFER_FLUSHED, {
7844
+ type: type
7845
+ });
7846
+ },
7847
+ onError: function onError(error) {
7848
+ _this7.warn("Failed to remove from " + type + " SourceBuffer", error);
7849
+ }
7850
+ };
7851
+ };
7754
7852
  _proto.onBufferFlushing = function onBufferFlushing(event, data) {
7755
- var _this6 = this;
7853
+ var _this8 = this;
7756
7854
  var operationQueue = this.operationQueue;
7757
- var flushOperation = function flushOperation(type) {
7758
- return {
7759
- execute: _this6.removeExecutor.bind(_this6, type, data.startOffset, data.endOffset),
7760
- onStart: function onStart() {
7761
- // logger.debug(`[buffer-controller]: Started flushing ${data.startOffset} -> ${data.endOffset} for ${type} Source Buffer`);
7762
- },
7763
- onComplete: function onComplete() {
7764
- // logger.debug(`[buffer-controller]: Finished flushing ${data.startOffset} -> ${data.endOffset} for ${type} Source Buffer`);
7765
- _this6.hls.trigger(Events.BUFFER_FLUSHED, {
7766
- type: type
7767
- });
7768
- },
7769
- onError: function onError(error) {
7770
- _this6.warn("Failed to remove from " + type + " SourceBuffer", error);
7771
- }
7772
- };
7773
- };
7774
- if (data.type) {
7775
- operationQueue.append(flushOperation(data.type), data.type);
7855
+ var type = data.type,
7856
+ startOffset = data.startOffset,
7857
+ endOffset = data.endOffset;
7858
+ if (type) {
7859
+ operationQueue.append(this.getFlushOp(type, startOffset, endOffset), type);
7776
7860
  } else {
7777
- this.getSourceBufferTypes().forEach(function (type) {
7778
- operationQueue.append(flushOperation(type), type);
7861
+ this.getSourceBufferTypes().forEach(function (sbType) {
7862
+ operationQueue.append(_this8.getFlushOp(sbType, startOffset, endOffset), sbType);
7779
7863
  });
7780
7864
  }
7781
7865
  };
7782
7866
  _proto.onFragParsed = function onFragParsed(event, data) {
7783
- var _this7 = this;
7867
+ var _this9 = this;
7784
7868
  var frag = data.frag,
7785
7869
  part = data.part;
7786
7870
  var buffersAppendedTo = [];
@@ -7802,7 +7886,7 @@
7802
7886
  part.stats.buffering.end = now;
7803
7887
  }
7804
7888
  var stats = part ? part.stats : frag.stats;
7805
- _this7.hls.trigger(Events.FRAG_BUFFERED, {
7889
+ _this9.hls.trigger(Events.FRAG_BUFFERED, {
7806
7890
  frag: frag,
7807
7891
  part: part,
7808
7892
  stats: stats,
@@ -7822,14 +7906,17 @@
7822
7906
  // an undefined data.type will mark all buffers as EOS.
7823
7907
  ;
7824
7908
  _proto.onBufferEos = function onBufferEos(event, data) {
7825
- var _this8 = this;
7909
+ var _this10 = this;
7910
+ if (data.type === 'video') {
7911
+ this.unblockAudio();
7912
+ }
7826
7913
  var ended = this.getSourceBufferTypes().reduce(function (acc, type) {
7827
- var sb = _this8.sourceBuffer[type];
7914
+ var sb = _this10.sourceBuffer[type];
7828
7915
  if (sb && (!data.type || data.type === type)) {
7829
7916
  sb.ending = true;
7830
7917
  if (!sb.ended) {
7831
7918
  sb.ended = true;
7832
- _this8.log(type + " sourceBuffer now EOS");
7919
+ _this10.log(type + " sourceBuffer now EOS");
7833
7920
  }
7834
7921
  }
7835
7922
  return acc && !!(!sb || sb.ended);
@@ -7837,35 +7924,42 @@
7837
7924
  if (ended) {
7838
7925
  this.log("Queueing mediaSource.endOfStream()");
7839
7926
  this.blockBuffers(function () {
7840
- _this8.getSourceBufferTypes().forEach(function (type) {
7841
- var sb = _this8.sourceBuffer[type];
7927
+ _this10.getSourceBufferTypes().forEach(function (type) {
7928
+ var sb = _this10.sourceBuffer[type];
7842
7929
  if (sb) {
7843
7930
  sb.ending = false;
7844
7931
  }
7845
7932
  });
7846
- var mediaSource = _this8.mediaSource;
7933
+ var mediaSource = _this10.mediaSource;
7847
7934
  if (!mediaSource || mediaSource.readyState !== 'open') {
7848
7935
  if (mediaSource) {
7849
- _this8.log("Could not call mediaSource.endOfStream(). mediaSource.readyState: " + mediaSource.readyState);
7936
+ _this10.log("Could not call mediaSource.endOfStream(). mediaSource.readyState: " + mediaSource.readyState);
7850
7937
  }
7851
7938
  return;
7852
7939
  }
7853
- _this8.log("Calling mediaSource.endOfStream()");
7940
+ _this10.log("Calling mediaSource.endOfStream()");
7854
7941
  // Allow this to throw and be caught by the enqueueing function
7855
7942
  mediaSource.endOfStream();
7856
7943
  });
7857
7944
  }
7858
7945
  };
7859
7946
  _proto.onLevelUpdated = function onLevelUpdated(event, _ref) {
7947
+ var _this11 = this;
7860
7948
  var details = _ref.details;
7861
7949
  if (!details.fragments.length) {
7862
7950
  return;
7863
7951
  }
7864
7952
  this.details = details;
7953
+ var durationAndRange = this.getDurationAndRange();
7954
+ if (!durationAndRange) {
7955
+ return;
7956
+ }
7865
7957
  if (this.getSourceBufferTypes().length) {
7866
- this.blockBuffers(this.updateMediaElementDuration.bind(this));
7958
+ this.blockBuffers(function () {
7959
+ return _this11.updateMediaSource(durationAndRange);
7960
+ });
7867
7961
  } else {
7868
- this.updateMediaElementDuration();
7962
+ this.updateMediaSource(durationAndRange);
7869
7963
  }
7870
7964
  };
7871
7965
  _proto.trimBuffers = function trimBuffers() {
@@ -7898,7 +7992,7 @@
7898
7992
  }
7899
7993
  };
7900
7994
  _proto.flushBackBuffer = function flushBackBuffer(currentTime, targetDuration, targetBackBufferPosition) {
7901
- var _this9 = this;
7995
+ var _this12 = this;
7902
7996
  var details = this.details,
7903
7997
  sourceBuffer = this.sourceBuffer;
7904
7998
  var sourceBufferTypes = this.getSourceBufferTypes();
@@ -7908,20 +8002,20 @@
7908
8002
  var buffered = BufferHelper.getBuffered(sb);
7909
8003
  // when target buffer start exceeds actual buffer start
7910
8004
  if (buffered.length > 0 && targetBackBufferPosition > buffered.start(0)) {
7911
- _this9.hls.trigger(Events.BACK_BUFFER_REACHED, {
8005
+ _this12.hls.trigger(Events.BACK_BUFFER_REACHED, {
7912
8006
  bufferEnd: targetBackBufferPosition
7913
8007
  });
7914
8008
 
7915
8009
  // Support for deprecated event:
7916
8010
  if (details != null && details.live) {
7917
- _this9.hls.trigger(Events.LIVE_BACK_BUFFER_REACHED, {
8011
+ _this12.hls.trigger(Events.LIVE_BACK_BUFFER_REACHED, {
7918
8012
  bufferEnd: targetBackBufferPosition
7919
8013
  });
7920
8014
  } else if (sb.ended && buffered.end(buffered.length - 1) - currentTime < targetDuration * 2) {
7921
- _this9.log("Cannot flush " + type + " back buffer while SourceBuffer is in ended state");
8015
+ _this12.log("Cannot flush " + type + " back buffer while SourceBuffer is in ended state");
7922
8016
  return;
7923
8017
  }
7924
- _this9.hls.trigger(Events.BUFFER_FLUSHING, {
8018
+ _this12.hls.trigger(Events.BUFFER_FLUSHING, {
7925
8019
  startOffset: 0,
7926
8020
  endOffset: targetBackBufferPosition,
7927
8021
  type: type
@@ -7931,7 +8025,7 @@
7931
8025
  });
7932
8026
  };
7933
8027
  _proto.flushFrontBuffer = function flushFrontBuffer(currentTime, targetDuration, targetFrontBufferPosition) {
7934
- var _this10 = this;
8028
+ var _this13 = this;
7935
8029
  var sourceBuffer = this.sourceBuffer;
7936
8030
  var sourceBufferTypes = this.getSourceBufferTypes();
7937
8031
  sourceBufferTypes.forEach(function (type) {
@@ -7949,10 +8043,10 @@
7949
8043
  if (targetFrontBufferPosition > bufferStart || currentTime >= bufferStart && currentTime <= bufferEnd) {
7950
8044
  return;
7951
8045
  } else if (sb.ended && currentTime - bufferEnd < 2 * targetDuration) {
7952
- _this10.log("Cannot flush " + type + " front buffer while SourceBuffer is in ended state");
8046
+ _this13.log("Cannot flush " + type + " front buffer while SourceBuffer is in ended state");
7953
8047
  return;
7954
8048
  }
7955
- _this10.hls.trigger(Events.BUFFER_FLUSHING, {
8049
+ _this13.hls.trigger(Events.BUFFER_FLUSHING, {
7956
8050
  startOffset: bufferStart,
7957
8051
  endOffset: Infinity,
7958
8052
  type: type
@@ -7966,9 +8060,9 @@
7966
8060
  * 'liveDurationInfinity` is set to `true`
7967
8061
  * More details: https://github.com/video-dev/hls.js/issues/355
7968
8062
  */;
7969
- _proto.updateMediaElementDuration = function updateMediaElementDuration() {
8063
+ _proto.getDurationAndRange = function getDurationAndRange() {
7970
8064
  if (!this.details || !this.media || !this.mediaSource || this.mediaSource.readyState !== 'open') {
7971
- return;
8065
+ return null;
7972
8066
  }
7973
8067
  var details = this.details,
7974
8068
  hls = this.hls,
@@ -7980,25 +8074,40 @@
7980
8074
  if (details.live && hls.config.liveDurationInfinity) {
7981
8075
  // Override duration to Infinity
7982
8076
  mediaSource.duration = Infinity;
7983
- this.updateSeekableRange(details);
8077
+ var len = details.fragments.length;
8078
+ if (len && details.live && !!mediaSource.setLiveSeekableRange) {
8079
+ var start = Math.max(0, details.fragments[0].start);
8080
+ var end = Math.max(start, start + details.totalduration);
8081
+ return {
8082
+ duration: Infinity,
8083
+ start: start,
8084
+ end: end
8085
+ };
8086
+ }
8087
+ return {
8088
+ duration: Infinity
8089
+ };
7984
8090
  } else if (levelDuration > msDuration && levelDuration > mediaDuration || !isFiniteNumber(mediaDuration)) {
7985
- // levelDuration was the last value we set.
7986
- // not using mediaSource.duration as the browser may tweak this value
7987
- // only update Media Source duration if its value increase, this is to avoid
7988
- // flushing already buffered portion when switching between quality level
7989
- this.log("Updating Media Source duration to " + levelDuration.toFixed(3));
7990
- mediaSource.duration = levelDuration;
8091
+ return {
8092
+ duration: levelDuration
8093
+ };
7991
8094
  }
8095
+ return null;
7992
8096
  };
7993
- _proto.updateSeekableRange = function updateSeekableRange(levelDetails) {
7994
- var mediaSource = this.mediaSource;
7995
- var fragments = levelDetails.fragments;
7996
- var len = fragments.length;
7997
- if (len && levelDetails.live && mediaSource != null && mediaSource.setLiveSeekableRange) {
7998
- var start = Math.max(0, fragments[0].start);
7999
- var end = Math.max(start, start + levelDetails.totalduration);
8000
- this.log("Media Source duration is set to " + mediaSource.duration + ". Setting seekable range to " + start + "-" + end + ".");
8001
- mediaSource.setLiveSeekableRange(start, end);
8097
+ _proto.updateMediaSource = function updateMediaSource(_ref2) {
8098
+ var duration = _ref2.duration,
8099
+ start = _ref2.start,
8100
+ end = _ref2.end;
8101
+ if (!this.media || !this.mediaSource || this.mediaSource.readyState !== 'open') {
8102
+ return;
8103
+ }
8104
+ if (isFiniteNumber(duration)) {
8105
+ this.log("Updating Media Source duration to " + duration.toFixed(3));
8106
+ }
8107
+ this.mediaSource.duration = duration;
8108
+ if (start !== undefined && end !== undefined) {
8109
+ this.log("Media Source duration is set to " + this.mediaSource.duration + ". Setting seekable range to " + start + "-" + end + ".");
8110
+ this.mediaSource.setLiveSeekableRange(start, end);
8002
8111
  }
8003
8112
  };
8004
8113
  _proto.checkPendingTracks = function checkPendingTracks() {
@@ -8037,7 +8146,7 @@
8037
8146
  }
8038
8147
  };
8039
8148
  _proto.createSourceBuffers = function createSourceBuffers(tracks) {
8040
- var _this11 = this;
8149
+ var _this14 = this;
8041
8150
  var sourceBuffer = this.sourceBuffer,
8042
8151
  mediaSource = this.mediaSource;
8043
8152
  if (!mediaSource) {
@@ -8053,28 +8162,28 @@
8053
8162
  var codec = track.levelCodec || track.codec;
8054
8163
  if (codec) {
8055
8164
  if (trackName.slice(0, 5) === 'audio') {
8056
- codec = getCodecCompatibleName(codec, _this11.hls.config.preferManagedMediaSource);
8165
+ codec = getCodecCompatibleName(codec, _this14.hls.config.preferManagedMediaSource);
8057
8166
  }
8058
8167
  }
8059
8168
  var mimeType = track.container + ";codecs=" + codec;
8060
- _this11.log("creating sourceBuffer(" + mimeType + ")");
8169
+ _this14.log("creating sourceBuffer(" + mimeType + ")");
8061
8170
  try {
8062
8171
  var sb = sourceBuffer[trackName] = mediaSource.addSourceBuffer(mimeType);
8063
8172
  var sbName = trackName;
8064
- _this11.addBufferListener(sbName, 'updatestart', _this11._onSBUpdateStart);
8065
- _this11.addBufferListener(sbName, 'updateend', _this11._onSBUpdateEnd);
8066
- _this11.addBufferListener(sbName, 'error', _this11._onSBUpdateError);
8173
+ _this14.addBufferListener(sbName, 'updatestart', _this14._onSBUpdateStart);
8174
+ _this14.addBufferListener(sbName, 'updateend', _this14._onSBUpdateEnd);
8175
+ _this14.addBufferListener(sbName, 'error', _this14._onSBUpdateError);
8067
8176
  // ManagedSourceBuffer bufferedchange event
8068
- _this11.addBufferListener(sbName, 'bufferedchange', function (type, event) {
8177
+ _this14.addBufferListener(sbName, 'bufferedchange', function (type, event) {
8069
8178
  // If media was ejected check for a change. Added ranges are redundant with changes on 'updateend' event.
8070
8179
  var removedRanges = event.removedRanges;
8071
8180
  if (removedRanges != null && removedRanges.length) {
8072
- _this11.hls.trigger(Events.BUFFER_FLUSHED, {
8181
+ _this14.hls.trigger(Events.BUFFER_FLUSHED, {
8073
8182
  type: trackName
8074
8183
  });
8075
8184
  }
8076
8185
  });
8077
- _this11.tracks[trackName] = {
8186
+ _this14.tracks[trackName] = {
8078
8187
  buffer: sb,
8079
8188
  codec: codec,
8080
8189
  container: track.container,
@@ -8083,8 +8192,8 @@
8083
8192
  id: track.id
8084
8193
  };
8085
8194
  } catch (err) {
8086
- _this11.error("error while trying to add sourceBuffer: " + err.message);
8087
- _this11.hls.trigger(Events.ERROR, {
8195
+ _this14.error("error while trying to add sourceBuffer: " + err.message);
8196
+ _this14.hls.trigger(Events.ERROR, {
8088
8197
  type: ErrorTypes.MEDIA_ERROR,
8089
8198
  details: ErrorDetails.BUFFER_ADD_CODEC_ERROR,
8090
8199
  fatal: false,
@@ -8172,6 +8281,7 @@
8172
8281
  }
8173
8282
  return;
8174
8283
  }
8284
+ sb.ending = false;
8175
8285
  sb.ended = false;
8176
8286
  sb.appendBuffer(data);
8177
8287
  }
@@ -8181,7 +8291,7 @@
8181
8291
  // upon completion, since we already do it here
8182
8292
  ;
8183
8293
  _proto.blockBuffers = function blockBuffers(onUnblocked, buffers) {
8184
- var _this12 = this;
8294
+ var _this15 = this;
8185
8295
  if (buffers === void 0) {
8186
8296
  buffers = this.getSourceBufferTypes();
8187
8297
  }
@@ -8196,11 +8306,15 @@
8196
8306
  var blockingOperations = buffers.map(function (type) {
8197
8307
  return operationQueue.appendBlocker(type);
8198
8308
  });
8199
- Promise.all(blockingOperations).then(function () {
8309
+ var audioBlocked = buffers.length > 1 && !!this.blockedAudioAppend;
8310
+ if (audioBlocked) {
8311
+ this.unblockAudio();
8312
+ }
8313
+ Promise.all(blockingOperations).then(function (result) {
8200
8314
  // logger.debug(`[buffer-controller]: Blocking operation resolved; unblocking ${buffers} SourceBuffer`);
8201
8315
  onUnblocked();
8202
- buffers.forEach(function (type) {
8203
- var sb = _this12.sourceBuffer[type];
8316
+ buffers.forEach(function (type, i) {
8317
+ var sb = _this15.sourceBuffer[type];
8204
8318
  // Only cycle the queue if the SB is not updating. There's a bug in Chrome which sets the SB updating flag to
8205
8319
  // true when changing the MediaSource duration (https://bugs.chromium.org/p/chromium/issues/detail?id=959359&can=2&q=mediasource%20duration)
8206
8320
  // While this is a workaround, it's probably useful to have around
@@ -10559,11 +10673,14 @@
10559
10673
  * If not found any Fragment, return null
10560
10674
  */;
10561
10675
  _proto.getBufferedFrag = function getBufferedFrag(position, levelType) {
10676
+ return this.getFragAtPos(position, levelType, true);
10677
+ };
10678
+ _proto.getFragAtPos = function getFragAtPos(position, levelType, buffered) {
10562
10679
  var fragments = this.fragments;
10563
10680
  var keys = Object.keys(fragments);
10564
10681
  for (var i = keys.length; i--;) {
10565
10682
  var fragmentEntity = fragments[keys[i]];
10566
- if ((fragmentEntity == null ? void 0 : fragmentEntity.body.type) === levelType && fragmentEntity.buffered) {
10683
+ if ((fragmentEntity == null ? void 0 : fragmentEntity.body.type) === levelType && (!buffered || fragmentEntity.buffered)) {
10567
10684
  var frag = fragmentEntity.body;
10568
10685
  if (frag.start <= position && position <= frag.end) {
10569
10686
  return frag;
@@ -10813,10 +10930,10 @@
10813
10930
  };
10814
10931
  };
10815
10932
  _proto.onBufferAppended = function onBufferAppended(event, data) {
10816
- var _this3 = this;
10817
10933
  var frag = data.frag,
10818
10934
  part = data.part,
10819
- timeRanges = data.timeRanges;
10935
+ timeRanges = data.timeRanges,
10936
+ type = data.type;
10820
10937
  if (frag.sn === 'initSegment') {
10821
10938
  return;
10822
10939
  }
@@ -10830,10 +10947,8 @@
10830
10947
  }
10831
10948
  // Store the latest timeRanges loaded in the buffer
10832
10949
  this.timeRanges = timeRanges;
10833
- Object.keys(timeRanges).forEach(function (elementaryStream) {
10834
- var timeRange = timeRanges[elementaryStream];
10835
- _this3.detectEvictedFragments(elementaryStream, timeRange, playlistType, part);
10836
- });
10950
+ var timeRange = timeRanges[type];
10951
+ this.detectEvictedFragments(type, timeRange, playlistType, part);
10837
10952
  };
10838
10953
  _proto.onFragBuffered = function onFragBuffered(event, data) {
10839
10954
  this.detectPartialFragments(data);
@@ -10847,12 +10962,12 @@
10847
10962
  return !!((_this$activePartLists = this.activePartLists[type]) != null && _this$activePartLists.length);
10848
10963
  };
10849
10964
  _proto.removeFragmentsInRange = function removeFragmentsInRange(start, end, playlistType, withGapOnly, unbufferedOnly) {
10850
- var _this4 = this;
10965
+ var _this3 = this;
10851
10966
  if (withGapOnly && !this.hasGaps) {
10852
10967
  return;
10853
10968
  }
10854
10969
  Object.keys(this.fragments).forEach(function (key) {
10855
- var fragmentEntity = _this4.fragments[key];
10970
+ var fragmentEntity = _this3.fragments[key];
10856
10971
  if (!fragmentEntity) {
10857
10972
  return;
10858
10973
  }
@@ -10861,7 +10976,7 @@
10861
10976
  return;
10862
10977
  }
10863
10978
  if (frag.start < end && frag.end > start && (fragmentEntity.buffered || unbufferedOnly)) {
10864
- _this4.removeFragment(frag);
10979
+ _this3.removeFragment(frag);
10865
10980
  }
10866
10981
  });
10867
10982
  };
@@ -13049,7 +13164,7 @@
13049
13164
  // Workaround flaw in getting forward buffer when maxBufferHole is smaller than gap at current pos
13050
13165
  if (bufferInfo.len === 0 && bufferInfo.nextStart !== undefined) {
13051
13166
  var bufferedFragAtPos = this.fragmentTracker.getBufferedFrag(pos, type);
13052
- if (bufferedFragAtPos && bufferInfo.nextStart < bufferedFragAtPos.end) {
13167
+ if (bufferedFragAtPos && (bufferInfo.nextStart <= bufferedFragAtPos.end || bufferedFragAtPos.gap)) {
13053
13168
  return BufferHelper.bufferInfo(bufferable, pos, Math.max(bufferInfo.nextStart, maxBufferHole));
13054
13169
  }
13055
13170
  }
@@ -20408,6 +20523,17 @@
20408
20523
  }
20409
20524
  };
20410
20525
  _createClass(StreamController, [{
20526
+ key: "maxBufferLength",
20527
+ get: function get() {
20528
+ var levels = this.levels,
20529
+ level = this.level;
20530
+ var levelInfo = levels == null ? void 0 : levels[level];
20531
+ if (!levelInfo) {
20532
+ return this.config.maxBufferLength;
20533
+ }
20534
+ return this.getMaxBufferLength(levelInfo.maxBitrate);
20535
+ }
20536
+ }, {
20411
20537
  key: "nextLevel",
20412
20538
  get: function get() {
20413
20539
  var frag = this.nextBufferedFrag;
@@ -20544,7 +20670,9 @@
20544
20670
  ConfigFpsController = config.fpsController;
20545
20671
  var errorController = new ConfigErrorController(this);
20546
20672
  var abrController = this.abrController = new ConfigAbrController(this);
20547
- var bufferController = this.bufferController = new ConfigBufferController(this);
20673
+ // FragmentTracker must be defined before StreamController because the order of event handling is important
20674
+ var fragmentTracker = new FragmentTracker(this);
20675
+ var bufferController = this.bufferController = new ConfigBufferController(this, fragmentTracker);
20548
20676
  var capLevelController = this.capLevelController = new ConfigCapLevelController(this);
20549
20677
  var fpsController = new ConfigFpsController(this);
20550
20678
  var playListLoader = new PlaylistLoader(this);
@@ -20553,8 +20681,6 @@
20553
20681
  // ConentSteeringController is defined before LevelController to receive Multivariant Playlist events first
20554
20682
  var contentSteering = ConfigContentSteeringController ? new ConfigContentSteeringController(this) : null;
20555
20683
  var levelController = this.levelController = new LevelController(this, contentSteering);
20556
- // FragmentTracker must be defined before StreamController because the order of event handling is important
20557
- var fragmentTracker = new FragmentTracker(this);
20558
20684
  var keyLoader = new KeyLoader(this.config);
20559
20685
  var streamController = this.streamController = new StreamController(this, fragmentTracker, keyLoader);
20560
20686
 
@@ -21151,6 +21277,11 @@
21151
21277
  get: function get() {
21152
21278
  return this.streamController.getMainFwdBufferInfo();
21153
21279
  }
21280
+ }, {
21281
+ key: "maxBufferLength",
21282
+ get: function get() {
21283
+ return this.streamController.maxBufferLength;
21284
+ }
21154
21285
  }, {
21155
21286
  key: "allAudioTracks",
21156
21287
  get: function get() {
@@ -21333,7 +21464,7 @@
21333
21464
  * Get the video-dev/hls.js package version.
21334
21465
  */
21335
21466
  function get() {
21336
- return "1.5.7-0.canary.10015";
21467
+ return "1.5.7-0.canary.10016";
21337
21468
  }
21338
21469
  }, {
21339
21470
  key: "Events",