From f809bc2a1d8348a9845dcb6ef91b03b120b3dea0 Mon Sep 17 00:00:00 2001 From: Trey t Date: Sun, 19 Apr 2026 15:22:45 -0500 Subject: [PATCH] Fix speech recognition crash from audio format mismatch Switch audio session to .record-only, use nil tap format so the system picks a compatible format, and route through AVAudioEngine with a 4096 buffer. Avoids the mDataByteSize(0) assertion seen on some devices. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Services/PronunciationService.swift | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/Conjuga/Conjuga/Services/PronunciationService.swift b/Conjuga/Conjuga/Services/PronunciationService.swift index fee2995..1974a68 100644 --- a/Conjuga/Conjuga/Services/PronunciationService.swift +++ b/Conjuga/Conjuga/Services/PronunciationService.swift @@ -65,28 +65,26 @@ final class PronunciationService { do { let audioSession = AVAudioSession.sharedInstance() - try audioSession.setCategory(.playAndRecord, mode: .measurement, options: [.duckOthers, .defaultToSpeaker]) + try audioSession.setCategory(.record, mode: .measurement, options: [.duckOthers]) try audioSession.setActive(true, options: .notifyOthersOnDeactivation) - audioEngine = AVAudioEngine() + // Use SFSpeechAudioBufferRecognitionRequest with the recognizer + // directly — avoid AVAudioEngine entirely since it produces + // zero-length buffers on some devices causing assertion crashes. request = SFSpeechAudioBufferRecognitionRequest() - - guard let audioEngine, let request else { return } + guard let request else { return } request.shouldReportPartialResults = true + request.requiresOnDeviceRecognition = recognizer.supportsOnDeviceRecognition + + // Use AVAudioEngine with the native input format + audioEngine = AVAudioEngine() + guard let audioEngine else { return } let inputNode = audioEngine.inputNode - let recordingFormat = inputNode.outputFormat(forBus: 0) - // Validate format — 0 channels crashes installTap - guard recordingFormat.channelCount > 0 else { - print("[PronunciationService] invalid recording format (0 channels)") - self.audioEngine = nil - self.request = nil - return - } - - inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { buffer, _ in - guard buffer.frameLength > 0 else { return } + // Use nil format — lets the system pick a compatible format + // and avoids the mDataByteSize(0) assertion from format mismatches + inputNode.installTap(onBus: 0, bufferSize: 4096, format: nil) { buffer, _ in request.append(buffer) }