0

In C, I have the following code to allocate a AudioBufferList with the appropriate size and then populate it with relevant data.

AudioObjectPropertyScope scope = mIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
AudioObjectPropertyAddress address = { kAudioDevicePropertyStreamConfiguration, scope, 0 };
UInt32 propertySize;
__Verify_noErr(
  AudioObjectGetPropertyDataSize(mID, &address, 0, NULL, &propertySize)
);
AudioBufferList *bufferList = (AudioBufferList *) malloc(propertySize);
__Verify_noErr(
  AudioObjectGetPropertyData(mID, &address, 0, NULL, &propertySize, bufferList)
);

Then, I can access struct element :

UInt32 result { 0 };
for(UInt32 i = 0; i < bufferList->mNumberBuffers; ++i)
{
  result += bufferList->mBuffers[i].mNumberChannels;
}
free(bufferList)

How can I replicate this behavior in Swift, given the fact that I use the same framework, i.e. AudioToolbox?

I have tried the following but I can't access the mNumberBuffers

let scope: AudioObjectPropertyScope = scope ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput
var address: AudioObjectPropertyAddress = AudioObjectPropertyAddress(mSelector: kAudioDevicePropertyStreamConfiguration, mScope: scope, mElement: 0)
var size: UInt32 = 0
CheckError(
  AudioObjectGetPropertyDataSize(mID, &address, 0, nil, &size),
  "Couldn't get stream configuration data size."
)
var bufferList = UnsafeMutableRawPointer.allocate(bytes: Int(size), alignedTo: MemoryLayout<AudioBufferList>.alignment).assumingMemoryBound(to: AudioBufferList.self)
CheckError(
  AudioObjectGetPropertyData(mID, &address, 0, nil, &size, bufferList),
  "Couldn't get device's stream configuration"
)
Pierre P.
  • 1,055
  • 2
  • 14
  • 26
  • Possible duplicate of [Swift access to variable length array](https://stackoverflow.com/q/27061028/1187415) – Martin R Mar 02 '18 at 20:28

1 Answers1

1

You can create an AudioBufferList like this:

import AudioUnit
import AVFoundation

var myBufferList = AudioBufferList(
              mNumberBuffers: 2,
              mBuffers: AudioBuffer(
                  mNumberChannels: UInt32(2),
                  mDataByteSize: 2048,
                  mData: nil) )

When handed a bufferList with an unknown number of buffers, you can get the number of buffers and the sample data like this:

let myBufferListPtr = UnsafeMutableAudioBufferListPointer(myBufferList)
let numBuffers = myBufferListPtr.count
if (numBuffers > 0) {
        let buffer : AudioBuffer = myBufferListPtr[0]
        let bufferDataPointer = UnsafeMutableRawPointer(buffer.mData)
        if let dataPtr = bufferDataPointer {
            dataPtr.assumingMemoryBound(to: Float.self)[ i ] = x
            ...

The rest of my source code example is on GitHub: https://gist.github.com/hotpaw2/ba815fc23b5d642705f2b1dedfaf0107

hotpaw2
  • 70,107
  • 14
  • 90
  • 153
  • Thanks for your help. Yet, I don't understand how the first case and the second one are related? If I don't know the number of buffers, why should I create an UnsafeMutableAudioBufferListPointer (`myBufferListPtr`) from a previously created AudioBufferList (`myBufferList`) whose number of buffers is defined, i.e 2? – Pierre P. Mar 03 '18 at 16:32
  • The 1st and 2nd case are unrelated. – hotpaw2 Mar 06 '18 at 17:28