Skip to content

Commit d7b9b3a

Browse files
authored
fix: bypass voice processing only for stereo (#25)
ref: GetStream/stream-video-swift#1009 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Consolidated default audio constraints so tracks use sensible defaults while still honoring user-specified audio settings * **Bug Fixes** * Voice processing no longer forcibly bypassed by default * Stereo playout preference now correctly aligns with voice processing bypass state * **Chores** * Updated copyright year to 2026 <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent e506298 commit d7b9b3a

2 files changed

Lines changed: 39 additions & 18 deletions

File tree

ios/RCTWebRTC/Utils/AudioDeviceModule/AudioDeviceModule.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright © 2025 Stream.io Inc. All rights reserved.
2+
// Copyright © 2026 Stream.io Inc. All rights reserved.
33
//
44

55
import AudioToolbox
@@ -92,7 +92,7 @@ import WebRTC
9292
return ".willReleaseAudioEngine(\(engine))"
9393

9494
case .configureInputFromSource(let engine, let source, let destination, let format):
95-
return ".configureInputFromSource(\(engine), source:\(source?.description ?? "nil"), destination:\(destination), format:\(format))"
95+
return ".configureInputFromSource(\(engine), source:\(source), destination:\(destination), format:\(format))"
9696

9797
case .configureOutputFromSource(let engine, let source, let destination, let format):
9898
return ".configureOutputFromSource(\(engine), source:\(source), destination:\(destination?.description ?? "nil"), format:\(format))"
@@ -221,9 +221,6 @@ import WebRTC
221221

222222
audioLevelsAdapter.subject = audioLevelSubject
223223
source.observer = self
224-
225-
source.isVoiceProcessingBypassed = true
226-
isVoiceProcessingBypassedSubject.send(true)
227224
}
228225

229226
/// Objective-C compatible convenience initializer.
@@ -255,6 +252,7 @@ import WebRTC
255252
/// sendAudio capability.
256253
_ = source.setRecordingAlwaysPreparedMode(false)
257254
source.prefersStereoPlayout = isPreferred
255+
source.isVoiceProcessingBypassed = isPreferred
258256
}
259257

260258
/// Starts or stops speaker playout on the ADM, retrying transient failures.

ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,25 @@ - (void)setVideoEffectProcessor:(VideoEffectProcessor *)videoEffectProcessor
3030
objc_setAssociatedObject(self, @selector(videoEffectProcessor), videoEffectProcessor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
3131
}
3232

33+
#pragma mark - Default Media Constraints
34+
35+
/**
36+
* Returns common optional constraints for improved audio quality.
37+
* Ported from stream-video-swift DefaultRTCMediaConstraints.
38+
* https://github.com/GetStream/stream-video-swift/blob/develop/Sources/StreamVideo/WebRTC/DefaultRTCMediaConstraints.swift
39+
*/
40+
+ (NSDictionary *)commonOptionalConstraints {
41+
return @{
42+
@"DtlsSrtpKeyAgreement": kRTCMediaConstraintsValueTrue,
43+
@"googAutoGainControl": kRTCMediaConstraintsValueTrue,
44+
@"googNoiseSuppression": kRTCMediaConstraintsValueTrue,
45+
@"googEchoCancellation": kRTCMediaConstraintsValueTrue,
46+
@"googHighpassFilter": kRTCMediaConstraintsValueTrue,
47+
@"googTypingNoiseDetection": kRTCMediaConstraintsValueTrue,
48+
@"googAudioMirroring": kRTCMediaConstraintsValueFalse
49+
};
50+
}
51+
3352
#pragma mark - getUserMedia
3453

3554
- (NSString *)convertBoolToString:(id)value {
@@ -45,19 +64,23 @@ - (NSString *)convertBoolToString:(id)value {
4564
- (RTCAudioTrack *)createAudioTrack:(NSDictionary *)constraints {
4665
NSString *trackId = [[NSUUID UUID] UUIDString];
4766
NSDictionary *audioConstraints = constraints[@"audio"];
48-
NSMutableDictionary *optionalConstraints = [NSMutableDictionary dictionary];
49-
optionalConstraints[@"googAutoGainControl"] = audioConstraints[@"autoGainControl"] != nil
50-
? [self convertBoolToString:audioConstraints[@"autoGainControl"]]
51-
: @"true";
52-
optionalConstraints[@"googNoiseSuppression"] =
53-
audioConstraints[@"noiseSuppression"] != nil ? [self convertBoolToString:audioConstraints[@"noiseSuppression"]]
54-
: @"true";
55-
optionalConstraints[@"googEchoCancellation"] =
56-
audioConstraints[@"echoCancellation"] != nil ? [self convertBoolToString:audioConstraints[@"echoCancellation"]]
57-
: @"true";
58-
optionalConstraints[@"googHighpassFilter"] = audioConstraints[@"highpassFilter"] != nil
59-
? [self convertBoolToString:audioConstraints[@"highpassFilter"]]
60-
: @"true";
67+
68+
// Start with common optional constraints as defaults
69+
NSMutableDictionary *optionalConstraints = [[[self class] commonOptionalConstraints] mutableCopy];
70+
71+
// Override with user-provided constraints if specified
72+
if (audioConstraints[@"autoGainControl"] != nil) {
73+
optionalConstraints[@"googAutoGainControl"] = [self convertBoolToString:audioConstraints[@"autoGainControl"]];
74+
}
75+
if (audioConstraints[@"noiseSuppression"] != nil) {
76+
optionalConstraints[@"googNoiseSuppression"] = [self convertBoolToString:audioConstraints[@"noiseSuppression"]];
77+
}
78+
if (audioConstraints[@"echoCancellation"] != nil) {
79+
optionalConstraints[@"googEchoCancellation"] = [self convertBoolToString:audioConstraints[@"echoCancellation"]];
80+
}
81+
if (audioConstraints[@"highpassFilter"] != nil) {
82+
optionalConstraints[@"googHighpassFilter"] = [self convertBoolToString:audioConstraints[@"highpassFilter"]];
83+
}
6184

6285
RTCMediaConstraints *mediaConstraints =
6386
[[RTCMediaConstraints alloc] initWithMandatoryConstraints:nil optionalConstraints:optionalConstraints];

0 commit comments

Comments
 (0)