我正在使用AVAudioCV录制声音,并使用苹果内置的口述进行分析。但是,当我尝试用按钮打开音频引擎时,音频缓冲区立即完成,并且没有拾取任何声音。然而,只有当我第二次打开按钮时,缓冲区才开始出现故障,这让我相信,当我停止录制时,一些点击没有从音频引擎中删除,并且这些点击相互碰撞,立即结束了缓冲区。
我已经搜索了许多关于AVAudioCV中由于未删除的水龙头而导致的小故障的帖子,但到目前为止我还没有看到任何有用的帖子。这就是我所拥有的:
func recognizeAudioStream() {
let speechRecognizer = SFSpeechRecognizer()
//performs speech recognition on live audio; as audio is captured, call append
//to request object, call endAudio() to end speech recognition
var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
//determines & edits state of speech recognition task (end, start, cancel, etc)
var recognitionTask: SFSpeechRecognitionTask?
let audioEngine = AVAudioEngine()
func startRecording() throws{
//cancel previous audio task
recognitionTask?.cancel()
recognitionTask = nil
//get info from microphone
let audioSession = AVAudioSession.sharedInstance()
try audioSession.setCategory(.record, mode: .measurement, options: .duckOthers)
try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
let inputNode = audioEngine.inputNode
//audio buffer; takes a continuous input of audio and recognizes speech
recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
//allows device to print results of your speech before you're done talking
recognitionRequest?.shouldReportPartialResults = true
recognitionTask = speechRecognizer!.recognitionTask(with: recognitionRequest!) {result, error in
var isFinal = false
if let result = result{ //if we can let result be the nonoptional version of result, then
isFinal = result.isFinal
print("Text: \(result.bestTranscription.formattedString)")
}
if error != nil || result!.isFinal{ //if an error occurs or we're done speaking
audioEngine.stop()
inputNode.removeTap(onBus: 0)
recognitionTask = nil
recognitionRequest = nil
let bufferText = result?.bestTranscription.formattedString.components(separatedBy: (" "))
print("completed buffer")
self.addToDictionary(wordNames: bufferText)
self.populateTempWords()
wordsColl.reloadData()
do{
try startRecording()
}
catch{
print(error)
}
}
}
//configure microphone; let the recording format match with that of the bus we are using
let recordingFormat = inputNode.outputFormat(forBus: 0)
//contents of buffer will be dumped into recognitionRequest and into result, where
//it will then be transcribed and printed out
//1024 bytes = dumping "limit": once buffer fills to 1024 bytes, it is appended to recognitionRequest
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
recognitionRequest?.append(buffer)
}
audioEngine.prepare()
try audioEngine.start()
}
do{
if(!isRecording){
audioEngine.mainMixerNode.removeTap(onBus: 0)
audioEngine.stop()
return
}
try startRecording()
}
catch{
print(error)
}
}上面是我的recognizeAudioStream()函数。它首先初始化SFSpeechRecognizer()和AVAudioEngine(),然后调用startRecording()。取消之前的音频任务,并将AVAudioEngine()类型的audioEngine设置为安装tap的inputNode。变量isFinal存储变量isFinal的数据成员result,该成员在其上方的recognitionTask()闭包中设置。当1024字节过滤器填满并且inputNode上的抽头被移除时,isFinal设置为真。recognitionTask被重置,缓冲区中的文本被分析并加载到我的单词字典中。在这个块的下面是buffer和audioEngine的设置。
最后,do/catch块检查audioEngine是否应该记录(如果不应该,isRecording= false ),在这种情况下,将删除tap并停止audioEngine。否则,将再次调用startRecording()来填充另一个缓冲区。在第二次打开录制按钮之前,我对此没有任何问题。
下面是我的记录按钮的objc函数:
@objc func recordingState(){
if isRecording{
recordButton.setImage(UIImage(named: "unfilled_star.png"), for: .normal)
isRecording = false
}
else{
print("try to start recording")
recordButton.setImage(UIImage(named: "filled_star.png"), for: .normal)
let speechRecognizer = SFSpeechRecognizer()
requestDictAccess();
if speechRecognizer!.isAvailable { //if the user has granted permission
speechRecognizer?.supportsOnDeviceRecognition = true //for offline data
isRecording = true
recognizeAudioStream()
}
}
}当第二次运行recognizeAudioStream()时,我得到了这个输出,整个代码块大约在一秒钟内完成:
authorized
2021-04-22 22:38:29.671122-0400 DictoCounter[76126:11539342] [aurioc] 323: Unable to join I/O thread to workgroup ((null)): 2
2021-04-22 22:38:29.679718-0400 DictoCounter[76126:11539130] [Utility] +[AFAggregator logDictationFailedWithError:] Error Domain=kAFAssistantErrorDomain Code=209 "(null)"
completed buffer
2021-04-22 22:38:29.688449-0400 DictoCounter[76126:11538858] Words successfully saved.
2021-04-22 22:38:29.690209-0400 DictoCounter[76126:11539349] [aurioc] 323: Unable to join I/O thread to workgroup ((null)): 2
2021-04-22 22:38:29.699224-0400 DictoCounter[76126:11539130] [Utility] +[AFAggregator logDictationFailedWithError:] Error Domain=kAFAssistantErrorDomain Code=209 "(null)"
completed buffer
2021-04-22 22:38:29.719147-0400 DictoCounter[76126:11538858] Words successfully saved.
2021-04-22 22:38:29.720698-0400 DictoCounter[76126:11539352] [aurioc] 323: Unable to join I/O thread to workgroup ((null)): 2
2021-04-22 22:38:29.734173-0400 DictoCounter[76126:11539102] [Utility] +[AFAggregator logDictationFailedWithError:] Error Domain=kAFAssistantErrorDomain Code=209 "(null)"
completed buffer
2021-04-22 22:38:29.740684-0400 DictoCounter[76126:11538858] Words successfully saved.
2021-04-22 22:38:29.741952-0400 DictoCounter[76126:11539370] [aurioc] 323: Unable to join I/O thread to workgroup ((null)): 2
2021-04-22 22:38:29.754000-0400 DictoCounter[76126:11539102] [Utility] +[AFAggregator logDictationFailedWithError:] Error Domain=kAFAssistantErrorDomain Code=209 "(null)"
completed buffer
2021-04-22 22:38:29.761909-0400 DictoCounter[76126:11538858] Words successfully saved.
2021-04-22 22:38:29.763036-0400 DictoCounter[76126:11539371] [aurioc] 323: Unable to join I/O thread to workgroup ((null)): 2
2021-04-22 22:38:29.776616-0400 DictoCounter[76126:11539104] [Utility] +[AFAggregator logDictationFailedWithError:] Error Domain=kAFAssistantErrorDomain Code=209 "(null)"
completed buffer我不太确定在这里该做什么。我已经查看了许多其他帖子,这些帖子建议没有删除taps,但我删除了do/catch块中的所有taps。我不确定我在演奏什么。非常感谢大家的帮助--提前谢谢!
发布于 2021-04-27 13:18:24
可能的问题是路由/配置更改或中断,您可以检查在结束录制时是否调用这些通知中的任何一个
private var notificationTokens = [NSObjectProtocol]()
// init
notificationTokens = [
NotificationCenter.default.addObserver(
forName: AVAudioSession.routeChangeNotification,
object: nil,
queue: .main
) { notification in
self.engineStartTimer?.invalidate()
guard self.resumePlaybackAfterSeek == nil else { return }
self.scheduledBufferFrames = 0
self.ignoreBufferIndex = self.lastBufferIndex
self.resumePlaybackAfterSeek = false
startRestartEngineTimer()
},
NotificationCenter.default.addObserver(
forName: AVAudioSession.interruptionNotification,
object: nil,
queue: .main
) { notification in
startRestartEngineTimer()
},
NotificationCenter.default.addObserver(
forName: .AVAudioEngineConfigurationChange,
object: nil,
queue: .main
) { notification in
startRestartEngineTimer()
}
]如果这不起作用,请提供一个MRE
https://stackoverflow.com/questions/67223480
复制相似问题