我正在使用新的iOS10框架进行实时语音识别.我使用AVCaptureSession来获取音频.
我有一个“聆听”的嘟嘟声,通知用户他可以开始说话.放置声音的最佳方式是第一次调用captureOutput(:didOutputSampleBuffer ..),但如果我在开始会话后尝试播放声音,则声音将无法播放.没有错误被抛出..它只是默默无法发挥…
我尝试了什么:
>播放系统声音(AudioServicesPlaySystemSound …())
>使用AVPlayer播放资产
>还尝试了主队列上的上述解决方案async / sync
似乎无论我在做什么,触发识别后都不可能触发播放任何类型的音频(不确定它是否特别是AVCaptureSession或SFSpeechAudioBufferRecognitionRequest / SFSpeechRecognitionTask ……)
有任何想法吗? Apple even recommends playing a “listening” sound effect(和Siri一起做)但是我找不到任何参考/示例显示如何实际做到这一点……(他们的“SpeakToMe”示例不播放声音)
>我可以在触发会话之前播放声音,并且它确实有效(在完成播放声音时开始会话)但有时实际上是在识别识别时(主要是在使用BT耳机和从不同的AudioSession切换时)类别 – 我没有完成事件…) – 因为我需要一种方法来播放录音实际开始时的声音,而不是在它触发和交叉手指之前它不会延迟启动它… .
最佳答案 好吧,显然有一堆必须遵循的“规则”才能成功开始语音识别会话,并且只有在识别真正开始之后(之后)才能发挥“聆听”效果.
>会话设置&必须在主队列上调用触发器.所以:
DispatchQueue.main.async {
speechRequest = SFSpeechAudioBufferRecognitionRequest()
task = recognizer.recognitionTask(with: speechRequest, delegate: self)
capture = AVCaptureSession()
//.....
shouldHandleRecordingBegan = true
capture?.startRunning()
}
>“收听”效果应该是通过AVPlayer的播放器,而不是系统声音.
>当我们得到第一个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)
}
>识别效果结束很容易:
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()
}