hls.js 1.6.0-beta.1.0.canary.10801 → 1.6.0-beta.1.0.canary.10804

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
@@ -1028,7 +1028,7 @@
1028
1028
  // Some browsers don't allow to use bind on console object anyway
1029
1029
  // fallback to default if needed
1030
1030
  try {
1031
- newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.6.0-beta.1.0.canary.10801");
1031
+ newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.6.0-beta.1.0.canary.10804");
1032
1032
  } catch (e) {
1033
1033
  /* log fn threw an exception. All logger methods are no-ops. */
1034
1034
  return createLogger();
@@ -2287,7 +2287,7 @@
2287
2287
  var forcedAutoLevel = _this3.forcedAutoLevel;
2288
2288
  if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
2289
2289
  if (levelsSkipped.length) {
2290
- _this3.trace("Skipped level(s) " + levelsSkipped.join(',') + " of " + maxAutoLevel + " max with CODECS and VIDEO-RANGE:\"" + levels[levelsSkipped[0]].codecs + "\" " + levels[levelsSkipped[0]].videoRange + "; not compatible with \"" + level.codecs + "\" " + currentVideoRange);
2290
+ _this3.trace("Skipped level(s) " + levelsSkipped.join(',') + " of " + maxAutoLevel + " max with CODECS and VIDEO-RANGE:\"" + levels[levelsSkipped[0]].codecs + "\" " + levels[levelsSkipped[0]].videoRange + "; not compatible with \"" + currentCodecSet + "\" " + currentVideoRange);
2291
2291
  }
2292
2292
  _this3.info("switch candidate:" + selectionBaseLevel + "->" + i + " adjustedbw(" + Math.round(adjustedbw) + ")-bitrate=" + Math.round(adjustedbw - bitrate) + " ttfb:" + ttfbEstimateSec.toFixed(1) + " avgDuration:" + avgDuration.toFixed(1) + " maxFetchDuration:" + maxFetchDuration.toFixed(1) + " fetchDuration:" + fetchDuration.toFixed(1) + " firstSelection:" + firstSelection + " codecSet:" + levelInfo.codecSet + " videoRange:" + levelInfo.videoRange + " hls.loadLevel:" + loadLevel);
2293
2293
  }
@@ -5911,6 +5911,23 @@
5911
5911
  }
5912
5912
  return -1;
5913
5913
  }
5914
+ }, {
5915
+ key: "maxPartIndex",
5916
+ get: function get() {
5917
+ var partList = this.partList;
5918
+ if (partList) {
5919
+ var lastIndex = this.lastPartIndex;
5920
+ if (lastIndex !== -1) {
5921
+ for (var i = partList.length; i--;) {
5922
+ if (partList[i].index > lastIndex) {
5923
+ return partList[i].index;
5924
+ }
5925
+ }
5926
+ return lastIndex;
5927
+ }
5928
+ }
5929
+ return 0;
5930
+ }
5914
5931
  }, {
5915
5932
  key: "lastPartSn",
5916
5933
  get: function get() {
@@ -8270,10 +8287,14 @@
8270
8287
  }
8271
8288
  function reassignFragmentLevelIndexes(levels) {
8272
8289
  levels.forEach(function (level, index) {
8273
- var details = level.details;
8274
- if (details != null && details.fragments) {
8275
- details.fragments.forEach(function (fragment) {
8290
+ var _level$details;
8291
+ var fragments = (_level$details = level.details) == null ? void 0 : _level$details.fragments;
8292
+ if (fragments) {
8293
+ fragments.forEach(function (fragment) {
8276
8294
  fragment.level = index;
8295
+ if (fragment.initSegment) {
8296
+ fragment.initSegment.level = index;
8297
+ }
8277
8298
  });
8278
8299
  }
8279
8300
  });
@@ -16329,8 +16350,8 @@
16329
16350
  var _this;
16330
16351
  _this = _Logger.call(this, logPrefix, hls.logger) || this;
16331
16352
  _this.hls = void 0;
16332
- _this.timer = -1;
16333
16353
  _this.canLoad = false;
16354
+ _this.timer = -1;
16334
16355
  _this.hls = hls;
16335
16356
  return _this;
16336
16357
  }
@@ -16436,11 +16457,23 @@
16436
16457
  if (details.live || previousDetails != null && previousDetails.live) {
16437
16458
  var levelOrTrack = 'levelInfo' in data ? data.levelInfo : data.track;
16438
16459
  details.reloaded(previousDetails);
16439
- this.log("live playlist " + index + " " + (details.advanced ? 'REFRESHED ' + details.lastPartSn + '-' + details.lastPartIndex : details.updated ? 'UPDATED' : 'MISSED'));
16440
16460
  // Merge live playlists to adjust fragment starts and fill in delta playlist skipped segments
16441
16461
  if (previousDetails && details.fragments.length > 0) {
16442
16462
  mergeDetails(previousDetails, details);
16443
16463
  }
16464
+ if (details.requestScheduled === -1) {
16465
+ details.requestScheduled = stats.loading.start;
16466
+ }
16467
+ var bufferInfo = this.hls.mainForwardBufferInfo;
16468
+ var position = bufferInfo ? bufferInfo.end - bufferInfo.len : 0;
16469
+ var distanceToLiveEdgeMs = (details.edge - position) * 1000;
16470
+ var reloadInterval = computeReloadInterval(details, distanceToLiveEdgeMs);
16471
+ if (details.requestScheduled + reloadInterval < now) {
16472
+ details.requestScheduled = now;
16473
+ } else {
16474
+ details.requestScheduled += reloadInterval;
16475
+ }
16476
+ this.log("live playlist " + index + " " + (details.advanced ? 'REFRESHED ' + details.lastPartSn + '-' + details.lastPartIndex : details.updated ? 'UPDATED' : 'MISSED'));
16444
16477
  if (!this.canLoad || !details.live) {
16445
16478
  return;
16446
16479
  }
@@ -16454,12 +16487,16 @@
16454
16487
  var endSn = details.endSN;
16455
16488
  var lastPartIndex = details.lastPartIndex;
16456
16489
  var hasParts = lastPartIndex !== -1;
16457
- var lastPart = lastPartSn === endSn;
16458
- // When low latency mode is disabled, we'll skip part requests once the last part index is found
16459
- var nextSnStartIndex = lowLatencyMode ? 0 : lastPartIndex;
16490
+ var atLastPartOfSegment = lastPartSn === endSn;
16460
16491
  if (hasParts) {
16461
- msn = lastPart ? endSn + 1 : lastPartSn;
16462
- part = lastPart ? nextSnStartIndex : lastPartIndex + 1;
16492
+ // When low latency mode is disabled, request the last part of the next segment
16493
+ if (atLastPartOfSegment) {
16494
+ msn = endSn + 1;
16495
+ part = lowLatencyMode ? 0 : lastPartIndex;
16496
+ } else {
16497
+ msn = lastPartSn;
16498
+ part = lowLatencyMode ? lastPartIndex + 1 : details.maxPartIndex;
16499
+ }
16463
16500
  } else {
16464
16501
  msn = endSn + 1;
16465
16502
  }
@@ -16491,36 +16528,25 @@
16491
16528
  details.tuneInGoal = currentGoal;
16492
16529
  }
16493
16530
  deliveryDirectives = this.getDeliveryDirectives(details, data.deliveryDirectives, msn, part);
16494
- if (lowLatencyMode || !lastPart) {
16531
+ if (lowLatencyMode || !atLastPartOfSegment) {
16532
+ details.requestScheduled = now;
16495
16533
  this.loadingPlaylist(levelOrTrack, deliveryDirectives);
16496
16534
  return;
16497
16535
  }
16498
16536
  } else if (details.canBlockReload || details.canSkipUntil) {
16499
16537
  deliveryDirectives = this.getDeliveryDirectives(details, data.deliveryDirectives, msn, part);
16500
16538
  }
16501
- if (details.requestScheduled === -1) {
16502
- details.requestScheduled = stats.loading.start;
16503
- }
16504
16539
  if (deliveryDirectives && msn !== undefined && details.canBlockReload) {
16505
- details.requestScheduled -= details.partTarget * 1000 || 1000;
16506
- }
16507
- var bufferInfo = this.hls.mainForwardBufferInfo;
16508
- var position = bufferInfo ? bufferInfo.end - bufferInfo.len : 0;
16509
- var distanceToLiveEdgeMs = (details.edge - position) * 1000;
16510
- var reloadInterval = computeReloadInterval(details, distanceToLiveEdgeMs);
16511
- if (details.requestScheduled + reloadInterval < now) {
16512
- details.requestScheduled = now;
16513
- } else {
16514
- details.requestScheduled += reloadInterval;
16540
+ details.requestScheduled = stats.loading.first + Math.max(reloadInterval - elapsed * 2, reloadInterval / 2);
16515
16541
  }
16516
- this.scheduleLoading(levelOrTrack, deliveryDirectives);
16542
+ this.scheduleLoading(levelOrTrack, deliveryDirectives, details);
16517
16543
  } else {
16518
16544
  this.clearTimer();
16519
16545
  }
16520
16546
  };
16521
- _proto.scheduleLoading = function scheduleLoading(levelOrTrack, deliveryDirectives) {
16547
+ _proto.scheduleLoading = function scheduleLoading(levelOrTrack, deliveryDirectives, updatedDetails) {
16522
16548
  var _this2 = this;
16523
- var details = levelOrTrack.details;
16549
+ var details = updatedDetails || levelOrTrack.details;
16524
16550
  if (!details) {
16525
16551
  this.loadingPlaylist(levelOrTrack, deliveryDirectives);
16526
16552
  return;
@@ -16533,22 +16559,7 @@
16533
16559
  }
16534
16560
  var estimatedTimeUntilUpdate = requestScheduled - now;
16535
16561
  this.log("reload live playlist " + (levelOrTrack.name || levelOrTrack.bitrate + 'bps') + " in " + Math.round(estimatedTimeUntilUpdate) + " ms");
16536
- // this.log(
16537
- // `live reload ${details.updated ? 'REFRESHED' : 'MISSED'}
16538
- // reload in ${estimatedTimeUntilUpdate / 1000}
16539
- // round trip ${(stats.loading.end - stats.loading.start) / 1000}
16540
- // diff ${
16541
- // (reloadInterval -
16542
- // (estimatedTimeUntilUpdate +
16543
- // stats.loading.end -
16544
- // stats.loading.start)) /
16545
- // 1000
16546
- // }
16547
- // reload interval ${reloadInterval / 1000}
16548
- // target duration ${details.targetduration}
16549
- // distance to edge ${distanceToLiveEdgeMs / 1000}`
16550
- // );
16551
-
16562
+ this.clearTimer();
16552
16563
  this.timer = self.setTimeout(function () {
16553
16564
  return _this2.loadingPlaylist(levelOrTrack, deliveryDirectives);
16554
16565
  }, estimatedTimeUntilUpdate);
@@ -16585,6 +16596,7 @@
16585
16596
  } else {
16586
16597
  var delay = getRetryDelay(retryConfig, retryCount);
16587
16598
  // Schedule level/track reload
16599
+ this.clearTimer();
16588
16600
  this.timer = self.setTimeout(function () {
16589
16601
  return _this3.loadPlaylist();
16590
16602
  }, delay);
@@ -16880,17 +16892,6 @@
16880
16892
  })
16881
16893
  };
16882
16894
  this.hls.trigger(Events.MANIFEST_PARSED, edata);
16883
-
16884
- // Initiate loading after all controllers have received MANIFEST_PARSED
16885
- var _this$hls = this.hls,
16886
- _this$hls$config = _this$hls.config,
16887
- autoStartLoad = _this$hls$config.autoStartLoad,
16888
- startPosition = _this$hls$config.startPosition,
16889
- forceStartLoad = _this$hls.forceStartLoad;
16890
- if (autoStartLoad || forceStartLoad) {
16891
- this.log((autoStartLoad ? 'auto' : 'force') + " startLoad with configured startPosition " + startPosition);
16892
- this.hls.startLoad(startPosition);
16893
- }
16894
16895
  };
16895
16896
  _proto.onError = function onError(event, data) {
16896
16897
  if (data.fatal || !data.context) {
@@ -16933,8 +16934,8 @@
16933
16934
  return;
16934
16935
  }
16935
16936
 
16936
- // only process level loaded events matching with expected level
16937
- if (curLevel === this.currentLevel) {
16937
+ // only process level loaded events matching with expected level or prior to switch when media playlist is loaded directly
16938
+ if (curLevel === this.currentLevel || data.withoutMultiVariant) {
16938
16939
  // reset level load error counter on successful level loaded only if there is no issues with fragments
16939
16940
  if (curLevel.fragmentError === 0) {
16940
16941
  curLevel.loadError = 0;
@@ -16977,6 +16978,9 @@
16977
16978
  _proto.removeLevel = function removeLevel(levelIndex) {
16978
16979
  var _this4 = this,
16979
16980
  _this$currentLevel;
16981
+ if (this._levels.length === 1) {
16982
+ return;
16983
+ }
16980
16984
  var levels = this._levels.filter(function (level, index) {
16981
16985
  if (index !== levelIndex) {
16982
16986
  return true;
@@ -17000,6 +17004,14 @@
17000
17004
  if (this.currentLevelIndex > -1 && (_this$currentLevel = this.currentLevel) != null && _this$currentLevel.details) {
17001
17005
  this.currentLevelIndex = this.currentLevel.details.fragments[0].level;
17002
17006
  }
17007
+ if (this.manualLevelIndex > -1) {
17008
+ this.manualLevelIndex = this.currentLevelIndex;
17009
+ }
17010
+ var maxLevel = levels.length - 1;
17011
+ this._firstLevel = Math.min(this._firstLevel, maxLevel);
17012
+ if (this._startLevel) {
17013
+ this._startLevel = Math.min(this._startLevel, maxLevel);
17014
+ }
17003
17015
  this.hls.trigger(Events.LEVELS_UPDATED, {
17004
17016
  levels: levels
17005
17017
  });
@@ -17009,10 +17021,10 @@
17009
17021
  this._levels = levels;
17010
17022
  };
17011
17023
  _proto.checkMaxAutoUpdated = function checkMaxAutoUpdated() {
17012
- var _this$hls2 = this.hls,
17013
- autoLevelCapping = _this$hls2.autoLevelCapping,
17014
- maxAutoLevel = _this$hls2.maxAutoLevel,
17015
- maxHdcpLevel = _this$hls2.maxHdcpLevel;
17024
+ var _this$hls = this.hls,
17025
+ autoLevelCapping = _this$hls.autoLevelCapping,
17026
+ maxAutoLevel = _this$hls.maxAutoLevel,
17027
+ maxHdcpLevel = _this$hls.maxHdcpLevel;
17016
17028
  if (this._maxAutoLevel !== maxAutoLevel) {
17017
17029
  this._maxAutoLevel = maxAutoLevel;
17018
17030
  this.hls.trigger(Events.MAX_AUTO_LEVEL_UPDATED, {
@@ -19744,7 +19756,7 @@
19744
19756
  return !remuxResult.audio && !remuxResult.video && !remuxResult.text && !remuxResult.id3 && !remuxResult.initSegment;
19745
19757
  }
19746
19758
 
19747
- var version = "1.6.0-beta.1.0.canary.10801";
19759
+ var version = "1.6.0-beta.1.0.canary.10804";
19748
19760
 
19749
19761
  // ensure the worker ends up in the bundle
19750
19762
  // If the worker should not be included this gets aliased to empty.js
@@ -20935,6 +20947,9 @@
20935
20947
  _proto.onLevelsUpdated = function onLevelsUpdated(event, data) {
20936
20948
  if (this.level > -1 && this.fragCurrent) {
20937
20949
  this.level = this.fragCurrent.level;
20950
+ if (this.level === -1) {
20951
+ this.resetWhenMissingContext(this.fragCurrent);
20952
+ }
20938
20953
  }
20939
20954
  this.levels = data.levels;
20940
20955
  };
@@ -21835,7 +21850,7 @@
21835
21850
  if (loaderContext && loaderContext.levelOrTrack === context.levelOrTrack && (loaderContext.url === context.url || loaderContext.deliveryDirectives && !context.deliveryDirectives)) {
21836
21851
  // same URL can't overlap, or wait for blocking request
21837
21852
  if (loaderContext.url === context.url) {
21838
- logger.log("[playlist-loader]: playlist request ongoing");
21853
+ logger.log("[playlist-loader]: ignore " + context.url + " ongoing request");
21839
21854
  } else {
21840
21855
  logger.log("[playlist-loader]: ignore " + context.url + " in favor of " + loaderContext.url);
21841
21856
  }
@@ -21901,7 +21916,7 @@
21901
21916
  return;
21902
21917
  }
21903
21918
  stats.parsing.start = performance.now();
21904
- if (M3U8Parser.isMediaPlaylist(string)) {
21919
+ if (M3U8Parser.isMediaPlaylist(string) || context.type !== PlaylistContextType.MANIFEST) {
21905
21920
  _this.handleTrackOrLevelPlaylist(response, stats, context, networkDetails || null, loader);
21906
21921
  } else {
21907
21922
  _this.handleMasterPlaylist(response, stats, context, networkDetails);
@@ -21919,6 +21934,20 @@
21919
21934
 
21920
21935
  loader.load(context, loaderConfig, loaderCallbacks);
21921
21936
  };
21937
+ _proto.checkAutostartLoad = function checkAutostartLoad() {
21938
+ if (!this.hls) {
21939
+ return;
21940
+ }
21941
+ var _this$hls = this.hls,
21942
+ _this$hls$config = _this$hls.config,
21943
+ autoStartLoad = _this$hls$config.autoStartLoad,
21944
+ startPosition = _this$hls$config.startPosition,
21945
+ forceStartLoad = _this$hls.forceStartLoad;
21946
+ if (autoStartLoad || forceStartLoad) {
21947
+ this.hls.logger.log((autoStartLoad ? 'auto' : 'force') + " startLoad with configured startPosition " + startPosition);
21948
+ this.hls.startLoad(startPosition);
21949
+ }
21950
+ };
21922
21951
  _proto.handleMasterPlaylist = function handleMasterPlaylist(response, stats, context, networkDetails) {
21923
21952
  var hls = this.hls;
21924
21953
  var string = response.data;
@@ -21980,6 +22009,7 @@
21980
22009
  startTimeOffset: startTimeOffset,
21981
22010
  variableList: variableList
21982
22011
  });
22012
+ this.checkAutostartLoad();
21983
22013
  };
21984
22014
  _proto.handleTrackOrLevelPlaylist = function handleTrackOrLevelPlaylist(response, stats, context, networkDetails, loader) {
21985
22015
  var hls = this.hls;
@@ -22023,6 +22053,9 @@
22023
22053
  // extend the context with the new levelDetails property
22024
22054
  context.levelDetails = levelDetails;
22025
22055
  this.handlePlaylistLoaded(levelDetails, response, stats, context, networkDetails, loader);
22056
+ if (type === PlaylistContextType.MANIFEST && (!levelDetails.playlistParsingError || !levelDetails.fragments.length && levelDetails.live)) {
22057
+ this.checkAutostartLoad();
22058
+ }
22026
22059
  };
22027
22060
  _proto.handleManifestParsingError = function handleManifestParsingError(response, context, error, networkDetails, stats) {
22028
22061
  this.hls.trigger(Events.ERROR, {
@@ -22106,7 +22139,7 @@
22106
22139
  var parent = mapContextToLevelType(context);
22107
22140
  var levelIndex = typeof context.level === 'number' && parent === PlaylistLevelType.MAIN ? level : undefined;
22108
22141
  if (!levelDetails.fragments.length) {
22109
- var _error = new Error('No Segments found in Playlist');
22142
+ var _error = levelDetails.playlistParsingError = new Error('No Segments found in Playlist');
22110
22143
  hls.trigger(Events.ERROR, {
22111
22144
  type: ErrorTypes.NETWORK_ERROR,
22112
22145
  details: ErrorDetails.LEVEL_EMPTY_ERROR,
@@ -22162,7 +22195,8 @@
22162
22195
  id: id || 0,
22163
22196
  stats: stats,
22164
22197
  networkDetails: networkDetails,
22165
- deliveryDirectives: deliveryDirectives
22198
+ deliveryDirectives: deliveryDirectives,
22199
+ withoutMultiVariant: type === PlaylistContextType.MANIFEST
22166
22200
  });
22167
22201
  break;
22168
22202
  case PlaylistContextType.AUDIO_TRACK:
@@ -22337,8 +22371,9 @@
22337
22371
  this.cmcdController = void 0;
22338
22372
  this._media = null;
22339
22373
  this._url = null;
22340
- this.triggeringException = void 0;
22341
22374
  this._sessionId = void 0;
22375
+ this.triggeringException = void 0;
22376
+ this.started = false;
22342
22377
  var logger = this.logger = enableLogs(userConfig.debug || false, 'Hls instance', userConfig.assetPlayerId);
22343
22378
  var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
22344
22379
  this.userConfig = userConfig;
@@ -22611,10 +22646,14 @@
22611
22646
  startPosition = -1;
22612
22647
  }
22613
22648
  this.logger.log("startLoad(" + (startPosition + (skipSeekToStartPosition ? ', <skip seek to start>' : '')) + ")");
22649
+ this.started = true;
22614
22650
  this.resumeBuffering();
22615
- this.networkControllers.forEach(function (controller) {
22616
- controller.startLoad(startPosition, skipSeekToStartPosition);
22617
- });
22651
+ for (var i = 0; i < this.networkControllers.length; i++) {
22652
+ this.networkControllers[i].startLoad(startPosition, skipSeekToStartPosition);
22653
+ if (!this.started || !this.networkControllers) {
22654
+ break;
22655
+ }
22656
+ }
22618
22657
  }
22619
22658
 
22620
22659
  /**
@@ -22622,13 +22661,17 @@
22622
22661
  */;
22623
22662
  _proto.stopLoad = function stopLoad() {
22624
22663
  this.logger.log('stopLoad');
22625
- this.networkControllers.forEach(function (controller) {
22626
- controller.stopLoad();
22627
- });
22664
+ this.started = false;
22665
+ for (var i = 0; i < this.networkControllers.length; i++) {
22666
+ this.networkControllers[i].stopLoad();
22667
+ if (this.started || !this.networkControllers) {
22668
+ break;
22669
+ }
22670
+ }
22628
22671
  }
22629
22672
 
22630
22673
  /**
22631
- * Returns state of fragment loading toggled by calling `pauseBuffering()` and `resumeBuffering()`.
22674
+ * Returns whether loading, toggled with `startLoad()` and `stopLoad()`, is active or not`.
22632
22675
  */;
22633
22676
  /**
22634
22677
  * Resumes stream controller segment loading after `pauseBuffering` has been called.
@@ -22745,6 +22788,15 @@
22745
22788
  get: function get() {
22746
22789
  return this.streamController.startPositionValue;
22747
22790
  }
22791
+ }, {
22792
+ key: "loadingEnabled",
22793
+ get: function get() {
22794
+ return this.started;
22795
+ }
22796
+
22797
+ /**
22798
+ * Returns state of fragment loading toggled by calling `pauseBuffering()` and `resumeBuffering()`.
22799
+ */
22748
22800
  }, {
22749
22801
  key: "bufferingEnabled",
22750
22802
  get: function get() {