@@ -52,27 +52,28 @@ function AbrController() {
5252 const debug = Debug ( context ) . getInstance ( ) ;
5353 const eventBus = EventBus ( context ) . getInstance ( ) ;
5454
55- let instance ,
56- logger ,
57- abrRulesCollection ,
58- streamController ,
59- capabilities ,
60- streamProcessorDict ,
61- abandonmentStateDict ,
55+ let abandonmentStateDict ,
6256 abandonmentTimeout ,
63- windowResizeEventCalled ,
57+ abrRulesCollection ,
6458 adapter ,
65- videoModel ,
66- mediaPlayerModel ,
67- customParametersModel ,
59+ capabilities ,
6860 cmsdModel ,
69- domStorage ,
7061 currentRepresentationId ,
71- switchRequestHistory ,
62+ customParametersModel ,
63+ dashMetrics ,
64+ domStorage ,
7265 droppedFramesHistory ,
66+ instance ,
67+ logger ,
68+ mediaPlayerModel ,
69+ queuedManualQualitySwitches ,
70+ settings ,
71+ streamController ,
72+ streamProcessorDict ,
73+ switchRequestHistory ,
7374 throughputController ,
74- dashMetrics ,
75- settings ;
75+ videoModel ,
76+ windowResizeEventCalled ;
7677
7778 function setup ( ) {
7879 logger = debug . getLogger ( instance ) ;
@@ -149,6 +150,7 @@ function AbrController() {
149150 function resetInitialSettings ( ) {
150151 abandonmentStateDict = { } ;
151152 streamProcessorDict = { } ;
153+ queuedManualQualitySwitches = new Map ( ) ;
152154
153155 if ( windowResizeEventCalled === undefined ) {
154156 windowResizeEventCalled = false ;
@@ -538,19 +540,25 @@ function AbrController() {
538540 return ;
539541 }
540542
541- const rulesContext = RulesContext ( context ) . create ( {
543+ const rulesContext = _createRulesContext ( streamProcessor , e . request ) ;
544+ const switchRequest = abrRulesCollection . shouldAbandonFragment ( rulesContext ) ;
545+
546+ if ( switchRequest && switchRequest . representation !== SwitchRequest . NO_CHANGE ) {
547+ _onSegmentDownloadShouldBeAbandoned ( e , streamId , type , streamProcessor , switchRequest ) ;
548+ }
549+ }
550+
551+ function _createRulesContext ( streamProcessor , currentRequest ) {
552+ return RulesContext ( context ) . create ( {
542553 abrController : instance ,
543554 streamProcessor,
544- currentRequest : e . request ,
555+ currentRequest,
556+ switchRequestHistory,
557+ droppedFramesHistory,
545558 throughputController,
546559 adapter,
547560 videoModel
548561 } ) ;
549- const switchRequest = abrRulesCollection . shouldAbandonFragment ( rulesContext ) ;
550-
551- if ( switchRequest && switchRequest . representation !== SwitchRequest . NO_CHANGE ) {
552- _onSegmentDownloadShouldBeAbandoned ( e , streamId , type , streamProcessor , switchRequest ) ;
553- }
554562 }
555563
556564 function _canAbandonRequest ( lastSegment ) {
@@ -669,17 +677,8 @@ function AbrController() {
669677 return false ;
670678 }
671679
672-
673680 const currentRepresentation = streamProcessor . getRepresentation ( ) ;
674- const rulesContext = RulesContext ( context ) . create ( {
675- abrController : instance ,
676- throughputController,
677- switchRequestHistory,
678- droppedFramesHistory,
679- streamProcessor,
680- adapter,
681- videoModel
682- } ) ;
681+ const rulesContext = _createRulesContext ( streamProcessor ) ;
683682 const switchRequest = abrRulesCollection . getBestPossibleSwitchRequest ( rulesContext ) ;
684683
685684 if ( ! switchRequest || ! switchRequest . representation ) {
@@ -739,16 +738,74 @@ function AbrController() {
739738 */
740739 function setPlaybackQuality ( type , streamInfo , representation , reason = { } ) {
741740 if ( ! streamInfo || ! streamInfo . id || ! type || ! streamProcessorDict || ! streamProcessorDict [ streamInfo . id ] || ! streamProcessorDict [ streamInfo . id ] [ type ] || ! representation ) {
742- return ;
741+ return false ;
743742 }
744743
745744 const streamProcessor = streamProcessorDict [ streamInfo . id ] [ type ] ;
746745 const currentRepresentation = streamProcessor . getRepresentation ( ) ;
747746
748-
749747 if ( ! currentRepresentation || representation . id !== currentRepresentation . id ) {
750- _changeQuality ( currentRepresentation , representation , reason ) ;
748+ return _changeQuality ( currentRepresentation , representation , reason ) ;
749+ }
750+
751+ return false ;
752+ }
753+
754+ function manuallySetPlaybackQuality ( type , streamInfo , representation , reason = { } ) {
755+ const streamProcessor = streamProcessorDict [ streamInfo . id ] [ type ] ;
756+ const lastSegment = streamProcessor . getLastSegment ( ) ;
757+ const canPerformQualitySwitch = _canPerformQualitySwitch ( lastSegment ) ;
758+
759+ if ( ! canPerformQualitySwitch ) {
760+ _queueManualQualitySwitch ( type , streamInfo , representation , reason ) ;
761+ return ;
751762 }
763+
764+ return setPlaybackQuality ( type , streamInfo , representation , reason ) ;
765+ }
766+
767+ function _queueManualQualitySwitch ( type , streamInfo , representation , reason ) {
768+ try {
769+ logger . debug ( `[AbrController] Queuing manual quality switch for stream ${ streamInfo . id } and type ${ type } to representation ${ representation . id } ` ) ;
770+ const key = _getManualQualitySwitchKey ( streamInfo . id , type ) ;
771+ queuedManualQualitySwitches . set ( key , { type, streamInfo, representation, reason } ) ;
772+ } catch ( e ) {
773+ logger . error ( `Can not queue manual quality switch: ${ e } ` ) ;
774+ }
775+ }
776+
777+ function handlePendingManualQualitySwitch ( streamId , mediaType ) {
778+ try {
779+ const streamProcessor = streamProcessorDict [ streamId ] [ mediaType ] ;
780+ const lastSegment = streamProcessor . getLastSegment ( ) ;
781+ const canPerformQualitySwitch = _canPerformQualitySwitch ( lastSegment ) ;
782+
783+ if ( ! canPerformQualitySwitch ) {
784+ return false
785+ }
786+
787+ const key = _getManualQualitySwitchKey ( streamId , mediaType ) ;
788+ let switchRequest = null ;
789+ if ( queuedManualQualitySwitches . has ( key ) ) {
790+ switchRequest = queuedManualQualitySwitches . get ( key ) ;
791+ }
792+
793+ if ( ! switchRequest ) {
794+ return false
795+ }
796+
797+ const { type, streamInfo, representation, reason } = switchRequest ;
798+
799+ queuedManualQualitySwitches . delete ( key ) ;
800+ setPlaybackQuality ( type , streamInfo , representation , reason ) ;
801+ return true ;
802+ } catch ( e ) {
803+ logger . error ( `Can not handle pending manual quality switch: ${ e } ` ) ;
804+ }
805+ }
806+
807+ function _getManualQualitySwitchKey ( streamId , mediaType ) {
808+ return `${ streamId } -${ mediaType } `
752809 }
753810
754811 /**
@@ -778,7 +835,7 @@ function AbrController() {
778835 const type = newRepresentation . mediaInfo . type ;
779836
780837 if ( ! type || ! streamProcessorDict [ streamId ] || ! streamProcessorDict [ streamId ] [ type ] ) {
781- return
838+ return false
782839 }
783840
784841 const streamInfo = streamProcessorDict [ streamId ] [ type ] . getStreamInfo ( ) ;
@@ -800,6 +857,7 @@ function AbrController() {
800857 ) ;
801858
802859 _saveBitrateSettings ( type )
860+ return true
803861 }
804862
805863 function _saveBitrateSettings ( type ) {
@@ -908,9 +966,11 @@ function AbrController() {
908966 getPossibleVoRepresentationsFilteredBySettings,
909967 getRepresentationByAbsoluteIndex,
910968 handleNewMediaInfo,
969+ handlePendingManualQualitySwitch,
911970 initialize,
912971 isPlayingAtLowestQuality,
913972 isPlayingAtTopQuality,
973+ manuallySetPlaybackQuality,
914974 registerStreamType,
915975 reset,
916976 setConfig,
0 commit comments