Swift 调用AudioObjectGetPropertyData之前未分配AudioBufferListPointer分配

Swift 调用AudioObjectGetPropertyData之前未分配AudioBufferListPointer分配,swift,core-audio,Swift,Core Audio,我一直在尝试使用来自斯威夫特的苹果CoreAudio。 我发现了许多关于如何枚举设备上的流和通道的示例。 但是,在调用UnsafeMutablePointer.allocate()时,它们似乎都使用了不正确的大小 它们首先请求属性数据大小,返回字节数。 然后,他们使用这个字节数来分配该大小的(不安全的)AudioBufferList(使用字节数作为列表的大小!) 请参见下面我的评论: var address = AudioObjectPropertyAddress( mSelector:

我一直在尝试使用来自斯威夫特的苹果CoreAudio。 我发现了许多关于如何枚举设备上的流和通道的示例。 但是,在调用
UnsafeMutablePointer.allocate()
时,它们似乎都使用了不正确的大小

它们首先请求属性数据大小,返回字节数。 然后,他们使用这个字节数来分配该大小的(不安全的)
AudioBufferList
(使用字节数作为列表的大小!)

请参见下面我的评论:

var address = AudioObjectPropertyAddress(
    mSelector:AudioObjectPropertySelector(kAudioDevicePropertyStreamConfiguration),
    mScope:AudioObjectPropertyScope(kAudioDevicePropertyScopeInput),
    mElement:0)

var propsize = UInt32(0);
var result:OSStatus = AudioObjectGetPropertyDataSize(self.id, &address, 0, nil, &propsize);
if (result != 0) {
    return false;
}

// ABOVE: propsize is set to number of bytes that property data contains, typical number are 8 (no streams), 24 (1 stream, 2 interleaved channels)
// BELOW: propsize is used for AudioBufferList capacity (in number of buffers!)

let bufferList = UnsafeMutablePointer<AudioBufferList>.allocate(capacity:Int(propsize))
result = AudioObjectGetPropertyData(self.id, &address, 0, nil, &propsize, bufferList);
if (result != 0) {
    return false
}

let buffers = UnsafeMutableAudioBufferListPointer(bufferList)
for bufferNum in 0..<buffers.count {
    if buffers[bufferNum].mNumberChannels > 0 {
        return true
    }
}
var address=AudioObjectPropertyAddress(
mSelector:AudioObjectPropertySelector(kAudioDevicePropertyStreamConfiguration),
mScope:AudioObjectPropertyScope(kAudioDevicePropertyScopeInput),
合并:0)
var propsize=UInt32(0);
var结果:OSStatus=AudioObjectGetPropertyDataSize(self.id,&address,0,nil,&propsize);
如果(结果!=0){
返回false;
}
//上图:propsize设置为属性数据包含的字节数,典型数字为8(无流),24(1个流,2个交错通道)
//下面:propsize用于AudioBufferList容量(以缓冲区数量为单位!)
让bufferList=UnsafemeutablePointer.allocate(容量:Int(propsize))
结果=AudioObjectGetPropertyData(self.id和address、0、nil和propsize、bufferList);
如果(结果!=0){
返回错误
}
let buffers=UnsafeMutableAudioBufferListPointer(bufferList)
对于0中的bufferNum。。0 {
返回真值
}
}
这一直都是有效的,因为它分配的内存远远超过了
unsafemeutablepointer
所需的内存,但这显然是错误的

我一直在寻找一种方法,从
AudioObjectGetPropertyDataSize()
返回的字节数中正确分配
UnsafemtablePointer
,但我一整天都找不到任何东西。请帮忙;)

AudioObjectGetPropertyDataSize()返回的字节数中正确分配
UnsafemeutablePointer

您不应该分配
UnsafeMutablePointer
,而是分配精确大小的原始字节并将其强制转换为
UnsafeMutablePointer

像这样的事情:

        let propData = UnsafeMutableRawPointer.allocate(byteCount: Int(propsize), alignment: MemoryLayout<AudioBufferList>.alignment)
        result = AudioObjectGetPropertyData(self.id, &address, 0, nil, &propsize, propData);
        if (result != 0) {
            return false
        }
        let bufferList = propData.assumingMemoryBound(to: AudioBufferList.self)
let propData=unsafemeutablerawpointer.allocate(字节数:Int(propsize),对齐方式:MemoryLayout.alignment)
结果=AudioObjectGetPropertyData(self.id和address、0、nil和propsize、propData);
如果(结果!=0){
返回错误
}
让bufferList=propData.AssumingMemoryBind(到:AudioBufferList.self)

我完全同意使用
UnsafemeutableRawPointer.allocate(字节数:对齐:)
(虽然它还应该与调用
deallocate()
来获取设备流配置配对,但为了完整性,我只想共享另一个选项(这个问题不应该被高估)

如果您真的需要根据字节数计算缓冲区的数量(我不确定是否真的需要),那么可以这样做

当我第一次将代码转换为Swift时,我使用了如下方法:

        let numBuffers = (Int(propsize) - MemoryLayout<AudioBufferList>.offset(of: \AudioBufferList.mBuffers)!) / MemoryLayout<AudioBuffer>.size
        if numBuffers == 0 { // Avoid trying to allocate zero buffers
            return false
        }
        let bufferList = AudioBufferList.allocate(maximumBuffers: numBuffers)
        defer { bufferList.unsafeMutablePointer.deallocate() }
        err = AudioObjectGetPropertyData(id, &address, 0, nil, &propsize, bufferList.unsafeMutablePointer)
让numBuffers=(Int(propsize)-MemoryLayout.offset(of:\AudioBufferList.mBuffers)!)/MemoryLayout.size
如果numBuffers==0{//,请避免尝试分配零缓冲区
返回错误
}
let bufferList=AudioBufferList.allocate(maximumBuffers:numBuffers)
延迟{bufferList.UnsafemeutablePointer.deallocate()}
err=AudioObjectGetPropertyData(id和地址、0、nil和propsize、bufferList.unsafeMutablePointer)

再说一次,我并不推荐这种方法来获得流配置-在我看来,这是不必要的复杂,而且我已经采纳了类似于公认答案的方法。因此,这可能除了作为一种学术练习之外没有其他价值。

这非常有效,谢谢!您能给我一些额外的信息,为什么我应该使用
assumingMemoryBound()
bindMemory()
相反?苹果有一些关于使用绑定到错误类型的内存的警告…@akuz,我认为绑定到特定类型的内存是一种虚构的概念,目前没有实际区别。(对不起,我的信息可能太旧了。)而且
bindMemory
根据指针类型的大小计算
capacity
,而指针类型的大小并不是实际分配的大小,正如您所知。OOPer-这就是我所想的,但我还是想问一下……谢谢!stackoverflow上的所有示例都使用
propSize
字节来分配这么多
AudioBufferList
s!你的答案非常有用,而且很有效-再次感谢!OOPer-你会碰巧知道这个问题的答案吗?在我看到的例子中,我最喜欢这个。我建议的唯一补充是调用
allocate()
通常应该与调用
deallocate()配对
这个答案有用吗?您想分配一个足够大的
AudioBufferList
来容纳您试图访问的属性,然后将其传递给对方reference@Alexander-如果答案使用的道具尺寸不正确,下面OOPer的答案是正确的