visionOS 2.4模拟器中SFSpeechRecognizer语音识别失效求解决方案
visionOS 2.4模拟器中SFSpeechRecognizer语音识别失败求助
已知iOS 17+模拟器的SFSpeechRecognizer存在问题,我在visionOS 2.4模拟器中也遇到了语音无法被识别的情况(推测因复用iOS框架导致)。由于没有Apple Vision Pro实体设备,无法进行真机测试,特向大家寻求该模拟器问题的解决办法或建议。
我使用的环境是Swift 6 + Xcode 16.3,以下是控制台日志及相关代码:
控制台日志
BACKGROUND SPATIAL TAP (hit BackgroundTapPlane) //signal to start recording SpeechToTextManager.startRecording() called [0x15388a900|InputElement #0|Initialize] Number of channels = 0 in AudioChannelLayout does not match number of channels = 2 in stream format. iOSSimulatorAudioDevice-22270-1: Abandoning I/O cycle because reconfig pending iOSSimulatorAudioDevice-22270-1: Abandoning I/O cycle because reconfig pending iOSSimulatorAudioDevice-22270-1: Abandoning I/O cycle because reconfig pending iOSSimulatorAudioDevice-22270-1: Abandoning I/O cycle because reconfig pending iOSSimulatorAudioDevice-22270-1: Abandoning I/O cycle because reconfig pending iOSSimulatorAudioDevice-22270-1: Abandoning I/O cycle because reconfig pending SpeechToTextManager.startRecording() completed successfully and recording is active. GameManager.onTapToggle received. speechToTextManager.isAvailable: true, speechToTextManager.isRecording: true GameManager received tap toggle callback. Tapped Object: None BACKGROUND SPATIAL TAP (hit BackgroundTapPlane) // signal to stop recording GESTURE MANAGER - User is already recording, stopping recording SpeechToTextManager.stopRecording() called GameManager.onTapToggle received. speechToTextManager.isAvailable: true, speechToTextManager.isRecording: false Audio data size: 134400 bytes Recognition task error: No speech detected <---
相关代码
private(set) var isRecording: Bool = false private var audioSessionConfigured = false private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest? private var recognitionTask: SFSpeechRecognitionTask? private let audioProcessor = AudioProcessingActor() @MainActor func startRecording() async throws { logger.debug("SpeechToTextManager.startRecording() called") guard !isRecording else { logger.warning("Cannot start recording: Already recording.") throw AppError.alreadyRecording } currentTranscript = "" processingError = nil audioBuffer = Data() isRecording = true do { try await configureAudioSession() try await Task.detached { [weak self] in guard let self = self else { throw AppError.internalError(description: "SpeechToTextManager instance deallocated during recording setup.") } try await self.audioProcessor.configureAudioEngine() let (recognizer, request) = try await MainActor.run { () -> (SFSpeechRecognizer, SFSpeechAudioBufferRecognitionRequest) in guard let result = self.createRecognitionRequest() else { throw AppError.configurationError(description: "Speech recognition not available or SFSpeechRecognizer initialization failed.") } return result } await MainActor.run { self.recognitionRequest = request } await MainActor.run { self.recognitionTask = recognizer.recognitionTask(with: request) { [weak self] result, error in guard let self = self else { return } if let error = error { // WE ENTER INTO THIS BLOCK, ALWAYS self.logger.error("Recognition task error: \(error.localizedDescription)") self.processingError = .speechRecognitionError(description: error.localizedDescription) return } . . . } } . . . }.value } catch { . . . } } @MainActor func stopRecording() { logger.debug("SpeechToTextManager.stopRecording() called") guard isRecording else { logger.debug("Not recording, nothing to do") return } isRecording = false Task.detached { [weak self] in guard let self = self else { return } await self.audioProcessor.stopEngine() let finalBuffer = await self.audioProcessor.getAudioBuffer() await MainActor.run { self.recognitionRequest?.endAudio() self.recognitionTask?.cancel() } . . . } } private func configureAudioSession() async throws { guard !audioSessionConfigured else { return } logger.debug("Configuring audio session for speech recognition...") do { let audioSession = AVAudioSession.sharedInstance() try audioSession.setCategory(.playAndRecord, mode: .default, options: [.duckOthers, .defaultToSpeaker]) try audioSession.setActive(true) audioSessionConfigured = true logger.info("Audio session configured successfully") } catch { logger.error("Failed to configure audio session: \(error.localizedDescription)") throw AppError.audioSessionError(description: "Failed to configure audio session: \(error.localizedDescription)") } } private actor AudioProcessingActor { private let audioEngine = AVAudioEngine() private var audioBuffer = Data() func configureAudioEngine() async throws { let inputNode = audioEngine.inputNode let recordingFormat = inputNode.outputFormat(forBus: 0) // Install tap for audio buffer collection inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { [weak self] buffer, _ in // Create a task to handle the buffer on the actor Task { [weak self] in guard let self = self else { return } // Convert buffer to Data and append to audioBuffer let channelData = buffer.floatChannelData?[0] let frameLength = UInt32(buffer.frameLength) let data = Data(bytes: channelData!, count: Int(frameLength) * MemoryLayout<Float>.size) // Mutate audioBuffer within actor context await self.appendToBuffer(data) } } audioEngine.prepare() } private func appendToBuffer(_ data: Data) { audioBuffer.append(data) } func startEngine() throws { try audioEngine.start() } func stopEngine() { audioEngine.stop() audioEngine.inputNode.removeTap(onBus: 0) } . . . }
内容的提问来源于stack exchange,提问作者cadburia
相关产品推荐
相关产品推荐

