iOS10语音识别"Listening"音效

iOS10 Speech Recognition "Listening" sound effect

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

我有一个 "listening" 哔声通知用户他可以开始说话了。放置声音的最佳方式是在第一次调用 captureOutput(:didOutputSampleBuffer..) 时,但如果我在开始会话后尝试播放声音,声音就不会播放。并且没有抛出任何错误..它只是静静地无法播放...

我尝试了什么:

似乎无论我在做什么,在触发识别后都无法触发播放任何类型的音频(不确定是AVCaptureSession还是SFSpeechAudioBufferRecognitionRequest / SFSpeechRecognitionTask...)

有什么想法吗? Apple even recommends playing a "listening" sound effect (and do it themselves with Siri) but I couldn't find any reference/example showing how to actually do it... (their "SpeakToMe" 示例不播放声音)

好吧,显然有一堆 "rules" 必须遵循才能成功开始语音识别会话并仅在识别 [=25= 之后(之后)播放 "listening" 效果]真的开始了。

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

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

  3. 知道我们正在绝对记录的最安全的地方是在 AVCaptureAudioDataOutputSampleBufferDelegate 的委托调用中,当我们获得第一个 sampleBuffer 回调时:

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