Завершение работы приложения из-за непредвиденного сбоя приложения при использовании Speech kit ios
Я получил эту ошибку при реализации речи в текст:
Завершение работы приложения из-за необработанного исключения "com.apple.coreaudio.avfaudio", причина: "обязательное условие - ложь: _recordingTap == nil"
а также:
ОШИБКА: [0x1b2df5c40] >avae> AVAudioNode.mm:565: CreateRecordingTap: обязательное условие ложно: _recordingTap == nil
Вот код моего viewController:
public class ViewController: UIViewController, SFSpeechRecognizerDelegate {
// MARK: Properties
private let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))!
private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
private var recognitionTask: SFSpeechRecognitionTask?
private let audioEngine = AVAudioEngine()
@IBOutlet var textView : UITextView!
@IBOutlet var recordButton : UIButton!
// MARK: UIViewController
public override func viewDidLoad() {
super.viewDidLoad()
// Disable the record buttons until authorization has been granted.
recordButton.isEnabled = false
}
override public func viewDidAppear(_ animated: Bool) {
speechRecognizer.delegate = self
SFSpeechRecognizer.requestAuthorization { authStatus in
/*
The callback may not be called on the main thread. Add an
operation to the main queue to update the record button's state.
*/
OperationQueue.main.addOperation {
switch authStatus {
case .authorized:
self.recordButton.isEnabled = true
case .denied:
self.recordButton.isEnabled = false
self.recordButton.setTitle("User denied access to speech recognition", for: .disabled)
case .restricted:
self.recordButton.isEnabled = false
self.recordButton.setTitle("Speech recognition restricted on this device", for: .disabled)
case .notDetermined:
self.recordButton.isEnabled = false
self.recordButton.setTitle("Speech recognition not yet authorized", for: .disabled)
}
}
}
}
private func startRecording() throws {
// Cancel the previous task if it's running.
if let recognitionTask = recognitionTask {
recognitionTask.cancel()
self.recognitionTask = nil
}
let audioSession = AVAudioSession.sharedInstance()
try audioSession.setCategory(AVAudioSessionCategoryRecord)
try audioSession.setMode(AVAudioSessionModeMeasurement)
try audioSession.setActive(true, with: .notifyOthersOnDeactivation)
recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
guard let inputNode = audioEngine.inputNode else { fatalError("Audio engine has no input node") }
guard let recognitionRequest = recognitionRequest else { fatalError("Unable to created a SFSpeechAudioBufferRecognitionRequest object") }
// Configure request so that results are returned before audio recording is finished
recognitionRequest.shouldReportPartialResults = true
// A recognition task represents a speech recognition session.
// We keep a reference to the task so that it can be cancelled.
recognitionTask = speechRecognizer.recognitionTask(with: recognitionRequest) { result, error in
var isFinal = false
if let result = result {
self.textView.text = result.bestTranscription.formattedString
isFinal = result.isFinal
}
if error != nil || isFinal {
self.audioEngine.stop()
inputNode.removeTap(onBus: 0)
self.recognitionRequest = nil
self.recognitionTask = nil
self.recordButton.isEnabled = true
self.recordButton.setTitle("Start Recording", for: [])
}
}
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
self.recognitionRequest?.append(buffer)
}
audioEngine.prepare()
try audioEngine.start()
textView.text = "(Go ahead, I'm listening)"
}
// MARK: SFSpeechRecognizerDelegate
public func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
if available {
recordButton.isEnabled = true
recordButton.setTitle("Start Recording", for: [])
} else {
recordButton.isEnabled = false
recordButton.setTitle("Recognition not available", for: .disabled)
}
}
// MARK: Interface Builder actions
@IBAction func recordButtonTapped() {
if audioEngine.isRunning {
audioEngine.stop()
recognitionRequest?.endAudio()
recordButton.isEnabled = false
recordButton.setTitle("Stopping", for: .disabled)
} else {
try! startRecording()
recordButton.setTitle("Stop recording", for: [])
}
}
}
4 ответа
Вы можете попробовать использовать его на остановке записи
Свифт 3:
audioEngine.inputNode?.removeTap(onBus: 0)
Это помогло мне и должно помочь вам тоже.
Вы, вероятно, уже нажали на автобус, и вы не можете иметь еще один на том же автобусе. Вы должны удалить TapOnBus, когда вы останавливаете свой двигатель.
audioEngine.inputNode?.removeTap(onBus: 0)
Ошибка говорит о том, что на этой шине уже установлен кран, а другого нет.
Сначала вы должны удалить кран для этого автобуса. Затем снова вы можете установить кран на автобусе.
let inputNode = audioEngine.inputNode
inputNode.removeTap(onBus: 0)
Это поможет.
Во-первых, как все говорят, вы должны очистить inputNode
Но в моем случае эта ошибка все еще была, потому что я строго ссылался на audioEngine = AVAudioEngine(). После того, как я начну воссоздавать его, проблема исчезла.
Вот мой класс для работы с речевым движком: (Создавайте экземпляр WordRecouncer каждый раз, когда вам нужно работать с речевым движком)
import Speech
final class WordRecognizer {
private let audioEngine = AVAudioEngine()
private let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))
private var request: SFSpeechAudioBufferRecognitionRequest?
private var task: SFSpeechRecognitionTask?
private unowned let delegate: WordRecognizerDelegate
init(delegate: WordRecognizerDelegate) {
self.delegate = delegate
debugPrint("init audio system")
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(.record, mode: .measurement, options: .duckOthers)
try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
} catch {
debugPrint("init error: \(error.localizedDescription)")
}
}
deinit {
debugPrint("clear audio system")
do {
try AVAudioSession.sharedInstance().setActive(false)
} catch {
debugPrint("clear error: \(error.localizedDescription)")
}
}
func startTask() {
guard let recognizer = speechRecognizer else { return }
let newRequest = SFSpeechAudioBufferRecognitionRequest()
self.request = newRequest
let task = recognizer.recognitionTask(with: newRequest, resultHandler: { [weak self] result, error in
guard let result = result else { return }
debugPrint(result.bestTranscription.formattedString)
if Thread.isMainThread {
self?.onRecoginize(transcriptions: result.transcriptions)
} else {
DispatchQueue.main.async { [weak self] in
self?.onRecoginize(transcriptions: result.transcriptions)
}
}
})
self.task = task
let recordingFormat = audioEngine.inputNode.outputFormat(forBus: 0)
audioEngine.inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { [weak self] buffer, time in
self?.request?.append(buffer)
}
audioEngine.prepare()
debugPrint("start audio system")
do {
try audioEngine.start()
} catch {
debugPrint("start error: \(error.localizedDescription)")
}
}
private func onRecoginize(transcriptions: [SFTranscription]) {
for transcription in transcriptions {
for segment in transcription.segments {
let text = segment.substring.lowercased()
if delegate.recognize(text: text) {
self.stopTask()
self.startTask()
}
}
}
}
private func stopTask() {
if audioEngine.isRunning {
audioEngine.stop()
audioEngine.inputNode.removeTap(onBus: 0)
}
if let request = self.request {
request.endAudio()
self.request = nil
}
if let task = self.task {
task.cancel()
self.task = nil
}
}
}
protocol WordRecognizerDelegate: AnyObject {
func recognize(text: String) -> Bool
}