首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用通过使用音频线程外的AVAudioEngine获得的PCM缓冲区的数据?

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

Stack Overflow用户
提问于 2020-08-26 20:55:40
回答 1查看 625关注 0票数 1

我使用AVAudioEngine中的iOS从麦克风中获取音频,并使用输入节点及其函数installTap将其写入缓冲区。

在tapBlock的installTap函数中,它应该是读取和/或操作PCM缓冲区的地方,我需要调用C库函数,这个函数处理PCM缓冲区数据,它计算音频指纹,这个函数还需要读取一个文件,该文件是预计算的音频指纹的数据库,以寻找可能的匹配。

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

我如何在主线程中操作PCM缓冲区,这样我就可以进行文件I/O调用,并且能够计算我在C端需要的匹配?

我做错了什么?

还有其他选择吗?谢谢。

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


}

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

代码语言:javascript
复制
 let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
    

   let dbPath = documentsPath+"/mydb.db"
     do {
        let text = try String(contentsOfFile: dbPath)
      
        //converting dbPath to a pointer to be use in C
        let cstringForDB = (dbPath as NSString).utf8String
        let dbFilePathForC = UnsafeMutablePointer<Int8>(mutating: cstringForDB!);
       

    } catch  {
        print("error cannot read the db file")
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-27 07:17:19

允许在任何线程上调用I/O。问题在于您的C-字符串转换为UnsafeMutablePointer<Int8> (它被称为不安全的原因很好)。当PCM音频非主线程完成后,您将在堆栈let“变量”上执行此操作。因此,您将得到一个指向某个随机内存的悬空指针。我怀疑您在主线程上似乎没有遇到相同的问题,因为它在整个应用程序生命周期中始终存在,并且在其堆栈上单击一个悬空指针的可能性较小(但仍然肯定是可能的)。解决方案是让您的UnsafeMutablePointer<Int8> (由约桑提供)如下:

代码语言:javascript
复制
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-字符串分配空间,该字符串在所有线程之间以一种安全的方式共享(只要它是一个只读内存)。

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

https://stackoverflow.com/questions/63605615

复制
相关文章

相似问题

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