hls.js 1.6.0-beta.1.0.canary.10712 → 1.6.0-beta.1.0.canary.10715

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.
@@ -296,15 +296,18 @@ class AbrController extends Logger implements AbrComponentAPI {
296
296
  ? (stats.loaded * 1000) / timeStreaming
297
297
  : 0;
298
298
  // fragLoadDelay is an estimate of the time (in seconds) it will take to buffer the remainder of the fragment
299
+ const ttfbSeconds = ttfbEstimate / 1000;
299
300
  const fragLoadedDelay = loadRate
300
301
  ? (expectedLen - stats.loaded) / loadRate
301
- : (expectedLen * 8) / bwEstimate + ttfbEstimate / 1000;
302
+ : (expectedLen * 8) / bwEstimate + ttfbSeconds;
302
303
  // Only downswitch if the time to finish loading the current fragment is greater than the amount of buffer left
303
304
  if (fragLoadedDelay <= bufferStarvationDelay) {
304
305
  return;
305
306
  }
306
307
 
307
308
  const bwe = loadRate ? loadRate * 8 : bwEstimate;
309
+ const live = this.hls.latestLevelDetails?.live === true;
310
+ const abrBandWidthUpFactor = this.hls.config.abrBandWidthUpFactor;
308
311
  let fragLevelNextLoadedDelay: number = Number.POSITIVE_INFINITY;
309
312
  let nextLoadLevel: number;
310
313
  // Iterate through lower level and try to find the largest one that avoids rebuffering
@@ -316,13 +319,17 @@ class AbrController extends Logger implements AbrComponentAPI {
316
319
  // compute time to load next fragment at lower level
317
320
  // 8 = bits per byte (bps/Bps)
318
321
  const levelNextBitrate = levels[nextLoadLevel].maxBitrate;
322
+ const requiresLevelLoad = !levels[nextLoadLevel].details || live;
319
323
  fragLevelNextLoadedDelay = this.getTimeToLoadFrag(
320
- ttfbEstimate / 1000,
324
+ ttfbSeconds,
321
325
  bwe,
322
326
  duration * levelNextBitrate,
323
- !levels[nextLoadLevel].details,
327
+ requiresLevelLoad,
324
328
  );
325
- if (fragLevelNextLoadedDelay < bufferStarvationDelay) {
329
+ if (
330
+ fragLevelNextLoadedDelay <
331
+ Math.min(bufferStarvationDelay, duration + ttfbSeconds)
332
+ ) {
326
333
  break;
327
334
  }
328
335
  }
@@ -336,7 +343,6 @@ class AbrController extends Logger implements AbrComponentAPI {
336
343
  if (fragLevelNextLoadedDelay > duration * 10) {
337
344
  return;
338
345
  }
339
- hls.nextLoadLevel = hls.nextAutoLevel = nextLoadLevel;
340
346
  if (loadedFirstByte) {
341
347
  // If there has been loading progress, sample bandwidth using loading time offset by minimum TTFB time
342
348
  this.bwEstimator.sample(
@@ -348,17 +354,26 @@ class AbrController extends Logger implements AbrComponentAPI {
348
354
  this.bwEstimator.sampleTTFB(timeLoading);
349
355
  }
350
356
  const nextLoadLevelBitrate = levels[nextLoadLevel].maxBitrate;
351
- if (
352
- this.getBwEstimate() * this.hls.config.abrBandWidthUpFactor >
353
- nextLoadLevelBitrate
354
- ) {
357
+ if (this.getBwEstimate() * abrBandWidthUpFactor > nextLoadLevelBitrate) {
355
358
  this.resetEstimator(nextLoadLevelBitrate);
356
359
  }
360
+ const bestSwitchLevel = this.findBestLevel(
361
+ nextLoadLevelBitrate,
362
+ minAutoLevel,
363
+ nextLoadLevel,
364
+ 0,
365
+ bufferStarvationDelay,
366
+ 1,
367
+ 1,
368
+ );
369
+ if (bestSwitchLevel > -1) {
370
+ nextLoadLevel = bestSwitchLevel;
371
+ }
357
372
 
358
- this.clearTimer();
359
373
  this.warn(`Fragment ${frag.sn}${
360
374
  part ? ' part ' + part.index : ''
361
375
  } of level ${frag.level} is loading too slowly;
376
+ Fragment duration: ${frag.duration.toFixed(3)}
362
377
  Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s
363
378
  Estimated load time for current fragment: ${fragLoadedDelay.toFixed(3)} s
364
379
  Estimated load time for down switch fragment: ${fragLevelNextLoadedDelay.toFixed(
@@ -370,6 +385,44 @@ class AbrController extends Logger implements AbrComponentAPI {
370
385
  } bps
371
386
  New BW estimate: ${this.getBwEstimate() | 0} bps
372
387
  Switching to level ${nextLoadLevel} @ ${nextLoadLevelBitrate | 0} bps`);
388
+
389
+ hls.nextLoadLevel = hls.nextAutoLevel = nextLoadLevel;
390
+
391
+ this.clearTimer();
392
+ this.timer = self.setInterval(() => {
393
+ // Are nextLoadLevel details available or is stream-controller still in "WAITING_LEVEL" state?
394
+ this.clearTimer();
395
+ if (
396
+ this.fragCurrent === frag &&
397
+ this.hls.loadLevel === nextLoadLevel &&
398
+ nextLoadLevel > 0
399
+ ) {
400
+ const bufferStarvationDelay = this.getStarvationDelay();
401
+ this
402
+ .warn(`Aborting inflight request ${nextLoadLevel > 0 ? 'and switching down' : ''}
403
+ Fragment duration: ${frag.duration.toFixed(3)} s
404
+ Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s`);
405
+ frag.abortRequests();
406
+ this.fragCurrent = this.partCurrent = null;
407
+ if (nextLoadLevel > minAutoLevel) {
408
+ let lowestSwitchLevel = this.findBestLevel(
409
+ this.hls.levels[minAutoLevel].bitrate,
410
+ minAutoLevel,
411
+ nextLoadLevel,
412
+ 0,
413
+ bufferStarvationDelay,
414
+ 1,
415
+ 1,
416
+ );
417
+ if (lowestSwitchLevel === -1) {
418
+ lowestSwitchLevel = minAutoLevel;
419
+ }
420
+ this.hls.nextLoadLevel = this.hls.nextAutoLevel = lowestSwitchLevel;
421
+ this.resetEstimator(this.hls.levels[lowestSwitchLevel].bitrate);
422
+ }
423
+ }
424
+ }, fragLevelNextLoadedDelay * 1000);
425
+
373
426
  hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, { frag, part, stats });
374
427
  };
375
428
 
@@ -665,7 +718,7 @@ class AbrController extends Logger implements AbrComponentAPI {
665
718
  return 0;
666
719
  }
667
720
  const level: Level | undefined = levels[selectionBaseLevel];
668
- const live = !!level?.details?.live;
721
+ const live = !!this.hls.latestLevelDetails?.live;
669
722
  const firstSelection = loadLevel === -1 || lastLoadedFragLevel === -1;
670
723
  let currentCodecSet: string | undefined;
671
724
  let currentVideoRange: VideoRange | undefined = 'SDR';
@@ -439,11 +439,12 @@ export default class LevelController extends BasePlaylistController {
439
439
 
440
440
  if (
441
441
  lastLevelIndex === newLevel &&
442
- level.details &&
443
442
  lastLevel &&
444
443
  lastPathwayId === pathwayId
445
444
  ) {
446
- return;
445
+ if (level.details || this.requestScheduled !== -1) {
446
+ return;
447
+ }
447
448
  }
448
449
 
449
450
  this.log(
@@ -571,7 +572,10 @@ export default class LevelController extends BasePlaylistController {
571
572
  data.context.type === PlaylistContextType.LEVEL &&
572
573
  data.context.level === this.level
573
574
  ) {
574
- this.checkRetry(data);
575
+ const retry = this.checkRetry(data);
576
+ if (!retry) {
577
+ this.requestScheduled = -1;
578
+ }
575
579
  }
576
580
  }
577
581