【问题标题】:UnsafeMutableAudioBufferListPointer allocation before calling AudioObjectGetPropertyData在调用 AudioObjectGetPropertyData 之前分配 UnsafeMutableAudioBufferListPointer
【发布时间】:2020-07-02 15:39:02
【问题描述】:

我一直在尝试从 swift 使用 Apple 的 CoreAudio。 我发现了许多关于如何枚举设备上的流和通道的示例。 但是,在调用UnsafeMutablePointer<AudioBufferList>.allocate() 时,它们似乎都使用了不正确的大小。

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

请在下面查看我的 cmets:

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&lt;AudioBufferList&gt; 需要的多得多,但这显然是错误的。

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

【问题讨论】:

  • 这个答案有帮助吗? stackoverflow.com/a/38982906/3141234 您想分配一个足够大的AudioBufferList 以适合您尝试访问的属性,然后通过引用传递它
  • @Alexander-ReinstateMonica 回答是错误地使用了道具尺寸,下面 OOPer 的回答是正确的

标签: swift core-audio


【解决方案1】:

AudioObjectGetPropertyDataSize()返回的字节数中正确分配UnsafeMutablePointer&lt;AudioBufferList&gt;

您不应该分配UnsafeMutablePointer&lt;AudioBufferList&gt;,而是分配精确大小的原始字节并将其转换为UnsafeMutablePointer&lt;AudioBufferList&gt;

类似这样的事情:

        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)

【讨论】:

  • 这非常好用,谢谢!您能否给我一些额外的信息,为什么我应该使用assumingMemoryBound() 而不是bindMemory()?苹果有一些关于使用绑定到错误类型的内存的警告......
  • @akuz,我认为绑定到特定类型的内存是一种虚构的概念,目前没有实际区别。 (对不起,但我的信息可能太旧了。)bindMemory 按指针类型的大小计算 capacity,这不是您知道的实际分配的大小。
  • OOPer - 这就是我的想法,但还是想问一下......谢谢!令人惊讶的是,stackoverflow 上的所有示例都使用propSize(以字节为单位)来分配那么多AudioBufferLists 的内存!您的回答非常有帮助,并且有效 - 再次感谢!
  • OOPer——你会不会也知道这个问题的答案? stackoverflow.com/questions/60801491/…
  • 在我见过的例子中,我最喜欢这个。我建议的唯一补充是对allocate() 的调用通常应与对deallocate() 的调用配对
【解决方案2】:

我完全同意使用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,我已经采用了类似于接受的答案的方法。因此,除了作为学术练习之外,这可能没有其他价值。

【讨论】:

    猜你喜欢
    • 2013-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-22
    • 2017-05-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多