2017-02-19 33 views
1

Я использую картинку 6s плюс, вот код для ViewController распознавания речи:в Swift 3 и прошивке 10

import Speech 
import UIKit 

protocol SpeechRecognitionDelegate: class { 
    func speechRecognitionComplete(query: String?) 
    func speechRecognitionCancelled() 
} 

class SpeechRecognitionViewController: UIViewController, SFSpeechRecognizerDelegate { 

    var textView: UITextView! 

    private let speechRecognizer = SFSpeechRecognizer(locale: Locale.init(identifier: "en-US")) 
    private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest? 
    private var recognitionTask: SFSpeechRecognitionTask? 
    private let audioEngine = AVAudioEngine() 
    private var query: String? 
    weak var delegate: SpeechRecognitionDelegate? 
    var isListening: Bool = false 

    init(delegate: SpeechRecognitionDelegate, frame: CGRect) { 
     super.init(nibName: nil, bundle: nil) 
     self.delegate = delegate 
     self.view.frame = frame 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    enum ErrorMessage: String { 
     case denied = "To enable Speech Recognition go to Settings -> Privacy." 
     case notDetermined = "Authorization not determined - please try again." 
     case restricted = "Speech Recognition is restricted on this device." 
     case noResults = "No results found - please try a different search." 
    } 



    func displayErrorAlert(message: ErrorMessage) { 
     let alertController = UIAlertController(title: nil, 
               message: message.rawValue, 
               preferredStyle: .alert) 
     let alertAction = UIAlertAction(title: "OK", style: .default, handler: nil) 
     alertController.addAction(alertAction) 
     OperationQueue.main.addOperation { 
      self.present(alertController, animated: true, completion: nil) 
     } 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 

    } 

    override func viewWillAppear(_ animated: Bool) { 
     super.viewWillAppear(animated) 

     speechRecognizer?.delegate = self 

     //initialize textView and add it to self.view 
    } 

    func startListening() { 
     guard !isListening else {return} 
     isListening = true 

     recognitionRequest = SFSpeechAudioBufferRecognitionRequest() 
     guard let recognitionRequest = recognitionRequest else { 
      print("SpeechRecognitionViewController recognitionRequest \(self.recognitionRequest)") 
      return 
     } 

     recognitionRequest.shouldReportPartialResults = true 

     recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in 
      var isFinal = false 

      if result != nil { 
       self.query = result?.bestTranscription.formattedString 
       self.textView.text = self.query 
       isFinal = (result?.isFinal)! 
      } 

      if error != nil || isFinal { 
       print("recognitionTask error = \(error?.localizedDescription)") 
       self.stopListening() 
      } 
     }) 

     let audioSession = AVAudioSession.sharedInstance() 
     do { 
      try audioSession.setCategory(AVAudioSessionCategoryRecord) 
      try audioSession.setMode(AVAudioSessionModeMeasurement) 
      try audioSession.setActive(true, with: .notifyOthersOnDeactivation) 
     } catch { 
      print("Audio session isn't configured correctly") 
     } 

     let recordingFormat = audioEngine.inputNode?.outputFormat(forBus: 0) 
     audioEngine.inputNode?.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, time) in 
      self.recognitionRequest?.append(buffer) 
     } 

     audioEngine.prepare() 

     do { 
      try audioEngine.start() 
      textView.text = "Listening..." 
     } catch { 
      print("Audio engine failed to start") 
     } 
    } 

    func stopListening() { 
     guard isListening else {return} 
     audioEngine.stop() 
     audioEngine.inputNode?.removeTap(onBus: 0) 
     recognitionRequest = nil 
     recognitionTask = nil 
     isListening = false 
    } 

    // MARK: SFSpeechRecognizerDelegate 

    func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) { 
     if !available { 
      let alertController = UIAlertController(title: nil, 
                message: "Speech Recognition is currently unavailable.", 
                preferredStyle: .alert) 
      let alertAction = UIAlertAction(title: "OK", style: .default) { (alertAction) in 
       .self.stopListening() 
      } 
      alertController.addAction(alertAction) 
      present(alertController, animated: true) 
     } 
    } 
} 

Это VC вложен в другой ViewController. Когда кнопка постучана в родительском контроллере просмотра, вызывается startListening(). Когда эта же кнопка снова нажата, вызывается stopListening().

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

recognitionTask error = Optional("The operation couldn’t be completed. (kAFAssistantErrorDomain error 209.)") 

и распознавание речи не работает больше. Через 30 секунд я получаю ошибку таймаута:

Optional(Error Domain=kAFAssistantErrorDomain Code=203 "Timeout" UserInfo={NSLocalizedDescription=Timeout, NSUnderlyingError=0x170446f90 {Error Domain=SiriSpeechErrorDomain Code=100 "(null)"}}) 

Оригинальный код здесь SayWhat

Что мне не хватает?

+0

Вы не должны только быть установлен в значение 'isListening' свойство' true' внутри 'do' блока, где прослушивания фактически инициировано? Я не знаю, является ли это источником проблемы, но я вижу, что многие ваши методы охраняются на основе значения этого свойства. – Pierce

+0

Нет, 'guard' не имеет ничего общего с этой ошибкой. Ошибка всегда генерируется в этой строке 'accountTask = speechRecognizer? .RecognitionTask (с: recognitionRequest, resultHandler' – Carpsen90

ответ

1

Все, что я должен был сделать, это добавить recognitionRequest?.endAudio() при попытке остановить прослушивание:

func stopListening() { 
    guard isListening else {return} 
    audioEngine.stop() 
    audioEngine.inputNode?.removeTap(onBus: 0) 
    // Indicate that the audio source is finished and no more audio will be appended 
    recognitionRequest?.endAudio() 
    recognitionRequest = nil 
    recognitionTask = nil 
    isListening = false 
}