2016-10-26 3 views
7

Итак, я создал простое приложение, которое распознает речевое сообщение с использованием SFSpeechRecognizer и отображает преобразованную речь в текст в UITextView на экране. Теперь я пытаюсь заставить телефон говорить, что отображаемый текст. По какой-то причине это не работает. Функция работы AVSpeechSynthesizer работает только до использования SFSpeechRecognizer. Например, когда приложение запускается, у него есть некоторый приветственный текст, отображаемый в UITextView, если я нажимаю кнопку «говорить», телефон будет говорить приветственный текст. Затем, если я записываю (для распознавания речи), распознанная речь будет отображаться в UITextView. Теперь я хочу, чтобы телефон говорил этот текст, но, к сожалению, это не так.AVSpeechSynthesizer не говорит после использования SFSpeechRecognizer

здесь код

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 
     } 
    } 
} 
+0

Показать. Ваш. Код. – matt

+0

@matt Я добавил код. Оригинальная речь в текстовом коде была из учебника для приложения. https://www.appcoda.com/siri-speech-framework/ –

+0

Я нашел [эту ссылку] (http://avikam.com/software/sfspeechrecognizer-tutorial) очень полезно. Он содержит полный исходный код речи для текста, а затем текст в речь с использованием 'AVSpeechSynthesizer' –

ответ

7

Проблема заключается в том, что при запуске распознавания речи, вы установили аудио категорию сеанса записи. Вы не можете воспроизводить аудио (включая синтез речи) со звуковым сеансом записи.

+0

Но если вы посмотрите на эту микрофонНажмите кнопку, нажав на микрофон, если звуковой движок работает, он остановит его и закончит звук. Я что-то упустил? –

+2

Я не говорю, что удаляю часть категории аудиосеанса. Вы нуждаетесь в управлении аудиозаписями больше, не меньше. – matt

7

Вы должны изменить эту строку метода startRecording от:

try audioSession.setCategory(AVAudioSessionCategoryRecord)    

к:

try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord) 
+0

Это прекрасно работает. Но я заметил, что текст в речь звучит ниже во второй раз (и последовательные прогоны). И я не знаю почему. –

+0

Я согласен с Самуэлем Мендесом. Я сталкиваюсь с той же проблемой. –

+0

Это должен быть принятый ответ. Благодаря! – Emilio

-1

попробовать это:

audioSession.setCategory(AVAudioSessionCategoryRecord) 
+0

Дайте некоторое объяснение –

+1

Зачем OP «попробуйте это»? ** Хороший ответ ** всегда будет иметь объяснение того, что было сделано, и почему это было сделано именно так, а не только для OP, но для будущих посетителей SO, которые могут найти этот вопрос и прочитать ваш ответ. –

7

Пожалуйста, используйте приведенный ниже код для крепления проблемы :

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) 
     } 
    } 

Здесь После остановки AudioEngine мы устанавливаем audioSessionКатегория к AVAudioSessionCategoryPlayback и audioSession Режим в AVAudioSessionModeDefault .Затем при вызове следующего текста к способу речи, он будет работа хорошо.

+0

Этот комментарий помог мне решить мою проблему и не оставил меня с изменением громкости звука. Похоже, что важная часть заключается в сбросе настроек audioSession и режима после того, как вы закончите с распознаванием. Спасибо, что поделились этой информацией. –

+0

спасибо, это сэкономило много времени, я искал ошибку в сети и не замечал, что это происходит только после активации активатора. хотя это было ошибкой в ​​11.0.1, но это не так. –

0

при использовании STT, вы должны установить, как это:

AVAudioSession *avAudioSession = [AVAudioSession sharedInstance]; 

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

При использовании ТТС набор AudioSession снова, как это:

[regRequest endAudio]; 

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

Его работа идеально подходит для меня. Также решена проблема LOW AUDIO.

+0

Я согласен с этим. Использование 'AVAudioSessionModeMeasurement' должно быть проверено, если вы испытываете очень низкий уровень громкости и/или проблемы переключения между' AVSpeechSynthesizer' и 'SFSpeechRecognizer' – coco

Смежные вопросы