@@ -296,15 +296,18 @@ class AbrController extends Logger implements AbrComponentAPI {
296296 ? ( stats . loaded * 1000 ) / timeStreaming
297297 : 0 ;
298298 // fragLoadDelay is an estimate of the time (in seconds) it will take to buffer the remainder of the fragment
299+ const ttfbSeconds = ttfbEstimate / 1000 ;
299300 const fragLoadedDelay = loadRate
300301 ? ( expectedLen - stats . loaded ) / loadRate
301- : ( expectedLen * 8 ) / bwEstimate + ttfbEstimate / 1000 ;
302+ : ( expectedLen * 8 ) / bwEstimate + ttfbSeconds ;
302303 // Only downswitch if the time to finish loading the current fragment is greater than the amount of buffer left
303304 if ( fragLoadedDelay <= bufferStarvationDelay ) {
304305 return ;
305306 }
306307
307308 const bwe = loadRate ? loadRate * 8 : bwEstimate ;
309+ const live = this . hls . latestLevelDetails ?. live === true ;
310+ const abrBandWidthUpFactor = this . hls . config . abrBandWidthUpFactor ;
308311 let fragLevelNextLoadedDelay : number = Number . POSITIVE_INFINITY ;
309312 let nextLoadLevel : number ;
310313 // Iterate through lower level and try to find the largest one that avoids rebuffering
@@ -316,13 +319,17 @@ class AbrController extends Logger implements AbrComponentAPI {
316319 // compute time to load next fragment at lower level
317320 // 8 = bits per byte (bps/Bps)
318321 const levelNextBitrate = levels [ nextLoadLevel ] . maxBitrate ;
322+ const requiresLevelLoad = ! levels [ nextLoadLevel ] . details || live ;
319323 fragLevelNextLoadedDelay = this . getTimeToLoadFrag (
320- ttfbEstimate / 1000 ,
324+ ttfbSeconds ,
321325 bwe ,
322326 duration * levelNextBitrate ,
323- ! levels [ nextLoadLevel ] . details ,
327+ requiresLevelLoad ,
324328 ) ;
325- if ( fragLevelNextLoadedDelay < bufferStarvationDelay ) {
329+ if (
330+ fragLevelNextLoadedDelay <
331+ Math . min ( bufferStarvationDelay , duration + ttfbSeconds )
332+ ) {
326333 break ;
327334 }
328335 }
@@ -336,7 +343,6 @@ class AbrController extends Logger implements AbrComponentAPI {
336343 if ( fragLevelNextLoadedDelay > duration * 10 ) {
337344 return ;
338345 }
339- hls . nextLoadLevel = hls . nextAutoLevel = nextLoadLevel ;
340346 if ( loadedFirstByte ) {
341347 // If there has been loading progress, sample bandwidth using loading time offset by minimum TTFB time
342348 this . bwEstimator . sample (
@@ -348,17 +354,26 @@ class AbrController extends Logger implements AbrComponentAPI {
348354 this . bwEstimator . sampleTTFB ( timeLoading ) ;
349355 }
350356 const nextLoadLevelBitrate = levels [ nextLoadLevel ] . maxBitrate ;
351- if (
352- this . getBwEstimate ( ) * this . hls . config . abrBandWidthUpFactor >
353- nextLoadLevelBitrate
354- ) {
357+ if ( this . getBwEstimate ( ) * abrBandWidthUpFactor > nextLoadLevelBitrate ) {
355358 this . resetEstimator ( nextLoadLevelBitrate ) ;
356359 }
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+ }
357372
358- this . clearTimer ( ) ;
359373 this . warn ( `Fragment ${ frag . sn } ${
360374 part ? ' part ' + part . index : ''
361375 } of level ${ frag . level } is loading too slowly;
376+ Fragment duration: ${ frag . duration . toFixed ( 3 ) }
362377 Time to underbuffer: ${ bufferStarvationDelay . toFixed ( 3 ) } s
363378 Estimated load time for current fragment: ${ fragLoadedDelay . toFixed ( 3 ) } s
364379 Estimated load time for down switch fragment: ${ fragLevelNextLoadedDelay . toFixed (
@@ -370,6 +385,44 @@ class AbrController extends Logger implements AbrComponentAPI {
370385 } bps
371386 New BW estimate: ${ this . getBwEstimate ( ) | 0 } bps
372387 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+
373426 hls . trigger ( Events . FRAG_LOAD_EMERGENCY_ABORTED , { frag, part, stats } ) ;
374427 } ;
375428
@@ -665,7 +718,7 @@ class AbrController extends Logger implements AbrComponentAPI {
665718 return 0 ;
666719 }
667720 const level : Level | undefined = levels [ selectionBaseLevel ] ;
668- const live = ! ! level ?. details ?. live ;
721+ const live = ! ! this . hls . latestLevelDetails ?. live ;
669722 const firstSelection = loadLevel === - 1 || lastLoadedFragLevel === - 1 ;
670723 let currentCodecSet : string | undefined ;
671724 let currentVideoRange : VideoRange | undefined = 'SDR' ;
0 commit comments