@@ -2,13 +2,15 @@ import './mocks/webrtc.mocks';
22
33import { afterEach , beforeEach , describe , expect , it , vi } from 'vitest' ;
44import { anyString } from 'vitest-mock-extended' ;
5+ import { fromPartial } from '@total-typescript/shoehorn' ;
56import { NegotiationError } from '../NegotiationError' ;
67import { Publisher } from '../Publisher' ;
78import { ReconnectReason } from '../types' ;
89import { CallState } from '../../store' ;
910import { StreamSfuClient } from '../../StreamSfuClient' ;
1011import { DispatchableMessage , Dispatcher } from '../Dispatcher' ;
1112import {
13+ DegradationPreference ,
1214 ErrorCode ,
1315 PeerType ,
1416 PublishOption ,
@@ -82,6 +84,7 @@ describe('Publisher', () => {
8284 fps : 30 ,
8385 maxTemporalLayers : 3 ,
8486 maxSpatialLayers : 3 ,
87+ degradationPreference : DegradationPreference . UNSPECIFIED ,
8588 } ,
8689 ] ,
8790 ) ;
@@ -168,16 +171,19 @@ describe('Publisher', () => {
168171 changePublishQuality : {
169172 audioSenders : [ ] ,
170173 videoSenders : [
171- {
174+ fromPartial ( {
172175 publishOptionId : 1 ,
173176 trackType : TrackType . VIDEO ,
174177 layers : [ ] ,
175- } ,
176- {
178+ degradationPreference : DegradationPreference . BALANCED ,
179+ } ) ,
180+ fromPartial ( {
177181 publishOptionId : 2 ,
178182 trackType : TrackType . SCREEN_SHARE ,
179183 layers : [ ] ,
180- } ,
184+ degradationPreference :
185+ DegradationPreference . MAINTAIN_RESOLUTION ,
186+ } ) ,
181187 ] ,
182188 } ,
183189 } ,
@@ -657,6 +663,7 @@ describe('Publisher', () => {
657663 await publisher [ 'changePublishQuality' ] ( {
658664 publishOptionId : 1 ,
659665 trackType : TrackType . VIDEO ,
666+ degradationPreference : DegradationPreference . UNSPECIFIED ,
660667 layers : [
661668 {
662669 name : 'q' ,
@@ -733,6 +740,7 @@ describe('Publisher', () => {
733740 await publisher [ 'changePublishQuality' ] ( {
734741 publishOptionId : 1 ,
735742 trackType : TrackType . VIDEO ,
743+ degradationPreference : DegradationPreference . UNSPECIFIED ,
736744 layers : [
737745 {
738746 name : 'q' ,
@@ -796,6 +804,7 @@ describe('Publisher', () => {
796804 await publisher [ 'changePublishQuality' ] ( {
797805 publishOptionId : 1 ,
798806 trackType : TrackType . VIDEO ,
807+ degradationPreference : DegradationPreference . UNSPECIFIED ,
799808 layers : [
800809 {
801810 name : 'q' ,
@@ -855,6 +864,7 @@ describe('Publisher', () => {
855864 await publisher [ 'changePublishQuality' ] ( {
856865 publishOptionId : 1 ,
857866 trackType : TrackType . VIDEO ,
867+ degradationPreference : DegradationPreference . UNSPECIFIED ,
858868 layers : [
859869 {
860870 name : 'q' ,
@@ -879,6 +889,93 @@ describe('Publisher', () => {
879889 } ,
880890 ] ) ;
881891 } ) ;
892+
893+ it ( 'applies degradationPreference from the SFU event' , async ( ) => {
894+ const transceiver = new RTCRtpTransceiver ( ) ;
895+ const setParametersSpy = vi
896+ . spyOn ( transceiver . sender , 'setParameters' )
897+ . mockResolvedValue ( ) ;
898+ vi . spyOn ( transceiver . sender , 'getParameters' ) . mockReturnValue ( {
899+ // @ts -expect-error incomplete data
900+ codecs : [ { mimeType : 'video/VP8' } ] ,
901+ encodings : [ { rid : 'q' , active : true } ] ,
902+ degradationPreference : 'maintain-framerate' ,
903+ } ) ;
904+
905+ publisher [ 'transceiverCache' ] . add ( {
906+ // @ts -expect-error incomplete data
907+ publishOption : { trackType : TrackType . VIDEO , id : 1 } ,
908+ transceiver,
909+ options : { } ,
910+ } ) ;
911+
912+ await publisher [ 'changePublishQuality' ] ( {
913+ publishOptionId : 1 ,
914+ trackType : TrackType . VIDEO ,
915+ degradationPreference : DegradationPreference . BALANCED ,
916+ layers : [
917+ {
918+ name : 'q' ,
919+ active : true ,
920+ maxBitrate : 100 ,
921+ scaleResolutionDownBy : 1 ,
922+ maxFramerate : 30 ,
923+ scalabilityMode : '' ,
924+ } ,
925+ ] ,
926+ } ) ;
927+
928+ expect ( setParametersSpy ) . toHaveBeenCalled ( ) ;
929+ expect ( setParametersSpy . mock . calls [ 0 ] [ 0 ] . degradationPreference ) . toBe (
930+ 'balanced' ,
931+ ) ;
932+ } ) ;
933+
934+ it ( 'does not call setParameters when nothing changes and degradationPreference is UNSPECIFIED' , async ( ) => {
935+ const transceiver = new RTCRtpTransceiver ( ) ;
936+ const setParametersSpy = vi
937+ . spyOn ( transceiver . sender , 'setParameters' )
938+ . mockResolvedValue ( ) ;
939+ vi . spyOn ( transceiver . sender , 'getParameters' ) . mockReturnValue ( {
940+ // @ts -expect-error incomplete data
941+ codecs : [ { mimeType : 'video/VP8' } ] ,
942+ encodings : [
943+ {
944+ rid : 'q' ,
945+ active : true ,
946+ maxBitrate : 100 ,
947+ scaleResolutionDownBy : 1 ,
948+ maxFramerate : 30 ,
949+ } ,
950+ ] ,
951+ degradationPreference : 'maintain-framerate' ,
952+ } ) ;
953+
954+ publisher [ 'transceiverCache' ] . add ( {
955+ // @ts -expect-error incomplete data
956+ publishOption : { trackType : TrackType . VIDEO , id : 1 } ,
957+ transceiver,
958+ options : { } ,
959+ } ) ;
960+
961+ await publisher [ 'changePublishQuality' ] ( {
962+ publishOptionId : 1 ,
963+ trackType : TrackType . VIDEO ,
964+ degradationPreference : DegradationPreference . UNSPECIFIED ,
965+ layers : [
966+ {
967+ name : 'q' ,
968+ active : true ,
969+ maxBitrate : 100 ,
970+ scaleResolutionDownBy : 1 ,
971+ maxFramerate : 30 ,
972+ scalabilityMode : '' ,
973+ } ,
974+ ] ,
975+ } ) ;
976+
977+ expect ( setParametersSpy ) . not . toHaveBeenCalled ( ) ;
978+ } ) ;
882979 } ) ;
883980
884981 describe ( 'changePublishOptions' , ( ) => {
@@ -893,12 +990,27 @@ describe('Publisher', () => {
893990 vi . spyOn ( publisher , 'negotiate' ) . mockResolvedValue ( ) ;
894991
895992 publisher [ 'publishOptions' ] = [
896- // @ts -expect-error incomplete data
897- { trackType : TrackType . VIDEO , id : 0 , codec : { name : 'vp8' } } ,
898- // @ts -expect-error incomplete data
899- { trackType : TrackType . VIDEO , id : 1 , codec : { name : 'av1' } } ,
900- // @ts -expect-error incomplete data
901- { trackType : TrackType . VIDEO , id : 2 , codec : { name : 'vp9' } } ,
993+ {
994+ trackType : TrackType . VIDEO ,
995+ id : 0 ,
996+ // @ts -expect-error incomplete data
997+ codec : { name : 'vp8' } ,
998+ degradationPreference : DegradationPreference . UNSPECIFIED ,
999+ } ,
1000+ {
1001+ trackType : TrackType . VIDEO ,
1002+ id : 1 ,
1003+ // @ts -expect-error incomplete data
1004+ codec : { name : 'av1' } ,
1005+ degradationPreference : DegradationPreference . UNSPECIFIED ,
1006+ } ,
1007+ {
1008+ trackType : TrackType . VIDEO ,
1009+ id : 2 ,
1010+ // @ts -expect-error incomplete data
1011+ codec : { name : 'vp9' } ,
1012+ degradationPreference : DegradationPreference . UNSPECIFIED ,
1013+ } ,
9021014 ] ;
9031015
9041016 publisher [ 'transceiverCache' ] . add ( {
0 commit comments