【问题标题】:iOS10 Speech Recognition "Listening" sound effectiOS10语音识别“听”音效
【发布时间】:2016-12-12 07:40:33
【问题描述】:
我正在使用新的 iOS10 框架进行实时语音识别。我使用AVCaptureSession 来获取音频。
我有一个“正在听”的哔声通知用户他可以开始说话了。发出该声音的最佳方式是在第一次致电captureOutput(:didOutputSampleBuffer..) 时,但如果我在开始会话后尝试播放声音,声音就不会播放。并且没有抛出错误..它只是默默地无法播放......
我尝试了什么:
- 通过系统声音播放 (
AudioServicesPlaySystemSound...())
- 使用
AVPlayer 播放资产
- 还尝试了上述两种解决方案异步/同步主队列
似乎无论我在做什么,触发识别后都无法触发播放任何类型的音频(不确定是具体是AVCaptureSession还是SFSpeechAudioBufferRecognitionRequest/SFSpeechRecognitionTask...)
有什么想法吗? Apple even recommends playing a "listening" sound effect(用 Siri 自己做)但我找不到任何参考/示例来说明如何实际操作...(他们的“SpeakToMe”示例不播放声音)
- 我可以在触发会话之前播放声音,并且它确实有效(在播放声音完成后开始会话时)但有时在实际盯着识别时会有延迟(主要是在使用 BT 耳机并从不同的 AudioSession 类别-我没有完成事件...)-因此,我需要一种在录制实际开始时播放声音的方法,而不是在它触发和交叉手指之前它不会延迟启动它...
【问题讨论】:
标签:
ios
iphone
speech-recognition
【解决方案1】:
好吧,显然,为了成功开始语音识别会话并仅在识别真正开始(之后)发挥“聆听”效果,必须遵循一系列“规则”。
-
必须在主队列上调用会话设置和触发。所以:
DispatchQueue.main.async {
speechRequest = SFSpeechAudioBufferRecognitionRequest()
task = recognizer.recognitionTask(with: speechRequest, delegate: self)
capture = AVCaptureSession()
//.....
shouldHandleRecordingBegan = true
capture?.startRunning()
}
“聆听”效果应该是通过AVPlayer 播放的,而不是系统声音。
-
知道我们肯定录制的最安全的地方是在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)
}
-
识别效果的结束要容易得多:
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()
}