iOS10语音识别"Listening"音效
iOS10 Speech Recognition "Listening" sound effect
我正在使用新的 iOS10 框架进行实时语音识别。我使用 AVCaptureSession
获取音频。
我有一个 "listening" 哔声通知用户他可以开始说话了。放置声音的最佳方式是在第一次调用 captureOutput(:didOutputSampleBuffer..)
时,但如果我在开始会话后尝试播放声音,声音就不会播放。并且没有抛出任何错误..它只是静静地无法播放...
我尝试了什么:
- 通过系统声音播放(
AudioServicesPlaySystemSound...()
)
- 使用
AVPlayer
播放资产
- 还在主队列
上尝试了上述两种解决方案async/sync
似乎无论我在做什么,在触发识别后都无法触发播放任何类型的音频(不确定是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" 示例不播放声音)
- 我可以在触发会话之前播放声音,它确实有效(在播放声音完成后开始会话时)但有时实际开始识别时会有延迟(主要是在使用 BT 耳机和切换时来自不同的 AudioSession 类别 - 我没有完成事件...) - 因此我需要一种方法来在录音实际开始时播放声音,而不是在它触发和交叉手指之前它不会滞后开始吧...
好吧,显然有一堆 "rules" 必须遵循才能成功开始语音识别会话并仅在识别 [=25= 之后(之后)播放 "listening" 效果]真的开始了。
必须在主队列上调用会话设置和触发。所以:
DispatchQueue.main.async {
speechRequest = SFSpeechAudioBufferRecognitionRequest()
task = recognizer.recognitionTask(with: speechRequest, delegate: self)
capture = AVCaptureSession()
//.....
shouldHandleRecordingBegan = true
capture?.startRunning()
}
"listening" 效果应该通过 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()
}
我正在使用新的 iOS10 框架进行实时语音识别。我使用 AVCaptureSession
获取音频。
我有一个 "listening" 哔声通知用户他可以开始说话了。放置声音的最佳方式是在第一次调用 captureOutput(:didOutputSampleBuffer..)
时,但如果我在开始会话后尝试播放声音,声音就不会播放。并且没有抛出任何错误..它只是静静地无法播放...
我尝试了什么:
- 通过系统声音播放(
AudioServicesPlaySystemSound...()
) - 使用
AVPlayer
播放资产
- 还在主队列 上尝试了上述两种解决方案async/sync
似乎无论我在做什么,在触发识别后都无法触发播放任何类型的音频(不确定是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" 示例不播放声音)
- 我可以在触发会话之前播放声音,它确实有效(在播放声音完成后开始会话时)但有时实际开始识别时会有延迟(主要是在使用 BT 耳机和切换时来自不同的 AudioSession 类别 - 我没有完成事件...) - 因此我需要一种方法来在录音实际开始时播放声音,而不是在它触发和交叉手指之前它不会滞后开始吧...
好吧,显然有一堆 "rules" 必须遵循才能成功开始语音识别会话并仅在识别 [=25= 之后(之后)播放 "listening" 效果]真的开始了。
必须在主队列上调用会话设置和触发。所以:
DispatchQueue.main.async { speechRequest = SFSpeechAudioBufferRecognitionRequest() task = recognizer.recognitionTask(with: speechRequest, delegate: self) capture = AVCaptureSession() //..... shouldHandleRecordingBegan = true capture?.startRunning() }
"listening" 效果应该通过
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() }