AVSpeechSynthesizer does not speak after using SFSpeechRecognizer

So, I created a simple application that recognizes speech recognition using SFSpeechRecognizer and displays the converted speech into text in a UITextView on the screen. Now I'm trying to make the phone say that the text is displayed. For some reason this does not work. Operation Function AVSpeechSynthesizer only works before using SFSpeechRecognizer. For example, when the application starts, it has some welcome text displayed in the UITextView, if I click the talk button, the phone will say the welcome text. Then, if I record (for speech recognition), the recognized speech will be displayed in a UITextView. Now I want the phone to say this text, but unfortunately it doesn’t.

here is the code

import UIKit import Speech import AVFoundation class ViewController: UIViewController, SFSpeechRecognizerDelegate, AVSpeechSynthesizerDelegate { @IBOutlet weak var textView: UITextView! @IBOutlet weak var microphoneButton: UIButton! private let speechRecognizer = SFSpeechRecognizer(locale: Locale.init(identifier: "en-US"))! private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest? private var recognitionTask: SFSpeechRecognitionTask? private let audioEngine = AVAudioEngine() override func viewDidLoad() { super.viewDidLoad() microphoneButton.isEnabled = false speechRecognizer.delegate = self SFSpeechRecognizer.requestAuthorization { (authStatus) in var isButtonEnabled = false switch authStatus { case .authorized: isButtonEnabled = true case .denied: isButtonEnabled = false print("User denied access to speech recognition") case .restricted: isButtonEnabled = false print("Speech recognition restricted on this device") case .notDetermined: isButtonEnabled = false print("Speech recognition not yet authorized") } OperationQueue.main.addOperation() { self.microphoneButton.isEnabled = isButtonEnabled } } } @IBAction func speakTapped(_ sender: UIButton) { let string = self.textView.text let utterance = AVSpeechUtterance(string: string!) let synthesizer = AVSpeechSynthesizer() synthesizer.delegate = self synthesizer.speak(utterance) } @IBAction func microphoneTapped(_ sender: AnyObject) { if audioEngine.isRunning { audioEngine.stop() recognitionRequest?.endAudio() microphoneButton.isEnabled = false microphoneButton.setTitle("Start Recording", for: .normal) } else { startRecording() microphoneButton.setTitle("Stop Recording", for: .normal) } } func startRecording() { if recognitionTask != nil { //1 recognitionTask?.cancel() recognitionTask = nil } let audioSession = AVAudioSession.sharedInstance() //2 do { try audioSession.setCategory(AVAudioSessionCategoryRecord) try audioSession.setMode(AVAudioSessionModeMeasurement) try audioSession.setActive(true, with: .notifyOthersOnDeactivation) } catch { print("audioSession properties weren't set because of an error.") } recognitionRequest = SFSpeechAudioBufferRecognitionRequest() //3 guard let inputNode = audioEngine.inputNode else { fatalError("Audio engine has no input node") } //4 guard let recognitionRequest = recognitionRequest else { fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object") } //5 recognitionRequest.shouldReportPartialResults = true //6 recognitionTask = speechRecognizer.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in //7 var isFinal = false //8 if result != nil { self.textView.text = result?.bestTranscription.formattedString //9 isFinal = (result?.isFinal)! } if error != nil || isFinal { //10 self.audioEngine.stop() inputNode.removeTap(onBus: 0) self.recognitionRequest = nil self.recognitionTask = nil self.microphoneButton.isEnabled = true } }) let recordingFormat = inputNode.outputFormat(forBus: 0) //11 inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in self.recognitionRequest?.append(buffer) } audioEngine.prepare() //12 do { try audioEngine.start() } catch { print("audioEngine couldn't start because of an error.") } textView.text = "Say something, I'm listening!" } func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) { if available { microphoneButton.isEnabled = true } else { microphoneButton.isEnabled = false } } } 
+6
source share
5 answers

The problem is that when you start speech recognition, you set up an audio recording for your category. You cannot play audio (including speech synthesis) with an audio recording session.

+7
source

Please use the code below to fix the problem:

 let audioSession = AVAudioSession.sharedInstance() do { try audioSession.setCategory(AVAudioSessionCategoryPlayback) try audioSession.setMode(AVAudioSessionModeDefault) } catch { print("audioSession properties weren't set because of an error.") } Here, we have to use the above code in the following way: @IBAction func microphoneTapped(_ sender: AnyObject) { if audioEngine.isRunning { audioEngine.stop() recognitionRequest?.endAudio() let audioSession = AVAudioSession.sharedInstance() do { try audioSession.setCategory(AVAudioSessionCategoryPlayback) try audioSession.setMode(AVAudioSessionModeDefault) } catch { print("audioSession properties weren't set because of an error.") } microphoneButton.isEnabled = false microphoneButton.setTitle("Start Recording", for: .normal) } else { startRecording() microphoneButton.setTitle("Stop Recording", for: .normal) } } 

Here, after stopping audioengine , we set the audioSession Category to AVAudioSessionCategoryPlayback and audioSession Mode . AVAudioSessionModeDefault . Then, when you call the next text to speech method, it will work fine.

+8
source

You should change this line of the startRecording method to:

 try audioSession.setCategory(AVAudioSessionCategoryRecord) 

to:

 try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord) 
+7
source

when using STT you should set the following:

 AVAudioSession *avAudioSession = [AVAudioSession sharedInstance]; if (avAudioSession) { [avAudioSession setCategory:AVAudioSessionCategoryRecord error:nil]; [avAudioSession setMode:AVAudioSessionModeMeasurement error:nil]; [avAudioSession setActive:true withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil]; } 

If using TTS, set AudioSession again, for example:

 [regRequest endAudio]; AVAudioSession *avAudioSession = [AVAudioSession sharedInstance]; if (avAudioSession) { [avAudioSession setCategory:AVAudioSessionCategoryPlayback error:nil]; [avAudioSession setMode:AVAudioSessionModeDefault error:nil]; } 

His work is excellent for me. Also fixed the problem with LOW AUDIO.

0
source

try the following:

 audioSession.setCategory(AVAudioSessionCategoryRecord) 
-one
source

Source: https://habr.com/ru/post/1011731/


All Articles