@@ -29,6 +29,7 @@ import {merge, createTimeRanges} from './util/vjs-compat';
2929import { addMetadata , createMetadataTrackIfNotExists , addDateRangeMetadata } from './util/text-tracks' ;
3030import ContentSteeringController from './content-steering-controller' ;
3131import { bufferToHexString } from './util/string.js' ;
32+ import { debounce } from './util/fn' ;
3233
3334const ABORT_EARLY_EXCLUSION_SECONDS = 10 ;
3435
@@ -152,6 +153,11 @@ export class PlaylistController extends videojs.EventTarget {
152153 constructor ( options ) {
153154 super ( ) ;
154155
156+ // Adding a slight debounce to avoid duplicate calls during rapid quality changes, for example:
157+ // When selecting quality from the quality list,
158+ // where we may have multiple bandwidth profiles for the same vertical resolution.
159+ this . fastQualityChange_ = debounce ( this . fastQualityChange_ . bind ( this ) , 100 ) ;
160+
155161 const {
156162 src,
157163 withCredentials,
@@ -701,7 +707,16 @@ export class PlaylistController extends videojs.EventTarget {
701707
702708 if ( this . sourceType_ === 'dash' ) {
703709 // we don't want to re-request the same hls playlist right after it was changed
704- this . mainPlaylistLoader_ . load ( ) ;
710+
711+ // Initially it was implemented as workaround to restart playlist loader for live
712+ // when playlist loader is paused because of playlist exclusions:
713+ // see: https://github.com/videojs/http-streaming/pull/1339
714+ // but this introduces duplicate "loadedplaylist" event.
715+ // Ideally we want to re-think playlist loader life-cycle events,
716+ // but simply checking "paused" state should help a lot
717+ if ( this . mainPlaylistLoader_ . isPaused ) {
718+ this . mainPlaylistLoader_ . load ( ) ;
719+ }
705720 }
706721
707722 // TODO: Create a new event on the PlaylistLoader that signals
@@ -962,6 +977,24 @@ export class PlaylistController extends videojs.EventTarget {
962977 this . tech_ . setCurrentTime ( newTime ) ;
963978 } ) ;
964979
980+ this . timelineChangeController_ . on ( 'fixBadTimelineChange' , ( ) => {
981+ // pause, reset-everything and load for all segment-loaders
982+ this . logger_ ( 'Fix bad timeline change. Restarting al segment loaders...' ) ;
983+ this . mainSegmentLoader_ . pause ( ) ;
984+ this . mainSegmentLoader_ . resetEverything ( ) ;
985+ if ( this . mediaTypes_ . AUDIO . activePlaylistLoader ) {
986+ this . audioSegmentLoader_ . pause ( ) ;
987+ this . audioSegmentLoader_ . resetEverything ( ) ;
988+ }
989+ if ( this . mediaTypes_ . SUBTITLES . activePlaylistLoader ) {
990+ this . subtitleSegmentLoader_ . pause ( ) ;
991+ this . subtitleSegmentLoader_ . resetEverything ( ) ;
992+ }
993+
994+ // start segment loader loading in case they are paused
995+ this . load ( ) ;
996+ } ) ;
997+
965998 this . mainSegmentLoader_ . on ( 'earlyabort' , ( event ) => {
966999 // never try to early abort with the new ABR algorithm
9671000 if ( this . bufferBasedABR ) {
@@ -1109,13 +1142,19 @@ export class PlaylistController extends videojs.EventTarget {
11091142
11101143 runFastQualitySwitch_ ( ) {
11111144 this . waitingForFastQualityPlaylistReceived_ = false ;
1112- // Delete all buffered data to allow an immediate quality switch.
11131145 this . mainSegmentLoader_ . pause ( ) ;
1114- this . mainSegmentLoader_ . resetEverything ( ( ) => {
1115- this . mainSegmentLoader_ . load ( ) ;
1116- } ) ;
1146+ this . mainSegmentLoader_ . resetEverything ( ) ;
1147+ if ( this . mediaTypes_ . AUDIO . activePlaylistLoader ) {
1148+ this . audioSegmentLoader_ . pause ( ) ;
1149+ this . audioSegmentLoader_ . resetEverything ( ) ;
1150+ }
1151+ if ( this . mediaTypes_ . SUBTITLES . activePlaylistLoader ) {
1152+ this . subtitleSegmentLoader_ . pause ( ) ;
1153+ this . subtitleSegmentLoader_ . resetEverything ( ) ;
1154+ }
11171155
1118- // don't need to reset audio as it is reset when media changes
1156+ // start segment loader loading in case they are paused
1157+ this . load ( ) ;
11191158 }
11201159
11211160 /**
0 commit comments