From 117b01acbd585812e8ad0b87a1a07c22c46265eb Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 13 Dec 2025 00:26:05 +0000 Subject: [PATCH] fix(ios): avoid MainActor isolation in audio tap --- apps/ios/Sources/Voice/VoiceWakeManager.swift | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/ios/Sources/Voice/VoiceWakeManager.swift b/apps/ios/Sources/Voice/VoiceWakeManager.swift index f336a4ec1..f77a16588 100644 --- a/apps/ios/Sources/Voice/VoiceWakeManager.swift +++ b/apps/ios/Sources/Voice/VoiceWakeManager.swift @@ -2,6 +2,14 @@ import AVFAudio import Foundation import Speech +enum SpeechAudioTapFactory { + static func makeAppendTap(requestBox: SpeechRequestBox) -> @Sendable (AVAudioPCMBuffer, AVAudioTime) -> Void { + { buffer, _ in + requestBox.append(buffer) + } + } +} + final class SpeechRequestBox: @unchecked Sendable { let request: SFSpeechAudioBufferRecognitionRequest @@ -109,19 +117,18 @@ final class VoiceWakeManager: NSObject, ObservableObject { let requestBox = SpeechRequestBox(request: request) let recordingFormat = inputNode.outputFormat(forBus: 0) - inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { @Sendable [requestBox] buffer, _ in - requestBox.append(buffer) - } + let tap = SpeechAudioTapFactory.makeAppendTap(requestBox: requestBox) + inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat, block: tap) self.audioEngine.prepare() try self.audioEngine.start() - self.recognitionTask = self.speechRecognizer?.recognitionTask(with: request) { [weak self] result, error in - guard let self else { return } - Task { @MainActor in - self.handleRecognitionCallback(result: result, error: error) + self.recognitionTask = self.speechRecognizer? + .recognitionTask(with: request) { [weak manager = self] result, error in + Task { @MainActor in + manager?.handleRecognitionCallback(result: result, error: error) + } } - } } private func handleRecognitionCallback(result: SFSpeechRecognitionResult?, error: Error?) {