@@ -70,7 +70,6 @@ export default class StreamController
7070 private altAudio : AlternateAudio = AlternateAudio . DISABLED ;
7171 private audioOnly : boolean = false ;
7272 private fragPlaying : Fragment | null = null ;
73- private fragLastKbps : number = 0 ;
7473 private couldBacktrack : boolean = false ;
7574 private backtrackFragment : Fragment | null = null ;
7675 private audioCodecSwitch : boolean = false ;
@@ -436,43 +435,46 @@ export default class StreamController
436435 * we should take into account new segment fetch time
437436 */
438437 public nextLevelSwitch ( ) {
439- const { levels, media } = this ;
438+ const { levels, media, hls , config } = this ;
440439 // ensure that media is defined and that metadata are available (to retrieve currentTime)
441- if ( media ?. readyState ) {
442- let fetchdelay ;
443- const fragPlayingCurrent = this . getAppendedFrag ( media . currentTime ) ;
444- if ( fragPlayingCurrent && fragPlayingCurrent . start > 1 ) {
445- // flush buffer preceding current fragment (flush until current fragment start offset)
446- // minus 1s to avoid video freezing, that could happen if we flush keyframe of current video ...
447- this . flushMainBuffer ( 0 , fragPlayingCurrent . start - 1 ) ;
440+ if ( media ?. readyState && levels && hls && config ) {
441+ const bufferInfo = this . getMainFwdBufferInfo ( ) ;
442+ if ( ! bufferInfo ) {
443+ return ;
448444 }
449445 const levelDetails = this . getLevelDetails ( ) ;
450- if ( levelDetails ?. live ) {
451- const bufferInfo = this . getMainFwdBufferInfo ( ) ;
452- // Do not flush in live stream with low buffer
453- if ( ! bufferInfo || bufferInfo . len < levelDetails . targetduration * 2 ) {
454- return ;
455- }
456- }
457- if ( ! media . paused && levels ) {
446+
447+ let fetchdelay = 0 ;
448+ if ( ! media . paused ) {
458449 // add a safety delay of 1s
459- const nextLevelId = this . hls . nextLoadLevel ;
450+ const ttfbSec = 1 + hls . ttfbEstimate / 1000 ;
451+ const bandwidth = hls . bandwidthEstimate * config . abrBandWidthUpFactor ;
452+ const nextLevelId = hls . nextLoadLevel ;
460453 const nextLevel = levels [ nextLevelId ] ;
461- const fragLastKbps = this . fragLastKbps ;
462- if ( fragLastKbps && this . fragCurrent ) {
463- fetchdelay =
464- ( this . fragCurrent . duration * nextLevel . maxBitrate ) /
465- ( 1000 * fragLastKbps ) +
466- 1 ;
467- } else {
468- fetchdelay = 0 ;
454+ const fragDuration =
455+ ( levelDetails &&
456+ ( this . loadingParts
457+ ? levelDetails . partTarget
458+ : levelDetails . averagetargetduration ) ) ||
459+ this . fragCurrent ?. duration ||
460+ 6 ;
461+ fetchdelay =
462+ ttfbSec + ( nextLevel . maxBitrate * fragDuration ) / bandwidth ;
463+ if ( ! nextLevel . details ) {
464+ fetchdelay += ttfbSec ;
469465 }
470- } else {
471- fetchdelay = 0 ;
472466 }
473- // this.log('fetchdelay:'+fetchdelay);
467+
468+ // Do not flush in live stream with low buffer
469+
470+ const okToFlushForwardBuffer =
471+ ! levelDetails ?. live ||
472+ ( bufferInfo . len || 0 ) > levelDetails . targetduration * 2 ;
473+
474474 // find buffer range that will be reached once new fragment will be fetched
475- const bufferedFrag = this . getBufferedFrag ( media . currentTime + fetchdelay ) ;
475+ const bufferedFrag = okToFlushForwardBuffer
476+ ? this . getBufferedFrag ( media . currentTime + fetchdelay )
477+ : null ;
476478 if ( bufferedFrag ) {
477479 // we can flush buffer range following this one without stalling playback
478480 const nextBufferedFrag = this . followingBufferedFrag ( bufferedFrag ) ;
@@ -498,7 +500,15 @@ export default class StreamController
498500 this . flushMainBuffer ( startPts , Number . POSITIVE_INFINITY ) ;
499501 }
500502 }
503+ // remove back-buffer
504+ const fragPlayingCurrent = this . getAppendedFrag ( media . currentTime ) ;
505+ if ( fragPlayingCurrent && fragPlayingCurrent . start > 1 ) {
506+ // flush buffer preceding current fragment (flush until current fragment start offset)
507+ // minus 1s to avoid video freezing, that could happen if we flush keyframe of current video ...
508+ this . flushMainBuffer ( 0 , fragPlayingCurrent . start - 1 ) ;
509+ }
501510 }
511+ this . tickImmediate ( ) ;
502512 }
503513
504514 private abortCurrentFrag ( ) {
@@ -601,7 +611,6 @@ export default class StreamController
601611 this . log ( 'Trigger BUFFER_RESET' ) ;
602612 this . hls . trigger ( Events . BUFFER_RESET , undefined ) ;
603613 this . couldBacktrack = false ;
604- this . fragLastKbps = 0 ;
605614 this . fragPlaying = this . backtrackFragment = null ;
606615 this . altAudio = AlternateAudio . DISABLED ;
607616 this . audioOnly = false ;
@@ -987,10 +996,6 @@ export default class StreamController
987996 }
988997 return ;
989998 }
990- const stats = part ? part . stats : frag . stats ;
991- this . fragLastKbps = Math . round (
992- ( 8 * stats . total ) / ( stats . buffering . end - stats . loading . first ) ,
993- ) ;
994999 if ( isMediaFragment ( frag ) ) {
9951000 this . fragPrevious = frag ;
9961001 }
0 commit comments