Skip to content

Commit dc5964c

Browse files
author
Mikael Wills
committed
WIP
1 parent e39b339 commit dc5964c

File tree

1 file changed

+221
-58
lines changed

1 file changed

+221
-58
lines changed

lib/src/rtc_session.dart

Lines changed: 221 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)