From 0627e00f3b250e470e9442d49e21f5f363ede1b6 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Tue, 3 Feb 2026 10:45:31 +0100 Subject: [PATCH 1/2] fix: bypass voice processing only for stereo --- .../Utils/AudioDeviceModule/AudioDeviceModule.swift | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ios/RCTWebRTC/Utils/AudioDeviceModule/AudioDeviceModule.swift b/ios/RCTWebRTC/Utils/AudioDeviceModule/AudioDeviceModule.swift index 64113fcf3..5212e41c9 100644 --- a/ios/RCTWebRTC/Utils/AudioDeviceModule/AudioDeviceModule.swift +++ b/ios/RCTWebRTC/Utils/AudioDeviceModule/AudioDeviceModule.swift @@ -1,5 +1,5 @@ // -// Copyright © 2025 Stream.io Inc. All rights reserved. +// Copyright © 2026 Stream.io Inc. All rights reserved. // import AudioToolbox @@ -92,7 +92,7 @@ import WebRTC return ".willReleaseAudioEngine(\(engine))" case .configureInputFromSource(let engine, let source, let destination, let format): - return ".configureInputFromSource(\(engine), source:\(source?.description ?? "nil"), destination:\(destination), format:\(format))" + return ".configureInputFromSource(\(engine), source:\(source), destination:\(destination), format:\(format))" case .configureOutputFromSource(let engine, let source, let destination, let format): return ".configureOutputFromSource(\(engine), source:\(source), destination:\(destination?.description ?? "nil"), format:\(format))" @@ -221,9 +221,6 @@ import WebRTC audioLevelsAdapter.subject = audioLevelSubject source.observer = self - - source.isVoiceProcessingBypassed = true - isVoiceProcessingBypassedSubject.send(true) } /// Objective-C compatible convenience initializer. @@ -255,6 +252,7 @@ import WebRTC /// sendAudio capability. _ = source.setRecordingAlwaysPreparedMode(false) source.prefersStereoPlayout = isPreferred + source.isVoiceProcessingBypassed = isPreferred } /// Starts or stops speaker playout on the ADM, retrying transient failures. From 25831e0fc3b802df714390f921874ee71207b07b Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Tue, 3 Feb 2026 11:29:52 +0100 Subject: [PATCH 2/2] chore: sync more default media constriants --- ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m | 49 +++++++++++++++------ 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m b/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m index e64b32218..d828f4260 100644 --- a/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m +++ b/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m @@ -30,6 +30,25 @@ - (void)setVideoEffectProcessor:(VideoEffectProcessor *)videoEffectProcessor objc_setAssociatedObject(self, @selector(videoEffectProcessor), videoEffectProcessor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } +#pragma mark - Default Media Constraints + +/** + * Returns common optional constraints for improved audio quality. + * Ported from stream-video-swift DefaultRTCMediaConstraints. + * https://github.com/GetStream/stream-video-swift/blob/develop/Sources/StreamVideo/WebRTC/DefaultRTCMediaConstraints.swift + */ ++ (NSDictionary *)commonOptionalConstraints { + return @{ + @"DtlsSrtpKeyAgreement": kRTCMediaConstraintsValueTrue, + @"googAutoGainControl": kRTCMediaConstraintsValueTrue, + @"googNoiseSuppression": kRTCMediaConstraintsValueTrue, + @"googEchoCancellation": kRTCMediaConstraintsValueTrue, + @"googHighpassFilter": kRTCMediaConstraintsValueTrue, + @"googTypingNoiseDetection": kRTCMediaConstraintsValueTrue, + @"googAudioMirroring": kRTCMediaConstraintsValueFalse + }; +} + #pragma mark - getUserMedia - (NSString *)convertBoolToString:(id)value { @@ -45,19 +64,23 @@ - (NSString *)convertBoolToString:(id)value { - (RTCAudioTrack *)createAudioTrack:(NSDictionary *)constraints { NSString *trackId = [[NSUUID UUID] UUIDString]; NSDictionary *audioConstraints = constraints[@"audio"]; - NSMutableDictionary *optionalConstraints = [NSMutableDictionary dictionary]; - optionalConstraints[@"googAutoGainControl"] = audioConstraints[@"autoGainControl"] != nil - ? [self convertBoolToString:audioConstraints[@"autoGainControl"]] - : @"true"; - optionalConstraints[@"googNoiseSuppression"] = - audioConstraints[@"noiseSuppression"] != nil ? [self convertBoolToString:audioConstraints[@"noiseSuppression"]] - : @"true"; - optionalConstraints[@"googEchoCancellation"] = - audioConstraints[@"echoCancellation"] != nil ? [self convertBoolToString:audioConstraints[@"echoCancellation"]] - : @"true"; - optionalConstraints[@"googHighpassFilter"] = audioConstraints[@"highpassFilter"] != nil - ? [self convertBoolToString:audioConstraints[@"highpassFilter"]] - : @"true"; + + // Start with common optional constraints as defaults + NSMutableDictionary *optionalConstraints = [[[self class] commonOptionalConstraints] mutableCopy]; + + // Override with user-provided constraints if specified + if (audioConstraints[@"autoGainControl"] != nil) { + optionalConstraints[@"googAutoGainControl"] = [self convertBoolToString:audioConstraints[@"autoGainControl"]]; + } + if (audioConstraints[@"noiseSuppression"] != nil) { + optionalConstraints[@"googNoiseSuppression"] = [self convertBoolToString:audioConstraints[@"noiseSuppression"]]; + } + if (audioConstraints[@"echoCancellation"] != nil) { + optionalConstraints[@"googEchoCancellation"] = [self convertBoolToString:audioConstraints[@"echoCancellation"]]; + } + if (audioConstraints[@"highpassFilter"] != nil) { + optionalConstraints[@"googHighpassFilter"] = [self convertBoolToString:audioConstraints[@"highpassFilter"]]; + } RTCMediaConstraints *mediaConstraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:nil optionalConstraints:optionalConstraints];