iOS10语音识别"听力"音效

时间:2016-12-12 07:40:33

标签: ios iphone speech-recognition

我正在使用新的iOS10框架进行实时语音识别。我使用AVCaptureSession来获取音频。

我有一个"听"发出哔哔声以通知用户他可以开始说话。发出声音的最好方法是在captureOutput(:didOutputSampleBuffer..)的第一次通话,但是如果我在开始会话后尝试播放声音,那么声音就不会播放。没有错误被抛出..它只是默默无法发挥...

我尝试了什么:

  • 播放系统声音(AudioServicesPlaySystemSound...()
  • 使用AVPlayer
  • 播放资源
  • 同时尝试了主队列上的上述解决方案async / sync

似乎无论我在做什么,都不可能在触发识别后触发播放任何类型的音频(不确定它是否具体是AVCaptureSessionSFSpeechAudioBufferRecognitionRequest / SFSpeechRecognitionTask ...)

有什么想法吗? Apple even recommends playing a "listening" sound effect(和Siri一起做)但是我找不到任何参考/示例来说明如何实际做到这一点......(他们的" SpeakToMe"示例没有发出声音)

  • 我可以在触发会话之前播放声音,并且它确实有效(在播放声音时完成会话时)但有时实际上是在识别识别时(主要是在使用BT耳机和切换时)不同的AudioSession类别 - 我没有完成事件...) - 因为我需要一种方法来播放录音实际开始时的声音,而不是在它触发和交叉手指之前它不会延迟开始吧......

1 个答案:

答案 0 :(得分:2)

嗯,显然有很多"规则"必须遵循以便成功开始语音识别会话并播放"听"只有在识别真正之后(之后)才会生效。

  1. 会话设置&必须在主队列上调用触发器。所以:

    DispatchQueue.main.async {
        speechRequest = SFSpeechAudioBufferRecognitionRequest()
        task = recognizer.recognitionTask(with: speechRequest, delegate: self)
        capture = AVCaptureSession()
        //.....
        shouldHandleRecordingBegan = true
        capture?.startRunning()
    }
    
  2. "听"效果应该是播放器AVPlayer,而不是系统声音。

  3. 当我们获得第一个sampleBuffer回调时,最安全的地方是肯定是录音,在AVCaptureAudioDataOutputSampleBufferDelegate的委托调用中:

    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
    
        //only once per recognition session
        if shouldHandleRecordingBegan {
            shouldHandleRecordingBegan = false
    
            player = AVPlayer(url: Bundle.main.url(forResource: "listening", withExtension: "aiff")!)
            player.play()            
    
            DispatchQueue.main.async {
                //call delegate/handler closure/post notification etc...
            }
        }
    
        // append buffer to speech recognition
        speechRequest?.appendAudioSampleBuffer(sampleBuffer)
    }
    
  4. 识别效果的结束很容易:

    var ended = false
    
    if task?.state == .running || task?.state == .starting {
        task?.finish() // or task?.cancel() to cancel and not get results.
        ended = true
    }
    
    if true == capture?.isRunning {
        capture?.stopRunning()
    }
    
    if ended {
        player = AVPlayer(url: Bundle.main.url(forResource: "done", withExtension: "aiff")!)
        player.play()
    }