hls.js 1.6.0-beta.1.0.canary.10803 → 1.6.0-beta.1.0.canary.10806

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
@@ -235,8 +235,8 @@ export declare type BaseData = {
235
235
 
236
236
  export declare class BasePlaylistController extends Logger implements NetworkComponentAPI {
237
237
  protected hls: Hls;
238
+ protected canLoad: boolean;
238
239
  private timer;
239
- private canLoad;
240
240
  constructor(hls: Hls, logPrefix: string);
241
241
  destroy(): void;
242
242
  private clearTimer;
@@ -248,7 +248,7 @@ export declare class BasePlaylistController extends Logger implements NetworkCom
248
248
  protected shouldLoadPlaylist(playlist: Level | MediaPlaylist | null | undefined): playlist is Level | MediaPlaylist;
249
249
  protected getUrlWithDirectives(uri: string, hlsUrlParameters: HlsUrlParameters | undefined): string;
250
250
  protected playlistLoaded(index: number, data: LevelLoadedData | AudioTrackLoadedData | TrackLoadedData, previousDetails?: LevelDetails): void;
251
- protected scheduleLoading(levelOrTrack: Level | MediaPlaylist, deliveryDirectives?: HlsUrlParameters): void;
251
+ protected scheduleLoading(levelOrTrack: Level | MediaPlaylist, deliveryDirectives?: HlsUrlParameters, updatedDetails?: LevelDetails): void;
252
252
  private getDeliveryDirectives;
253
253
  protected checkRetry(errorEvent: ErrorData): boolean;
254
254
  }
@@ -376,7 +376,7 @@ export declare class BaseStreamController extends TaskLoop implements NetworkCom
376
376
  protected afterBufferFlushed(media: Bufferable, bufferType: SourceBufferName, playlistType: PlaylistLevelType): void;
377
377
  protected resetLoadingState(): void;
378
378
  protected resetStartWhenNotLoaded(level: Level | null): void;
379
- protected resetWhenMissingContext(chunkMeta: ChunkMetadata): void;
379
+ protected resetWhenMissingContext(chunkMeta: ChunkMetadata | Fragment): void;
380
380
  protected removeUnbufferedFrags(start?: number): void;
381
381
  private updateLevelTiming;
382
382
  private playlistLabel;
@@ -1505,8 +1505,9 @@ declare class Hls implements HlsEventEmitter {
1505
1505
  private cmcdController?;
1506
1506
  private _media;
1507
1507
  private _url;
1508
- private triggeringException?;
1509
1508
  private _sessionId?;
1509
+ private triggeringException?;
1510
+ private started;
1510
1511
  /**
1511
1512
  * Get the video-dev/hls.js package version.
1512
1513
  */
@@ -1593,6 +1594,10 @@ declare class Hls implements HlsEventEmitter {
1593
1594
  * Stop loading of any stream data.
1594
1595
  */
1595
1596
  stopLoad(): void;
1597
+ /**
1598
+ * Returns whether loading, toggled with `startLoad()` and `stopLoad()`, is active or not`.
1599
+ */
1600
+ get loadingEnabled(): boolean;
1596
1601
  /**
1597
1602
  * Returns state of fragment loading toggled by calling `pauseBuffering()` and `resumeBuffering()`.
1598
1603
  */
@@ -2306,6 +2311,7 @@ export declare class InterstitialsController extends Logger implements NetworkCo
2306
2311
  private getPrimaryResumption;
2307
2312
  private isAssetBuffered;
2308
2313
  private attachPrimary;
2314
+ private startLoadingPrimaryAt;
2309
2315
  private onManifestLoading;
2310
2316
  private onLevelUpdated;
2311
2317
  private onAudioTrackUpdated;
@@ -2589,6 +2595,7 @@ export declare class LevelDetails {
2589
2595
  get fragmentStart(): number;
2590
2596
  get age(): number;
2591
2597
  get lastPartIndex(): number;
2598
+ get maxPartIndex(): number;
2592
2599
  get lastPartSn(): number;
2593
2600
  get expired(): boolean;
2594
2601
  }
@@ -2618,6 +2625,7 @@ export declare interface LevelLoadedData {
2618
2625
  networkDetails: any;
2619
2626
  stats: LoaderStats;
2620
2627
  deliveryDirectives: HlsUrlParameters | null;
2628
+ withoutMultiVariant?: boolean;
2621
2629
  }
2622
2630
 
2623
2631
  export declare interface LevelLoadingData {
package/dist/hls.d.ts CHANGED
@@ -235,8 +235,8 @@ export declare type BaseData = {
235
235
 
236
236
  export declare class BasePlaylistController extends Logger implements NetworkComponentAPI {
237
237
  protected hls: Hls;
238
+ protected canLoad: boolean;
238
239
  private timer;
239
- private canLoad;
240
240
  constructor(hls: Hls, logPrefix: string);
241
241
  destroy(): void;
242
242
  private clearTimer;
@@ -248,7 +248,7 @@ export declare class BasePlaylistController extends Logger implements NetworkCom
248
248
  protected shouldLoadPlaylist(playlist: Level | MediaPlaylist | null | undefined): playlist is Level | MediaPlaylist;
249
249
  protected getUrlWithDirectives(uri: string, hlsUrlParameters: HlsUrlParameters | undefined): string;
250
250
  protected playlistLoaded(index: number, data: LevelLoadedData | AudioTrackLoadedData | TrackLoadedData, previousDetails?: LevelDetails): void;
251
- protected scheduleLoading(levelOrTrack: Level | MediaPlaylist, deliveryDirectives?: HlsUrlParameters): void;
251
+ protected scheduleLoading(levelOrTrack: Level | MediaPlaylist, deliveryDirectives?: HlsUrlParameters, updatedDetails?: LevelDetails): void;
252
252
  private getDeliveryDirectives;
253
253
  protected checkRetry(errorEvent: ErrorData): boolean;
254
254
  }
@@ -376,7 +376,7 @@ export declare class BaseStreamController extends TaskLoop implements NetworkCom
376
376
  protected afterBufferFlushed(media: Bufferable, bufferType: SourceBufferName, playlistType: PlaylistLevelType): void;
377
377
  protected resetLoadingState(): void;
378
378
  protected resetStartWhenNotLoaded(level: Level | null): void;
379
- protected resetWhenMissingContext(chunkMeta: ChunkMetadata): void;
379
+ protected resetWhenMissingContext(chunkMeta: ChunkMetadata | Fragment): void;
380
380
  protected removeUnbufferedFrags(start?: number): void;
381
381
  private updateLevelTiming;
382
382
  private playlistLabel;
@@ -1505,8 +1505,9 @@ declare class Hls implements HlsEventEmitter {
1505
1505
  private cmcdController?;
1506
1506
  private _media;
1507
1507
  private _url;
1508
- private triggeringException?;
1509
1508
  private _sessionId?;
1509
+ private triggeringException?;
1510
+ private started;
1510
1511
  /**
1511
1512
  * Get the video-dev/hls.js package version.
1512
1513
  */
@@ -1593,6 +1594,10 @@ declare class Hls implements HlsEventEmitter {
1593
1594
  * Stop loading of any stream data.
1594
1595
  */
1595
1596
  stopLoad(): void;
1597
+ /**
1598
+ * Returns whether loading, toggled with `startLoad()` and `stopLoad()`, is active or not`.
1599
+ */
1600
+ get loadingEnabled(): boolean;
1596
1601
  /**
1597
1602
  * Returns state of fragment loading toggled by calling `pauseBuffering()` and `resumeBuffering()`.
1598
1603
  */
@@ -2306,6 +2311,7 @@ export declare class InterstitialsController extends Logger implements NetworkCo
2306
2311
  private getPrimaryResumption;
2307
2312
  private isAssetBuffered;
2308
2313
  private attachPrimary;
2314
+ private startLoadingPrimaryAt;
2309
2315
  private onManifestLoading;
2310
2316
  private onLevelUpdated;
2311
2317
  private onAudioTrackUpdated;
@@ -2589,6 +2595,7 @@ export declare class LevelDetails {
2589
2595
  get fragmentStart(): number;
2590
2596
  get age(): number;
2591
2597
  get lastPartIndex(): number;
2598
+ get maxPartIndex(): number;
2592
2599
  get lastPartSn(): number;
2593
2600
  get expired(): boolean;
2594
2601
  }
@@ -2618,6 +2625,7 @@ export declare interface LevelLoadedData {
2618
2625
  networkDetails: any;
2619
2626
  stats: LoaderStats;
2620
2627
  deliveryDirectives: HlsUrlParameters | null;
2628
+ withoutMultiVariant?: boolean;
2621
2629
  }
2622
2630
 
2623
2631
  export declare interface LevelLoadingData {
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.10803");
1060
+ newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.6.0-beta.1.0.canary.10806");
1061
1061
  } catch (e) {
1062
1062
  /* log fn threw an exception. All logger methods are no-ops. */
1063
1063
  return createLogger();
@@ -2615,7 +2615,7 @@
2615
2615
  var forcedAutoLevel = _this3.forcedAutoLevel;
2616
2616
  if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
2617
2617
  if (levelsSkipped.length) {
2618
- _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);
2618
+ _this3.trace("Skipped level(s) " + levelsSkipped.join(',') + " of " + maxAutoLevel + " max with CODECS and VIDEO-RANGE:\"" + levels[levelsSkipped[0]].codecs + "\" " + levels[levelsSkipped[0]].videoRange + "; not compatible with \"" + currentCodecSet + "\" " + currentVideoRange);
2619
2619
  }
2620
2620
  _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);
2621
2621
  }
@@ -7108,6 +7108,23 @@
7108
7108
  }
7109
7109
  return -1;
7110
7110
  }
7111
+ }, {
7112
+ key: "maxPartIndex",
7113
+ get: function get() {
7114
+ var partList = this.partList;
7115
+ if (partList) {
7116
+ var lastIndex = this.lastPartIndex;
7117
+ if (lastIndex !== -1) {
7118
+ for (var i = partList.length; i--;) {
7119
+ if (partList[i].index > lastIndex) {
7120
+ return partList[i].index;
7121
+ }
7122
+ }
7123
+ return lastIndex;
7124
+ }
7125
+ }
7126
+ return 0;
7127
+ }
7111
7128
  }, {
7112
7129
  key: "lastPartSn",
7113
7130
  get: function get() {
@@ -8586,10 +8603,14 @@
8586
8603
  }
8587
8604
  function reassignFragmentLevelIndexes(levels) {
8588
8605
  levels.forEach(function (level, index) {
8589
- var details = level.details;
8590
- if (details != null && details.fragments) {
8591
- details.fragments.forEach(function (fragment) {
8606
+ var _level$details;
8607
+ var fragments = (_level$details = level.details) == null ? void 0 : _level$details.fragments;
8608
+ if (fragments) {
8609
+ fragments.forEach(function (fragment) {
8592
8610
  fragment.level = index;
8611
+ if (fragment.initSegment) {
8612
+ fragment.initSegment.level = index;
8613
+ }
8593
8614
  });
8594
8615
  }
8595
8616
  });
@@ -16265,7 +16286,7 @@
16265
16286
  return !remuxResult.audio && !remuxResult.video && !remuxResult.text && !remuxResult.id3 && !remuxResult.initSegment;
16266
16287
  }
16267
16288
 
16268
- var version = "1.6.0-beta.1.0.canary.10803";
16289
+ var version = "1.6.0-beta.1.0.canary.10806";
16269
16290
 
16270
16291
  // ensure the worker ends up in the bundle
16271
16292
  // If the worker should not be included this gets aliased to empty.js
@@ -17436,8 +17457,8 @@
17436
17457
  var _this;
17437
17458
  _this = _Logger.call(this, logPrefix, hls.logger) || this;
17438
17459
  _this.hls = void 0;
17439
- _this.timer = -1;
17440
17460
  _this.canLoad = false;
17461
+ _this.timer = -1;
17441
17462
  _this.hls = hls;
17442
17463
  return _this;
17443
17464
  }
@@ -17543,11 +17564,23 @@
17543
17564
  if (details.live || previousDetails != null && previousDetails.live) {
17544
17565
  var levelOrTrack = 'levelInfo' in data ? data.levelInfo : data.track;
17545
17566
  details.reloaded(previousDetails);
17546
- this.log("live playlist " + index + " " + (details.advanced ? 'REFRESHED ' + details.lastPartSn + '-' + details.lastPartIndex : details.updated ? 'UPDATED' : 'MISSED'));
17547
17567
  // Merge live playlists to adjust fragment starts and fill in delta playlist skipped segments
17548
17568
  if (previousDetails && details.fragments.length > 0) {
17549
17569
  mergeDetails(previousDetails, details);
17550
17570
  }
17571
+ if (details.requestScheduled === -1) {
17572
+ details.requestScheduled = stats.loading.start;
17573
+ }
17574
+ var bufferInfo = this.hls.mainForwardBufferInfo;
17575
+ var position = bufferInfo ? bufferInfo.end - bufferInfo.len : 0;
17576
+ var distanceToLiveEdgeMs = (details.edge - position) * 1000;
17577
+ var reloadInterval = computeReloadInterval(details, distanceToLiveEdgeMs);
17578
+ if (details.requestScheduled + reloadInterval < now) {
17579
+ details.requestScheduled = now;
17580
+ } else {
17581
+ details.requestScheduled += reloadInterval;
17582
+ }
17583
+ this.log("live playlist " + index + " " + (details.advanced ? 'REFRESHED ' + details.lastPartSn + '-' + details.lastPartIndex : details.updated ? 'UPDATED' : 'MISSED'));
17551
17584
  if (!this.canLoad || !details.live) {
17552
17585
  return;
17553
17586
  }
@@ -17561,12 +17594,16 @@
17561
17594
  var endSn = details.endSN;
17562
17595
  var lastPartIndex = details.lastPartIndex;
17563
17596
  var hasParts = lastPartIndex !== -1;
17564
- var lastPart = lastPartSn === endSn;
17565
- // When low latency mode is disabled, we'll skip part requests once the last part index is found
17566
- var nextSnStartIndex = lowLatencyMode ? 0 : lastPartIndex;
17597
+ var atLastPartOfSegment = lastPartSn === endSn;
17567
17598
  if (hasParts) {
17568
- msn = lastPart ? endSn + 1 : lastPartSn;
17569
- part = lastPart ? nextSnStartIndex : lastPartIndex + 1;
17599
+ // When low latency mode is disabled, request the last part of the next segment
17600
+ if (atLastPartOfSegment) {
17601
+ msn = endSn + 1;
17602
+ part = lowLatencyMode ? 0 : lastPartIndex;
17603
+ } else {
17604
+ msn = lastPartSn;
17605
+ part = lowLatencyMode ? lastPartIndex + 1 : details.maxPartIndex;
17606
+ }
17570
17607
  } else {
17571
17608
  msn = endSn + 1;
17572
17609
  }
@@ -17598,36 +17635,25 @@
17598
17635
  details.tuneInGoal = currentGoal;
17599
17636
  }
17600
17637
  deliveryDirectives = this.getDeliveryDirectives(details, data.deliveryDirectives, msn, part);
17601
- if (lowLatencyMode || !lastPart) {
17638
+ if (lowLatencyMode || !atLastPartOfSegment) {
17639
+ details.requestScheduled = now;
17602
17640
  this.loadingPlaylist(levelOrTrack, deliveryDirectives);
17603
17641
  return;
17604
17642
  }
17605
17643
  } else if (details.canBlockReload || details.canSkipUntil) {
17606
17644
  deliveryDirectives = this.getDeliveryDirectives(details, data.deliveryDirectives, msn, part);
17607
17645
  }
17608
- if (details.requestScheduled === -1) {
17609
- details.requestScheduled = stats.loading.start;
17610
- }
17611
17646
  if (deliveryDirectives && msn !== undefined && details.canBlockReload) {
17612
- details.requestScheduled -= details.partTarget * 1000 || 1000;
17647
+ details.requestScheduled = stats.loading.first + Math.max(reloadInterval - elapsed * 2, reloadInterval / 2);
17613
17648
  }
17614
- var bufferInfo = this.hls.mainForwardBufferInfo;
17615
- var position = bufferInfo ? bufferInfo.end - bufferInfo.len : 0;
17616
- var distanceToLiveEdgeMs = (details.edge - position) * 1000;
17617
- var reloadInterval = computeReloadInterval(details, distanceToLiveEdgeMs);
17618
- if (details.requestScheduled + reloadInterval < now) {
17619
- details.requestScheduled = now;
17620
- } else {
17621
- details.requestScheduled += reloadInterval;
17622
- }
17623
- this.scheduleLoading(levelOrTrack, deliveryDirectives);
17649
+ this.scheduleLoading(levelOrTrack, deliveryDirectives, details);
17624
17650
  } else {
17625
17651
  this.clearTimer();
17626
17652
  }
17627
17653
  };
17628
- _proto.scheduleLoading = function scheduleLoading(levelOrTrack, deliveryDirectives) {
17654
+ _proto.scheduleLoading = function scheduleLoading(levelOrTrack, deliveryDirectives, updatedDetails) {
17629
17655
  var _this2 = this;
17630
- var details = levelOrTrack.details;
17656
+ var details = updatedDetails || levelOrTrack.details;
17631
17657
  if (!details) {
17632
17658
  this.loadingPlaylist(levelOrTrack, deliveryDirectives);
17633
17659
  return;
@@ -17640,22 +17666,7 @@
17640
17666
  }
17641
17667
  var estimatedTimeUntilUpdate = requestScheduled - now;
17642
17668
  this.log("reload live playlist " + (levelOrTrack.name || levelOrTrack.bitrate + 'bps') + " in " + Math.round(estimatedTimeUntilUpdate) + " ms");
17643
- // this.log(
17644
- // `live reload ${details.updated ? 'REFRESHED' : 'MISSED'}
17645
- // reload in ${estimatedTimeUntilUpdate / 1000}
17646
- // round trip ${(stats.loading.end - stats.loading.start) / 1000}
17647
- // diff ${
17648
- // (reloadInterval -
17649
- // (estimatedTimeUntilUpdate +
17650
- // stats.loading.end -
17651
- // stats.loading.start)) /
17652
- // 1000
17653
- // }
17654
- // reload interval ${reloadInterval / 1000}
17655
- // target duration ${details.targetduration}
17656
- // distance to edge ${distanceToLiveEdgeMs / 1000}`
17657
- // );
17658
-
17669
+ this.clearTimer();
17659
17670
  this.timer = self.setTimeout(function () {
17660
17671
  return _this2.loadingPlaylist(levelOrTrack, deliveryDirectives);
17661
17672
  }, estimatedTimeUntilUpdate);
@@ -17692,6 +17703,7 @@
17692
17703
  } else {
17693
17704
  var delay = getRetryDelay(retryConfig, retryCount);
17694
17705
  // Schedule level/track reload
17706
+ this.clearTimer();
17695
17707
  this.timer = self.setTimeout(function () {
17696
17708
  return _this3.loadPlaylist();
17697
17709
  }, delay);
@@ -24390,7 +24402,7 @@
24390
24402
  (_player$media = _player.media) == null ? void 0 : _player$media.play();
24391
24403
  }
24392
24404
  } else if (scheduledItem !== null) {
24393
- this.resumePrimary(scheduledItem, index);
24405
+ this.resumePrimary(scheduledItem, index, currentItem);
24394
24406
  if (this.shouldPlay) {
24395
24407
  var _this$hls$media;
24396
24408
  (_this$hls$media = this.hls.media) == null ? void 0 : _this$hls$media.play();
@@ -24405,12 +24417,15 @@
24405
24417
  }
24406
24418
  }
24407
24419
  };
24408
- _proto.resumePrimary = function resumePrimary(scheduledItem, index) {
24420
+ _proto.resumePrimary = function resumePrimary(scheduledItem, index, fromItem) {
24409
24421
  var _this$detachedData2;
24410
24422
  this.playingItem = scheduledItem;
24411
24423
  this.playingAsset = null;
24412
24424
  this.waitingItem = null;
24413
24425
  this.bufferedToItem(scheduledItem);
24426
+ if (!fromItem) {
24427
+ return;
24428
+ }
24414
24429
  this.log("resuming " + segmentToString(scheduledItem));
24415
24430
  if (!((_this$detachedData2 = this.detachedData) != null && _this$detachedData2.mediaSource)) {
24416
24431
  var timelinePos = this.timelinePos;
@@ -24468,13 +24483,18 @@
24468
24483
  } else {
24469
24484
  this.transferMediaTo(hls, media);
24470
24485
  if (skipSeekToStartPosition) {
24471
- hls.startLoad(timelinePos, skipSeekToStartPosition);
24486
+ this.startLoadingPrimaryAt(timelinePos, skipSeekToStartPosition);
24472
24487
  }
24473
24488
  }
24474
24489
  if (!skipSeekToStartPosition) {
24475
24490
  // Set primary position to resume time
24476
24491
  this.timelinePos = timelinePos;
24477
- hls.startLoad(timelinePos, skipSeekToStartPosition);
24492
+ this.startLoadingPrimaryAt(timelinePos, skipSeekToStartPosition);
24493
+ }
24494
+ };
24495
+ _proto.startLoadingPrimaryAt = function startLoadingPrimaryAt(timelinePos, skipSeekToStartPosition) {
24496
+ if (this.hls.loadingEnabled) {
24497
+ this.hls.startLoad(timelinePos, skipSeekToStartPosition);
24478
24498
  }
24479
24499
  }
24480
24500
 
@@ -24729,7 +24749,7 @@
24729
24749
  _proto.preloadPrimary = function preloadPrimary(item) {
24730
24750
  var index = this.findItemIndex(item);
24731
24751
  var timelinePos = this.getPrimaryResumption(item, index);
24732
- this.hls.startLoad(timelinePos);
24752
+ this.startLoadingPrimaryAt(timelinePos);
24733
24753
  };
24734
24754
  _proto.bufferedToEvent = function bufferedToEvent(item, assetListIndex) {
24735
24755
  var interstitial = item.event;
@@ -24870,7 +24890,7 @@
24870
24890
  }
24871
24891
  }
24872
24892
  var playerConfig = _objectSpread2(_objectSpread2({}, userConfig), {}, {
24873
- // autoStartLoad: false,
24893
+ autoStartLoad: true,
24874
24894
  startFragPrefetch: true,
24875
24895
  primarySessionId: primary.sessionId,
24876
24896
  assetPlayerId: assetItem.identifier,
@@ -31319,17 +31339,6 @@
31319
31339
  })
31320
31340
  };
31321
31341
  this.hls.trigger(Events.MANIFEST_PARSED, edata);
31322
-
31323
- // Initiate loading after all controllers have received MANIFEST_PARSED
31324
- var _this$hls = this.hls,
31325
- _this$hls$config = _this$hls.config,
31326
- autoStartLoad = _this$hls$config.autoStartLoad,
31327
- startPosition = _this$hls$config.startPosition,
31328
- forceStartLoad = _this$hls.forceStartLoad;
31329
- if (autoStartLoad || forceStartLoad) {
31330
- this.log((autoStartLoad ? 'auto' : 'force') + " startLoad with configured startPosition " + startPosition);
31331
- this.hls.startLoad(startPosition);
31332
- }
31333
31342
  };
31334
31343
  _proto.onError = function onError(event, data) {
31335
31344
  if (data.fatal || !data.context) {
@@ -31372,8 +31381,8 @@
31372
31381
  return;
31373
31382
  }
31374
31383
 
31375
- // only process level loaded events matching with expected level
31376
- if (curLevel === this.currentLevel) {
31384
+ // only process level loaded events matching with expected level or prior to switch when media playlist is loaded directly
31385
+ if (curLevel === this.currentLevel || data.withoutMultiVariant) {
31377
31386
  // reset level load error counter on successful level loaded only if there is no issues with fragments
31378
31387
  if (curLevel.fragmentError === 0) {
31379
31388
  curLevel.loadError = 0;
@@ -31416,6 +31425,9 @@
31416
31425
  _proto.removeLevel = function removeLevel(levelIndex) {
31417
31426
  var _this4 = this,
31418
31427
  _this$currentLevel;
31428
+ if (this._levels.length === 1) {
31429
+ return;
31430
+ }
31419
31431
  var levels = this._levels.filter(function (level, index) {
31420
31432
  if (index !== levelIndex) {
31421
31433
  return true;
@@ -31439,6 +31451,14 @@
31439
31451
  if (this.currentLevelIndex > -1 && (_this$currentLevel = this.currentLevel) != null && _this$currentLevel.details) {
31440
31452
  this.currentLevelIndex = this.currentLevel.details.fragments[0].level;
31441
31453
  }
31454
+ if (this.manualLevelIndex > -1) {
31455
+ this.manualLevelIndex = this.currentLevelIndex;
31456
+ }
31457
+ var maxLevel = levels.length - 1;
31458
+ this._firstLevel = Math.min(this._firstLevel, maxLevel);
31459
+ if (this._startLevel) {
31460
+ this._startLevel = Math.min(this._startLevel, maxLevel);
31461
+ }
31442
31462
  this.hls.trigger(Events.LEVELS_UPDATED, {
31443
31463
  levels: levels
31444
31464
  });
@@ -31448,10 +31468,10 @@
31448
31468
  this._levels = levels;
31449
31469
  };
31450
31470
  _proto.checkMaxAutoUpdated = function checkMaxAutoUpdated() {
31451
- var _this$hls2 = this.hls,
31452
- autoLevelCapping = _this$hls2.autoLevelCapping,
31453
- maxAutoLevel = _this$hls2.maxAutoLevel,
31454
- maxHdcpLevel = _this$hls2.maxHdcpLevel;
31471
+ var _this$hls = this.hls,
31472
+ autoLevelCapping = _this$hls.autoLevelCapping,
31473
+ maxAutoLevel = _this$hls.maxAutoLevel,
31474
+ maxHdcpLevel = _this$hls.maxHdcpLevel;
31455
31475
  if (this._maxAutoLevel !== maxAutoLevel) {
31456
31476
  this._maxAutoLevel = maxAutoLevel;
31457
31477
  this.hls.trigger(Events.MAX_AUTO_LEVEL_UPDATED, {
@@ -32786,6 +32806,9 @@
32786
32806
  _proto.onLevelsUpdated = function onLevelsUpdated(event, data) {
32787
32807
  if (this.level > -1 && this.fragCurrent) {
32788
32808
  this.level = this.fragCurrent.level;
32809
+ if (this.level === -1) {
32810
+ this.resetWhenMissingContext(this.fragCurrent);
32811
+ }
32789
32812
  }
32790
32813
  this.levels = data.levels;
32791
32814
  };
@@ -33686,7 +33709,7 @@
33686
33709
  if (loaderContext && loaderContext.levelOrTrack === context.levelOrTrack && (loaderContext.url === context.url || loaderContext.deliveryDirectives && !context.deliveryDirectives)) {
33687
33710
  // same URL can't overlap, or wait for blocking request
33688
33711
  if (loaderContext.url === context.url) {
33689
- logger.log("[playlist-loader]: playlist request ongoing");
33712
+ logger.log("[playlist-loader]: ignore " + context.url + " ongoing request");
33690
33713
  } else {
33691
33714
  logger.log("[playlist-loader]: ignore " + context.url + " in favor of " + loaderContext.url);
33692
33715
  }
@@ -33752,7 +33775,7 @@
33752
33775
  return;
33753
33776
  }
33754
33777
  stats.parsing.start = performance.now();
33755
- if (M3U8Parser.isMediaPlaylist(string)) {
33778
+ if (M3U8Parser.isMediaPlaylist(string) || context.type !== PlaylistContextType.MANIFEST) {
33756
33779
  _this.handleTrackOrLevelPlaylist(response, stats, context, networkDetails || null, loader);
33757
33780
  } else {
33758
33781
  _this.handleMasterPlaylist(response, stats, context, networkDetails);
@@ -33770,6 +33793,20 @@
33770
33793
 
33771
33794
  loader.load(context, loaderConfig, loaderCallbacks);
33772
33795
  };
33796
+ _proto.checkAutostartLoad = function checkAutostartLoad() {
33797
+ if (!this.hls) {
33798
+ return;
33799
+ }
33800
+ var _this$hls = this.hls,
33801
+ _this$hls$config = _this$hls.config,
33802
+ autoStartLoad = _this$hls$config.autoStartLoad,
33803
+ startPosition = _this$hls$config.startPosition,
33804
+ forceStartLoad = _this$hls.forceStartLoad;
33805
+ if (autoStartLoad || forceStartLoad) {
33806
+ this.hls.logger.log((autoStartLoad ? 'auto' : 'force') + " startLoad with configured startPosition " + startPosition);
33807
+ this.hls.startLoad(startPosition);
33808
+ }
33809
+ };
33773
33810
  _proto.handleMasterPlaylist = function handleMasterPlaylist(response, stats, context, networkDetails) {
33774
33811
  var hls = this.hls;
33775
33812
  var string = response.data;
@@ -33831,6 +33868,7 @@
33831
33868
  startTimeOffset: startTimeOffset,
33832
33869
  variableList: variableList
33833
33870
  });
33871
+ this.checkAutostartLoad();
33834
33872
  };
33835
33873
  _proto.handleTrackOrLevelPlaylist = function handleTrackOrLevelPlaylist(response, stats, context, networkDetails, loader) {
33836
33874
  var hls = this.hls;
@@ -33874,6 +33912,9 @@
33874
33912
  // extend the context with the new levelDetails property
33875
33913
  context.levelDetails = levelDetails;
33876
33914
  this.handlePlaylistLoaded(levelDetails, response, stats, context, networkDetails, loader);
33915
+ if (type === PlaylistContextType.MANIFEST && (!levelDetails.playlistParsingError || !levelDetails.fragments.length && levelDetails.live)) {
33916
+ this.checkAutostartLoad();
33917
+ }
33877
33918
  };
33878
33919
  _proto.handleManifestParsingError = function handleManifestParsingError(response, context, error, networkDetails, stats) {
33879
33920
  this.hls.trigger(Events.ERROR, {
@@ -33957,7 +33998,7 @@
33957
33998
  var parent = mapContextToLevelType(context);
33958
33999
  var levelIndex = typeof context.level === 'number' && parent === PlaylistLevelType.MAIN ? level : undefined;
33959
34000
  if (!levelDetails.fragments.length) {
33960
- var _error = new Error('No Segments found in Playlist');
34001
+ var _error = levelDetails.playlistParsingError = new Error('No Segments found in Playlist');
33961
34002
  hls.trigger(Events.ERROR, {
33962
34003
  type: ErrorTypes.NETWORK_ERROR,
33963
34004
  details: ErrorDetails.LEVEL_EMPTY_ERROR,
@@ -34013,7 +34054,8 @@
34013
34054
  id: id || 0,
34014
34055
  stats: stats,
34015
34056
  networkDetails: networkDetails,
34016
- deliveryDirectives: deliveryDirectives
34057
+ deliveryDirectives: deliveryDirectives,
34058
+ withoutMultiVariant: type === PlaylistContextType.MANIFEST
34017
34059
  });
34018
34060
  break;
34019
34061
  case PlaylistContextType.AUDIO_TRACK:
@@ -34086,8 +34128,9 @@
34086
34128
  this.cmcdController = void 0;
34087
34129
  this._media = null;
34088
34130
  this._url = null;
34089
- this.triggeringException = void 0;
34090
34131
  this._sessionId = void 0;
34132
+ this.triggeringException = void 0;
34133
+ this.started = false;
34091
34134
  var logger = this.logger = enableLogs(userConfig.debug || false, 'Hls instance', userConfig.assetPlayerId);
34092
34135
  var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
34093
34136
  this.userConfig = userConfig;
@@ -34360,10 +34403,14 @@
34360
34403
  startPosition = -1;
34361
34404
  }
34362
34405
  this.logger.log("startLoad(" + (startPosition + (skipSeekToStartPosition ? ', <skip seek to start>' : '')) + ")");
34406
+ this.started = true;
34363
34407
  this.resumeBuffering();
34364
- this.networkControllers.forEach(function (controller) {
34365
- controller.startLoad(startPosition, skipSeekToStartPosition);
34366
- });
34408
+ for (var i = 0; i < this.networkControllers.length; i++) {
34409
+ this.networkControllers[i].startLoad(startPosition, skipSeekToStartPosition);
34410
+ if (!this.started || !this.networkControllers) {
34411
+ break;
34412
+ }
34413
+ }
34367
34414
  }
34368
34415
 
34369
34416
  /**
@@ -34371,13 +34418,17 @@
34371
34418
  */;
34372
34419
  _proto.stopLoad = function stopLoad() {
34373
34420
  this.logger.log('stopLoad');
34374
- this.networkControllers.forEach(function (controller) {
34375
- controller.stopLoad();
34376
- });
34421
+ this.started = false;
34422
+ for (var i = 0; i < this.networkControllers.length; i++) {
34423
+ this.networkControllers[i].stopLoad();
34424
+ if (this.started || !this.networkControllers) {
34425
+ break;
34426
+ }
34427
+ }
34377
34428
  }
34378
34429
 
34379
34430
  /**
34380
- * Returns state of fragment loading toggled by calling `pauseBuffering()` and `resumeBuffering()`.
34431
+ * Returns whether loading, toggled with `startLoad()` and `stopLoad()`, is active or not`.
34381
34432
  */;
34382
34433
  /**
34383
34434
  * Resumes stream controller segment loading after `pauseBuffering` has been called.
@@ -34494,6 +34545,15 @@
34494
34545
  get: function get() {
34495
34546
  return this.streamController.startPositionValue;
34496
34547
  }
34548
+ }, {
34549
+ key: "loadingEnabled",
34550
+ get: function get() {
34551
+ return this.started;
34552
+ }
34553
+
34554
+ /**
34555
+ * Returns state of fragment loading toggled by calling `pauseBuffering()` and `resumeBuffering()`.
34556
+ */
34497
34557
  }, {
34498
34558
  key: "bufferingEnabled",
34499
34559
  get: function get() {