首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >swift AVAudioEngine故障

swift AVAudioEngine故障
EN

Stack Overflow用户
提问于 2021-04-23 11:10:54
回答 1查看 129关注 0票数 1

我正在使用AVAudioCV录制声音,并使用苹果内置的口述进行分析。但是,当我尝试用按钮打开音频引擎时,音频缓冲区立即完成,并且没有拾取任何声音。然而,只有当我第二次打开按钮时,缓冲区才开始出现故障,这让我相信,当我停止录制时,一些点击没有从音频引擎中删除,并且这些点击相互碰撞,立即结束了缓冲区。

我已经搜索了许多关于AVAudioCV中由于未删除的水龙头而导致的小故障的帖子,但到目前为止我还没有看到任何有用的帖子。这就是我所拥有的:

代码语言:javascript
复制
 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函数:

代码语言:javascript
复制
    @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()时,我得到了这个输出,整个代码块大约在一秒钟内完成:

代码语言:javascript
复制
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。我不确定我在演奏什么。非常感谢大家的帮助--提前谢谢!

EN

回答 1

Stack Overflow用户

发布于 2021-04-27 13:18:24

可能的问题是路由/配置更改或中断,您可以检查在结束录制时是否调用这些通知中的任何一个

代码语言:javascript
复制
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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67223480

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档