iOS开发:如何在持续运行SFSpeechRecognizer时定时清除识别结果?
解决方案
核心问题分析
你当前代码的关键问题是:在识别完成(isFinal = true)或出现错误时,调用了audioEngine.stop()和inputNode.removeTap(onBus: 0),直接终止了音频输入,导致麦克风关闭无法持续识别。另外,移除输入节点的tap并不能清除识别结果,反而会中断音频流。
具体修改步骤
保留音频引擎持续运行
移除error != nil || isFinal分支中停止音频引擎、移除tap的代码,仅在用户主动停止识别时才执行这些操作。当识别完成(isFinal)时,只需要取消当前的recognitionTask并重新创建新任务,就能继续接收新的语音输入。实现定时清除识别结果
使用定时器实现每隔2秒清空文本框,每次收到新的识别结果时重置定时器,避免在用户说话过程中提前清空内容,同时确保在主线程更新UI。
修改后的完整代码
private var clearResultTimer: Timer? private func startRecording() throws { // 取消之前的任务和定时器 recognitionTask?.cancel() self.recognitionTask = nil clearResultTimer?.invalidate() let audioSession = AVAudioSession.sharedInstance() try audioSession.setCategory(.record, mode: .measurement, options: .duckOthers) try audioSession.setActive(true, options: .notifyOthersOnDeactivation) let inputNode = audioEngine.inputNode recognitionRequest = SFSpeechAudioBufferRecognitionRequest() guard let recognitionRequest = recognitionRequest else { fatalError("Unable to create a SFSpeechAudioBufferRecognitionRequest object") } recognitionRequest.shouldReportPartialResults = true if #available(iOS 13, *) { recognitionRequest.requiresOnDeviceRecognition = false } recognitionTask = speechRecognizer.recognitionTask(with: recognitionRequest) { [weak self] result, error in guard let self = self else { return } var isFinal = false if let result = result { self.textView.text = result.bestTranscription.formattedString // 重置定时器:每次收到新结果后,2秒后清空 self.clearResultTimer?.invalidate() self.clearResultTimer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { _ in DispatchQueue.main.async { self.textView.text = "(Go ahead, I'm listening)" } } isFinal = result.isFinal print("Text \(result.bestTranscription.formattedString)") } // 错误处理:根据实际错误类型决定是否终止,这里仅打印错误 if error != nil { print("识别错误: \(error!.localizedDescription)") } else if isFinal { // 识别完成后,重新创建任务继续监听 self.recognitionTask?.cancel() self.recognitionTask = nil do { try self.startRecording() } catch { print("重新启动识别失败: \(error.localizedDescription)") } } } let recordingFormat = inputNode.outputFormat(forBus: 0) // 避免重复安装tap,先移除再添加 inputNode.removeTap(onBus: 0) inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in self.recognitionRequest?.append(buffer) } if !audioEngine.isRunning { audioEngine.prepare() try audioEngine.start() } textView.text = "(Go ahead, I'm listening)" } // 供用户主动停止识别调用的方法 private func stopRecording() { recognitionTask?.cancel() recognitionTask = nil clearResultTimer?.invalidate() audioEngine.stop() audioEngine.inputNode.removeTap(onBus: 0) recognitionRequest = nil recordButton.isEnabled = true recordButton.setTitle("Start Recording", for: []) }
关键说明
- 定时器重置逻辑:每次收到新的识别结果(包括部分结果)时重置定时器,确保只有用户停止说话2秒后才清空结果,不打断正在进行的识别。
- 持续识别实现:当一次语音识别完成(
isFinal = true)时,取消当前任务并重新启动识别,实现无间断监听。 - 错误处理优化:仅在严重错误(如权限失效、硬件故障)时才考虑停止引擎,普通识别错误可忽略,保持识别持续运行。
内容的提问来源于stack exchange,提问作者Sanzhar
相关产品推荐
相关产品推荐

