11import 'dart:async' ;
2+ import 'dart:math' as math;
23
34import 'package:flutter/foundation.dart' ;
45
@@ -34,6 +35,9 @@ typedef RetryCondition = bool Function(
3435
3536// Collection of state-less static methods
3637class Utils {
38+ // order of rids
39+ static final videoRids = ['q' , 'h' , 'f' ];
40+
3741 /// Returns a [Future] that will retry [future] while it throws
3842 /// for a maximum of [tries] times with [delay] in between.
3943 /// If all the attempts throws, the future will throw a [List] of the
@@ -191,17 +195,62 @@ class Utils {
191195 required bool isScreenShare,
192196 required VideoDimensions dimensions,
193197 }) {
194- if (isScreenShare) return VideoParametersPresets .allScreenShare;
198+ if (isScreenShare) {
199+ return VideoParametersPresets .allScreenShare;
200+ }
195201
196- final double aspect = dimensions.width > dimensions.height
197- ? dimensions.width / dimensions.height
198- : dimensions.height / dimensions.width;
199- if ((aspect - 16.0 / 9.0 ).abs () < (aspect - 4.0 / 3.0 ).abs ()) {
202+ final a = dimensions.aspect ();
203+ if ((a - VideoDimensionsHelpers .aspect169).abs () <
204+ (a - VideoDimensionsHelpers .aspect43).abs ()) {
200205 return VideoParametersPresets .all169;
201206 }
207+
202208 return VideoParametersPresets .all43;
203209 }
204210
211+ static List <VideoParameters > _computeDefaultScreenShareSimulcastParams ({
212+ required VideoParameters original,
213+ }) {
214+ final layers = [
215+ rtc.RTCRtpEncoding (scaleResolutionDownBy: 2 , maxFramerate: 3 )
216+ ];
217+ return layers.map ((e) {
218+ final scale = e.scaleResolutionDownBy ?? 1 ;
219+ final fps = e.maxFramerate ?? 3 ;
220+
221+ return VideoParameters (
222+ dimensions: VideoDimensions ((original.dimensions.width / scale).floor (),
223+ (original.dimensions.height / scale).floor ()),
224+ encoding: VideoEncoding (
225+ maxBitrate: math.max (
226+ 150 * 1000 ,
227+ (original.encoding.maxBitrate /
228+ (math.pow (scale, 2 ) *
229+ (original.encoding.maxFramerate / fps)))
230+ .floor (),
231+ ),
232+ maxFramerate: fps,
233+ ),
234+ );
235+ }).toList ();
236+ }
237+
238+ static List <VideoParameters > _computeDefaultSimulcastParams ({
239+ required bool isScreenShare,
240+ required VideoParameters original,
241+ }) {
242+ if (isScreenShare) {
243+ return _computeDefaultScreenShareSimulcastParams (original: original);
244+ }
245+ final a = original.dimensions.aspect ();
246+ if ((a - VideoDimensionsHelpers .aspect169).abs () <
247+ (a - VideoDimensionsHelpers .aspect43).abs ()) {
248+ return VideoParametersPresets .defaultSimulcast169;
249+ }
250+
251+ return VideoParametersPresets .defaultSimulcast43;
252+ }
253+
205254 static VideoEncoding _findAppropriateEncoding ({
206255 required bool isScreenShare,
207256 required VideoDimensions dimensions,
@@ -221,8 +270,6 @@ class Utils {
221270 return result;
222271 }
223272
224- static final videoRids = ['q' , 'h' , 'f' ];
225-
226273 @internal
227274 static List <rtc.RTCRtpEncoding > encodingsFromPresets (
228275 VideoDimensions dimensions, {
@@ -233,11 +280,12 @@ class Utils {
233280 if (i >= videoRids.length) {
234281 return ;
235282 }
283+ final size = dimensions.min ();
236284 final rid = videoRids[i];
237285
238286 result.add (e.encoding.toRTCRtpEncoding (
239287 rid: rid,
240- scaleResolutionDownBy: findEvenScaleDownBy (dimensions, e.dimensions),
288+ scaleResolutionDownBy: math. max ( 1 , size / e.dimensions. min () ),
241289 ));
242290 });
243291 return result;
@@ -279,12 +327,10 @@ class Utils {
279327
280328 VideoEncoding ? videoEncoding = options.videoEncoding;
281329
282- final useSimulcast = ! isScreenShare && options.simulcast;
283-
284- if ((videoEncoding == null && ! useSimulcast) || dimensions == null ) {
330+ if ((videoEncoding == null && ! options.simulcast) || dimensions == null ) {
285331 // don't set encoding when we are not simulcasting and user isn't restricting
286332 // encoding parameters
287- return null ;
333+ return [rtc. RTCRtpEncoding ()] ;
288334 }
289335
290336 final presets = _presetsForDimensions (
@@ -299,34 +345,48 @@ class Utils {
299345 dimensions: dimensions,
300346 presets: presets,
301347 );
348+
302349 logger.fine ('using video encoding' , videoEncoding);
303350 }
304351
305- // Not simulcast
306- if (! useSimulcast) return [videoEncoding.toRTCRtpEncoding ()];
307-
308- final VideoParameters lowPreset = presets.first;
309- VideoParameters ? midPreset;
310- if (presets.length > 1 ) {
311- midPreset = presets[1 ];
352+ if (! options.simulcast) {
353+ // not using simulcast
354+ return [videoEncoding.toRTCRtpEncoding ()];
312355 }
356+
313357 final original = VideoParameters (
314358 dimensions: dimensions,
315359 encoding: videoEncoding,
316360 );
317361
362+ final userParams = isScreenShare
363+ ? options.screenShareSimulcastLayers
364+ : options.videoSimulcastLayers;
365+
366+ final params = (userParams.isNotEmpty
367+ ? userParams
368+ : _computeDefaultSimulcastParams (
369+ isScreenShare: isScreenShare, original: original))
370+ .sorted ();
371+
372+ final VideoParameters lowPreset = params.first;
373+ VideoParameters ? midPreset;
374+ if (params.length > 1 ) {
375+ midPreset = params[1 ];
376+ }
377+
318378 final size = dimensions.max ();
319- List <VideoParameters > computedPresets = [original];
379+ List <VideoParameters > computedParams = [original];
320380
321381 if (size >= 960 && midPreset != null ) {
322- computedPresets = [lowPreset, midPreset, original];
323- } else if (size >= 500 ) {
324- computedPresets = [lowPreset, original];
382+ computedParams = [lowPreset, midPreset, original];
383+ } else if (size >= 480 ) {
384+ computedParams = [lowPreset, original];
325385 }
326386
327387 return encodingsFromPresets (
328388 dimensions,
329- presets: computedPresets ,
389+ presets: computedParams ,
330390 );
331391 }
332392
0 commit comments