2017-03-22 37 views
0

我試圖使用iOS語音將文本API和文本一起使用到語音API。基本上用戶會說話,他們說的話將會在textview中被轉錄。然後用戶將按下一個按鈕,該按鈕將從文本視圖中的轉錄文本中提供文本到語音。我的錯誤是當用戶按下語音到文本按鈕時,文本到語音按鈕停止工作。但是,如果我沒有按語音到文本按鈕,並通過鍵盤在文本視圖中輸入一些文本,則文本到語音按鈕的作用。我猜這是與文字按鈕的演講有問題。我的代碼沒有出現任何錯誤,我對發生的事情感到困惑。文本到語音錯誤,與文本按鈕的語音衝突

import UIKit 
import Speech 
import AVFoundation 

class SpeechRecognitionViewController: UIViewController, SFSpeechRecognizerDelegate, UIPickerViewDataSource, UIPickerViewDelegate { 

    private var speechRecognizer: SFSpeechRecognizer! 
    private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest! 
    private var recognitionTask: SFSpeechRecognitionTask! 
    private let audioEngine = AVAudioEngine() 
    private var locales: [Locale]! 
    private let defaultLocale = Locale(identifier: "en-US") 

    @IBOutlet weak var recordBtn: UIButton! 

    @IBOutlet weak var speaker: UIButton! 
    @IBOutlet weak var textView: UITextField! 
    //@IBOutlet weak var textView: UITextView! 
    //@IBOutlet private weak var recordBtn : UIButton! 
    //@IBOutlet private weak var picker: UIPickerView! 
    @IBOutlet weak var picker: UIPickerView! 


    override func viewDidLoad() { 
     super.viewDidLoad() 

     recordBtn.isEnabled = false 

     locales = SFSpeechRecognizer.supportedLocales().map({$0}) 

     let index = NSArray(array: locales).index(of: defaultLocale) 
     picker.selectRow(index, inComponent: 0, animated: false) 

     prepareRecognizer(locale: defaultLocale) 
    } 

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

     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.recordBtn.isEnabled = true 

       case .denied: 
        self.recordBtn.isEnabled = false 
        self.recordBtn.setTitle("User denied access to speech recognition", for: .disabled) 

       case .restricted: 
        self.recordBtn.isEnabled = false 
        self.recordBtn.setTitle("Speech recognition restricted on this device", for: .disabled) 

       case .notDetermined: 
        self.recordBtn.isEnabled = false 
        self.recordBtn.setTitle("Speech recognition not yet authorized", for: .disabled) 
       } 
      } 
     } 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
    } 

    private func prepareRecognizer(locale: Locale) { 
     speechRecognizer = SFSpeechRecognizer(locale: locale)! 
     speechRecognizer.delegate = self 
    } 

    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.recordBtn.isEnabled = true 
       self.recordBtn.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 = "(listening...)" 
    } 

    // ========================================================================= 
    // MARK: - UIPickerViewDataSource 

    func numberOfComponents(in pickerView: UIPickerView) -> Int { 
     return 1 
    } 

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 
     return locales.count 
    } 

    // ========================================================================= 
    // MARK: - UIPickerViewDelegate 

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { 
     return locales[row].identifier 
    } 

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 
     let locale = locales[row] 
     prepareRecognizer(locale: locale) 
    } 

    // ========================================================================= 
    // MARK: - SFSpeechRecognizerDelegate 

    public func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) { 
     if available { 
      recordBtn.isEnabled = true 
      recordBtn.setTitle("Start Recording", for: []) 
     } else { 
      recordBtn.isEnabled = false 
      recordBtn.setTitle("Recognition not available", for: .disabled) 
     } 
    } 

    // ========================================================================= 
    // MARK: - Actions 


    @IBAction func recordbuttontapped(_ sender: Any) { 

     if audioEngine.isRunning { 
      audioEngine.stop() 
      recognitionRequest?.endAudio() 
      recordBtn.isEnabled = false 
      recordBtn.setTitle("Stopping", for: .disabled) 
     } else { 
      try! startRecording() 
      recordBtn.setTitle("Stop recording", for: []) 
     } 
    } 

    @IBAction func speaktome(_ sender: Any) { 

     let something = textView.text! 
     let utterance = AVSpeechUtterance(string: something) 
     utterance.voice = AVSpeechSynthesisVoice(language: "en-US") 

     let synthesizer = AVSpeechSynthesizer() 

     synthesizer.speak(utterance) 
    } 
} 

回答

0

使用另一個線程來得到的聲音在這種情況下,當你按下語音到文本按鈕,您的方案重點從用戶和一個無限狀態或持續你的程序獲得的聲音沒有任何停頓狀態,使用獲得的聲音另一個線程在語音到文本按鈕上獲取用戶語音並在獲取語音後終止

+1

嗨,謝謝你的回覆,請你給我舉一個例子,說明如何用提供的代碼來做到這一點,或者你可以指示我進一步說明。將不勝感激。謝謝 – aneey123

0

try audioSession.setCategory(AVAudioSessionCategoryRecord) 更改爲try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord) 它應該按預期工作。在對文本進行演講期間,您正在將音頻會話更改爲錄製模式,並且在TTS期間不會更改爲播放模式。另一種方法是在TTS期間將音頻會話設置爲AVAudioSessionCategoryPlayback