@@ -442,7 +442,7 @@ describe('AbrController', function () {
442442 } ) ;
443443 } )
444444
445- describe ( 'abrCtrl. canPerformQualitySwitch()' , function ( ) {
445+ describe ( 'canPerformQualitySwitch()' , function ( ) {
446446
447447 it ( 'should return true if lastSegment is undefined' , function ( ) {
448448 expect ( abrCtrl . canPerformQualitySwitch ( undefined , { } ) ) . to . be . true ;
@@ -563,6 +563,111 @@ describe('AbrController', function () {
563563
564564 } )
565565
566+ describe ( 'manuallySetPlaybackQuality' , function ( ) {
567+
568+ it ( 'should immediately switch quality when canPerformQualitySwitch returns true' , function ( done ) {
569+ // Override streamProcessor to simulate current representation and last segment allowing switch
570+ const rep0 = dummyRepresentations [ 0 ] ;
571+ const rep1 = dummyRepresentations [ 1 ] ;
572+ const streamInfo = dummyMediaInfo . streamInfo ;
573+
574+ streamProcessor . getRepresentation = ( ) => rep0 ; // current representation
575+ streamProcessor . getRepresentationController = ( ) => {
576+ return {
577+ getCurrentCompositeRepresentation : ( ) => rep0
578+ }
579+ }
580+ streamProcessor . getLastSegment = ( ) => undefined ;
581+
582+ const onQualityChange = function ( e ) {
583+ expect ( e . oldRepresentation . id ) . to . be . equal ( rep0 . id ) ;
584+ expect ( e . newRepresentation . id ) . to . be . equal ( rep1 . id ) ;
585+ eventBus . off ( MediaPlayerEvents . QUALITY_CHANGE_REQUESTED , onQualityChange ) ;
586+ done ( ) ;
587+ } ;
588+ eventBus . on ( MediaPlayerEvents . QUALITY_CHANGE_REQUESTED , onQualityChange , this ) ;
589+
590+ // First set current quality manually to rep0 so subsequent switch has oldRepresentation
591+ abrCtrl . setPlaybackQuality ( Constants . VIDEO , streamInfo , rep0 ) ;
592+ // Now manually trigger switch to rep1
593+ abrCtrl . manuallySetPlaybackQuality ( Constants . VIDEO , streamInfo , rep1 , { reason : 'manual-test' } ) ;
594+ } ) ;
595+
596+
597+ it ( 'should queue manual quality switch when canPerformQualitySwitch returns false' , function ( ) {
598+ const rep0 = dummyRepresentations [ 0 ] ;
599+ const rep1 = dummyRepresentations [ 1 ] ;
600+ const streamInfo = dummyMediaInfo . streamInfo ;
601+
602+ // Set current representation
603+ streamProcessor . getRepresentation = ( ) => rep0 ;
604+ streamProcessor . getRepresentationController = ( ) => {
605+ return {
606+ getCurrentCompositeRepresentation : ( ) => rep0
607+ }
608+ }
609+ // Simulate a last segment that blocks switching (partial segment with unsuitable properties)
610+ streamProcessor . getLastSegment = ( ) => ( {
611+ isPartialSegment : true ,
612+ totalNumberOfPartialSegments : 4 ,
613+ replacementSubNumber : 1
614+ } ) ;
615+ // Current representation missing segmentSequenceProperties => canPerformQualitySwitch should be false
616+ rep0 . segmentSequenceProperties = [ ] ;
617+
618+ const spy = sinon . spy ( ) ;
619+ eventBus . on ( MediaPlayerEvents . QUALITY_CHANGE_REQUESTED , spy , this ) ;
620+
621+ abrCtrl . manuallySetPlaybackQuality ( Constants . VIDEO , streamInfo , rep1 , { reason : 'manual-test' } ) ;
622+
623+ // No immediate quality change event emitted
624+ expect ( spy . notCalled ) . to . be . true ;
625+ } ) ;
626+
627+ it ( 'should execute queued manual quality switch when handlePendingManualQualitySwitch is called and conditions allow switching' , function ( done ) {
628+ const rep0 = dummyRepresentations [ 0 ] ;
629+ const rep1 = dummyRepresentations [ 1 ] ;
630+ const streamInfo = dummyMediaInfo . streamInfo ;
631+
632+ // First block switching so it gets queued
633+ streamProcessor . getRepresentation = ( ) => rep0 ;
634+ streamProcessor . getRepresentationController = ( ) => {
635+ return {
636+ getCurrentCompositeRepresentation : ( ) => rep0
637+ }
638+ }
639+ streamProcessor . getLastSegment = ( ) => ( {
640+ isPartialSegment : true ,
641+ totalNumberOfPartialSegments : 4 ,
642+ replacementSubNumber : 1
643+ } ) ;
644+ rep0 . segmentSequenceProperties = [ ] ;
645+
646+ abrCtrl . manuallySetPlaybackQuality ( Constants . VIDEO , streamInfo , rep1 , { reason : 'queue-test' } ) ;
647+
648+ // Now allow switching by changing last segment to end of sequence
649+ streamProcessor . getLastSegment = ( ) => ( {
650+ isPartialSegment : true ,
651+ totalNumberOfPartialSegments : 4 ,
652+ replacementSubNumber : 3 // end of sequence -> allows switch
653+ } ) ;
654+ // Provide segmentSequenceProperties so canPerformQualitySwitch returns true; but because replacementSubNumber === totalNumber-1 it already allows
655+ rep0 . segmentSequenceProperties = [ new SegmentSequenceProperties ( ) ] ;
656+
657+ const onQualityChange = ( e ) => {
658+ expect ( e . oldRepresentation . id ) . to . be . equal ( rep0 . id ) ;
659+ expect ( e . newRepresentation . id ) . to . be . equal ( rep1 . id ) ;
660+ eventBus . off ( MediaPlayerEvents . QUALITY_CHANGE_REQUESTED , onQualityChange ) ;
661+ done ( ) ;
662+ } ;
663+ eventBus . on ( MediaPlayerEvents . QUALITY_CHANGE_REQUESTED , onQualityChange , this ) ;
664+
665+ // Trigger handling of queued switch
666+ const handled = abrCtrl . handlePendingManualQualitySwitch ( streamInfo . id , Constants . VIDEO ) ;
667+ expect ( handled ) . to . be . true ;
668+ } ) ;
669+ } )
670+
566671 describe ( 'Additional Tests' , function ( ) {
567672 it ( 'should return null when attempting to get abandonment state when abandonmentStateDict array is empty' , function ( ) {
568673 const state = abrCtrl . getAbandonmentStateFor ( '1' , Constants . AUDIO ) ;
@@ -595,20 +700,20 @@ describe('AbrController', function () {
595700 it ( 'should switch to a new enhancement Representation and have the correct dependentRep' , function ( done ) {
596701 const enhancementRepresentation = dummyRepresentations [ 2 ] ;
597702 const dependentRepresentation = dummyRepresentations [ 0 ] ;
598-
703+
599704 const onQualityChange = ( e ) => {
600705 expect ( e . oldRepresentation ) . to . not . exist ;
601-
706+
602707 // Representation 2 should have dependentRepresentation with id 0
603708 expect ( e . newRepresentation . id ) . to . be . equal ( enhancementRepresentation . id ) ;
604709 expect ( e . newRepresentation . dependentRepresentation . id ) . to . be . equal ( dependentRepresentation . id ) ;
605-
710+
606711 eventBus . off ( MediaPlayerEvents . QUALITY_CHANGE_REQUESTED , onQualityChange ) ;
607712 done ( ) ;
608713 }
609-
714+
610715 eventBus . on ( MediaPlayerEvents . QUALITY_CHANGE_REQUESTED , onQualityChange , this ) ;
611-
716+
612717 abrCtrl . setPlaybackQuality ( Constants . VIDEO , enhancementMediaInfo . streamInfo , enhancementRepresentation ) ;
613718 } ) ;
614719
0 commit comments