如何在音频线程之外使用通过AVAudioEngine获得的PCM缓冲区的数据?

问题描述

我正在使用iOS中的AVAudioEngine从麦克风获取音频,并使用输入节点及其功能installTap将其写入缓冲区。
在installTap函数的tapBlock内部,应该在该位置读取和/或操作PCM缓冲区,我需要调用C库函数,此函数处理PCM缓冲区数据,计算音频指纹,函数还需要读取一个文件,该文件是预先计算出的音频指纹的数据库,以查找可能的匹配项。

问题是,显然(如果我错了,请纠正我),您不能在此块内进行任何文件I / O调用,因为此代码正在另一个线程中运行,并且我将传递给C的文件指针事物的一面总是null或垃圾,这不会在此函数之外发生,(在事物的主线程中)指针起作用,并且C可以读取数据库文件

如何在主线程中操纵PCM缓冲区,以便可以进行文件I / O调用并能够计算出C端所需的匹配项?

我在做什么错了?

还有其他选择吗?谢谢。

application.conf

代码块以获取指向数据库文件的指针

import Foundation
import AVFoundation

let audioEngine = AVAudioEngine()

class AudioEngineTest: NSObject {
   func setupAudioEngine() {
       let input = audioEngine.inputNode

    let inputFormat = input.outputFormat(forBus: 0)
    let inputNode = audioEngine.inputNode;
    
    //Convert received buffer to required format
     let recordingFormat = AVAudioFormat(commonFormat: .pcmFormatInt16,sampleRate: Double(44100),channels: 2,interleaved: false)
     let formatConverter =  AVAudioConverter(from:inputFormat,to: recordingFormat!)
     
     let pcmBuffer = AVAudioPCMBuffer(pcmFormat: recordingFormat!,frameCapacity: AVAudioFrameCount(recordingFormat!.sampleRate * 4.0))
     var error: NSError? = nil
                             
    
                
    inputNode.installTap(onBus: 0,bufferSize: AVAudioFrameCount(2048),format: inputFormat)
    {
        (buffer,time) in
         
      
        let inputBlock: AVAudioConverterInputBlock = { inNumPackets,outStatus in
          outStatus.pointee = AVAudioConverterInputStatus.haveData
          return buffer
        }
        
        formatConverter?.convert(to: pcmBuffer!,error: &error,withInputFrom: inputBlock)
                

        if error != nil {
          print(error!.localizedDescription)
        }
        

        //Calling the function from the C library,passing it the buffer and the pointer to the db file: dbFilePathForC an UnsafeMutablePointer<Int8>

       creatingFingerprintAndLookingForMatch(pcmbuffer,dbFilePathForC)

      //In this scope,the pointer dbFilePathFoC is either null or garbage,so the C side of things cannot read the database file,outside of this scope,the same pointer works and C can read the file,but I cannot read the PCM buffer because it only exists inside this scope of this closure of installTap,called the tapBlock 
    }  
    
      try! audioEngine.start()
    
    
   }


}

解决方法

在任何线程上都可以进行I / O调用。问题出在您将C字符串转换为UnsafeMutablePointer<Int8>有充分的理由称其为不安全)。您在堆栈上执行此操作,使“变量”消失,一旦您的PCM Audio非主线程完成,该变量将消失。因此,您最终会得到一个悬空的指针,指向某些随机存储器。我怀疑您似乎在主线程上没有遇到相同的问题,因为它在应用程序的整个生命周期中始终存在,并且不太可能在其堆栈上碰到悬挂的指针(但仍然绝对可能)。 解决方案是让您的UnsafeMutablePointer<Int8>yossan礼貌)是这样的:

func makeCString(from str: String) -> UnsafeMutablePointer<Int8> {
    let count = str.utf8CString.count 
    let result: UnsafeMutableBufferPointer<Int8> = UnsafeMutableBufferPointer<Int8>.allocate(capacity: count)
    _ = result.initialize(from: str.utf8CString)
    return result.baseAddress!
}

这样做,您可以在堆上为C字符串分配空间,以安全的方式在所有线程之间共享C字符串(只要它是只读内存)。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...