Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ - (BOOL)hasTrackedGraph;
- (AVAudioFormat *)currentInputConnectionFormat;
- (void)materializeSourceNodeWithId:(NSString *)sourceNodeId;
- (BOOL)materializeInputNodeIfNeeded;
- (void)syncVoiceProcessingWithSessionMode;
- (void)materializeTrackedNodesIfNeeded;

- (AVAudioFormat *)liveInputFormat;
Expand Down Expand Up @@ -186,6 +187,8 @@ - (BOOL)materializeInputNodeIfNeeded
return YES;
}

[self syncVoiceProcessingWithSessionMode];

AVAudioFormat *inputFormat = [self currentInputConnectionFormat];

if (inputFormat == nil) {
Expand All @@ -199,6 +202,33 @@ - (BOOL)materializeInputNodeIfNeeded
return YES;
}

// Voice-chat session modes imply Apple's voice-processing I/O (echo
// cancellation, noise suppression, AGC). Without it, speaker output loops back
// into the microphone — full-duplex apps (VoIP, voice agents) hear themselves
// and speech detection self-triggers. Must run before the input format is read
// (voice processing changes the hardware format) and while the engine is
// stopped.
- (void)syncVoiceProcessingWithSessionMode
{
AVAudioSessionMode mode = self.sessionManager.desiredMode;
BOOL wantsVoiceProcessing = [mode isEqualToString:AVAudioSessionModeVoiceChat] ||
[mode isEqualToString:AVAudioSessionModeVideoChat];

AVAudioInputNode *systemInputNode = self.audioEngine.inputNode;
if (systemInputNode.isVoiceProcessingEnabled == wantsVoiceProcessing) {
return;
}

if (self.audioEngine.isRunning) {
[self.audioEngine stop];
}

NSError *vpError = nil;
if (![systemInputNode setVoiceProcessingEnabled:wantsVoiceProcessing error:&vpError]) {
NSLog(@"[AudioEngine] setVoiceProcessingEnabled:%d failed: %@", wantsVoiceProcessing, vpError);
}
}

- (void)materializeTrackedNodesIfNeeded
{
NSArray<NSString *> *sourceNodeIds =
Expand Down