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.mjs CHANGED
@@ -400,7 +400,7 @@ function enableLogs(debugConfig, context, id) {
400
400
  // Some browsers don't allow to use bind on console object anyway
401
401
  // fallback to default if needed
402
402
  try {
403
- newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.0-beta.1.0.canary.10764"}`);
403
+ newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.0-beta.1.0.canary.10766"}`);
404
404
  } catch (e) {
405
405
  /* log fn threw an exception. All logger methods are no-ops. */
406
406
  return createLogger();
@@ -1884,8 +1884,10 @@ class AbrController extends Logger {
1884
1884
  continue;
1885
1885
  }
1886
1886
  if (config.useMediaCapabilities && !levelInfo.supportedResult && !levelInfo.supportedPromise) {
1887
+ var _levelInfo$videoCodec;
1887
1888
  const mediaCapabilities = navigator.mediaCapabilities;
1888
- if (typeof (mediaCapabilities == null ? void 0 : mediaCapabilities.decodingInfo) === 'function' && requiresMediaCapabilitiesDecodingInfo(levelInfo, audioTracksByGroup, currentVideoRange, currentFrameRate, currentBw, audioPreference)) {
1889
+ 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
1890
+ ) {
1889
1891
  levelInfo.supportedPromise = getMediaDecodingInfoPromise(levelInfo, audioTracksByGroup, mediaCapabilities);
1890
1892
  levelInfo.supportedPromise.then(decodingInfo => {
1891
1893
  if (!this.hls) {
@@ -1901,6 +1903,9 @@ class AbrController extends Logger {
1901
1903
  if (index > -1 && levels.length > 1) {
1902
1904
  this.log(`Removing unsupported level ${index}`);
1903
1905
  this.hls.removeLevel(index);
1906
+ if (this.hls.loadLevel === -1) {
1907
+ this.hls.nextLoadLevel = 0;
1908
+ }
1904
1909
  }
1905
1910
  }
1906
1911
  });
@@ -3724,6 +3729,10 @@ class BaseSegment {
3724
3729
  elementaryStreams[ElementaryStreamTypes.AUDIOVIDEO] = null;
3725
3730
  }
3726
3731
  }
3732
+ function isMediaFragment(frag) {
3733
+ return frag.sn !== 'initSegment';
3734
+ }
3735
+
3727
3736
  /**
3728
3737
  * Object representing parsed data from an HLS Segment. Found in {@link hls.js#LevelDetails.fragments}.
3729
3738
  */
@@ -3877,7 +3886,7 @@ class Fragment extends BaseSegment {
3877
3886
  this._programDateTime = value;
3878
3887
  }
3879
3888
  get ref() {
3880
- if (this.sn === 'initSegment') {
3889
+ if (!isMediaFragment(this)) {
3881
3890
  return null;
3882
3891
  }
3883
3892
  if (!this._ref) {
@@ -8461,7 +8470,7 @@ class BaseStreamController extends TaskLoop {
8461
8470
  fragBufferedComplete(frag, part) {
8462
8471
  const media = this.mediaBuffer ? this.mediaBuffer : this.media;
8463
8472
  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)'})`);
8464
- if (frag.sn !== 'initSegment') {
8473
+ if (isMediaFragment(frag)) {
8465
8474
  var _this$levels;
8466
8475
  if (frag.type !== PlaylistLevelType.SUBTITLE) {
8467
8476
  const el = frag.elementaryStreams;
@@ -8530,7 +8539,7 @@ class BaseStreamController extends TaskLoop {
8530
8539
  this.keyLoader.loadClear(frag, details.encryptedFragments);
8531
8540
  }
8532
8541
  const fragPrevious = this.fragPrevious;
8533
- if (frag.sn !== 'initSegment' && (!fragPrevious || frag.sn !== fragPrevious.sn)) {
8542
+ if (isMediaFragment(frag) && (!fragPrevious || frag.sn !== fragPrevious.sn)) {
8534
8543
  const shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
8535
8544
  if (shouldLoadParts !== this.loadingParts) {
8536
8545
  this.log(`LL-Part loading ${shouldLoadParts ? 'ON' : 'OFF'} loading sn ${fragPrevious == null ? void 0 : fragPrevious.sn}->${frag.sn}`);
@@ -8538,7 +8547,7 @@ class BaseStreamController extends TaskLoop {
8538
8547
  }
8539
8548
  }
8540
8549
  targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
8541
- if (this.loadingParts && frag.sn !== 'initSegment') {
8550
+ if (this.loadingParts && isMediaFragment(frag)) {
8542
8551
  const partList = details.partList;
8543
8552
  if (partList && progressCallback) {
8544
8553
  if (targetBufferTime > frag.end && details.fragmentHint) {
@@ -8577,7 +8586,7 @@ class BaseStreamController extends TaskLoop {
8577
8586
  }
8578
8587
  }
8579
8588
  }
8580
- if (frag.sn !== 'initSegment' && this.loadingParts) {
8589
+ if (isMediaFragment(frag) && this.loadingParts) {
8581
8590
  this.log(`LL-Part loading OFF after next part miss @${targetBufferTime.toFixed(2)}`);
8582
8591
  this.loadingParts = false;
8583
8592
  } else if (!frag.url) {
@@ -9136,7 +9145,7 @@ class BaseStreamController extends TaskLoop {
9136
9145
  return pos;
9137
9146
  }
9138
9147
  handleFragLoadAborted(frag, part) {
9139
- if (this.transmuxer && frag.sn !== 'initSegment' && frag.stats.aborted) {
9148
+ if (this.transmuxer && isMediaFragment(frag) && frag.stats.aborted) {
9140
9149
  this.warn(`Fragment ${frag.sn}${part ? ' part ' + part.index : ''} of level ${frag.level} was aborted`);
9141
9150
  this.resetFragmentLoading(frag);
9142
9151
  }
@@ -9171,10 +9180,18 @@ class BaseStreamController extends TaskLoop {
9171
9180
  const errorAction = data.errorAction;
9172
9181
  const {
9173
9182
  action,
9183
+ flags,
9174
9184
  retryCount = 0,
9175
9185
  retryConfig
9176
9186
  } = errorAction || {};
9177
- if (errorAction && action === NetworkErrorAction.RetryRequest && retryConfig) {
9187
+ const couldRetry = !!errorAction && !!retryConfig;
9188
+ const retry = couldRetry && action === NetworkErrorAction.RetryRequest;
9189
+ const noAlternate = couldRetry && !errorAction.resolved && flags === ErrorActionFlags.MoveAllAlternatesMatchingHost;
9190
+ if (!retry && noAlternate && isMediaFragment(frag) && !frag.endList) {
9191
+ this.resetFragmentErrors(filterType);
9192
+ this.treatAsGap(frag);
9193
+ errorAction.resolved = true;
9194
+ } else if ((retry || noAlternate) && retryCount < retryConfig.maxNumRetry) {
9178
9195
  this.resetStartWhenNotLoaded(this.levelLastLoaded);
9179
9196
  const delay = getRetryDelay(retryConfig, retryCount);
9180
9197
  this.warn(`Fragment ${frag.sn} of ${filterType} ${frag.level} errored with ${data.details}, retrying loading ${retryCount + 1}/${retryConfig.maxNumRetry} in ${delay}ms`);
@@ -9192,7 +9209,7 @@ class BaseStreamController extends TaskLoop {
9192
9209
  this.warn(`${data.details} reached or exceeded max retry (${retryCount})`);
9193
9210
  return;
9194
9211
  }
9195
- } else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
9212
+ } else if (action === NetworkErrorAction.SendAlternateToPenaltyBox) {
9196
9213
  this.state = State.WAITING_LEVEL;
9197
9214
  } else {
9198
9215
  this.state = State.ERROR;
@@ -9324,10 +9341,7 @@ class BaseStreamController extends TaskLoop {
9324
9341
  const error = new Error(`Found no media in fragment ${frag.sn} of level ${frag.level} resetting transmuxer to fallback to playlist timing`);
9325
9342
  if (level.fragmentError === 0) {
9326
9343
  // Mark and track the odd empty segment as a gap to avoid reloading
9327
- level.fragmentError++;
9328
- frag.gap = true;
9329
- this.fragmentTracker.removeFragment(frag);
9330
- this.fragmentTracker.fragBuffered(frag, true);
9344
+ this.treatAsGap(frag, level);
9331
9345
  }
9332
9346
  this.warn(error.message);
9333
9347
  this.hls.trigger(Events.ERROR, {
@@ -9358,6 +9372,14 @@ class BaseStreamController extends TaskLoop {
9358
9372
  var _ref, _ref2;
9359
9373
  return `${this.playlistLabel()} ${frag.level} (${part ? 'part' : 'frag'}:[${((_ref = pts && !part ? frag.startPTS : (part || frag).start) != null ? _ref : NaN).toFixed(3)}-${((_ref2 = pts && !part ? frag.endPTS : (part || frag).end) != null ? _ref2 : NaN).toFixed(3)}]${part && frag.type === 'main' ? 'INDEPENDENT=' + (part.independent ? 'YES' : 'NO') : ''}`;
9360
9374
  }
9375
+ treatAsGap(frag, level) {
9376
+ if (level) {
9377
+ level.fragmentError++;
9378
+ }
9379
+ frag.gap = true;
9380
+ this.fragmentTracker.removeFragment(frag);
9381
+ this.fragmentTracker.fragBuffered(frag, true);
9382
+ }
9361
9383
  resetTransmuxer() {
9362
9384
  var _this$transmuxer2;
9363
9385
  (_this$transmuxer2 = this.transmuxer) == null ? void 0 : _this$transmuxer2.reset();
@@ -9769,7 +9791,7 @@ var eventemitter3 = {exports: {}};
9769
9791
  var eventemitter3Exports = eventemitter3.exports;
9770
9792
  var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
9771
9793
 
9772
- const version = "1.6.0-beta.1.0.canary.10764";
9794
+ const version = "1.6.0-beta.1.0.canary.10766";
9773
9795
 
9774
9796
  // ensure the worker ends up in the bundle
9775
9797
  // If the worker should not be included this gets aliased to empty.js
@@ -16332,7 +16354,7 @@ class AudioStreamController extends BaseStreamController {
16332
16354
 
16333
16355
  // Request audio segments up to one fragment ahead of main stream-controller
16334
16356
  const mainFragLoading = (_this$mainFragLoading = this.mainFragLoading) == null ? void 0 : _this$mainFragLoading.frag;
16335
- if (this.startFragRequested && mainFragLoading && mainFragLoading.sn !== 'initSegment' && frag.sn !== 'initSegment' && !frag.endList && (!trackDetails.live || !this.loadingParts && targetBufferTime < this.hls.liveSyncPosition)) {
16357
+ if (this.startFragRequested && mainFragLoading && isMediaFragment(mainFragLoading) && isMediaFragment(frag) && !frag.endList && (!trackDetails.live || !this.loadingParts && targetBufferTime < this.hls.liveSyncPosition)) {
16336
16358
  let mainFrag = mainFragLoading;
16337
16359
  if (frag.start > mainFrag.end) {
16338
16360
  // Get buffered frag at target position from tracker (loaded out of sequence)
@@ -16544,7 +16566,7 @@ class AudioStreamController extends BaseStreamController {
16544
16566
  }
16545
16567
  }
16546
16568
  onFragLoading(event, data) {
16547
- if (data.frag.type === PlaylistLevelType.MAIN && data.frag.sn !== 'initSegment') {
16569
+ if (data.frag.type === PlaylistLevelType.MAIN && isMediaFragment(data.frag)) {
16548
16570
  this.mainFragLoading = data;
16549
16571
  if (this.state === State.IDLE) {
16550
16572
  this.tick();
@@ -16565,7 +16587,7 @@ class AudioStreamController extends BaseStreamController {
16565
16587
  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'}`);
16566
16588
  return;
16567
16589
  }
16568
- if (frag.sn !== 'initSegment') {
16590
+ if (isMediaFragment(frag)) {
16569
16591
  this.fragPrevious = frag;
16570
16592
  const track = this.switchingTrack;
16571
16593
  if (track) {
@@ -16777,7 +16799,7 @@ class AudioStreamController extends BaseStreamController {
16777
16799
  // we force a frag loading in audio switch as fragment tracker might not have evicted previous frags in case of quick audio switch
16778
16800
  if (this.switchingTrack || fragState === FragmentState.NOT_LOADED || fragState === FragmentState.PARTIAL) {
16779
16801
  var _track$details2;
16780
- if (frag.sn === 'initSegment') {
16802
+ if (!isMediaFragment(frag)) {
16781
16803
  this._loadInitSegment(frag, track);
16782
16804
  } else if ((_track$details2 = track.details) != null && _track$details2.live && !this.initPTS[frag.cc]) {
16783
16805
  this.log(`Waiting for video PTS in continuity counter ${frag.cc} of live stream before loading audio fragment ${frag.sn} of level ${this.trackId}`);
@@ -17379,7 +17401,8 @@ class AudioTrackController extends BasePlaylistController {
17379
17401
  url,
17380
17402
  id,
17381
17403
  groupId,
17382
- deliveryDirectives: hlsUrlParameters || null
17404
+ deliveryDirectives: hlsUrlParameters || null,
17405
+ track: audioTrack
17383
17406
  });
17384
17407
  }
17385
17408
  }
@@ -22420,7 +22443,8 @@ class SubtitleTrackController extends BasePlaylistController {
22420
22443
  url,
22421
22444
  id,
22422
22445
  groupId,
22423
- deliveryDirectives: hlsUrlParameters || null
22446
+ deliveryDirectives: hlsUrlParameters || null,
22447
+ track: currentTrack
22424
22448
  });
22425
22449
  }
22426
22450
  }
@@ -25260,7 +25284,7 @@ class SubtitleStreamController extends BaseStreamController {
25260
25284
  frag,
25261
25285
  success
25262
25286
  } = data;
25263
- if (frag.sn !== 'initSegment') {
25287
+ if (isMediaFragment(frag)) {
25264
25288
  this.fragPrevious = frag;
25265
25289
  }
25266
25290
  this.state = State.IDLE;
@@ -25537,7 +25561,7 @@ class SubtitleStreamController extends BaseStreamController {
25537
25561
  return;
25538
25562
  }
25539
25563
  foundFrag = this.mapToInitFragWhenRequired(foundFrag);
25540
- if (foundFrag.sn !== 'initSegment') {
25564
+ if (isMediaFragment(foundFrag)) {
25541
25565
  // Load earlier fragment in same discontinuity to make up for misaligned playlists and cues that extend beyond end of segment
25542
25566
  const curSNIdx = foundFrag.sn - trackDetails.startSN;
25543
25567
  const prevFrag = fragments[curSNIdx - 1];
@@ -25552,7 +25576,7 @@ class SubtitleStreamController extends BaseStreamController {
25552
25576
  }
25553
25577
  }
25554
25578
  loadFragment(frag, level, targetBufferTime) {
25555
- if (frag.sn === 'initSegment') {
25579
+ if (!isMediaFragment(frag)) {
25556
25580
  this._loadInitSegment(frag, level);
25557
25581
  } else {
25558
25582
  super.loadFragment(frag, level, targetBufferTime);
@@ -30495,7 +30519,7 @@ class LevelController extends BasePlaylistController {
30495
30519
  level,
30496
30520
  details
30497
30521
  } = data;
30498
- const curLevel = this._levels[level];
30522
+ const curLevel = data.levelInfo;
30499
30523
  if (!curLevel) {
30500
30524
  var _data$deliveryDirecti;
30501
30525
  this.warn(`Invalid level index ${level}`);
@@ -30506,7 +30530,7 @@ class LevelController extends BasePlaylistController {
30506
30530
  }
30507
30531
 
30508
30532
  // only process level loaded events matching with expected level
30509
- if (level === this.currentLevelIndex) {
30533
+ if (curLevel === this.currentLevel) {
30510
30534
  // reset level load error counter on successful level loaded only if there is no issues with fragments
30511
30535
  if (curLevel.fragmentError === 0) {
30512
30536
  curLevel.loadError = 0;
@@ -30544,6 +30568,7 @@ class LevelController extends BasePlaylistController {
30544
30568
  this.hls.trigger(Events.LEVEL_LOADING, {
30545
30569
  url,
30546
30570
  level: currentLevelIndex,
30571
+ levelInfo: currentLevel,
30547
30572
  pathwayId: currentLevel.attrs['PATHWAY-ID'],
30548
30573
  id: 0,
30549
30574
  // Deprecated Level urlId
@@ -31246,7 +31271,7 @@ class StreamController extends BaseStreamController {
31246
31271
  const targetBufferTime = this.backtrackFragment ? this.backtrackFragment.start : bufferInfo.end;
31247
31272
  let frag = this.getNextFragment(targetBufferTime, levelDetails);
31248
31273
  // Avoid backtracking by loading an earlier segment in streams with segments that do not start with a key frame (flagged by `couldBacktrack`)
31249
- if (this.couldBacktrack && !this.fragPrevious && frag && frag.sn !== 'initSegment' && this.fragmentTracker.getState(frag) !== FragmentState.OK) {
31274
+ if (this.couldBacktrack && !this.fragPrevious && frag && isMediaFragment(frag) && this.fragmentTracker.getState(frag) !== FragmentState.OK) {
31250
31275
  var _this$backtrackFragme;
31251
31276
  const backtrackSn = ((_this$backtrackFragme = this.backtrackFragment) != null ? _this$backtrackFragme : frag).sn;
31252
31277
  const fragIdx = backtrackSn - levelDetails.startSN;
@@ -31283,7 +31308,7 @@ class StreamController extends BaseStreamController {
31283
31308
  // Check if fragment is not loaded
31284
31309
  const fragState = this.fragmentTracker.getState(frag);
31285
31310
  if (fragState === FragmentState.NOT_LOADED || fragState === FragmentState.PARTIAL) {
31286
- if (frag.sn === 'initSegment') {
31311
+ if (!isMediaFragment(frag)) {
31287
31312
  this._loadInitSegment(frag, level);
31288
31313
  } else if (this.bitrateTest) {
31289
31314
  this.log(`Fragment ${frag.sn} of level ${frag.level} is being downloaded to test bitrate and will not be buffered`);
@@ -31477,7 +31502,7 @@ class StreamController extends BaseStreamController {
31477
31502
  if (!levels || this.state !== State.IDLE) {
31478
31503
  return;
31479
31504
  }
31480
- const level = levels[data.level];
31505
+ const level = data.levelInfo;
31481
31506
  if (!level.details || level.details.live && this.levelLastLoaded !== level || this.waitForCdnTuneIn(level.details)) {
31482
31507
  this.state = State.WAITING_LEVEL;
31483
31508
  }
@@ -31496,7 +31521,7 @@ class StreamController extends BaseStreamController {
31496
31521
  return;
31497
31522
  }
31498
31523
  this.log(`Level ${newLevelId} loaded [${newDetails.startSN},${newDetails.endSN}]${newDetails.lastPartSn ? `[part-${newDetails.lastPartSn}-${newDetails.lastPartIndex}]` : ''}, cc [${newDetails.startCC}, ${newDetails.endCC}] duration:${duration}`);
31499
- const curLevel = levels[newLevelId];
31524
+ const curLevel = data.levelInfo;
31500
31525
  const fragCurrent = this.fragCurrent;
31501
31526
  if (fragCurrent && (this.state === State.FRAG_LOADING || this.state === State.FRAG_LOADING_WAITING_RETRY)) {
31502
31527
  if (fragCurrent.level !== data.level && fragCurrent.loader) {
@@ -31709,7 +31734,7 @@ class StreamController extends BaseStreamController {
31709
31734
  }
31710
31735
  const stats = part ? part.stats : frag.stats;
31711
31736
  this.fragLastKbps = Math.round(8 * stats.total / (stats.buffering.end - stats.loading.first));
31712
- if (frag.sn !== 'initSegment') {
31737
+ if (isMediaFragment(frag)) {
31713
31738
  this.fragPrevious = frag;
31714
31739
  }
31715
31740
  this.fragBufferedComplete(frag, part);
@@ -32569,6 +32594,7 @@ class PlaylistLoader {
32569
32594
  hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
32570
32595
  hls.on(Events.AUDIO_TRACK_LOADING, this.onAudioTrackLoading, this);
32571
32596
  hls.on(Events.SUBTITLE_TRACK_LOADING, this.onSubtitleTrackLoading, this);
32597
+ hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
32572
32598
  }
32573
32599
  unregisterListeners() {
32574
32600
  const {
@@ -32578,6 +32604,7 @@ class PlaylistLoader {
32578
32604
  hls.off(Events.LEVEL_LOADING, this.onLevelLoading, this);
32579
32605
  hls.off(Events.AUDIO_TRACK_LOADING, this.onAudioTrackLoading, this);
32580
32606
  hls.off(Events.SUBTITLE_TRACK_LOADING, this.onSubtitleTrackLoading, this);
32607
+ hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
32581
32608
  }
32582
32609
 
32583
32610
  /**
@@ -32629,7 +32656,8 @@ class PlaylistLoader {
32629
32656
  responseType: 'text',
32630
32657
  type: PlaylistContextType.MANIFEST,
32631
32658
  url,
32632
- deliveryDirectives: null
32659
+ deliveryDirectives: null,
32660
+ levelOrTrack: null
32633
32661
  });
32634
32662
  }
32635
32663
  onLevelLoading(event, data) {
@@ -32638,7 +32666,8 @@ class PlaylistLoader {
32638
32666
  level,
32639
32667
  pathwayId,
32640
32668
  url,
32641
- deliveryDirectives
32669
+ deliveryDirectives,
32670
+ levelInfo
32642
32671
  } = data;
32643
32672
  this.load({
32644
32673
  id,
@@ -32647,7 +32676,8 @@ class PlaylistLoader {
32647
32676
  responseType: 'text',
32648
32677
  type: PlaylistContextType.LEVEL,
32649
32678
  url,
32650
- deliveryDirectives
32679
+ deliveryDirectives,
32680
+ levelOrTrack: levelInfo
32651
32681
  });
32652
32682
  }
32653
32683
  onAudioTrackLoading(event, data) {
@@ -32655,7 +32685,8 @@ class PlaylistLoader {
32655
32685
  id,
32656
32686
  groupId,
32657
32687
  url,
32658
- deliveryDirectives
32688
+ deliveryDirectives,
32689
+ track
32659
32690
  } = data;
32660
32691
  this.load({
32661
32692
  id,
@@ -32664,7 +32695,8 @@ class PlaylistLoader {
32664
32695
  responseType: 'text',
32665
32696
  type: PlaylistContextType.AUDIO_TRACK,
32666
32697
  url,
32667
- deliveryDirectives
32698
+ deliveryDirectives,
32699
+ levelOrTrack: track
32668
32700
  });
32669
32701
  }
32670
32702
  onSubtitleTrackLoading(event, data) {
@@ -32672,7 +32704,8 @@ class PlaylistLoader {
32672
32704
  id,
32673
32705
  groupId,
32674
32706
  url,
32675
- deliveryDirectives
32707
+ deliveryDirectives,
32708
+ track
32676
32709
  } = data;
32677
32710
  this.load({
32678
32711
  id,
@@ -32681,9 +32714,21 @@ class PlaylistLoader {
32681
32714
  responseType: 'text',
32682
32715
  type: PlaylistContextType.SUBTITLE_TRACK,
32683
32716
  url,
32684
- deliveryDirectives
32717
+ deliveryDirectives,
32718
+ levelOrTrack: track
32685
32719
  });
32686
32720
  }
32721
+ onLevelsUpdated(event, data) {
32722
+ // abort and delete loader of removed levels
32723
+ const loader = this.loaders[PlaylistContextType.LEVEL];
32724
+ if (loader) {
32725
+ const context = loader.context;
32726
+ if (context && !data.levels.some(lvl => lvl === context.levelOrTrack)) {
32727
+ loader.abort();
32728
+ delete this.loaders[PlaylistContextType.LEVEL];
32729
+ }
32730
+ }
32731
+ }
32687
32732
  load(context) {
32688
32733
  var _context$deliveryDire;
32689
32734
  const config = this.hls.config;
@@ -32694,7 +32739,7 @@ class PlaylistLoader {
32694
32739
  let loader = this.getInternalLoader(context);
32695
32740
  if (loader) {
32696
32741
  const loaderContext = loader.context;
32697
- if (loaderContext && loaderContext.url === context.url && loaderContext.level === context.level) {
32742
+ if (loaderContext && loaderContext.url === context.url && loaderContext.levelOrTrack === context.levelOrTrack) {
32698
32743
  // same URL can't overlap
32699
32744
  this.hls.logger.trace('[playlist-loader]: playlist request ongoing');
32700
32745
  return;
@@ -33016,6 +33061,7 @@ class PlaylistLoader {
33016
33061
  case PlaylistContextType.LEVEL:
33017
33062
  hls.trigger(Events.LEVEL_LOADED, {
33018
33063
  details: levelDetails,
33064
+ levelInfo: context.levelOrTrack || hls.levels[0],
33019
33065
  level: levelIndex || 0,
33020
33066
  id: id || 0,
33021
33067
  stats,
@@ -33026,6 +33072,7 @@ class PlaylistLoader {
33026
33072
  case PlaylistContextType.AUDIO_TRACK:
33027
33073
  hls.trigger(Events.AUDIO_TRACK_LOADED, {
33028
33074
  details: levelDetails,
33075
+ track: context.levelOrTrack,
33029
33076
  id: id || 0,
33030
33077
  groupId: groupId || '',
33031
33078
  stats,
@@ -33036,6 +33083,7 @@ class PlaylistLoader {
33036
33083
  case PlaylistContextType.SUBTITLE_TRACK:
33037
33084
  hls.trigger(Events.SUBTITLE_TRACK_LOADED, {
33038
33085
  details: levelDetails,
33086
+ track: context.levelOrTrack,
33039
33087
  id: id || 0,
33040
33088
  groupId: groupId || '',
33041
33089
  stats,