问题
If I inspected the stamps for callbacks from the SFSpeechRecognizer
recognitionTask
callback (on macOS):
recognitionTask = speechRecognizer.recognitionTask( with: recognitionRequest )
{ result, error in
// if more than two seconds elapsed since the last update, we send a notification
NSLog( "speechRecognizer.recognitionTask callback" )
:
... I observe:
:
2019-11-08 14:51:00.35 ... speechRecognizer.recognitionTask callback
2019-11-08 14:51:00.45 ... speechRecognizer.recognitionTask callback
2019-11-08 14:51:32.31 ... speechRecognizer.recognitionTask callback
i.e. There is an additional unwanted callback approximately 30 seconds after my last utterance.
result
is nil
for this last callback.
The fact that it's close to 30 seconds suggests to me it is representing a max-timeout.
I'm not expecting a time out, because I have manually shutdown my session (at around the 5s mark, by clicking a button):
@objc
func stopRecording()
{
print( "stopRecording()" )
// Instructs the task to stop accepting new audio (e.g. stop recording) but complete processing on audio already buffered.
// This has no effect on URL-based recognition requests, which effectively buffer the entire file immediately.
recognitionTask?.finish()
// Indicate that the audio source is finished and no more audio will be appended
recognitionRequest?.endAudio()
//self.recognitionRequest = nil
audioEngine.stop()
audioEngine.inputNode.removeTap( onBus: 0 )
//recognitionTask?.cancel()
//self.recognitionTask = nil
self.timer?.invalidate()
print( "stopRecording() DONE" )
}
There's a lot of commented out code, as it seems to me there is some process I'm failing to shut down, but I can't figure it out.
Complete code is here.
Can anyone see what's going wrong?
回答1:
NOTE: in this solution, there is still one unwanted callback immediately after the destruction sequence is initiated. Hence I'm not going to accept the answer yet. Maybe there exists a more elegant solution to this problem, or someone may shed light on observed phenomena.
The following code does the job:
is_listening = true
recognitionTask = speechRecognizer.recognitionTask( with: recognitionRequest )
{ result, error in
if !self.is_listening {
NSLog( "IGNORED: speechRecognizer.recognitionTask callback" )
return
}
// if more than two seconds elapsed since the last update, we send a notification
self.timer?.invalidate()
NSLog( "speechRecognizer.recognitionTask callback" )
self.timer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { _ in
if !self.is_listening {
print( "IGNORED: Inactivity (timer) Callback" )
return
}
print( "Inactivity (timer) Callback" )
self.timer?.invalidate()
NotificationCenter.default.post( name: Dictation.notification_paused, object: nil )
//self.stopRecording()
}
:
}
@objc
func stopRecording()
{
print( "stopRecording()" )
is_listening = false
audioEngine.stop()
audioEngine.inputNode.removeTap(onBus: 0)
audioEngine.inputNode.reset()
recognitionRequest?.endAudio()
recognitionRequest = nil
timer?.invalidate()
timer = nil;
recognitionTask?.cancel()
recognitionTask = nil
}
The exact sequence is taken from https://github.com/2bbb/ofxSpeechRecognizer/blob/master/src/ofxSpeechRecognizer.mm -- I'm not sure to what extent it is order sensitive.
For starters, that destruction sequence seems to eliminate the 30s timeout? callback.
However the closures still get hit after stopListening
.
To deal with this I've created an is_listening
flag.
I have a hunch Apple should maybe have internalised this logic within the framework, but meh it works, I am a happy bunny.
来源:https://stackoverflow.com/questions/58774314/unwanted-callback-from-sfspeechrecognizer-recognitiontask-at-30s-mark