hls.js 1.5.12-0.canary.10366 → 1.5.12-0.canary.10367

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
@@ -522,7 +522,7 @@
522
522
  // Some browsers don't allow to use bind on console object anyway
523
523
  // fallback to default if needed
524
524
  try {
525
- newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.12-0.canary.10366");
525
+ newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.12-0.canary.10367");
526
526
  } catch (e) {
527
527
  /* log fn threw an exception. All logger methods are no-ops. */
528
528
  return createLogger();
@@ -4157,10 +4157,9 @@
4157
4157
  level = context.level,
4158
4158
  type = context.type;
4159
4159
  var url = getResponseUrl(response, context);
4160
- var levelUrlId = 0;
4161
4160
  var levelId = isFiniteNumber(level) ? level : isFiniteNumber(id) ? id : 0;
4162
4161
  var levelType = mapContextToLevelType(context);
4163
- var levelDetails = M3U8Parser.parseLevelPlaylist(response.data, url, levelId, levelType, levelUrlId, this.variableList);
4162
+ var levelDetails = M3U8Parser.parseLevelPlaylist(response.data, url, levelId, levelType, 0, this.variableList);
4164
4163
 
4165
4164
  // We have done our first request (Manifest-type) and receive
4166
4165
  // not a master playlist but a chunk-list (track/level)
@@ -6092,8 +6091,7 @@
6092
6091
  }
6093
6092
  return Math.round(reloadInterval);
6094
6093
  }
6095
- function getFragmentWithSN(level, sn, fragCurrent) {
6096
- var details = level == null ? void 0 : level.details;
6094
+ function getFragmentWithSN(details, sn, fragCurrent) {
6097
6095
  if (!details) {
6098
6096
  return null;
6099
6097
  }
@@ -6110,12 +6108,11 @@
6110
6108
  }
6111
6109
  return null;
6112
6110
  }
6113
- function getPartWith(level, sn, partIndex) {
6114
- var _level$details;
6115
- if (!(level != null && level.details)) {
6111
+ function getPartWith(details, sn, partIndex) {
6112
+ if (!details) {
6116
6113
  return null;
6117
6114
  }
6118
- return findPart((_level$details = level.details) == null ? void 0 : _level$details.partList, sn, partIndex);
6115
+ return findPart(details.partList, sn, partIndex);
6119
6116
  }
6120
6117
  function findPart(partList, sn, partIndex) {
6121
6118
  if (partList) {
@@ -6266,12 +6263,15 @@
6266
6263
  }
6267
6264
  var fragNext = null;
6268
6265
  if (fragPrevious) {
6269
- fragNext = fragments[fragPrevious.sn - fragments[0].sn + 1] || null;
6266
+ fragNext = fragments[1 + fragPrevious.sn - fragments[0].sn] || null;
6270
6267
  // check for buffer-end rounding error
6271
6268
  var bufferEdgeError = fragPrevious.endDTS - bufferEnd;
6272
6269
  if (bufferEdgeError > 0 && bufferEdgeError < 0.0000015) {
6273
6270
  bufferEnd += 0.0000015;
6274
6271
  }
6272
+ if (fragNext && fragPrevious.level !== fragNext.level && fragNext.end <= fragPrevious.end) {
6273
+ fragNext = fragments[2 + fragPrevious.sn - fragments[0].sn] || null;
6274
+ }
6275
6275
  } else if (bufferEnd === 0 && fragments[0].start === 0) {
6276
6276
  fragNext = fragments[0];
6277
6277
  }
@@ -6368,6 +6368,24 @@
6368
6368
  }
6369
6369
  });
6370
6370
  }
6371
+ function findNearestWithCC(details, cc, fragment) {
6372
+ if (details) {
6373
+ if (details.startCC <= cc && details.endCC >= cc) {
6374
+ var start = fragment.start;
6375
+ var end = fragment.end;
6376
+ return BinarySearch.search(details.fragments, function (candidate) {
6377
+ if (candidate.cc < cc || candidate.end <= start) {
6378
+ return 1;
6379
+ } else if (candidate.cc > cc || candidate.start >= end) {
6380
+ return -1;
6381
+ } else {
6382
+ return 0;
6383
+ }
6384
+ });
6385
+ }
6386
+ }
6387
+ return null;
6388
+ }
6371
6389
 
6372
6390
  var NetworkErrorAction = {
6373
6391
  DoNothing: 0,
@@ -6433,7 +6451,7 @@
6433
6451
  this.playlistError = 0;
6434
6452
  };
6435
6453
  _proto.onError = function onError(event, data) {
6436
- var _data$frag, _data$level;
6454
+ var _data$frag;
6437
6455
  if (data.fatal) {
6438
6456
  return;
6439
6457
  }
@@ -6449,10 +6467,7 @@
6449
6467
  case ErrorDetails.FRAG_PARSING_ERROR:
6450
6468
  // ignore empty segment errors marked as gap
6451
6469
  if ((_data$frag = data.frag) != null && _data$frag.gap) {
6452
- data.errorAction = {
6453
- action: NetworkErrorAction.DoNothing,
6454
- flags: ErrorActionFlags.None
6455
- };
6470
+ data.errorAction = createDoNothingErrorAction();
6456
6471
  return;
6457
6472
  }
6458
6473
  // falls through
@@ -6519,7 +6534,11 @@
6519
6534
  case ErrorDetails.BUFFER_ADD_CODEC_ERROR:
6520
6535
  case ErrorDetails.REMUX_ALLOC_ERROR:
6521
6536
  case ErrorDetails.BUFFER_APPEND_ERROR:
6522
- data.errorAction = this.getLevelSwitchAction(data, (_data$level = data.level) != null ? _data$level : hls.loadLevel);
6537
+ // Buffer-controller can set errorAction when append errors can be ignored or resolved locally
6538
+ if (!data.errorAction) {
6539
+ var _data$level;
6540
+ data.errorAction = this.getLevelSwitchAction(data, (_data$level = data.level) != null ? _data$level : hls.loadLevel);
6541
+ }
6523
6542
  return;
6524
6543
  case ErrorDetails.INTERNAL_EXCEPTION:
6525
6544
  case ErrorDetails.BUFFER_APPENDING_ERROR:
@@ -6528,10 +6547,7 @@
6528
6547
  case ErrorDetails.BUFFER_STALLED_ERROR:
6529
6548
  case ErrorDetails.BUFFER_SEEK_OVER_HOLE:
6530
6549
  case ErrorDetails.BUFFER_NUDGE_ON_STALL:
6531
- data.errorAction = {
6532
- action: NetworkErrorAction.DoNothing,
6533
- flags: ErrorActionFlags.None
6534
- };
6550
+ data.errorAction = createDoNothingErrorAction();
6535
6551
  return;
6536
6552
  }
6537
6553
  if (data.type === ErrorTypes.KEY_SYSTEM_ERROR) {
@@ -6750,6 +6766,13 @@
6750
6766
  };
6751
6767
  return ErrorController;
6752
6768
  }(Logger);
6769
+ function createDoNothingErrorAction(resolved) {
6770
+ var errorAction = {
6771
+ action: NetworkErrorAction.DoNothing,
6772
+ flags: ErrorActionFlags.None
6773
+ };
6774
+ return errorAction;
6775
+ }
6753
6776
 
6754
6777
  var BasePlaylistController = /*#__PURE__*/function (_Logger) {
6755
6778
  function BasePlaylistController(hls, logPrefix) {
@@ -7360,6 +7383,7 @@
7360
7383
  if (!hasCurrentVideoRange) {
7361
7384
  currentVideoRange = undefined;
7362
7385
  }
7386
+ var hasMultipleSets = codecSets.length > 1;
7363
7387
  var codecSet = codecSets.reduce(function (selected, candidate) {
7364
7388
  // Remove candiates which do not meet bitrate, default audio, stereo or channels preference, 1080p or lower, 30fps or lower, or SDR/HDR selection if present
7365
7389
  var candidateTier = codecTiers[candidate];
@@ -7369,48 +7393,50 @@
7369
7393
  videoRanges = hasCurrentVideoRange ? allowedVideoRanges.filter(function (range) {
7370
7394
  return candidateTier.videoRanges[range] > 0;
7371
7395
  }) : [];
7372
- if (candidateTier.minBitrate > currentBw) {
7373
- logStartCodecCandidateIgnored(candidate, "min bitrate of " + candidateTier.minBitrate + " > current estimate of " + currentBw);
7374
- return selected;
7375
- }
7376
- if (!candidateTier.hasDefaultAudio) {
7377
- logStartCodecCandidateIgnored(candidate, "no renditions with default or auto-select sound found");
7378
- return selected;
7379
- }
7380
- if (audioCodecPreference && candidate.indexOf(audioCodecPreference.substring(0, 4)) % 5 !== 0) {
7381
- logStartCodecCandidateIgnored(candidate, "audio codec preference \"" + audioCodecPreference + "\" not found");
7382
- return selected;
7383
- }
7384
- if (channelsPreference && !preferStereo) {
7385
- if (!candidateTier.channels[channelsPreference]) {
7386
- logStartCodecCandidateIgnored(candidate, "no renditions with " + channelsPreference + " channel sound found (channels options: " + Object.keys(candidateTier.channels) + ")");
7396
+ if (hasMultipleSets) {
7397
+ if (candidateTier.minBitrate > currentBw) {
7398
+ logStartCodecCandidateIgnored(candidate, "min bitrate of " + candidateTier.minBitrate + " > current estimate of " + currentBw);
7399
+ return selected;
7400
+ }
7401
+ if (!candidateTier.hasDefaultAudio) {
7402
+ logStartCodecCandidateIgnored(candidate, "no renditions with default or auto-select sound found");
7403
+ return selected;
7404
+ }
7405
+ if (audioCodecPreference && candidate.indexOf(audioCodecPreference.substring(0, 4)) % 5 !== 0) {
7406
+ logStartCodecCandidateIgnored(candidate, "audio codec preference \"" + audioCodecPreference + "\" not found");
7407
+ return selected;
7408
+ }
7409
+ if (channelsPreference && !preferStereo) {
7410
+ if (!candidateTier.channels[channelsPreference]) {
7411
+ logStartCodecCandidateIgnored(candidate, "no renditions with " + channelsPreference + " channel sound found (channels options: " + Object.keys(candidateTier.channels) + ")");
7412
+ return selected;
7413
+ }
7414
+ } else if ((!audioCodecPreference || preferStereo) && hasStereo && candidateTier.channels['2'] === 0) {
7415
+ logStartCodecCandidateIgnored(candidate, "no renditions with stereo sound found");
7416
+ return selected;
7417
+ }
7418
+ if (candidateTier.minHeight > maxHeight) {
7419
+ logStartCodecCandidateIgnored(candidate, "min resolution of " + candidateTier.minHeight + " > maximum of " + maxHeight);
7420
+ return selected;
7421
+ }
7422
+ if (candidateTier.minFramerate > maxFramerate) {
7423
+ logStartCodecCandidateIgnored(candidate, "min framerate of " + candidateTier.minFramerate + " > maximum of " + maxFramerate);
7424
+ return selected;
7425
+ }
7426
+ if (!videoRanges.some(function (range) {
7427
+ return candidateTier.videoRanges[range] > 0;
7428
+ })) {
7429
+ logStartCodecCandidateIgnored(candidate, "no variants with VIDEO-RANGE of " + JSON.stringify(videoRanges) + " found");
7430
+ return selected;
7431
+ }
7432
+ if (videoCodecPreference && candidate.indexOf(videoCodecPreference.substring(0, 4)) % 5 !== 0) {
7433
+ logStartCodecCandidateIgnored(candidate, "video codec preference \"" + videoCodecPreference + "\" not found");
7434
+ return selected;
7435
+ }
7436
+ if (candidateTier.maxScore < selectedScore) {
7437
+ logStartCodecCandidateIgnored(candidate, "max score of " + candidateTier.maxScore + " < selected max of " + selectedScore);
7387
7438
  return selected;
7388
7439
  }
7389
- } else if ((!audioCodecPreference || preferStereo) && hasStereo && candidateTier.channels['2'] === 0) {
7390
- logStartCodecCandidateIgnored(candidate, "no renditions with stereo sound found");
7391
- return selected;
7392
- }
7393
- if (candidateTier.minHeight > maxHeight) {
7394
- logStartCodecCandidateIgnored(candidate, "min resolution of " + candidateTier.minHeight + " > maximum of " + maxHeight);
7395
- return selected;
7396
- }
7397
- if (candidateTier.minFramerate > maxFramerate) {
7398
- logStartCodecCandidateIgnored(candidate, "min framerate of " + candidateTier.minFramerate + " > maximum of " + maxFramerate);
7399
- return selected;
7400
- }
7401
- if (!videoRanges.some(function (range) {
7402
- return candidateTier.videoRanges[range] > 0;
7403
- })) {
7404
- logStartCodecCandidateIgnored(candidate, "no variants with VIDEO-RANGE of " + JSON.stringify(videoRanges) + " found");
7405
- return selected;
7406
- }
7407
- if (videoCodecPreference && candidate.indexOf(videoCodecPreference.substring(0, 4)) % 5 !== 0) {
7408
- logStartCodecCandidateIgnored(candidate, "video codec preference \"" + videoCodecPreference + "\" not found");
7409
- return selected;
7410
- }
7411
- if (candidateTier.maxScore < selectedScore) {
7412
- logStartCodecCandidateIgnored(candidate, "max score of " + candidateTier.maxScore + " < selected max of " + selectedScore);
7413
- return selected;
7414
7440
  }
7415
7441
  // Remove candiates with less preferred codecs or more errors
7416
7442
  if (selected && (codecsSetSelectionPreferenceValue(candidate) >= codecsSetSelectionPreferenceValue(selected) || candidateTier.fragmentError > codecTiers[selected].fragmentError)) {
@@ -8145,7 +8171,7 @@
8145
8171
  if (levelsSkipped.length) {
8146
8172
  _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);
8147
8173
  }
8148
- _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:" + level.codecSet + " videoRange:" + level.videoRange + " hls.loadLevel:" + loadLevel);
8174
+ _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);
8149
8175
  }
8150
8176
  if (firstSelection) {
8151
8177
  _this3.firstSelection = i;
@@ -8381,12 +8407,14 @@
8381
8407
  var _proto = FragmentTracker.prototype;
8382
8408
  _proto._registerListeners = function _registerListeners() {
8383
8409
  var hls = this.hls;
8410
+ hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
8384
8411
  hls.on(Events.BUFFER_APPENDED, this.onBufferAppended, this);
8385
8412
  hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
8386
8413
  hls.on(Events.FRAG_LOADED, this.onFragLoaded, this);
8387
8414
  };
8388
8415
  _proto._unregisterListeners = function _unregisterListeners() {
8389
8416
  var hls = this.hls;
8417
+ hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
8390
8418
  hls.off(Events.BUFFER_APPENDED, this.onBufferAppended, this);
8391
8419
  hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
8392
8420
  hls.off(Events.FRAG_LOADED, this.onFragLoaded, this);
@@ -8450,7 +8478,7 @@
8450
8478
  * The browser will unload parts of the buffer to free up memory for new buffer data
8451
8479
  * Fragments will need to be reloaded when the buffer is freed up, removing partial fragments will allow them to reload(since there might be parts that are still playable)
8452
8480
  */;
8453
- _proto.detectEvictedFragments = function detectEvictedFragments(elementaryStream, timeRange, playlistType, appendedPart) {
8481
+ _proto.detectEvictedFragments = function detectEvictedFragments(elementaryStream, timeRange, playlistType, appendedPart, removeAppending) {
8454
8482
  var _this = this;
8455
8483
  if (this.timeRanges) {
8456
8484
  this.timeRanges[elementaryStream] = timeRange;
@@ -8466,7 +8494,7 @@
8466
8494
  if (appendedPartSn >= fragmentEntity.body.sn) {
8467
8495
  return;
8468
8496
  }
8469
- if (!fragmentEntity.buffered && !fragmentEntity.loaded) {
8497
+ if (!fragmentEntity.buffered && (!fragmentEntity.loaded || removeAppending)) {
8470
8498
  if (fragmentEntity.body.type === playlistType) {
8471
8499
  _this.removeFragment(fragmentEntity.body);
8472
8500
  }
@@ -8476,6 +8504,10 @@
8476
8504
  if (!esData) {
8477
8505
  return;
8478
8506
  }
8507
+ if (esData.time.length === 0) {
8508
+ _this.removeFragment(fragmentEntity.body);
8509
+ return;
8510
+ }
8479
8511
  esData.time.some(function (time) {
8480
8512
  var isNotBuffered = !_this.isTimeBuffered(time.startPTS, time.endPTS, timeRange);
8481
8513
  if (isNotBuffered) {
@@ -8663,6 +8695,9 @@
8663
8695
  }
8664
8696
  return false;
8665
8697
  };
8698
+ _proto.onManifestLoading = function onManifestLoading() {
8699
+ this.removeAllFragments();
8700
+ };
8666
8701
  _proto.onFragLoaded = function onFragLoaded(event, data) {
8667
8702
  // don't track initsegment (for which sn is not a number)
8668
8703
  // don't track frags used for bitrateTest, they're irrelevant.
@@ -8709,6 +8744,20 @@
8709
8744
  var fragKey = getFragmentKey(fragment);
8710
8745
  return !!this.fragments[fragKey];
8711
8746
  };
8747
+ _proto.hasFragments = function hasFragments(type) {
8748
+ var fragments = this.fragments;
8749
+ var keys = Object.keys(fragments);
8750
+ if (!type) {
8751
+ return keys.length > 0;
8752
+ }
8753
+ for (var i = keys.length; i--;) {
8754
+ var fragmentEntity = fragments[keys[i]];
8755
+ if ((fragmentEntity == null ? void 0 : fragmentEntity.body.type) === type) {
8756
+ return true;
8757
+ }
8758
+ }
8759
+ return false;
8760
+ };
8712
8761
  _proto.hasParts = function hasParts(type) {
8713
8762
  var _this$activePartLists;
8714
8763
  return !!((_this$activePartLists = this.activePartLists[type]) != null && _this$activePartLists.length);
@@ -9135,8 +9184,9 @@
9135
9184
  frag.gap = false;
9136
9185
  }
9137
9186
  }
9138
- var loader = _this.loader = frag.loader = FragmentILoader ? new FragmentILoader(config) : new DefaultILoader(config);
9187
+ var loader = _this.loader = FragmentILoader ? new FragmentILoader(config) : new DefaultILoader(config);
9139
9188
  var loaderContext = createLoaderContext(frag);
9189
+ frag.loader = loader;
9140
9190
  var loadPolicy = getLoaderConfigWithoutReties(config.fragLoadPolicy.default);
9141
9191
  var loaderConfig = {
9142
9192
  loadPolicy: loadPolicy,
@@ -9230,8 +9280,9 @@
9230
9280
  reject(createGapLoadError(frag, part));
9231
9281
  return;
9232
9282
  }
9233
- var loader = _this2.loader = frag.loader = FragmentILoader ? new FragmentILoader(config) : new DefaultILoader(config);
9283
+ var loader = _this2.loader = FragmentILoader ? new FragmentILoader(config) : new DefaultILoader(config);
9234
9284
  var loaderContext = createLoaderContext(frag, part);
9285
+ frag.loader = loader;
9235
9286
  // Should we define another load policy for parts?
9236
9287
  var loadPolicy = getLoaderConfigWithoutReties(config.fragLoadPolicy.default);
9237
9288
  var loaderConfig = {
@@ -9943,6 +9994,7 @@
9943
9994
  _this.initPTS = [];
9944
9995
  _this.buffering = true;
9945
9996
  _this.loadingParts = false;
9997
+ _this.loopSn = void 0;
9946
9998
  _this.onMediaSeeking = function () {
9947
9999
  var _this2 = _this,
9948
10000
  config = _this2.config,
@@ -10041,6 +10093,9 @@
10041
10093
  ;
10042
10094
  _proto.startLoad = function startLoad(startPosition) {};
10043
10095
  _proto.stopLoad = function stopLoad() {
10096
+ if (this.state === State.STOPPED) {
10097
+ return;
10098
+ }
10044
10099
  this.fragmentLoader.abort();
10045
10100
  this.keyLoader.abort(this.playlistType);
10046
10101
  var frag = this.fragCurrent;
@@ -10114,15 +10169,20 @@
10114
10169
  this.keyLoader.detach();
10115
10170
  }
10116
10171
  this.media = this.mediaBuffer = null;
10117
- this.loadedmetadata = false;
10172
+ this.loopSn = undefined;
10173
+ this.startFragRequested = this.loadedmetadata = this.loadingParts = false;
10118
10174
  this.fragmentTracker.removeAllFragments();
10119
10175
  this.stopLoad();
10120
10176
  };
10121
- _proto.onManifestLoading = function onManifestLoading() {};
10177
+ _proto.onManifestLoading = function onManifestLoading() {
10178
+ this.initPTS = [];
10179
+ this.levels = this.levelLastLoaded = this.fragCurrent = null;
10180
+ this.lastCurrentTime = this.startPosition = 0;
10181
+ this.startFragRequested = false;
10182
+ };
10122
10183
  _proto.onError = function onError(event, data) {};
10123
10184
  _proto.onManifestLoaded = function onManifestLoaded(event, data) {
10124
10185
  this.startTimeOffset = data.startTimeOffset;
10125
- this.initPTS = [];
10126
10186
  };
10127
10187
  _proto.onHandlerDestroying = function onHandlerDestroying() {
10128
10188
  this.stopLoad();
@@ -10145,6 +10205,7 @@
10145
10205
  _TaskLoop.prototype.onHandlerDestroyed.call(this);
10146
10206
  };
10147
10207
  _proto.loadFragment = function loadFragment(frag, level, targetBufferTime) {
10208
+ this.startFragRequested = true;
10148
10209
  this._loadFragForPlayback(frag, level, targetBufferTime);
10149
10210
  };
10150
10211
  _proto._loadFragForPlayback = function _loadFragForPlayback(frag, level, targetBufferTime) {
@@ -10373,6 +10434,7 @@
10373
10434
  if (targetBufferTime === void 0) {
10374
10435
  targetBufferTime = null;
10375
10436
  }
10437
+ this.fragCurrent = frag;
10376
10438
  var details = level == null ? void 0 : level.details;
10377
10439
  if (!this.levels || !details) {
10378
10440
  throw new Error("frag load aborted, missing level" + (details ? '' : ' detail') + "s");
@@ -10510,7 +10572,7 @@
10510
10572
  partsLoaded[part.index] = partLoadedData;
10511
10573
  var loadedPart = partLoadedData.part;
10512
10574
  _this6.hls.trigger(Events.FRAG_LOADED, partLoadedData);
10513
- var nextPart = getPartWith(level, frag.sn, part.index + 1) || findPart(initialPartList, frag.sn, part.index + 1);
10575
+ var nextPart = getPartWith(level.details, frag.sn, part.index + 1) || findPart(initialPartList, frag.sn, part.index + 1);
10514
10576
  if (nextPart) {
10515
10577
  loadPart(nextPart);
10516
10578
  } else {
@@ -10599,8 +10661,9 @@
10599
10661
  return null;
10600
10662
  }
10601
10663
  var level = levels[levelIndex];
10602
- var part = partIndex > -1 ? getPartWith(level, sn, partIndex) : null;
10603
- var frag = part ? part.fragment : getFragmentWithSN(level, sn, fragCurrent);
10664
+ var levelDetails = level.details;
10665
+ var part = partIndex > -1 ? getPartWith(levelDetails, sn, partIndex) : null;
10666
+ var frag = part ? part.fragment : getFragmentWithSN(levelDetails, sn, fragCurrent);
10604
10667
  if (!frag) {
10605
10668
  return null;
10606
10669
  }
@@ -10707,7 +10770,11 @@
10707
10770
  return false;
10708
10771
  };
10709
10772
  _proto.getAppendedFrag = function getAppendedFrag(position, playlistType) {
10710
- var fragOrPart = this.fragmentTracker.getAppendedFrag(position, PlaylistLevelType.MAIN);
10773
+ var _this$fragmentTracker;
10774
+ if (playlistType === void 0) {
10775
+ playlistType = PlaylistLevelType.MAIN;
10776
+ }
10777
+ var fragOrPart = (_this$fragmentTracker = this.fragmentTracker) == null ? void 0 : _this$fragmentTracker.getAppendedFrag(position, playlistType);
10711
10778
  if (fragOrPart && 'fragment' in fragOrPart) {
10712
10779
  return fragOrPart.fragment;
10713
10780
  }
@@ -10760,22 +10827,25 @@
10760
10827
  return (trackerState === FragmentState.OK || trackerState === FragmentState.PARTIAL && !!frag.gap) && this.nextLoadPosition > targetBufferTime;
10761
10828
  };
10762
10829
  _proto.getNextFragmentLoopLoading = function getNextFragmentLoopLoading(frag, levelDetails, bufferInfo, playlistType, maxBufLen) {
10763
- var gapStart = frag.gap;
10764
- var nextFragment = this.getNextFragment(this.nextLoadPosition, levelDetails);
10765
- if (nextFragment === null) {
10766
- return nextFragment;
10767
- }
10768
- frag = nextFragment;
10769
- if (gapStart && frag && !frag.gap && bufferInfo.nextStart) {
10770
- // Media buffered after GAP tags should not make the next buffer timerange exceed forward buffer length
10771
- var nextbufferInfo = this.getFwdBufferInfoAtPos(this.mediaBuffer ? this.mediaBuffer : this.media, bufferInfo.nextStart, playlistType);
10772
- if (nextbufferInfo !== null && bufferInfo.len + nextbufferInfo.len >= maxBufLen) {
10773
- // Returning here might result in not finding an audio and video candiate to skip to
10774
- this.log("buffer full after gaps in \"" + playlistType + "\" playlist starting at sn: " + frag.sn);
10775
- return null;
10830
+ var nextFragment = null;
10831
+ if (frag.gap) {
10832
+ nextFragment = this.getNextFragment(this.nextLoadPosition, levelDetails);
10833
+ if (nextFragment && !nextFragment.gap && bufferInfo.nextStart) {
10834
+ // Media buffered after GAP tags should not make the next buffer timerange exceed forward buffer length
10835
+ var nextbufferInfo = this.getFwdBufferInfoAtPos(this.mediaBuffer ? this.mediaBuffer : this.media, bufferInfo.nextStart, playlistType);
10836
+ if (nextbufferInfo !== null && bufferInfo.len + nextbufferInfo.len >= maxBufLen) {
10837
+ // Returning here might result in not finding an audio and video candiate to skip to
10838
+ var sn = nextFragment.sn;
10839
+ if (this.loopSn !== sn) {
10840
+ this.log("buffer full after gaps in \"" + playlistType + "\" playlist starting at sn: " + sn);
10841
+ this.loopSn = sn;
10842
+ }
10843
+ return null;
10844
+ }
10776
10845
  }
10777
10846
  }
10778
- return frag;
10847
+ this.loopSn = undefined;
10848
+ return nextFragment;
10779
10849
  };
10780
10850
  _proto.mapToInitFragWhenRequired = function mapToInitFragWhenRequired(frag) {
10781
10851
  // If an initSegment is present, it must be buffered first
@@ -10970,7 +11040,7 @@
10970
11040
  if (startTimeOffset !== null && isFiniteNumber(startTimeOffset)) {
10971
11041
  startPosition = sliding + startTimeOffset;
10972
11042
  if (startTimeOffset < 0) {
10973
- startPosition += details.totalduration;
11043
+ startPosition += details.edge;
10974
11044
  }
10975
11045
  startPosition = Math.min(Math.max(sliding, startPosition), sliding + details.totalduration);
10976
11046
  this.log("Start time offset " + startTimeOffset + " found in " + (offsetInMultivariantPlaylist ? 'multivariant' : 'media') + " playlist, adjust startPosition to " + startPosition);
@@ -15368,10 +15438,11 @@
15368
15438
  if (this.ISGenerated) {
15369
15439
  var _videoTrack$pixelRati, _config$pixelRatio, _videoTrack$pixelRati2, _config$pixelRatio2;
15370
15440
  var config = this.videoTrackConfig;
15371
- if (config && (videoTrack.width !== config.width || videoTrack.height !== config.height || ((_videoTrack$pixelRati = videoTrack.pixelRatio) == null ? void 0 : _videoTrack$pixelRati[0]) !== ((_config$pixelRatio = config.pixelRatio) == null ? void 0 : _config$pixelRatio[0]) || ((_videoTrack$pixelRati2 = videoTrack.pixelRatio) == null ? void 0 : _videoTrack$pixelRati2[1]) !== ((_config$pixelRatio2 = config.pixelRatio) == null ? void 0 : _config$pixelRatio2[1]))) {
15441
+ if (config && (videoTrack.width !== config.width || videoTrack.height !== config.height || ((_videoTrack$pixelRati = videoTrack.pixelRatio) == null ? void 0 : _videoTrack$pixelRati[0]) !== ((_config$pixelRatio = config.pixelRatio) == null ? void 0 : _config$pixelRatio[0]) || ((_videoTrack$pixelRati2 = videoTrack.pixelRatio) == null ? void 0 : _videoTrack$pixelRati2[1]) !== ((_config$pixelRatio2 = config.pixelRatio) == null ? void 0 : _config$pixelRatio2[1])) || !config && enoughVideoSamples || this.nextAudioPts === null && enoughAudioSamples) {
15372
15442
  this.resetInitSegment();
15373
15443
  }
15374
- } else {
15444
+ }
15445
+ if (!this.ISGenerated) {
15375
15446
  initSegment = this.generateIS(audioTrack, videoTrack, timeOffset, accurateTimeOffset);
15376
15447
  }
15377
15448
  var isVideoContiguous = this.isVideoContiguous;
@@ -16289,7 +16360,7 @@
16289
16360
  if (isInvalidInitPts(initPTS, decodeTime, timeOffset, duration) || initSegment.timescale !== initPTS.timescale && accurateTimeOffset) {
16290
16361
  initSegment.initPTS = decodeTime - timeOffset;
16291
16362
  if (initPTS && initPTS.timescale === 1) {
16292
- logger.warn("Adjusting initPTS by " + (initSegment.initPTS - initPTS.baseTime));
16363
+ logger.warn("Adjusting initPTS @" + timeOffset + " from " + initPTS.baseTime / initPTS.timescale + " to " + initSegment.initPTS);
16293
16364
  }
16294
16365
  this.initPTS = initPTS = {
16295
16366
  baseTime: initSegment.initPTS,
@@ -17579,9 +17650,8 @@
17579
17650
  function AudioStreamController(hls, fragmentTracker, keyLoader) {
17580
17651
  var _this;
17581
17652
  _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'audio-stream-controller', PlaylistLevelType.AUDIO) || this;
17582
- _this.videoBuffer = null;
17583
- _this.videoTrackCC = -1;
17584
- _this.waitingVideoCC = -1;
17653
+ _this.videoAnchor = null;
17654
+ _this.mainFragLoading = null;
17585
17655
  _this.bufferedTrack = null;
17586
17656
  _this.switchingTrack = null;
17587
17657
  _this.trackId = -1;
@@ -17614,6 +17684,7 @@
17614
17684
  hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
17615
17685
  hls.on(Events.BUFFER_FLUSHED, this.onBufferFlushed, this);
17616
17686
  hls.on(Events.INIT_PTS_FOUND, this.onInitPtsFound, this);
17687
+ hls.on(Events.FRAG_LOADING, this.onFragLoading, this);
17617
17688
  hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
17618
17689
  };
17619
17690
  _proto.unregisterListeners = function unregisterListeners() {
@@ -17631,6 +17702,7 @@
17631
17702
  hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
17632
17703
  hls.off(Events.BUFFER_FLUSHED, this.onBufferFlushed, this);
17633
17704
  hls.off(Events.INIT_PTS_FOUND, this.onInitPtsFound, this);
17705
+ hls.on(Events.FRAG_LOADING, this.onFragLoading, this);
17634
17706
  hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
17635
17707
  }
17636
17708
 
@@ -17643,20 +17715,35 @@
17643
17715
  timescale = _ref.timescale;
17644
17716
  // Always update the new INIT PTS
17645
17717
  // Can change due level switch
17646
- if (id === 'main') {
17718
+ if (id === PlaylistLevelType.MAIN) {
17647
17719
  var cc = frag.cc;
17648
- this.initPTS[frag.cc] = {
17720
+ var inFlightFrag = this.fragCurrent;
17721
+ this.initPTS[cc] = {
17649
17722
  baseTime: initPTS,
17650
17723
  timescale: timescale
17651
17724
  };
17652
17725
  this.log("InitPTS for cc: " + cc + " found from main: " + initPTS + "/" + timescale);
17653
- this.videoTrackCC = cc;
17726
+ this.videoAnchor = frag;
17654
17727
  // If we are waiting, tick immediately to unblock audio fragment transmuxing
17655
17728
  if (this.state === State.WAITING_INIT_PTS) {
17729
+ var waitingData = this.waitingData;
17730
+ if (!waitingData || waitingData.frag.cc !== cc) {
17731
+ this.nextLoadPosition = this.findSyncFrag(frag).start;
17732
+ }
17656
17733
  this.tick();
17734
+ } else if (!this.loadedmetadata && inFlightFrag && inFlightFrag.cc !== cc) {
17735
+ this.startFragRequested = false;
17736
+ this.nextLoadPosition = this.findSyncFrag(frag).start;
17737
+ inFlightFrag.abortRequests();
17738
+ this.resetLoadingState();
17657
17739
  }
17658
17740
  }
17659
17741
  };
17742
+ _proto.findSyncFrag = function findSyncFrag(mainFrag) {
17743
+ var trackDetails = this.getLevelDetails();
17744
+ var cc = mainFrag.cc;
17745
+ return findNearestWithCC(trackDetails, cc, mainFrag) || trackDetails && findFragWithCC(trackDetails.fragments, cc) || mainFrag;
17746
+ };
17660
17747
  _proto.startLoad = function startLoad(startPosition) {
17661
17748
  if (!this.levels) {
17662
17749
  this.startPosition = startPosition;
@@ -17720,9 +17807,9 @@
17720
17807
  part = waitingData.part,
17721
17808
  cache = waitingData.cache,
17722
17809
  complete = waitingData.complete;
17810
+ var videoAnchor = this.videoAnchor;
17723
17811
  if (this.initPTS[frag.cc] !== undefined) {
17724
17812
  this.waitingData = null;
17725
- this.waitingVideoCC = -1;
17726
17813
  this.state = State.FRAG_LOADING;
17727
17814
  var payload = cache.flush();
17728
17815
  var data = {
@@ -17735,21 +17822,13 @@
17735
17822
  if (complete) {
17736
17823
  _BaseStreamController.prototype._handleFragmentLoadComplete.call(this, data);
17737
17824
  }
17738
- } else if (this.videoTrackCC !== this.waitingVideoCC) {
17825
+ } else if (videoAnchor && videoAnchor.cc !== waitingData.frag.cc) {
17739
17826
  // Drop waiting fragment if videoTrackCC has changed since waitingFragment was set and initPTS was not found
17740
- this.log("Waiting fragment cc (" + frag.cc + ") cancelled because video is at cc " + this.videoTrackCC);
17827
+ this.log("Waiting fragment cc (" + frag.cc + ") cancelled because video is at cc " + videoAnchor.cc);
17828
+ this.nextLoadPosition = this.findSyncFrag(videoAnchor).start;
17741
17829
  this.clearWaitingFragment();
17742
- } else {
17743
- // Drop waiting fragment if an earlier fragment is needed
17744
- var pos = this.getLoadPosition();
17745
- var bufferInfo = BufferHelper.bufferInfo(this.mediaBuffer, pos, this.config.maxBufferHole);
17746
- var waitingFragmentAtPosition = fragmentWithinToleranceTest(bufferInfo.end, this.config.maxFragLookUpTolerance, frag);
17747
- if (waitingFragmentAtPosition < 0) {
17748
- this.log("Waiting fragment cc (" + frag.cc + ") @ " + frag.start + " cancelled because another fragment at " + bufferInfo.end + " is needed");
17749
- this.clearWaitingFragment();
17750
- }
17751
17830
  }
17752
- } else {
17831
+ } else if (this.state !== State.STOPPED) {
17753
17832
  this.state = State.IDLE;
17754
17833
  }
17755
17834
  }
@@ -17759,9 +17838,12 @@
17759
17838
  _proto.clearWaitingFragment = function clearWaitingFragment() {
17760
17839
  var waitingData = this.waitingData;
17761
17840
  if (waitingData) {
17841
+ if (!this.loadedmetadata) {
17842
+ // Load overlapping fragment on start when discontinuity start times are not aligned
17843
+ this.startFragRequested = false;
17844
+ }
17762
17845
  this.fragmentTracker.removeFragment(waitingData.frag);
17763
17846
  this.waitingData = null;
17764
- this.waitingVideoCC = -1;
17765
17847
  if (this.state !== State.STOPPED) {
17766
17848
  this.state = State.IDLE;
17767
17849
  }
@@ -17823,9 +17905,10 @@
17823
17905
  var maxBufLen = hls.maxBufferLength;
17824
17906
  var fragments = trackDetails.fragments;
17825
17907
  var start = fragments[0].start;
17826
- var targetBufferTime = this.flushing ? this.getLoadPosition() : bufferInfo.end;
17908
+ var loadPosition = this.getLoadPosition();
17909
+ var targetBufferTime = this.flushing ? loadPosition : bufferInfo.end;
17827
17910
  if (switchingTrack && media) {
17828
- var pos = this.getLoadPosition();
17911
+ var pos = loadPosition;
17829
17912
  // STABLE
17830
17913
  if (bufferedTrack && !mediaAttributesIdentical(switchingTrack.attrs, bufferedTrack.attrs)) {
17831
17914
  targetBufferTime = pos;
@@ -17845,37 +17928,26 @@
17845
17928
  return;
17846
17929
  }
17847
17930
  var frag = this.getNextFragment(targetBufferTime, trackDetails);
17848
- var atGap = false;
17849
17931
  // Avoid loop loading by using nextLoadPosition set for backtracking and skipping consecutive GAP tags
17850
17932
  if (frag && this.isLoopLoading(frag, targetBufferTime)) {
17851
- atGap = !!frag.gap;
17852
17933
  frag = this.getNextFragmentLoopLoading(frag, trackDetails, bufferInfo, PlaylistLevelType.MAIN, maxBufLen);
17853
17934
  }
17854
17935
  if (!frag) {
17855
17936
  this.bufferFlushed = true;
17856
17937
  return;
17857
17938
  }
17858
- if (!trackDetails.live || targetBufferTime < this.hls.liveSyncPosition) {
17939
+ if (this.startFragRequested && (!trackDetails.live || targetBufferTime < this.hls.liveSyncPosition)) {
17859
17940
  // Request audio segments up to one fragment ahead of main buffer
17860
- var mainBufferInfo = this.getFwdBufferInfo(this.videoBuffer ? this.videoBuffer : this.media, PlaylistLevelType.MAIN);
17861
- var atBufferSyncLimit = !!mainBufferInfo && frag.start > mainBufferInfo.end + frag.duration;
17862
- if (atBufferSyncLimit) {
17863
- // Check fragment-tracker for main fragments since GAP segments do not show up in bufferInfo
17864
- var mainFrag = this.fragmentTracker.getFragAtPos(frag.start, PlaylistLevelType.MAIN);
17865
- if (mainFrag === null) {
17866
- return;
17867
- }
17868
- // Bridge gaps in main buffer (also prevents loop loading at gaps)
17869
- atGap || (atGap = !!mainFrag.gap || mainBufferInfo.len === 0);
17870
- if (!atGap || bufferInfo.nextStart && bufferInfo.nextStart < mainFrag.end) {
17871
- return;
17872
- }
17941
+ var mainFragLoading = this.mainFragLoading;
17942
+ var mainTargetBufferEnd = mainFragLoading ? (mainFragLoading.part || mainFragLoading.frag).end : null;
17943
+ var atBufferSyncLimit = mainTargetBufferEnd !== null && frag.start > mainTargetBufferEnd;
17944
+ if (atBufferSyncLimit && !frag.endList) {
17945
+ return;
17873
17946
  }
17874
17947
  }
17875
17948
  this.loadFragment(frag, levelInfo, targetBufferTime);
17876
17949
  };
17877
17950
  _proto.onMediaDetaching = function onMediaDetaching() {
17878
- this.videoBuffer = null;
17879
17951
  this.bufferFlushed = this.flushing = false;
17880
17952
  _BaseStreamController.prototype.onMediaDetaching.call(this);
17881
17953
  };
@@ -17918,12 +17990,10 @@
17918
17990
  }
17919
17991
  };
17920
17992
  _proto.onManifestLoading = function onManifestLoading() {
17921
- this.fragmentTracker.removeAllFragments();
17922
- this.startPosition = this.lastCurrentTime = 0;
17993
+ _BaseStreamController.prototype.onManifestLoading.call(this);
17923
17994
  this.bufferFlushed = this.flushing = false;
17924
- this.levels = this.mainDetails = this.waitingData = this.bufferedTrack = this.cachedTrackLoadedData = this.switchingTrack = null;
17925
- this.startFragRequested = false;
17926
- this.trackId = this.videoTrackCC = this.waitingVideoCC = -1;
17995
+ this.mainDetails = this.waitingData = this.videoAnchor = this.bufferedTrack = this.cachedTrackLoadedData = this.switchingTrack = null;
17996
+ this.trackId = -1;
17927
17997
  };
17928
17998
  _proto.onLevelLoaded = function onLevelLoaded(event, data) {
17929
17999
  this.mainDetails = data.details;
@@ -18030,7 +18100,6 @@
18030
18100
  },
18031
18101
  cache = _this$waitingData.cache;
18032
18102
  cache.push(new Uint8Array(payload));
18033
- this.waitingVideoCC = this.videoTrackCC;
18034
18103
  this.state = State.WAITING_INIT_PTS;
18035
18104
  }
18036
18105
  };
@@ -18044,7 +18113,7 @@
18044
18113
  _proto.onBufferReset = function onBufferReset( /* event: Events.BUFFER_RESET */
18045
18114
  ) {
18046
18115
  // reset reference to sourcebuffers
18047
- this.mediaBuffer = this.videoBuffer = null;
18116
+ this.mediaBuffer = null;
18048
18117
  this.loadedmetadata = false;
18049
18118
  };
18050
18119
  _proto.onBufferCreated = function onBufferCreated(event, data) {
@@ -18052,8 +18121,13 @@
18052
18121
  if (audioTrack) {
18053
18122
  this.mediaBuffer = audioTrack.buffer || null;
18054
18123
  }
18055
- if (data.tracks.video) {
18056
- this.videoBuffer = data.tracks.video.buffer || null;
18124
+ };
18125
+ _proto.onFragLoading = function onFragLoading(event, data) {
18126
+ if (data.frag.type === PlaylistLevelType.MAIN && data.frag.sn !== 'initSegment') {
18127
+ this.mainFragLoading = data;
18128
+ if (this.state === State.IDLE) {
18129
+ this.tick();
18130
+ }
18057
18131
  }
18058
18132
  };
18059
18133
  _proto.onFragBuffered = function onFragBuffered(event, data) {
@@ -18061,12 +18135,9 @@
18061
18135
  part = data.part;
18062
18136
  if (frag.type !== PlaylistLevelType.AUDIO) {
18063
18137
  if (!this.loadedmetadata && frag.type === PlaylistLevelType.MAIN) {
18064
- var bufferable = this.videoBuffer || this.media;
18065
- if (bufferable) {
18066
- var bufferedTimeRanges = BufferHelper.getBuffered(bufferable);
18067
- if (bufferedTimeRanges.length) {
18068
- this.loadedmetadata = true;
18069
- }
18138
+ var bufferedState = this.fragmentTracker.getState(frag);
18139
+ if (bufferedState === FragmentState.OK || bufferedState === FragmentState.PARTIAL) {
18140
+ this.loadedmetadata = true;
18070
18141
  }
18071
18142
  }
18072
18143
  return;
@@ -18233,12 +18304,15 @@
18233
18304
  if (tracks.video) {
18234
18305
  delete tracks.video;
18235
18306
  }
18307
+ if (tracks.audiovideo) {
18308
+ delete tracks.audiovideo;
18309
+ }
18236
18310
 
18237
18311
  // include levelCodec in audio and video tracks
18238
- var track = tracks.audio;
18239
- if (!track) {
18312
+ if (!tracks.audio) {
18240
18313
  return;
18241
18314
  }
18315
+ var track = tracks.audio;
18242
18316
  track.id = 'audio';
18243
18317
  var variantAudioCodecs = currentLevel.audioCodec;
18244
18318
  this.log("Init audio buffer, container:" + track.container + ", codecs[level/parsed]=[" + variantAudioCodecs + "/" + track.codec + "]");
@@ -18265,7 +18339,6 @@
18265
18339
  _proto.loadFragment = function loadFragment(frag, track, targetBufferTime) {
18266
18340
  // only load if fragment is not loaded or if in audio switch
18267
18341
  var fragState = this.fragmentTracker.getState(frag);
18268
- this.fragCurrent = frag;
18269
18342
 
18270
18343
  // we force a frag loading in audio switch as fragment tracker might not have evicted previous frags in case of quick audio switch
18271
18344
  if (this.switchingTrack || fragState === FragmentState.NOT_LOADED || fragState === FragmentState.PARTIAL) {
@@ -18280,7 +18353,6 @@
18280
18353
  alignMediaPlaylistByPDT(track.details, mainDetails);
18281
18354
  }
18282
18355
  } else {
18283
- this.startFragRequested = true;
18284
18356
  _BaseStreamController.prototype.loadFragment.call(this, frag, track, targetBufferTime);
18285
18357
  }
18286
18358
  } else {
@@ -18683,8 +18755,8 @@
18683
18755
  this.tick();
18684
18756
  };
18685
18757
  _proto.onManifestLoading = function onManifestLoading() {
18758
+ _BaseStreamController.prototype.onManifestLoading.call(this);
18686
18759
  this.mainDetails = null;
18687
- this.fragmentTracker.removeAllFragments();
18688
18760
  };
18689
18761
  _proto.onMediaDetaching = function onMediaDetaching() {
18690
18762
  this.tracksBuffered = [];
@@ -18696,7 +18768,9 @@
18696
18768
  _proto.onSubtitleFragProcessed = function onSubtitleFragProcessed(event, data) {
18697
18769
  var frag = data.frag,
18698
18770
  success = data.success;
18699
- this.fragPrevious = frag;
18771
+ if (frag.sn !== 'initSegment') {
18772
+ this.fragPrevious = frag;
18773
+ }
18700
18774
  this.state = State.IDLE;
18701
18775
  if (!success) {
18702
18776
  return;
@@ -18981,11 +19055,9 @@
18981
19055
  }
18982
19056
  };
18983
19057
  _proto.loadFragment = function loadFragment(frag, level, targetBufferTime) {
18984
- this.fragCurrent = frag;
18985
19058
  if (frag.sn === 'initSegment') {
18986
19059
  this._loadInitSegment(frag, level);
18987
19060
  } else {
18988
- this.startFragRequested = true;
18989
19061
  _BaseStreamController.prototype.loadFragment.call(this, frag, level, targetBufferTime);
18990
19062
  }
18991
19063
  };
@@ -19670,6 +19742,7 @@
19670
19742
  hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
19671
19743
  hls.on(Events.FRAG_PARSED, this.onFragParsed, this);
19672
19744
  hls.on(Events.FRAG_CHANGED, this.onFragChanged, this);
19745
+ hls.on(Events.ERROR, this.onError, this);
19673
19746
  };
19674
19747
  _proto.unregisterListeners = function unregisterListeners() {
19675
19748
  var hls = this.hls;
@@ -19685,6 +19758,7 @@
19685
19758
  hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
19686
19759
  hls.off(Events.FRAG_PARSED, this.onFragParsed, this);
19687
19760
  hls.off(Events.FRAG_CHANGED, this.onFragChanged, this);
19761
+ hls.off(Events.ERROR, this.onError, this);
19688
19762
  };
19689
19763
  _proto._initSourceBuffer = function _initSourceBuffer() {
19690
19764
  this.sourceBuffer = {};
@@ -19694,11 +19768,7 @@
19694
19768
  video: [],
19695
19769
  audiovideo: []
19696
19770
  };
19697
- this.appendErrors = {
19698
- audio: 0,
19699
- video: 0,
19700
- audiovideo: 0
19701
- };
19771
+ this.resetAppendErrors();
19702
19772
  this.lastMpegAudioChunk = null;
19703
19773
  this.blockedAudioAppend = null;
19704
19774
  this.lastVideoAppendEnd = 0;
@@ -20228,6 +20298,22 @@
20228
20298
  this.updateMediaSource(durationAndRange);
20229
20299
  }
20230
20300
  };
20301
+ _proto.onError = function onError(event, data) {
20302
+ if (data.details === ErrorDetails.BUFFER_APPEND_ERROR && data.frag) {
20303
+ var _data$errorAction;
20304
+ var nextAutoLevel = (_data$errorAction = data.errorAction) == null ? void 0 : _data$errorAction.nextAutoLevel;
20305
+ if (isFiniteNumber(nextAutoLevel) && nextAutoLevel !== data.frag.level) {
20306
+ this.resetAppendErrors();
20307
+ }
20308
+ }
20309
+ };
20310
+ _proto.resetAppendErrors = function resetAppendErrors() {
20311
+ this.appendErrors = {
20312
+ audio: 0,
20313
+ video: 0,
20314
+ audiovideo: 0
20315
+ };
20316
+ };
20231
20317
  _proto.trimBuffers = function trimBuffers() {
20232
20318
  var hls = this.hls,
20233
20319
  details = this.details,
@@ -23120,7 +23206,7 @@
23120
23206
  initPTS = _ref.initPTS,
23121
23207
  timescale = _ref.timescale;
23122
23208
  var unparsedVttFrags = this.unparsedVttFrags;
23123
- if (id === 'main') {
23209
+ if (id === PlaylistLevelType.MAIN) {
23124
23210
  this.initPTS[frag.cc] = {
23125
23211
  baseTime: initPTS,
23126
23212
  timescale: timescale
@@ -28940,7 +29026,6 @@
28940
29026
  _proto.loadFragment = function loadFragment(frag, level, targetBufferTime) {
28941
29027
  // Check if fragment is not loaded
28942
29028
  var fragState = this.fragmentTracker.getState(frag);
28943
- this.fragCurrent = frag;
28944
29029
  if (fragState === FragmentState.NOT_LOADED || fragState === FragmentState.PARTIAL) {
28945
29030
  if (frag.sn === 'initSegment') {
28946
29031
  this._loadInitSegment(frag, level);
@@ -28948,7 +29033,6 @@
28948
29033
  this.log("Fragment " + frag.sn + " of level " + frag.level + " is being downloaded to test bitrate and will not be buffered");
28949
29034
  this._loadBitrateTestFrag(frag, level);
28950
29035
  } else {
28951
- this.startFragRequested = true;
28952
29036
  _BaseStreamController.prototype.loadFragment.call(this, frag, level, targetBufferTime);
28953
29037
  }
28954
29038
  } else {
@@ -29078,14 +29162,14 @@
29078
29162
  _BaseStreamController.prototype.onMediaDetaching.call(this);
29079
29163
  };
29080
29164
  _proto.onManifestLoading = function onManifestLoading() {
29165
+ _BaseStreamController.prototype.onManifestLoading.call(this);
29081
29166
  // reset buffer on manifest loading
29082
29167
  this.log('Trigger BUFFER_RESET');
29083
29168
  this.hls.trigger(Events.BUFFER_RESET, undefined);
29084
- this.fragmentTracker.removeAllFragments();
29085
29169
  this.couldBacktrack = false;
29086
- this.startPosition = this.lastCurrentTime = this.fragLastKbps = 0;
29087
- this.levels = this.fragPlaying = this.backtrackFragment = this.levelLastLoaded = null;
29088
- this.altAudio = this.audioOnly = this.startFragRequested = false;
29170
+ this.fragLastKbps = 0;
29171
+ this.fragPlaying = this.backtrackFragment = null;
29172
+ this.altAudio = this.audioOnly = false;
29089
29173
  };
29090
29174
  _proto.onManifestParsed = function onManifestParsed(event, data) {
29091
29175
  // detect if we have different kind of audio codecs used amongst playlists
@@ -29370,7 +29454,7 @@
29370
29454
  // in that case, reset startFragRequested flag
29371
29455
  if (!this.loadedmetadata) {
29372
29456
  this.startFragRequested = false;
29373
- this.nextLoadPosition = this.startPosition;
29457
+ this.nextLoadPosition = this.lastCurrentTime;
29374
29458
  }
29375
29459
  this.tickImmediate();
29376
29460
  };
@@ -29454,7 +29538,7 @@
29454
29538
  };
29455
29539
  _proto._handleTransmuxComplete = function _handleTransmuxComplete(transmuxResult) {
29456
29540
  var _id3$samples;
29457
- var id = 'main';
29541
+ var id = this.playlistType;
29458
29542
  var hls = this.hls;
29459
29543
  var remuxResult = transmuxResult.remuxResult,
29460
29544
  chunkMeta = transmuxResult.chunkMeta;
@@ -29644,31 +29728,38 @@
29644
29728
  audio.levelCodec = audioCodec;
29645
29729
  audio.id = 'main';
29646
29730
  this.log("Init audio buffer, container:" + audio.container + ", codecs[selected/level/parsed]=[" + (audioCodec || '') + "/" + (currentLevel.audioCodec || '') + "/" + audio.codec + "]");
29731
+ delete tracks.audiovideo;
29647
29732
  }
29648
29733
  if (video) {
29649
29734
  video.levelCodec = currentLevel.videoCodec;
29650
29735
  video.id = 'main';
29651
29736
  this.log("Init video buffer, container:" + video.container + ", codecs[level/parsed]=[" + (currentLevel.videoCodec || '') + "/" + video.codec + "]");
29737
+ delete tracks.audiovideo;
29652
29738
  }
29653
29739
  if (audiovideo) {
29654
29740
  this.log("Init audiovideo buffer, container:" + audiovideo.container + ", codecs[level/parsed]=[" + currentLevel.codecs + "/" + audiovideo.codec + "]");
29741
+ delete tracks.video;
29742
+ delete tracks.audio;
29743
+ }
29744
+ var trackTypes = Object.keys(tracks);
29745
+ if (trackTypes.length) {
29746
+ this.hls.trigger(Events.BUFFER_CODECS, tracks);
29747
+ // loop through tracks that are going to be provided to bufferController
29748
+ trackTypes.forEach(function (trackName) {
29749
+ var track = tracks[trackName];
29750
+ var initSegment = track.initSegment;
29751
+ if (initSegment != null && initSegment.byteLength) {
29752
+ _this3.hls.trigger(Events.BUFFER_APPENDING, {
29753
+ type: trackName,
29754
+ data: initSegment,
29755
+ frag: frag,
29756
+ part: null,
29757
+ chunkMeta: chunkMeta,
29758
+ parent: frag.type
29759
+ });
29760
+ }
29761
+ });
29655
29762
  }
29656
- this.hls.trigger(Events.BUFFER_CODECS, tracks);
29657
- // loop through tracks that are going to be provided to bufferController
29658
- Object.keys(tracks).forEach(function (trackName) {
29659
- var track = tracks[trackName];
29660
- var initSegment = track.initSegment;
29661
- if (initSegment != null && initSegment.byteLength) {
29662
- _this3.hls.trigger(Events.BUFFER_APPENDING, {
29663
- type: trackName,
29664
- data: initSegment,
29665
- frag: frag,
29666
- part: null,
29667
- chunkMeta: chunkMeta,
29668
- parent: frag.type
29669
- });
29670
- }
29671
- });
29672
29763
  // trigger handler right now
29673
29764
  this.tickImmediate();
29674
29765
  };
@@ -29749,22 +29840,30 @@
29749
29840
  }, {
29750
29841
  key: "currentFrag",
29751
29842
  get: function get() {
29752
- var media = this.media;
29753
- if (media) {
29754
- return this.fragPlaying || this.getAppendedFrag(media.currentTime);
29843
+ var _this$media2;
29844
+ if (this.fragPlaying) {
29845
+ return this.fragPlaying;
29846
+ }
29847
+ var currentTime = ((_this$media2 = this.media) == null ? void 0 : _this$media2.currentTime) || this.lastCurrentTime;
29848
+ if (isFiniteNumber(currentTime)) {
29849
+ return this.getAppendedFrag(currentTime);
29755
29850
  }
29756
29851
  return null;
29757
29852
  }
29758
29853
  }, {
29759
29854
  key: "currentProgramDateTime",
29760
29855
  get: function get() {
29761
- var media = this.media;
29762
- if (media) {
29763
- var currentTime = media.currentTime;
29764
- var frag = this.currentFrag;
29765
- if (frag && isFiniteNumber(currentTime) && isFiniteNumber(frag.programDateTime)) {
29766
- var epocMs = frag.programDateTime + (currentTime - frag.start) * 1000;
29767
- return new Date(epocMs);
29856
+ var _this$media3;
29857
+ var currentTime = ((_this$media3 = this.media) == null ? void 0 : _this$media3.currentTime) || this.lastCurrentTime;
29858
+ if (isFiniteNumber(currentTime)) {
29859
+ var details = this.getLevelDetails();
29860
+ var frag = this.currentFrag || (details ? findFragmentByPTS(null, details.fragments, currentTime) : null);
29861
+ if (frag) {
29862
+ var programDateTime = frag.programDateTime;
29863
+ if (programDateTime !== null) {
29864
+ var epocMs = programDateTime + (currentTime - frag.start) * 1000;
29865
+ return new Date(epocMs);
29866
+ }
29768
29867
  }
29769
29868
  }
29770
29869
  return null;
@@ -29882,7 +29981,7 @@
29882
29981
  if (AudioStreamControllerClass) {
29883
29982
  networkControllers.push(new AudioStreamControllerClass(this, fragmentTracker, keyLoader));
29884
29983
  }
29885
- // subtitleTrackController must be defined before subtitleStreamController because the order of event handling is important
29984
+ // Instantiate subtitleTrackController before SubtitleStreamController to receive level events first
29886
29985
  this.subtitleTrackController = this.createController(config.subtitleTrackController, networkControllers);
29887
29986
  var SubtitleStreamControllerClass = config.subtitleStreamController;
29888
29987
  if (SubtitleStreamControllerClass) {
@@ -30678,7 +30777,7 @@
30678
30777
  * Get the video-dev/hls.js package version.
30679
30778
  */
30680
30779
  function get() {
30681
- return "1.5.12-0.canary.10366";
30780
+ return "1.5.12-0.canary.10367";
30682
30781
  }
30683
30782
  }, {
30684
30783
  key: "Events",