为 `SFSpeechRecognizer` 实施 "user stopped speaking" 通知
Implementing "user stopped speaking" notification for `SFSpeechRecognizer`
我正在尝试解决这个问题:SFSpeechRecognizer - detect end of utterance
问题是每次检测到的语音字符串发生变化时都会触发 SFSpeechRecognizer
回调,但它只会在 60 秒的静音后触发(因此它会设置 isFinal
标志)。
建议的技术是每次启动一个 2 秒的计时器以触发回调,如果已设置计时器,则首先使它无效。
我已经实现了这个技术。然而,在我的计时器回调中永远不会被击中。
谁能告诉我为什么?
import Foundation
import Speech
@objc
public class Dictation : NSObject, SFSpeechRecognizerDelegate
{
@objc static let notification_finalText = Notification.Name("speech_gotFinalText")
@objc static let notification_interimText = Notification.Name("speech_textDidChange")
private let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-UK"))!
var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
private var recognitionTask: SFSpeechRecognitionTask?
let audioEngine = AVAudioEngine()
@objc var text_tmp : String? = ""
@objc var text_final : String? = ""
var timer : Timer?
override init()
{
super.init()
speechRecognizer.delegate = self
SFSpeechRecognizer.requestAuthorization { authStatus in
if authStatus != .authorized {
exit(0)
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@objc
func tryStartRecording()
{
try! startRecording()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func startRecording() throws
{
text_final = ""
// Cancel the previous task if it's running.
if let recognitionTask = recognitionTask {
recognitionTask.cancel()
self.recognitionTask = nil
}
recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
let inputNode = audioEngine.inputNode
/*
^ causes:
[plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x600000247200> F8BB1C28-BAE8-11D6-9C31-00039315CD46
HALC_ShellDriverPlugIn::Open: Can't get a pointer to the Open routine
HALC_ShellDriverPlugIn::Open: Can't get a pointer to the Open routine
*/
if inputNode.inputFormat(forBus: 0).sampleRate == 0 {
fatalError("Audio engine has no input node")
}
guard let recognitionRequest = recognitionRequest else {
fatalError("Unable to created a SFSpeechAudioBufferRecognitionRequest object")
}
// Configure request so that results are returned before audio recording is finished
recognitionRequest.shouldReportPartialResults = true
// A recognition task represents a speech recognition session.
// We keep a reference to the task so that it can be cancelled.
recognitionTask = speechRecognizer.recognitionTask( with: recognitionRequest )
{ result, error in
self.timer?.invalidate()
print( "New Timer" )
self.timer = Timer(timeInterval:2.0, repeats:false) { _ in
print( "*** Timer Callback -- NEVER HITS! ***" )
self.timer?.invalidate()
self.text_final = result!.bestTranscription.formattedString
NotificationCenter.default.post( name: Dictation.notification_finalText, object: nil )
self.stopRecording()
}
var isFinal = false
if let result = result {
isFinal = result.isFinal
if isFinal {
self.text_final = result.bestTranscription.formattedString
} else {
self.text_tmp = result.bestTranscription.formattedString
}
let notification = isFinal ? Dictation.notification_finalText : Dictation.notification_interimText
NotificationCenter.default.post( name: notification, object: nil )
}
if error != nil || isFinal {
self.audioEngine.stop()
inputNode.removeTap( onBus: 0 )
self.recognitionRequest = nil
self.recognitionTask = nil
}
}
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap( onBus: 0, bufferSize: 1024, format: recordingFormat )
{ (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
self.recognitionRequest?.append( buffer )
}
audioEngine.prepare()
try audioEngine.start()
print( self.audioEngine.description )
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@objc
func stopRecording()
{
audioEngine.stop()
recognitionRequest?.endAudio()
}
}
链接:
- SFSpeechRecognizer - detect end of utterance
这是因为您创建了计时器但从未启动它:
self.timer = Timer(timeInterval:2.0, repeats:false)
相反,说
self.timer = Timer.scheduledTimer( ...
我正在尝试解决这个问题:SFSpeechRecognizer - detect end of utterance
问题是每次检测到的语音字符串发生变化时都会触发 SFSpeechRecognizer
回调,但它只会在 60 秒的静音后触发(因此它会设置 isFinal
标志)。
建议的技术是每次启动一个 2 秒的计时器以触发回调,如果已设置计时器,则首先使它无效。
我已经实现了这个技术。然而,在我的计时器回调中永远不会被击中。
谁能告诉我为什么?
import Foundation
import Speech
@objc
public class Dictation : NSObject, SFSpeechRecognizerDelegate
{
@objc static let notification_finalText = Notification.Name("speech_gotFinalText")
@objc static let notification_interimText = Notification.Name("speech_textDidChange")
private let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-UK"))!
var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
private var recognitionTask: SFSpeechRecognitionTask?
let audioEngine = AVAudioEngine()
@objc var text_tmp : String? = ""
@objc var text_final : String? = ""
var timer : Timer?
override init()
{
super.init()
speechRecognizer.delegate = self
SFSpeechRecognizer.requestAuthorization { authStatus in
if authStatus != .authorized {
exit(0)
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@objc
func tryStartRecording()
{
try! startRecording()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func startRecording() throws
{
text_final = ""
// Cancel the previous task if it's running.
if let recognitionTask = recognitionTask {
recognitionTask.cancel()
self.recognitionTask = nil
}
recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
let inputNode = audioEngine.inputNode
/*
^ causes:
[plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x600000247200> F8BB1C28-BAE8-11D6-9C31-00039315CD46
HALC_ShellDriverPlugIn::Open: Can't get a pointer to the Open routine
HALC_ShellDriverPlugIn::Open: Can't get a pointer to the Open routine
*/
if inputNode.inputFormat(forBus: 0).sampleRate == 0 {
fatalError("Audio engine has no input node")
}
guard let recognitionRequest = recognitionRequest else {
fatalError("Unable to created a SFSpeechAudioBufferRecognitionRequest object")
}
// Configure request so that results are returned before audio recording is finished
recognitionRequest.shouldReportPartialResults = true
// A recognition task represents a speech recognition session.
// We keep a reference to the task so that it can be cancelled.
recognitionTask = speechRecognizer.recognitionTask( with: recognitionRequest )
{ result, error in
self.timer?.invalidate()
print( "New Timer" )
self.timer = Timer(timeInterval:2.0, repeats:false) { _ in
print( "*** Timer Callback -- NEVER HITS! ***" )
self.timer?.invalidate()
self.text_final = result!.bestTranscription.formattedString
NotificationCenter.default.post( name: Dictation.notification_finalText, object: nil )
self.stopRecording()
}
var isFinal = false
if let result = result {
isFinal = result.isFinal
if isFinal {
self.text_final = result.bestTranscription.formattedString
} else {
self.text_tmp = result.bestTranscription.formattedString
}
let notification = isFinal ? Dictation.notification_finalText : Dictation.notification_interimText
NotificationCenter.default.post( name: notification, object: nil )
}
if error != nil || isFinal {
self.audioEngine.stop()
inputNode.removeTap( onBus: 0 )
self.recognitionRequest = nil
self.recognitionTask = nil
}
}
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap( onBus: 0, bufferSize: 1024, format: recordingFormat )
{ (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
self.recognitionRequest?.append( buffer )
}
audioEngine.prepare()
try audioEngine.start()
print( self.audioEngine.description )
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@objc
func stopRecording()
{
audioEngine.stop()
recognitionRequest?.endAudio()
}
}
链接:
- SFSpeechRecognizer - detect end of utterance
这是因为您创建了计时器但从未启动它:
self.timer = Timer(timeInterval:2.0, repeats:false)
相反,说
self.timer = Timer.scheduledTimer( ...