hls.js 1.6.0-beta.1.0.canary.10764 → 1.6.0-beta.1.0.canary.10766

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.d.mts CHANGED
@@ -376,6 +376,7 @@ export declare class BaseStreamController extends TaskLoop implements NetworkCom
376
376
  private updateLevelTiming;
377
377
  private playlistLabel;
378
378
  private fragInfo;
379
+ private treatAsGap;
379
380
  protected resetTransmuxer(): void;
380
381
  protected recoverWorkerError(data: ErrorData): void;
381
382
  set state(nextState: string);
@@ -2606,6 +2607,7 @@ export declare interface LevelLoadedData {
2606
2607
  details: LevelDetails;
2607
2608
  id: number;
2608
2609
  level: number;
2610
+ levelInfo: Level;
2609
2611
  networkDetails: any;
2610
2612
  stats: LoaderStats;
2611
2613
  deliveryDirectives: HlsUrlParameters | null;
@@ -2614,6 +2616,7 @@ export declare interface LevelLoadedData {
2614
2616
  export declare interface LevelLoadingData {
2615
2617
  id: number;
2616
2618
  level: number;
2619
+ levelInfo: Level;
2617
2620
  pathwayId: string | undefined;
2618
2621
  url: string;
2619
2622
  deliveryDirectives: HlsUrlParameters | null;
@@ -3152,6 +3155,7 @@ export declare interface PlaylistLoaderContext extends LoaderContext {
3152
3155
  pathwayId?: string;
3153
3156
  levelDetails?: LevelDetails;
3154
3157
  deliveryDirectives: HlsUrlParameters | null;
3158
+ levelOrTrack: Level | MediaPlaylist | null;
3155
3159
  }
3156
3160
 
3157
3161
  export declare type RationalTimestamp = {
@@ -3654,11 +3658,13 @@ export declare interface TrackLoadedData {
3654
3658
  networkDetails: any;
3655
3659
  stats: LoaderStats;
3656
3660
  deliveryDirectives: HlsUrlParameters | null;
3661
+ track: MediaPlaylist;
3657
3662
  }
3658
3663
 
3659
3664
  export declare interface TrackLoadingData {
3660
3665
  id: number;
3661
3666
  groupId: string;
3667
+ track: MediaPlaylist;
3662
3668
  url: string;
3663
3669
  deliveryDirectives: HlsUrlParameters | null;
3664
3670
  }
package/dist/hls.d.ts CHANGED
@@ -376,6 +376,7 @@ export declare class BaseStreamController extends TaskLoop implements NetworkCom
376
376
  private updateLevelTiming;
377
377
  private playlistLabel;
378
378
  private fragInfo;
379
+ private treatAsGap;
379
380
  protected resetTransmuxer(): void;
380
381
  protected recoverWorkerError(data: ErrorData): void;
381
382
  set state(nextState: string);
@@ -2606,6 +2607,7 @@ export declare interface LevelLoadedData {
2606
2607
  details: LevelDetails;
2607
2608
  id: number;
2608
2609
  level: number;
2610
+ levelInfo: Level;
2609
2611
  networkDetails: any;
2610
2612
  stats: LoaderStats;
2611
2613
  deliveryDirectives: HlsUrlParameters | null;
@@ -2614,6 +2616,7 @@ export declare interface LevelLoadedData {
2614
2616
  export declare interface LevelLoadingData {
2615
2617
  id: number;
2616
2618
  level: number;
2619
+ levelInfo: Level;
2617
2620
  pathwayId: string | undefined;
2618
2621
  url: string;
2619
2622
  deliveryDirectives: HlsUrlParameters | null;
@@ -3152,6 +3155,7 @@ export declare interface PlaylistLoaderContext extends LoaderContext {
3152
3155
  pathwayId?: string;
3153
3156
  levelDetails?: LevelDetails;
3154
3157
  deliveryDirectives: HlsUrlParameters | null;
3158
+ levelOrTrack: Level | MediaPlaylist | null;
3155
3159
  }
3156
3160
 
3157
3161
  export declare type RationalTimestamp = {
@@ -3654,11 +3658,13 @@ export declare interface TrackLoadedData {
3654
3658
  networkDetails: any;
3655
3659
  stats: LoaderStats;
3656
3660
  deliveryDirectives: HlsUrlParameters | null;
3661
+ track: MediaPlaylist;
3657
3662
  }
3658
3663
 
3659
3664
  export declare interface TrackLoadingData {
3660
3665
  id: number;
3661
3666
  groupId: string;
3667
+ track: MediaPlaylist;
3662
3668
  url: string;
3663
3669
  deliveryDirectives: HlsUrlParameters | null;
3664
3670
  }
package/dist/hls.js CHANGED
@@ -1057,7 +1057,7 @@
1057
1057
  // Some browsers don't allow to use bind on console object anyway
1058
1058
  // fallback to default if needed
1059
1059
  try {
1060
- newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.6.0-beta.1.0.canary.10764");
1060
+ newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.6.0-beta.1.0.canary.10766");
1061
1061
  } catch (e) {
1062
1062
  /* log fn threw an exception. All logger methods are no-ops. */
1063
1063
  return createLogger();
@@ -2546,8 +2546,10 @@
2546
2546
  return 0; // continue
2547
2547
  }
2548
2548
  if (config.useMediaCapabilities && !levelInfo.supportedResult && !levelInfo.supportedPromise) {
2549
+ var _levelInfo$videoCodec;
2549
2550
  var mediaCapabilities = navigator.mediaCapabilities;
2550
- if (typeof (mediaCapabilities == null ? void 0 : mediaCapabilities.decodingInfo) === 'function' && requiresMediaCapabilitiesDecodingInfo(levelInfo, audioTracksByGroup, currentVideoRange, currentFrameRate, currentBw, audioPreference)) {
2551
+ if (typeof (mediaCapabilities == null ? void 0 : mediaCapabilities.decodingInfo) === 'function' && (requiresMediaCapabilitiesDecodingInfo(levelInfo, audioTracksByGroup, currentVideoRange, currentFrameRate, currentBw, audioPreference) || ((_levelInfo$videoCodec = levelInfo.videoCodec) == null ? void 0 : _levelInfo$videoCodec.substring(0, 4)) === 'hvc1') // Force media capabilities check for HEVC to avoid failure on Windows
2552
+ ) {
2551
2553
  levelInfo.supportedPromise = getMediaDecodingInfoPromise(levelInfo, audioTracksByGroup, mediaCapabilities);
2552
2554
  levelInfo.supportedPromise.then(function (decodingInfo) {
2553
2555
  if (!_this3.hls) {
@@ -2563,6 +2565,9 @@
2563
2565
  if (index > -1 && levels.length > 1) {
2564
2566
  _this3.log("Removing unsupported level " + index);
2565
2567
  _this3.hls.removeLevel(index);
2568
+ if (_this3.hls.loadLevel === -1) {
2569
+ _this3.hls.nextLoadLevel = 0;
2570
+ }
2566
2571
  }
2567
2572
  }
2568
2573
  });
@@ -4316,6 +4321,10 @@
4316
4321
  }
4317
4322
  }]);
4318
4323
  }();
4324
+ function isMediaFragment(frag) {
4325
+ return frag.sn !== 'initSegment';
4326
+ }
4327
+
4319
4328
  /**
4320
4329
  * Object representing parsed data from an HLS Segment. Found in {@link hls.js#LevelDetails.fragments}.
4321
4330
  */
@@ -4536,7 +4545,7 @@
4536
4545
  }, {
4537
4546
  key: "ref",
4538
4547
  get: function get() {
4539
- if (this.sn === 'initSegment') {
4548
+ if (!isMediaFragment(this)) {
4540
4549
  return null;
4541
4550
  }
4542
4551
  if (!this._ref) {
@@ -9191,7 +9200,7 @@
9191
9200
  _proto.fragBufferedComplete = function fragBufferedComplete(frag, part) {
9192
9201
  var media = this.mediaBuffer ? this.mediaBuffer : this.media;
9193
9202
  this.log("Buffered " + frag.type + " sn: " + frag.sn + (part ? ' part: ' + part.index : '') + " of " + this.fragInfo(frag, false, part) + " > buffer:" + (media ? TimeRanges.toString(BufferHelper.getBuffered(media)) : '(detached)') + ")");
9194
- if (frag.sn !== 'initSegment') {
9203
+ if (isMediaFragment(frag)) {
9195
9204
  var _this$levels;
9196
9205
  if (frag.type !== PlaylistLevelType.SUBTITLE) {
9197
9206
  var el = frag.elementaryStreams;
@@ -9265,7 +9274,7 @@
9265
9274
  this.keyLoader.loadClear(frag, details.encryptedFragments);
9266
9275
  }
9267
9276
  var fragPrevious = this.fragPrevious;
9268
- if (frag.sn !== 'initSegment' && (!fragPrevious || frag.sn !== fragPrevious.sn)) {
9277
+ if (isMediaFragment(frag) && (!fragPrevious || frag.sn !== fragPrevious.sn)) {
9269
9278
  var shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
9270
9279
  if (shouldLoadParts !== this.loadingParts) {
9271
9280
  this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " loading sn " + (fragPrevious == null ? void 0 : fragPrevious.sn) + "->" + frag.sn);
@@ -9273,7 +9282,7 @@
9273
9282
  }
9274
9283
  }
9275
9284
  targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
9276
- if (this.loadingParts && frag.sn !== 'initSegment') {
9285
+ if (this.loadingParts && isMediaFragment(frag)) {
9277
9286
  var partList = details.partList;
9278
9287
  if (partList && progressCallback) {
9279
9288
  if (targetBufferTime > frag.end && details.fragmentHint) {
@@ -9316,7 +9325,7 @@
9316
9325
  }
9317
9326
  }
9318
9327
  }
9319
- if (frag.sn !== 'initSegment' && this.loadingParts) {
9328
+ if (isMediaFragment(frag) && this.loadingParts) {
9320
9329
  this.log("LL-Part loading OFF after next part miss @" + targetBufferTime.toFixed(2));
9321
9330
  this.loadingParts = false;
9322
9331
  } else if (!frag.url) {
@@ -9858,7 +9867,7 @@
9858
9867
  return pos;
9859
9868
  };
9860
9869
  _proto.handleFragLoadAborted = function handleFragLoadAborted(frag, part) {
9861
- if (this.transmuxer && frag.sn !== 'initSegment' && frag.stats.aborted) {
9870
+ if (this.transmuxer && isMediaFragment(frag) && frag.stats.aborted) {
9862
9871
  this.warn("Fragment " + frag.sn + (part ? ' part ' + part.index : '') + " of level " + frag.level + " was aborted");
9863
9872
  this.resetFragmentLoading(frag);
9864
9873
  }
@@ -9893,10 +9902,18 @@
9893
9902
  var errorAction = data.errorAction;
9894
9903
  var _ref2 = errorAction || {},
9895
9904
  action = _ref2.action,
9905
+ flags = _ref2.flags,
9896
9906
  _ref2$retryCount = _ref2.retryCount,
9897
9907
  retryCount = _ref2$retryCount === void 0 ? 0 : _ref2$retryCount,
9898
9908
  retryConfig = _ref2.retryConfig;
9899
- if (errorAction && action === NetworkErrorAction.RetryRequest && retryConfig) {
9909
+ var couldRetry = !!errorAction && !!retryConfig;
9910
+ var retry = couldRetry && action === NetworkErrorAction.RetryRequest;
9911
+ var noAlternate = couldRetry && !errorAction.resolved && flags === ErrorActionFlags.MoveAllAlternatesMatchingHost;
9912
+ if (!retry && noAlternate && isMediaFragment(frag) && !frag.endList) {
9913
+ this.resetFragmentErrors(filterType);
9914
+ this.treatAsGap(frag);
9915
+ errorAction.resolved = true;
9916
+ } else if ((retry || noAlternate) && retryCount < retryConfig.maxNumRetry) {
9900
9917
  this.resetStartWhenNotLoaded(this.levelLastLoaded);
9901
9918
  var delay = getRetryDelay(retryConfig, retryCount);
9902
9919
  this.warn("Fragment " + frag.sn + " of " + filterType + " " + frag.level + " errored with " + data.details + ", retrying loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " in " + delay + "ms");
@@ -9914,7 +9931,7 @@
9914
9931
  this.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
9915
9932
  return;
9916
9933
  }
9917
- } else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
9934
+ } else if (action === NetworkErrorAction.SendAlternateToPenaltyBox) {
9918
9935
  this.state = State.WAITING_LEVEL;
9919
9936
  } else {
9920
9937
  this.state = State.ERROR;
@@ -10050,10 +10067,7 @@
10050
10067
  var error = new Error("Found no media in fragment " + frag.sn + " of level " + frag.level + " resetting transmuxer to fallback to playlist timing");
10051
10068
  if (level.fragmentError === 0) {
10052
10069
  // Mark and track the odd empty segment as a gap to avoid reloading
10053
- level.fragmentError++;
10054
- frag.gap = true;
10055
- this.fragmentTracker.removeFragment(frag);
10056
- this.fragmentTracker.fragBuffered(frag, true);
10070
+ this.treatAsGap(frag, level);
10057
10071
  }
10058
10072
  this.warn(error.message);
10059
10073
  this.hls.trigger(Events.ERROR, {
@@ -10087,6 +10101,14 @@
10087
10101
  }
10088
10102
  return this.playlistLabel() + " " + frag.level + " (" + (part ? 'part' : 'frag') + ":[" + ((_ref3 = pts && !part ? frag.startPTS : (part || frag).start) != null ? _ref3 : NaN).toFixed(3) + "-" + ((_ref4 = pts && !part ? frag.endPTS : (part || frag).end) != null ? _ref4 : NaN).toFixed(3) + "]" + (part && frag.type === 'main' ? 'INDEPENDENT=' + (part.independent ? 'YES' : 'NO') : '');
10089
10103
  };
10104
+ _proto.treatAsGap = function treatAsGap(frag, level) {
10105
+ if (level) {
10106
+ level.fragmentError++;
10107
+ }
10108
+ frag.gap = true;
10109
+ this.fragmentTracker.removeFragment(frag);
10110
+ this.fragmentTracker.fragBuffered(frag, true);
10111
+ };
10090
10112
  _proto.resetTransmuxer = function resetTransmuxer() {
10091
10113
  var _this$transmuxer2;
10092
10114
  (_this$transmuxer2 = this.transmuxer) == null ? void 0 : _this$transmuxer2.reset();
@@ -16217,7 +16239,7 @@
16217
16239
  return !remuxResult.audio && !remuxResult.video && !remuxResult.text && !remuxResult.id3 && !remuxResult.initSegment;
16218
16240
  }
16219
16241
 
16220
- var version = "1.6.0-beta.1.0.canary.10764";
16242
+ var version = "1.6.0-beta.1.0.canary.10766";
16221
16243
 
16222
16244
  // ensure the worker ends up in the bundle
16223
16245
  // If the worker should not be included this gets aliased to empty.js
@@ -16910,7 +16932,7 @@
16910
16932
 
16911
16933
  // Request audio segments up to one fragment ahead of main stream-controller
16912
16934
  var mainFragLoading = (_this$mainFragLoading = this.mainFragLoading) == null ? void 0 : _this$mainFragLoading.frag;
16913
- if (this.startFragRequested && mainFragLoading && mainFragLoading.sn !== 'initSegment' && frag.sn !== 'initSegment' && !frag.endList && (!trackDetails.live || !this.loadingParts && targetBufferTime < this.hls.liveSyncPosition)) {
16935
+ if (this.startFragRequested && mainFragLoading && isMediaFragment(mainFragLoading) && isMediaFragment(frag) && !frag.endList && (!trackDetails.live || !this.loadingParts && targetBufferTime < this.hls.liveSyncPosition)) {
16914
16936
  var mainFrag = mainFragLoading;
16915
16937
  if (frag.start > mainFrag.end) {
16916
16938
  // Get buffered frag at target position from tracker (loaded out of sequence)
@@ -17112,7 +17134,7 @@
17112
17134
  }
17113
17135
  };
17114
17136
  _proto.onFragLoading = function onFragLoading(event, data) {
17115
- if (data.frag.type === PlaylistLevelType.MAIN && data.frag.sn !== 'initSegment') {
17137
+ if (data.frag.type === PlaylistLevelType.MAIN && isMediaFragment(data.frag)) {
17116
17138
  this.mainFragLoading = data;
17117
17139
  if (this.state === State.IDLE) {
17118
17140
  this.tick();
@@ -17131,7 +17153,7 @@
17131
17153
  this.warn("Fragment " + frag.sn + (part ? ' p: ' + part.index : '') + " of level " + frag.level + " finished buffering, but was aborted. state: " + this.state + ", audioSwitch: " + (this.switchingTrack ? this.switchingTrack.name : 'false'));
17132
17154
  return;
17133
17155
  }
17134
- if (frag.sn !== 'initSegment') {
17156
+ if (isMediaFragment(frag)) {
17135
17157
  this.fragPrevious = frag;
17136
17158
  var track = this.switchingTrack;
17137
17159
  if (track) {
@@ -17329,7 +17351,7 @@
17329
17351
  // we force a frag loading in audio switch as fragment tracker might not have evicted previous frags in case of quick audio switch
17330
17352
  if (this.switchingTrack || fragState === FragmentState.NOT_LOADED || fragState === FragmentState.PARTIAL) {
17331
17353
  var _track$details2;
17332
- if (frag.sn === 'initSegment') {
17354
+ if (!isMediaFragment(frag)) {
17333
17355
  this._loadInitSegment(frag, track);
17334
17356
  } else if ((_track$details2 = track.details) != null && _track$details2.live && !this.initPTS[frag.cc]) {
17335
17357
  this.log("Waiting for video PTS in continuity counter " + frag.cc + " of live stream before loading audio fragment " + frag.sn + " of level " + this.trackId);
@@ -17925,7 +17947,8 @@
17925
17947
  url: url,
17926
17948
  id: id,
17927
17949
  groupId: groupId,
17928
- deliveryDirectives: hlsUrlParameters || null
17950
+ deliveryDirectives: hlsUrlParameters || null,
17951
+ track: audioTrack
17929
17952
  });
17930
17953
  }
17931
17954
  };
@@ -25504,7 +25527,7 @@
25504
25527
  _proto.onSubtitleFragProcessed = function onSubtitleFragProcessed(event, data) {
25505
25528
  var frag = data.frag,
25506
25529
  success = data.success;
25507
- if (frag.sn !== 'initSegment') {
25530
+ if (isMediaFragment(frag)) {
25508
25531
  this.fragPrevious = frag;
25509
25532
  }
25510
25533
  this.state = State.IDLE;
@@ -25773,7 +25796,7 @@
25773
25796
  return;
25774
25797
  }
25775
25798
  foundFrag = this.mapToInitFragWhenRequired(foundFrag);
25776
- if (foundFrag.sn !== 'initSegment') {
25799
+ if (isMediaFragment(foundFrag)) {
25777
25800
  // Load earlier fragment in same discontinuity to make up for misaligned playlists and cues that extend beyond end of segment
25778
25801
  var curSNIdx = foundFrag.sn - trackDetails.startSN;
25779
25802
  var prevFrag = fragments[curSNIdx - 1];
@@ -25788,7 +25811,7 @@
25788
25811
  }
25789
25812
  };
25790
25813
  _proto.loadFragment = function loadFragment(frag, level, targetBufferTime) {
25791
- if (frag.sn === 'initSegment') {
25814
+ if (!isMediaFragment(frag)) {
25792
25815
  this._loadInitSegment(frag, level);
25793
25816
  } else {
25794
25817
  _BaseStreamController.prototype.loadFragment.call(this, frag, level, targetBufferTime);
@@ -26290,7 +26313,8 @@
26290
26313
  url: url,
26291
26314
  id: id,
26292
26315
  groupId: groupId,
26293
- deliveryDirectives: hlsUrlParameters || null
26316
+ deliveryDirectives: hlsUrlParameters || null,
26317
+ track: currentTrack
26294
26318
  });
26295
26319
  }
26296
26320
  }
@@ -31264,7 +31288,7 @@
31264
31288
  var _data$deliveryDirecti2;
31265
31289
  var level = data.level,
31266
31290
  details = data.details;
31267
- var curLevel = this._levels[level];
31291
+ var curLevel = data.levelInfo;
31268
31292
  if (!curLevel) {
31269
31293
  var _data$deliveryDirecti;
31270
31294
  this.warn("Invalid level index " + level);
@@ -31275,7 +31299,7 @@
31275
31299
  }
31276
31300
 
31277
31301
  // only process level loaded events matching with expected level
31278
- if (level === this.currentLevelIndex) {
31302
+ if (curLevel === this.currentLevel) {
31279
31303
  // reset level load error counter on successful level loaded only if there is no issues with fragments
31280
31304
  if (curLevel.fragmentError === 0) {
31281
31305
  curLevel.loadError = 0;
@@ -31313,6 +31337,7 @@
31313
31337
  this.hls.trigger(Events.LEVEL_LOADING, {
31314
31338
  url: url,
31315
31339
  level: currentLevelIndex,
31340
+ levelInfo: currentLevel,
31316
31341
  pathwayId: currentLevel.attrs['PATHWAY-ID'],
31317
31342
  id: 0,
31318
31343
  // Deprecated Level urlId
@@ -32148,7 +32173,7 @@
32148
32173
  var targetBufferTime = this.backtrackFragment ? this.backtrackFragment.start : bufferInfo.end;
32149
32174
  var frag = this.getNextFragment(targetBufferTime, levelDetails);
32150
32175
  // Avoid backtracking by loading an earlier segment in streams with segments that do not start with a key frame (flagged by `couldBacktrack`)
32151
- if (this.couldBacktrack && !this.fragPrevious && frag && frag.sn !== 'initSegment' && this.fragmentTracker.getState(frag) !== FragmentState.OK) {
32176
+ if (this.couldBacktrack && !this.fragPrevious && frag && isMediaFragment(frag) && this.fragmentTracker.getState(frag) !== FragmentState.OK) {
32152
32177
  var _this$backtrackFragme;
32153
32178
  var backtrackSn = ((_this$backtrackFragme = this.backtrackFragment) != null ? _this$backtrackFragme : frag).sn;
32154
32179
  var fragIdx = backtrackSn - levelDetails.startSN;
@@ -32185,7 +32210,7 @@
32185
32210
  // Check if fragment is not loaded
32186
32211
  var fragState = this.fragmentTracker.getState(frag);
32187
32212
  if (fragState === FragmentState.NOT_LOADED || fragState === FragmentState.PARTIAL) {
32188
- if (frag.sn === 'initSegment') {
32213
+ if (!isMediaFragment(frag)) {
32189
32214
  this._loadInitSegment(frag, level);
32190
32215
  } else if (this.bitrateTest) {
32191
32216
  this.log("Fragment " + frag.sn + " of level " + frag.level + " is being downloaded to test bitrate and will not be buffered");
@@ -32373,7 +32398,7 @@
32373
32398
  if (!levels || this.state !== State.IDLE) {
32374
32399
  return;
32375
32400
  }
32376
- var level = levels[data.level];
32401
+ var level = data.levelInfo;
32377
32402
  if (!level.details || level.details.live && this.levelLastLoaded !== level || this.waitForCdnTuneIn(level.details)) {
32378
32403
  this.state = State.WAITING_LEVEL;
32379
32404
  }
@@ -32390,7 +32415,7 @@
32390
32415
  return;
32391
32416
  }
32392
32417
  this.log("Level " + newLevelId + " loaded [" + newDetails.startSN + "," + newDetails.endSN + "]" + (newDetails.lastPartSn ? "[part-" + newDetails.lastPartSn + "-" + newDetails.lastPartIndex + "]" : '') + ", cc [" + newDetails.startCC + ", " + newDetails.endCC + "] duration:" + duration);
32393
- var curLevel = levels[newLevelId];
32418
+ var curLevel = data.levelInfo;
32394
32419
  var fragCurrent = this.fragCurrent;
32395
32420
  if (fragCurrent && (this.state === State.FRAG_LOADING || this.state === State.FRAG_LOADING_WAITING_RETRY)) {
32396
32421
  if (fragCurrent.level !== data.level && fragCurrent.loader) {
@@ -32595,7 +32620,7 @@
32595
32620
  }
32596
32621
  var stats = part ? part.stats : frag.stats;
32597
32622
  this.fragLastKbps = Math.round(8 * stats.total / (stats.buffering.end - stats.loading.first));
32598
- if (frag.sn !== 'initSegment') {
32623
+ if (isMediaFragment(frag)) {
32599
32624
  this.fragPrevious = frag;
32600
32625
  }
32601
32626
  this.fragBufferedComplete(frag, part);
@@ -33452,6 +33477,7 @@
33452
33477
  hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
33453
33478
  hls.on(Events.AUDIO_TRACK_LOADING, this.onAudioTrackLoading, this);
33454
33479
  hls.on(Events.SUBTITLE_TRACK_LOADING, this.onSubtitleTrackLoading, this);
33480
+ hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
33455
33481
  };
33456
33482
  _proto.unregisterListeners = function unregisterListeners() {
33457
33483
  var hls = this.hls;
@@ -33459,6 +33485,7 @@
33459
33485
  hls.off(Events.LEVEL_LOADING, this.onLevelLoading, this);
33460
33486
  hls.off(Events.AUDIO_TRACK_LOADING, this.onAudioTrackLoading, this);
33461
33487
  hls.off(Events.SUBTITLE_TRACK_LOADING, this.onSubtitleTrackLoading, this);
33488
+ hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
33462
33489
  }
33463
33490
 
33464
33491
  /**
@@ -33508,7 +33535,8 @@
33508
33535
  responseType: 'text',
33509
33536
  type: PlaylistContextType.MANIFEST,
33510
33537
  url: url,
33511
- deliveryDirectives: null
33538
+ deliveryDirectives: null,
33539
+ levelOrTrack: null
33512
33540
  });
33513
33541
  };
33514
33542
  _proto.onLevelLoading = function onLevelLoading(event, data) {
@@ -33516,7 +33544,8 @@
33516
33544
  level = data.level,
33517
33545
  pathwayId = data.pathwayId,
33518
33546
  url = data.url,
33519
- deliveryDirectives = data.deliveryDirectives;
33547
+ deliveryDirectives = data.deliveryDirectives,
33548
+ levelInfo = data.levelInfo;
33520
33549
  this.load({
33521
33550
  id: id,
33522
33551
  level: level,
@@ -33524,14 +33553,16 @@
33524
33553
  responseType: 'text',
33525
33554
  type: PlaylistContextType.LEVEL,
33526
33555
  url: url,
33527
- deliveryDirectives: deliveryDirectives
33556
+ deliveryDirectives: deliveryDirectives,
33557
+ levelOrTrack: levelInfo
33528
33558
  });
33529
33559
  };
33530
33560
  _proto.onAudioTrackLoading = function onAudioTrackLoading(event, data) {
33531
33561
  var id = data.id,
33532
33562
  groupId = data.groupId,
33533
33563
  url = data.url,
33534
- deliveryDirectives = data.deliveryDirectives;
33564
+ deliveryDirectives = data.deliveryDirectives,
33565
+ track = data.track;
33535
33566
  this.load({
33536
33567
  id: id,
33537
33568
  groupId: groupId,
@@ -33539,14 +33570,16 @@
33539
33570
  responseType: 'text',
33540
33571
  type: PlaylistContextType.AUDIO_TRACK,
33541
33572
  url: url,
33542
- deliveryDirectives: deliveryDirectives
33573
+ deliveryDirectives: deliveryDirectives,
33574
+ levelOrTrack: track
33543
33575
  });
33544
33576
  };
33545
33577
  _proto.onSubtitleTrackLoading = function onSubtitleTrackLoading(event, data) {
33546
33578
  var id = data.id,
33547
33579
  groupId = data.groupId,
33548
33580
  url = data.url,
33549
- deliveryDirectives = data.deliveryDirectives;
33581
+ deliveryDirectives = data.deliveryDirectives,
33582
+ track = data.track;
33550
33583
  this.load({
33551
33584
  id: id,
33552
33585
  groupId: groupId,
@@ -33554,9 +33587,23 @@
33554
33587
  responseType: 'text',
33555
33588
  type: PlaylistContextType.SUBTITLE_TRACK,
33556
33589
  url: url,
33557
- deliveryDirectives: deliveryDirectives
33590
+ deliveryDirectives: deliveryDirectives,
33591
+ levelOrTrack: track
33558
33592
  });
33559
33593
  };
33594
+ _proto.onLevelsUpdated = function onLevelsUpdated(event, data) {
33595
+ // abort and delete loader of removed levels
33596
+ var loader = this.loaders[PlaylistContextType.LEVEL];
33597
+ if (loader) {
33598
+ var context = loader.context;
33599
+ if (context && !data.levels.some(function (lvl) {
33600
+ return lvl === context.levelOrTrack;
33601
+ })) {
33602
+ loader.abort();
33603
+ delete this.loaders[PlaylistContextType.LEVEL];
33604
+ }
33605
+ }
33606
+ };
33560
33607
  _proto.load = function load(context) {
33561
33608
  var _context$deliveryDire,
33562
33609
  _this = this;
@@ -33568,7 +33615,7 @@
33568
33615
  var loader = this.getInternalLoader(context);
33569
33616
  if (loader) {
33570
33617
  var loaderContext = loader.context;
33571
- if (loaderContext && loaderContext.url === context.url && loaderContext.level === context.level) {
33618
+ if (loaderContext && loaderContext.url === context.url && loaderContext.levelOrTrack === context.levelOrTrack) {
33572
33619
  // same URL can't overlap
33573
33620
  this.hls.logger.trace('[playlist-loader]: playlist request ongoing');
33574
33621
  return;
@@ -33889,6 +33936,7 @@
33889
33936
  case PlaylistContextType.LEVEL:
33890
33937
  hls.trigger(Events.LEVEL_LOADED, {
33891
33938
  details: levelDetails,
33939
+ levelInfo: context.levelOrTrack || hls.levels[0],
33892
33940
  level: levelIndex || 0,
33893
33941
  id: id || 0,
33894
33942
  stats: stats,
@@ -33899,6 +33947,7 @@
33899
33947
  case PlaylistContextType.AUDIO_TRACK:
33900
33948
  hls.trigger(Events.AUDIO_TRACK_LOADED, {
33901
33949
  details: levelDetails,
33950
+ track: context.levelOrTrack,
33902
33951
  id: id || 0,
33903
33952
  groupId: groupId || '',
33904
33953
  stats: stats,
@@ -33909,6 +33958,7 @@
33909
33958
  case PlaylistContextType.SUBTITLE_TRACK:
33910
33959
  hls.trigger(Events.SUBTITLE_TRACK_LOADED, {
33911
33960
  details: levelDetails,
33961
+ track: context.levelOrTrack,
33912
33962
  id: id || 0,
33913
33963
  groupId: groupId || '',
33914
33964
  stats: stats,
package/dist/hls.js.d.ts CHANGED
@@ -376,6 +376,7 @@ export declare class BaseStreamController extends TaskLoop implements NetworkCom
376
376
  private updateLevelTiming;
377
377
  private playlistLabel;
378
378
  private fragInfo;
379
+ private treatAsGap;
379
380
  protected resetTransmuxer(): void;
380
381
  protected recoverWorkerError(data: ErrorData): void;
381
382
  set state(nextState: string);
@@ -2606,6 +2607,7 @@ export declare interface LevelLoadedData {
2606
2607
  details: LevelDetails;
2607
2608
  id: number;
2608
2609
  level: number;
2610
+ levelInfo: Level;
2609
2611
  networkDetails: any;
2610
2612
  stats: LoaderStats;
2611
2613
  deliveryDirectives: HlsUrlParameters | null;
@@ -2614,6 +2616,7 @@ export declare interface LevelLoadedData {
2614
2616
  export declare interface LevelLoadingData {
2615
2617
  id: number;
2616
2618
  level: number;
2619
+ levelInfo: Level;
2617
2620
  pathwayId: string | undefined;
2618
2621
  url: string;
2619
2622
  deliveryDirectives: HlsUrlParameters | null;
@@ -3152,6 +3155,7 @@ export declare interface PlaylistLoaderContext extends LoaderContext {
3152
3155
  pathwayId?: string;
3153
3156
  levelDetails?: LevelDetails;
3154
3157
  deliveryDirectives: HlsUrlParameters | null;
3158
+ levelOrTrack: Level | MediaPlaylist | null;
3155
3159
  }
3156
3160
 
3157
3161
  export declare type RationalTimestamp = {
@@ -3654,11 +3658,13 @@ export declare interface TrackLoadedData {
3654
3658
  networkDetails: any;
3655
3659
  stats: LoaderStats;
3656
3660
  deliveryDirectives: HlsUrlParameters | null;
3661
+ track: MediaPlaylist;
3657
3662
  }
3658
3663
 
3659
3664
  export declare interface TrackLoadingData {
3660
3665
  id: number;
3661
3666
  groupId: string;
3667
+ track: MediaPlaylist;
3662
3668
  url: string;
3663
3669
  deliveryDirectives: HlsUrlParameters | null;
3664
3670
  }