调用 AudioObjectGetPropertyData 之前的 UnsafeMutableAudioBufferListPointer 分配

UnsafeMutableAudioBufferListPointer allocation before calling AudioObjectGetPropertyData

我一直在尝试使用来自 swift 的 Apple CoreAudio。 我找到了许多关于如何枚举设备上的流和频道的示例。 但是,在调用 UnsafeMutablePointer<AudioBufferList>.allocate().

时,它们似乎都使用了不正确的大小

他们首先请求属性数据大小,即returns字节数。 然后他们使用这个字节数来分配那个大小的(不安全的)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
    }
}

这一直有效,因为它分配的内存比 UnsafeMutablePointer<AudioBufferList> 所需的多得多,但这显然是错误的。

我一直在寻找一种方法来根据 AudioObjectGetPropertyDataSize() 返回的字节数正确分配 UnsafeMutablePointer<AudioBufferList>,但一整天都找不到任何东西。请帮助 ;)

根据 AudioObjectGetPropertyDataSize()[=15 返回的字节数正确分配 UnsafeMutablePointer<AudioBufferList> =]

您不应分配 UnsafeMutablePointer<AudioBufferList>,而应分配确切大小的原始字节并将其转换为 UnsafeMutablePointer<AudioBufferList>

像这样的东西:

        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)

我完全同意使用 UnsafeMutableRawPointer.allocate(byteCount:alignment:) 的公认答案(尽管它也应该与调用 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)

同样,我实际上并不推荐这种方法来获取流配置 - IMO 不必要地复杂,并且我已经采用了类似于公认答案的方法。因此,除了作为学术练习外,这可能没有任何价值。