@@ -2,6 +2,7 @@ import type { SignalClient } from '../../api/SignalClient';
22import log from '../../logger' ;
33import { VideoLayer , VideoQuality } from '../../proto/livekit_models' ;
44import type { SubscribedCodec , SubscribedQuality } from '../../proto/livekit_rtc' ;
5+ import { ScalabilityMode } from '../participant/publishUtils' ;
56import { computeBitrate , monitorFrequency } from '../stats' ;
67import type { VideoSenderStats } from '../stats' ;
78import { Mutex , isFireFox , isMobile , isWeb } from '../utils' ;
@@ -349,45 +350,88 @@ async function setPublishingLayersForSender(
349350 }
350351
351352 let hasChanged = false ;
352- encodings . forEach ( ( encoding , idx ) => {
353- let rid = encoding . rid ?? '' ;
354- if ( rid === '' ) {
355- rid = 'q' ;
356- }
357- const quality = videoQualityForRid ( rid ) ;
358- const subscribedQuality = qualities . find ( ( q ) => q . quality === quality ) ;
359- if ( ! subscribedQuality ) {
360- return ;
361- }
362- if ( encoding . active !== subscribedQuality . enabled ) {
353+
354+ /* @ts -ignore */
355+ if ( encodings . length === 1 && encodings [ 0 ] . scalabilityMode ) {
356+ // svc dynacast encodings
357+ const encoding = encodings [ 0 ] ;
358+ /* @ts -ignore */
359+ // const mode = new ScalabilityMode(encoding.scalabilityMode);
360+ let maxQuality = VideoQuality . OFF ;
361+ qualities . forEach ( ( q ) => {
362+ if ( q . enabled && ( maxQuality === VideoQuality . OFF || q . quality > maxQuality ) ) {
363+ maxQuality = q . quality ;
364+ }
365+ } ) ;
366+
367+ if ( maxQuality === VideoQuality . OFF ) {
368+ if ( encoding . active ) {
369+ encoding . active = false ;
370+ hasChanged = true ;
371+ }
372+ } else if ( ! encoding . active /* || mode.spatial !== maxQuality + 1*/ ) {
363373 hasChanged = true ;
364- encoding . active = subscribedQuality . enabled ;
365- log . debug (
366- `setting layer ${ subscribedQuality . quality } to ${
367- encoding . active ? 'enabled' : 'disabled'
368- } `,
369- ) ;
370-
371- // FireFox does not support setting encoding.active to false, so we
372- // have a workaround of lowering its bitrate and resolution to the min.
373- if ( isFireFox ( ) ) {
374- if ( subscribedQuality . enabled ) {
375- encoding . scaleResolutionDownBy = senderEncodings [ idx ] . scaleResolutionDownBy ;
376- encoding . maxBitrate = senderEncodings [ idx ] . maxBitrate ;
377- /* @ts -ignore */
378- encoding . maxFrameRate = senderEncodings [ idx ] . maxFrameRate ;
379- } else {
380- encoding . scaleResolutionDownBy = 4 ;
381- encoding . maxBitrate = 10 ;
382- /* @ts -ignore */
383- encoding . maxFrameRate = 2 ;
384- }
374+ encoding . active = true ;
375+ /* disable closable spatial layer as it has video blur/frozen issue with current server/client
376+ 1. chrome 113: when switching to up layer with scalability Mode change, it will generate a
377+ low resolution frame and recover very quickly, but noticable
378+ 2. livekit sfu: additional pli request cause video frozen for a few frames, also noticable
379+ @ts -ignore
380+ const originalMode = new ScalabilityMode(senderEncodings[0].scalabilityMode)
381+ mode.spatial = maxQuality + 1;
382+ mode.suffix = originalMode.suffix;
383+ if (mode.spatial === 1) {
384+ // no suffix for L1Tx
385+ mode.suffix = undefined;
385386 }
387+ @ts -ignore
388+ encoding.scalabilityMode = mode.toString();
389+ encoding.scaleResolutionDownBy = 2 ** (2 - maxQuality);
390+ */
386391 }
387- } ) ;
392+ } else {
393+ // simulcast dynacast encodings
394+ encodings . forEach ( ( encoding , idx ) => {
395+ let rid = encoding . rid ?? '' ;
396+ if ( rid === '' ) {
397+ rid = 'q' ;
398+ }
399+ const quality = videoQualityForRid ( rid ) ;
400+ const subscribedQuality = qualities . find ( ( q ) => q . quality === quality ) ;
401+ if ( ! subscribedQuality ) {
402+ return ;
403+ }
404+ if ( encoding . active !== subscribedQuality . enabled ) {
405+ hasChanged = true ;
406+ encoding . active = subscribedQuality . enabled ;
407+ log . debug (
408+ `setting layer ${ subscribedQuality . quality } to ${
409+ encoding . active ? 'enabled' : 'disabled'
410+ } `,
411+ ) ;
412+
413+ // FireFox does not support setting encoding.active to false, so we
414+ // have a workaround of lowering its bitrate and resolution to the min.
415+ if ( isFireFox ( ) ) {
416+ if ( subscribedQuality . enabled ) {
417+ encoding . scaleResolutionDownBy = senderEncodings [ idx ] . scaleResolutionDownBy ;
418+ encoding . maxBitrate = senderEncodings [ idx ] . maxBitrate ;
419+ /* @ts -ignore */
420+ encoding . maxFrameRate = senderEncodings [ idx ] . maxFrameRate ;
421+ } else {
422+ encoding . scaleResolutionDownBy = 4 ;
423+ encoding . maxBitrate = 10 ;
424+ /* @ts -ignore */
425+ encoding . maxFrameRate = 2 ;
426+ }
427+ }
428+ }
429+ } ) ;
430+ }
388431
389432 if ( hasChanged ) {
390433 params . encodings = encodings ;
434+ log . debug ( `setting encodings` , params . encodings ) ;
391435 await sender . setParameters ( params ) ;
392436 }
393437 } finally {
@@ -425,6 +469,25 @@ export function videoLayersFromEncodings(
425469 } ,
426470 ] ;
427471 }
472+
473+ /* @ts -ignore */
474+ if ( encodings . length === 1 && encodings [ 0 ] . scalabilityMode ) {
475+ // svc layers
476+ /* @ts -ignore */
477+ const sm = new ScalabilityMode ( encodings [ 0 ] . scalabilityMode ) ;
478+ const layers = [ ] ;
479+ for ( let i = 0 ; i < sm . spatial ; i += 1 ) {
480+ layers . push ( {
481+ quality : VideoQuality . HIGH - i ,
482+ width : width / 2 ** i ,
483+ height : height / 2 ** i ,
484+ bitrate : encodings [ 0 ] . maxBitrate ? encodings [ 0 ] . maxBitrate / 3 ** i : 0 ,
485+ ssrc : 0 ,
486+ } ) ;
487+ }
488+ return layers ;
489+ }
490+
428491 return encodings . map ( ( encoding ) => {
429492 const scale = encoding . scaleResolutionDownBy ?? 1 ;
430493 let quality = videoQualityForRid ( encoding . rid ?? '' ) ;
0 commit comments