hls.js 1.5.5-0.canary.9984 → 1.5.5-0.canary.9986

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.js CHANGED
@@ -644,7 +644,7 @@
644
644
  // Some browsers don't allow to use bind on console object anyway
645
645
  // fallback to default if needed
646
646
  try {
647
- newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.5-0.canary.9984");
647
+ newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.5-0.canary.9986");
648
648
  } catch (e) {
649
649
  /* log fn threw an exception. All logger methods are no-ops. */
650
650
  return createLogger();
@@ -6502,7 +6502,12 @@
6502
6502
  var cdnAge = lastAdvanced + details.ageHeader;
6503
6503
  var currentGoal = Math.min(cdnAge - details.partTarget, details.targetduration * 1.5);
6504
6504
  if (currentGoal > 0) {
6505
- if (previousDetails && currentGoal > previousDetails.tuneInGoal) {
6505
+ if (cdnAge > details.targetduration * 3) {
6506
+ // Omit segment and part directives when the last response was more than 3 target durations ago,
6507
+ this.log("Playlist last advanced " + lastAdvanced.toFixed(2) + "s ago. Omitting segment and part directives.");
6508
+ msn = undefined;
6509
+ part = undefined;
6510
+ } else if (previousDetails != null && previousDetails.tuneInGoal && cdnAge - details.partTarget > previousDetails.tuneInGoal) {
6506
6511
  // If we attempted to get the next or latest playlist update, but currentGoal increased,
6507
6512
  // then we either can't catchup, or the "age" header cannot be trusted.
6508
6513
  this.warn("CDN Tune-in goal increased from: " + previousDetails.tuneInGoal + " to: " + currentGoal + " with playlist age: " + details.age);
@@ -9549,6 +9554,7 @@
9549
9554
  _this.decrypter = void 0;
9550
9555
  _this.initPTS = [];
9551
9556
  _this.buffering = true;
9557
+ _this.loadingParts = false;
9552
9558
  _this.onMediaSeeking = function () {
9553
9559
  var _assertThisInitialize = _assertThisInitialized(_this),
9554
9560
  config = _assertThisInitialize.config,
@@ -9584,6 +9590,14 @@
9584
9590
  // Remove gap fragments
9585
9591
  _this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, _this.playlistType, true);
9586
9592
  _this.lastCurrentTime = currentTime;
9593
+ if (!_this.loadingParts) {
9594
+ var bufferEnd = Math.max(bufferInfo.end, currentTime);
9595
+ var shouldLoadParts = _this.shouldLoadParts(_this.getLevelDetails(), bufferEnd);
9596
+ if (shouldLoadParts) {
9597
+ _this.log("LL-Part loading ON after seeking to " + currentTime.toFixed(2) + " with buffer @" + bufferEnd.toFixed(2));
9598
+ _this.loadingParts = shouldLoadParts;
9599
+ }
9600
+ }
9587
9601
  }
9588
9602
 
9589
9603
  // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
@@ -9993,8 +10007,16 @@
9993
10007
  } else if (!frag.encrypted && details.encryptedFragments.length) {
9994
10008
  this.keyLoader.loadClear(frag, details.encryptedFragments);
9995
10009
  }
10010
+ var fragPrevious = this.fragPrevious;
10011
+ if (frag.sn !== 'initSegment' && (!fragPrevious || frag.sn !== fragPrevious.sn)) {
10012
+ var shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
10013
+ if (shouldLoadParts !== this.loadingParts) {
10014
+ this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " loading sn " + (fragPrevious == null ? void 0 : fragPrevious.sn) + "->" + frag.sn);
10015
+ this.loadingParts = shouldLoadParts;
10016
+ }
10017
+ }
9996
10018
  targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
9997
- if (this.config.lowLatencyMode && frag.sn !== 'initSegment') {
10019
+ if (this.loadingParts && frag.sn !== 'initSegment') {
9998
10020
  var partList = details.partList;
9999
10021
  if (partList && progressCallback) {
10000
10022
  if (targetBufferTime > frag.end && details.fragmentHint) {
@@ -10036,6 +10058,13 @@
10036
10058
  }
10037
10059
  }
10038
10060
  }
10061
+ if (frag.sn !== 'initSegment' && this.loadingParts) {
10062
+ this.log("LL-Part loading OFF after next part miss @" + targetBufferTime.toFixed(2));
10063
+ this.loadingParts = false;
10064
+ } else if (!frag.url) {
10065
+ // Selected fragment hint for part but not loading parts
10066
+ return Promise.resolve(null);
10067
+ }
10039
10068
  this.log("Loading fragment " + frag.sn + " cc: " + frag.cc + " " + (details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : '') + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
10040
10069
  // Don't update nextLoadPosition for fragments which are not buffered
10041
10070
  if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
@@ -10138,8 +10167,36 @@
10138
10167
  if (part) {
10139
10168
  part.stats.parsing.end = now;
10140
10169
  }
10170
+ // See if part loading should be disabled/enabled based on buffer and playback position.
10171
+ if (frag.sn !== 'initSegment') {
10172
+ var levelDetails = this.getLevelDetails();
10173
+ var loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
10174
+ var shouldLoadParts = loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
10175
+ if (shouldLoadParts !== this.loadingParts) {
10176
+ this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " after parsing segment ending @" + frag.end.toFixed(2));
10177
+ this.loadingParts = shouldLoadParts;
10178
+ }
10179
+ }
10141
10180
  this.updateLevelTiming(frag, part, level, chunkMeta.partial);
10142
10181
  };
10182
+ _proto.shouldLoadParts = function shouldLoadParts(details, bufferEnd) {
10183
+ if (this.config.lowLatencyMode) {
10184
+ if (!details) {
10185
+ return this.loadingParts;
10186
+ }
10187
+ if (details != null && details.partList) {
10188
+ var _details$fragmentHint;
10189
+ // Buffer must be ahead of first part + duration of parts after last segment
10190
+ // and playback must be at or past segment adjacent to part list
10191
+ var firstPart = details.partList[0];
10192
+ var safePartStart = firstPart.end + (((_details$fragmentHint = details.fragmentHint) == null ? void 0 : _details$fragmentHint.duration) || 0);
10193
+ if (bufferEnd >= safePartStart && this.lastCurrentTime > firstPart.start - firstPart.fragment.duration) {
10194
+ return true;
10195
+ }
10196
+ }
10197
+ }
10198
+ return false;
10199
+ };
10143
10200
  _proto.getCurrentContext = function getCurrentContext(chunkMeta) {
10144
10201
  var levels = this.levels,
10145
10202
  fragCurrent = this.fragCurrent;
@@ -10274,7 +10331,8 @@
10274
10331
  // find fragment index, contiguous with end of buffer position
10275
10332
  var config = this.config;
10276
10333
  var start = fragments[0].start;
10277
- var frag;
10334
+ var canLoadParts = config.lowLatencyMode && !!levelDetails.partList;
10335
+ var frag = null;
10278
10336
  if (levelDetails.live) {
10279
10337
  var initialLiveManifestSize = config.initialLiveManifestSize;
10280
10338
  if (fragLen < initialLiveManifestSize) {
@@ -10286,6 +10344,10 @@
10286
10344
  // Do not load using live logic if the starting frag is requested - we want to use getFragmentAtPosition() so that
10287
10345
  // we get the fragment matching that start time
10288
10346
  if (!levelDetails.PTSKnown && !this.startFragRequested && this.startPosition === -1 || pos < start) {
10347
+ if (canLoadParts && !this.loadingParts) {
10348
+ this.log("LL-Part loading ON for initial live fragment");
10349
+ this.loadingParts = true;
10350
+ }
10289
10351
  frag = this.getInitialLiveFragment(levelDetails, fragments);
10290
10352
  this.startPosition = this.nextLoadPosition = frag ? this.hls.liveSyncPosition || frag.start : pos;
10291
10353
  }
@@ -10296,7 +10358,7 @@
10296
10358
 
10297
10359
  // If we haven't run into any special cases already, just load the fragment most closely matching the requested position
10298
10360
  if (!frag) {
10299
- var end = config.lowLatencyMode ? levelDetails.partEnd : levelDetails.fragmentEnd;
10361
+ var end = this.loadingParts ? levelDetails.partEnd : levelDetails.fragmentEnd;
10300
10362
  frag = this.getFragmentAtPosition(pos, end, levelDetails);
10301
10363
  }
10302
10364
  return this.mapToInitFragWhenRequired(frag);
@@ -10410,7 +10472,7 @@
10410
10472
  var fragmentHint = levelDetails.fragmentHint;
10411
10473
  var tolerance = config.maxFragLookUpTolerance;
10412
10474
  var partList = levelDetails.partList;
10413
- var loadingParts = !!(config.lowLatencyMode && partList != null && partList.length && fragmentHint);
10475
+ var loadingParts = !!(this.loadingParts && partList != null && partList.length && fragmentHint);
10414
10476
  if (loadingParts && fragmentHint && !this.bitrateTest) {
10415
10477
  // Include incomplete fragment with parts at end
10416
10478
  fragments = fragments.concat(fragmentHint);
@@ -27203,7 +27265,12 @@
27203
27265
  if (curLevel.fragmentError === 0) {
27204
27266
  curLevel.loadError = 0;
27205
27267
  }
27206
- this.playlistLoaded(level, data, curLevel.details);
27268
+ // Ignore matching details populated by loading a Media Playlist directly
27269
+ var previousDetails = curLevel.details;
27270
+ if (previousDetails === data.details && previousDetails.advanced) {
27271
+ previousDetails = undefined;
27272
+ }
27273
+ this.playlistLoaded(level, data, previousDetails);
27207
27274
  } else if ((_data$deliveryDirecti2 = data.deliveryDirectives) != null && _data$deliveryDirecti2.skip) {
27208
27275
  // received a delta playlist update that cannot be merged
27209
27276
  details.deltaUpdateFailed = true;
@@ -30024,7 +30091,7 @@
30024
30091
  * Get the video-dev/hls.js package version.
30025
30092
  */
30026
30093
  function get() {
30027
- return "1.5.5-0.canary.9984";
30094
+ return "1.5.5-0.canary.9986";
30028
30095
  }
30029
30096
  }, {
30030
30097
  key: "Events",
package/dist/hls.js.d.ts CHANGED
@@ -247,6 +247,7 @@ export declare class BaseStreamController extends TaskLoop implements NetworkCom
247
247
  protected decrypter: Decrypter;
248
248
  protected initPTS: RationalTimestamp[];
249
249
  protected buffering: boolean;
250
+ private loadingParts;
250
251
  constructor(hls: Hls, fragmentTracker: FragmentTracker, keyLoader: KeyLoader, logPrefix: string, playlistType: PlaylistLevelType);
251
252
  protected registerListeners(): void;
252
253
  protected unregisterListeners(): void;
@@ -283,6 +284,7 @@ export declare class BaseStreamController extends TaskLoop implements NetworkCom
283
284
  private doFragPartsLoad;
284
285
  private handleFragLoadError;
285
286
  protected _handleTransmuxerFlush(chunkMeta: ChunkMetadata): void;
287
+ private shouldLoadParts;
286
288
  protected getCurrentContext(chunkMeta: ChunkMetadata): {
287
289
  frag: Fragment;
288
290
  part: Part | null;