@@ -2066,7 +2066,7 @@ class RTCSession extends EventManager implements Owner {
20662066 Map <String , dynamic > mediaConstraints = < String , dynamic > {
20672067 'audio' : true ,
20682068 'video' : < String , dynamic > {
2069- 'mandatory' : < String ,dynamic > {
2069+ 'mandatory' : < String , dynamic > {
20702070 'minWidth' : '320' ,
20712071 'minHeight' : '240' ,
20722072 'maxWidth' : '320' ,
@@ -2115,7 +2115,7 @@ class RTCSession extends EventManager implements Owner {
21152115 'Remote wants to upgrade to video but no camera available to send' );
21162116 }
21172117 }
2118- print (" \n\n\n\n\n\n\n ABOUT TO CALL SDP OFFER TO WEB RTTC \n\n\n\n\n\n " );
2118+ print (' \n\n\n\n\n\n\n ABOUT TO CALL SDP OFFER TO WEB RTTC \n\n\n\n\n\n ' );
21192119 logger.d ('emit "sdp"' );
21202120 final String ? processedSDP = _sdpOfferToWebRTC (request.body);
21212121 emit (EventSdp (
@@ -2764,6 +2764,7 @@ class RTCSession extends EventManager implements Owner {
27642764 options['pcConfig' ]? ['sdpSemantics' ] ?? 'unified-plan' ;
27652765
27662766 try {
2767+ print ('MediaConstraints going into upgrade: $mediaConstraints ' );
27672768 MediaStream localStream =
27682769 await navigator.mediaDevices.getUserMedia (mediaConstraints);
27692770 _localMediaStreamLocallyGenerated = true ;
@@ -3154,76 +3155,238 @@ class RTCSession extends EventManager implements Owner {
31543155 }
31553156
31563157 void _optimizeVideoCodecs (Map <String , dynamic > sdp) {
3157- print (" \n\n\n\n\n OPTIMIZING VIDEO CODECS \n\n\n\n\n " );
3158+ print ('Attempting STRATEGY B v2: Remove H264/VP8 and DEPENDENT codecs...' );
31583159
3159- bool isAvaDevice = true ; // Set based on your device detection logic
3160+ // final bool applyOptimizations =
3161+ // Platform.isAndroid; // Or more specific check
3162+ // if (!applyOptimizations) {
3163+ // print("Skipping codec removal (not required for this platform/device).");
3164+ // return;
3165+ // }
31603166
3161- for (Map <String , dynamic > media in sdp['media' ]) {
3162- if (media['type' ] == 'video' ) {
3163- // Get all codec entries with proper casting
3164- List <dynamic > rtpDynamic = media['rtp' ] ?? < dynamic > [];
3165- List <dynamic > fmtpDynamic = media['fmtp' ] ?? < dynamic > [];
3167+ final List <dynamic >? mediaList = sdp['media' ] as List <dynamic >? ;
3168+ if (mediaList == null ) return ;
31663169
3167- // Find payload types for different codecs
3168- List <int > h264PayloadTypes = < int > [];
3169- List <int > vpPayloadTypes = < int > [];
3170+ final List <dynamic > newMediaList = []; // Build a new list
31703171
3171- for (dynamic item in rtpDynamic) {
3172- if (item is Map ) {
3173- String codec = item['codec' ]? .toString ().toLowerCase () ?? '' ;
3172+ for (dynamic mediaDynamic in mediaList) {
3173+ if (mediaDynamic is ! Map <String , dynamic >) {
3174+ newMediaList.add (mediaDynamic);
3175+ continue ;
3176+ }
3177+ final Map <String , dynamic > media = mediaDynamic;
3178+
3179+ if (media['type' ] != 'video' ) {
3180+ newMediaList.add (media); // Keep non-video sections
3181+ continue ;
3182+ }
3183+
3184+ print (
3185+ 'Processing video media section to remove H264/VP8 + dependencies...' );
3186+
3187+ final List <dynamic > rtpDynamic = media['rtp' ] ?? < dynamic > [];
3188+ final List <dynamic > fmtpDynamic =
3189+ media['fmtp' ] ?? < dynamic > []; // Get fmtp lines
3190+
3191+ final Set <String > initialPayloadsToRemove =
3192+ < String > {}; // Use a Set for efficiency
3193+ final List <String > h264Payloads =
3194+ < String > []; // Keep for logging if needed
3195+ final List <String > vp8Payloads = < String > []; // Keep for logging if needed
3196+
3197+ // 1. Identify initial H264 and VP8 payloads
3198+ for (dynamic item in rtpDynamic) {
3199+ if (item is Map ) {
3200+ final String ? payload = item['payload' ]? .toString ();
3201+ final String codec = item['codec' ]? .toString ().toLowerCase () ?? '' ;
3202+ if (payload != null ) {
31743203 if (codec == 'h264' ) {
3175- h264PayloadTypes.add (item['payload' ]);
3176- } else if (codec == 'vp8' || codec == 'vp9' ) {
3177- vpPayloadTypes.add (item['payload' ]);
3204+ initialPayloadsToRemove.add (payload);
3205+ h264Payloads.add (payload);
3206+ } else if (codec == 'vp8' ) {
3207+ initialPayloadsToRemove.add (payload);
3208+ vp8Payloads.add (payload);
31783209 }
31793210 }
31803211 }
3212+ }
31813213
3182- if (isAvaDevice) {
3183- // APPROACH 1: For AVA devices - Try to modify H.264 profiles for better compatibility
3184- for (dynamic item in fmtpDynamic) {
3185- if (item is Map && h264PayloadTypes.contains (item['payload' ])) {
3186- String config = item['config' ]? .toString () ?? '' ;
3187- if (config.contains ('profile-level-id' )) {
3188- // Try a more basic/compatible H.264 profile
3189- // 42001f = Baseline Profile, Level 3.1 with constraint set
3190- config = config.replaceAll (RegExp (r'profile-level-id=[^;]+' ),
3191- 'profile-level-id=42001f' );
3192- item['config' ] = config;
3193- }
3194- }
3195- }
3214+ if (initialPayloadsToRemove.isEmpty) {
3215+ print ('No H264 or VP8 codecs found to remove.' );
3216+ newMediaList.add (media);
3217+ continue ;
3218+ }
3219+ print (
3220+ 'Initial H264/VP8 payloads targeted: ${initialPayloadsToRemove .toList ()}' );
31963221
3197- // APPROACH 2: Prioritize VP8/VP9 over H.264
3198- if (vpPayloadTypes.isNotEmpty) {
3199- List <String > payloads = media['payloads' ].toString ().split (' ' );
3200- List <String > reorderedPayloads = < String > [];
3222+ // 2. Identify dependent payloads (like RTX via 'apt')
3223+ final Set <String > allPayloadsToRemove =
3224+ Set <String >.from (initialPayloadsToRemove);
3225+ bool foundNewDependent = true ; // Flag to loop if needed (usually not)
3226+
3227+ while (foundNewDependent) {
3228+ foundNewDependent = false ;
3229+ for (dynamic item in fmtpDynamic) {
3230+ if (item is Map ) {
3231+ final String ? fmtpPayload = item['payload' ]? .toString ();
3232+ final String config = item['config' ]? .toString () ?? '' ;
3233+
3234+ if (fmtpPayload == null ) continue ;
32013235
3202- // Add VP codecs first
3203- for ( int payload in vpPayloadTypes ) {
3204- reorderedPayloads. add (payload. toString ()) ;
3236+ // Check if this fmtp line's payload is already marked for removal
3237+ if (allPayloadsToRemove. contains (fmtpPayload) ) {
3238+ continue ;
32053239 }
32063240
3207- // Add H.264 last
3208- for (String payload in payloads) {
3209- int ? payloadInt = int .tryParse (payload);
3210- if (payloadInt != null &&
3211- ! vpPayloadTypes.contains (payloadInt) &&
3212- ! h264PayloadTypes.contains (payloadInt)) {
3213- reorderedPayloads.add (payload);
3241+ // Simple check for 'apt=XXX'
3242+ final aptMatch = RegExp (r'apt=(\d+)' ).firstMatch (config);
3243+ if (aptMatch != null ) {
3244+ final String ? associatedPayload = aptMatch.group (1 );
3245+ // If the associated payload 'apt' is one we are removing,
3246+ // then we MUST also remove the payload defined for this fmtp line.
3247+ if (associatedPayload != null &&
3248+ allPayloadsToRemove.contains (associatedPayload)) {
3249+ if (allPayloadsToRemove.add (fmtpPayload)) {
3250+ // Add returns true if it was added
3251+ print (
3252+ 'Identified dependent payload $fmtpPayload (apt=$associatedPayload ) for removal.' );
3253+ foundNewDependent =
3254+ true ; // May need another pass if dependencies chain
3255+ }
32143256 }
32153257 }
3258+ // Add checks for other dependency types if necessary (e.g., FEC)
3259+ }
3260+ }
3261+ }
32163262
3217- // Add H.264 at the end (lowest priority)
3218- for (int payload in h264PayloadTypes) {
3219- reorderedPayloads.add (payload.toString ());
3220- }
3263+ print (
3264+ 'Final set of ALL payloads to remove (H264/VP8 + dependents): ${allPayloadsToRemove .toList ()}' );
32213265
3222- media['payloads' ] = reorderedPayloads.join (' ' );
3223- }
3266+ // --- Filter the media section using allPayloadsToRemove ---
3267+
3268+ Map <String , dynamic > modifiedMedia = Map <String , dynamic >.from (media);
32243269
3225- // APPROACH 3 (uncomment if needed): Complete removal of H.264
3226- /*
3270+ // 3. Filter Payloads line (m=video ...)
3271+ final String ? currentPayloadsStr = modifiedMedia['payloads' ]? .toString ();
3272+ if (currentPayloadsStr != null ) {
3273+ final List <String > originalPayloads = currentPayloadsStr.split (' ' );
3274+ final List <String > keptPayloads = originalPayloads
3275+ .where ((p) => ! allPayloadsToRemove.contains (p))
3276+ .toList ();
3277+ modifiedMedia['payloads' ] = keptPayloads.join (' ' );
3278+ print ("Filtered 'payloads': ${modifiedMedia ['payloads' ]}" );
3279+
3280+ if (keptPayloads.isEmpty) {
3281+ print (
3282+ 'Warning: Removing codecs and dependents left no video codecs! Video might fail.' );
3283+ // Optional: skip adding this media section entirely
3284+ // continue;
3285+ }
3286+ } else {
3287+ print ("Warning: 'payloads' field missing." );
3288+ }
3289+
3290+ // 4. Filter rtp array (a=rtpmap:...)
3291+ modifiedMedia['rtp' ] = (modifiedMedia['rtp' ] as List <dynamic >? )
3292+ ? .where ((item) =>
3293+ item is Map &&
3294+ ! allPayloadsToRemove.contains (item['payload' ]? .toString ()))
3295+ .toList () ??
3296+ [];
3297+
3298+ // 5. Filter fmtp array (a=fmtp:...)
3299+ modifiedMedia['fmtp' ] = (modifiedMedia['fmtp' ] as List <dynamic >? )
3300+ ? .where ((item) =>
3301+ item is Map &&
3302+ ! allPayloadsToRemove.contains (item['payload' ]? .toString ()))
3303+ .toList () ??
3304+ [];
3305+
3306+ // 6. Filter rtcpFb array (a=rtcp-fb:...)
3307+ modifiedMedia['rtcpFb' ] = (modifiedMedia['rtcpFb' ] as List <dynamic >? )
3308+ ? .where ((item) =>
3309+ item is Map &&
3310+ ! allPayloadsToRemove.contains (item['payload' ]? .toString ()))
3311+ .toList () ??
3312+ [];
3313+
3314+ newMediaList.add (modifiedMedia);
3315+ } // end iterating media sections
3316+
3317+ sdp['media' ] = newMediaList;
3318+ print ('Finished Strategy B v2: Removing H264/VP8 + dependents.' );
3319+
3320+ // print("\n\n\n\n\n OPTIMIZING VIDEO CODECS \n\n\n\n\n");
3321+ //
3322+ // bool isAvaDevice = true; // Set based on your device detection logic
3323+ //
3324+ // for (Map<String, dynamic> media in sdp['media']) {
3325+ // if (media['type'] == 'video') {
3326+ // // Get all codec entries with proper casting
3327+ // List<dynamic> rtpDynamic = media['rtp'] ?? <dynamic>[];
3328+ // List<dynamic> fmtpDynamic = media['fmtp'] ?? <dynamic>[];
3329+ //
3330+ // // Find payload types for different codecs
3331+ // List<int> h264PayloadTypes = <int>[];
3332+ // List<int> vpPayloadTypes = <int>[];
3333+ //
3334+ // for (dynamic item in rtpDynamic) {
3335+ // if (item is Map) {
3336+ // String codec = item['codec']?.toString().toLowerCase() ?? '';
3337+ // if (codec == 'h264') {
3338+ // h264PayloadTypes.add(item['payload']);
3339+ // } else if (codec == 'vp8' || codec == 'vp9') {
3340+ // vpPayloadTypes.add(item['payload']);
3341+ // }
3342+ // }
3343+ // }
3344+ //
3345+ // if (isAvaDevice) {
3346+ // // APPROACH 1: For AVA devices - Try to modify H.264 profiles for better compatibility
3347+ // for (dynamic item in fmtpDynamic) {
3348+ // if (item is Map && h264PayloadTypes.contains(item['payload'])) {
3349+ // String config = item['config']?.toString() ?? '';
3350+ // if (config.contains('profile-level-id')) {
3351+ // // Try a more basic/compatible H.264 profile
3352+ // // 42001f = Baseline Profile, Level 3.1 with constraint set
3353+ // config = config.replaceAll(RegExp(r'profile-level-id=[^;]+'),
3354+ // 'profile-level-id=42001f');
3355+ // item['config'] = config;
3356+ // }
3357+ // }
3358+ // }
3359+ //
3360+ // // APPROACH 2: Prioritize VP8/VP9 over H.264
3361+ // if (vpPayloadTypes.isNotEmpty) {
3362+ // List<String> payloads = media['payloads'].toString().split(' ');
3363+ // List<String> reorderedPayloads = <String>[];
3364+ //
3365+ // // Add VP codecs first
3366+ // for (int payload in vpPayloadTypes) {
3367+ // reorderedPayloads.add(payload.toString());
3368+ // }
3369+ //
3370+ // // Add H.264 last
3371+ // for (String payload in payloads) {
3372+ // int? payloadInt = int.tryParse(payload);
3373+ // if (payloadInt != null &&
3374+ // !vpPayloadTypes.contains(payloadInt) &&
3375+ // !h264PayloadTypes.contains(payloadInt)) {
3376+ // reorderedPayloads.add(payload);
3377+ // }
3378+ // }
3379+ //
3380+ // // Add H.264 at the end (lowest priority)
3381+ // for (int payload in h264PayloadTypes) {
3382+ // reorderedPayloads.add(payload.toString());
3383+ // }
3384+ //
3385+ // media['payloads'] = reorderedPayloads.join(' ');
3386+ // }
3387+
3388+ // APPROACH 3 (uncomment if needed): Complete removal of H.264
3389+ /*
32273390 if (h264PayloadTypes.isNotEmpty) {
32283391 // Remove H.264 from RTP entries
32293392 media['rtp'] = rtpDynamic.where((dynamic item) {
@@ -3246,13 +3409,13 @@ class RTCSession extends EventManager implements Owner {
32463409 }
32473410 }
32483411 */
3249- }
3250- }
3251- }
3412+ // }
3413+ // }
3414+ // }
32523415 }
32533416
32543417 void _filterH264Codec (Map <String , dynamic > sdp) {
3255- print (" \n\n\n\n\n\n FILTERING h264 \n\n\n\n\n " );
3418+ print (' \n\n\n\n\n\n FILTERING h264 \n\n\n\n\n ' );
32563419 // Go through each media section
32573420 for (Map <String , dynamic > m in sdp['media' ]) {
32583421 if (m['type' ] == 'video' ) {
0 commit comments