I am learning CoreAudio and I am just going through some of the examples on Apple's documentation and figuring out how to set things up and what not. So far I am able to connect to the default connected audio input device and output it to the default output device. I connected a 2 channel interface and was able to output the input from it and output it as well.
However I was searching through their API references and examples, but could not find any thing substantial to access the individual input channels from my interface.
I was able to hack away and extract the samples from the AudioBufferList in my Render Callback function and manipulate it that way but I am wondering if there is a correct way or a more official way of accessing the data from each individual input channels.
EDIT:
This is the user data that I found from an example that I am using:
typedef struct MyAUGraphPlayer
{
AudioStreamBasicDescription streamFormat;
AUGraph graph;
AudioUnit inputUnit;
AudioUnit outputUnit;
AudioBufferList * inputBuffer;
CARingBuffer * ringBuffer;
Float64 firstInputSampleTime;
Float64 firstOutputSampleTime;
Float64 inToOutSampleTimeOffset;
} MyAUGraphPlayer;
This is how i set up the input unit:
void CreateInputUnit(MyAUGraphPlayer * player)
{
//Generates a description that matches audio HAL
AudioComponentDescription inputcd = {0};
inputcd.componentType = kAudioUnitType_Output;
inputcd.componentSubType = kAudioUnitSubType_HALOutput;
inputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
UInt32 deviceCount = AudioComponentCount ( &inputcd );
printf("Found %d devices\n", deviceCount);
AudioComponent comp = AudioComponentFindNext(NULL, &inputcd);
if(comp == NULL) {
printf("Can't get output unit\n");
exit(1);
}
OSStatus status;
status = AudioComponentInstanceNew(comp, &player->inputUnit);
assert(status == noErr);
//Explicitly enable Input and disable output
UInt32 disableFlag = 0;
UInt32 enableFlag = 1;
AudioUnitScope outputBus = 0;
AudioUnitScope inputBus = 1;
status = AudioUnitSetProperty(player->inputUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
inputBus,
&enableFlag,
sizeof(enableFlag))
assert(status == noErr);
status = AudioUnitSetProperty(player->inputUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
outputBus,
&disableFlag,
sizeof(enableFlag));
assert(status == noErr);
printf("Finished enabling input and disabling output on an inputUnit\n");
//Get the default Audio input Device
AudioDeviceID defaultDevice = kAudioObjectUnknown;
UInt32 propertySize = sizeof(defaultDevice);
AudioObjectPropertyAddress defaultDeviceProperty;
defaultDeviceProperty.mSelector = kAudioHardwarePropertyDefaultInputDevice;
defaultDeviceProperty.mScope = kAudioObjectPropertyScopeGlobal;
defaultDeviceProperty.mElement = kAudioObjectPropertyElementMaster;
status = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&defaultDeviceProperty,
0,
NULL,
&propertySize,
&defaultDevice);
assert(status == noErr);
//Set the current device property of the AUHAL
status = AudioUnitSetProperty(player->inputUnit,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global,
outputBus,
&defaultDevice,
sizeof(defaultDevice));
assert(status == noErr);
//Get the AudioStreamBasicDescription from Input AUHAL
propertySize = sizeof(AudioStreamBasicDescription);
status = AudioUnitGetProperty(player->inputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
inputBus,
&player->streamFormat,
&propertySize);
assert(status == noErr);
//Adopt hardware input sample rate
AudioStreamBasicDescription deviceFormat;
status = AudioUnitGetProperty(player->inputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
inputBus,
&deviceFormat,
&propertySize);
assert(status == noErr);
player->streamFormat.mSampleRate = deviceFormat.mSampleRate;
printf("Sample Rate %f...\n", deviceFormat.mSampleRate);
propertySize = sizeof(AudioStreamBasicDescription);
status = AudioUnitSetProperty(player->inputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
inputBus,
&player->streamFormat,
propertySize);
assert(status == noErr);
//Calculating Capture buffer size for an I/O unit
UInt32 bufferSizeFrames = 0;
propertySize = sizeof(UInt32);
status = AudioUnitGetProperty(player->inputUnit,
kAudioDevicePropertyBufferFrameSize,
kAudioUnitScope_Global,
0,
&bufferSizeFrames,
&propertySize);
assert(status == noErr);
UInt32 bufferSizeBytes = bufferSizeFrames * sizeof(Float32);
//Create AudioBufferList to receive capture data
UInt32 propSize = offsetof(AudioBufferList, mBuffers[0]) +
(sizeof(AudioBuffer) * player->streamFormat.mChannelsPerFrame);
//Malloc buffer lists
player->inputBuffer = (AudioBufferList *) malloc(propSize);
player->inputBuffer->mNumberBuffers = player->streamFormat.mChannelsPerFrame;
//Pre malloc buffers for AudioBufferLists
for(UInt32 i = 0; i < player->inputBuffer->mNumberBuffers; i++){
player->inputBuffer->mBuffers[i].mNumberChannels = 1;
player->inputBuffer->mBuffers[i].mDataByteSize = bufferSizeBytes;
player->inputBuffer->mBuffers[i].mData = malloc(bufferSizeBytes);
}
//Create the ring buffer
player->ringBuffer = new CARingBuffer();
player->ringBuffer->Allocate(player->streamFormat.mChannelsPerFrame,
player->streamFormat.mBytesPerFrame,
bufferSizeFrames * 3);
printf("Number of channels: %d\n", player->streamFormat.mChannelsPerFrame);
printf("Number of buffers: %d\n", player->inputBuffer->mNumberBuffers);
//Set render proc to supply samples
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = InputRenderProc;
callbackStruct.inputProcRefCon = player;
status = AudioUnitSetProperty(player->inputUnit,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
0,
&callbackStruct,
sizeof(callbackStruct);
assert(status == noErr);
status = AudioUnitInitialize(player->inputUnit);
assert(status == noErr);
player->firstInputSampleTime = -1;
player->inToOutSampleTimeOffset = -1;
printf("Finished CreateInputUnit()\n");
}
So this is my render callback function where I am accessing the individual buffers. :
OSStatus GraphRenderProc(void * inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
MyAUGraphPlayer * player = (MyAUGraphPlayer *) inRefCon;
if(player->firstOutputSampleTime < 0.0) {
player->firstOutputSampleTime = inTimeStamp->mSampleTime;
if((player->firstInputSampleTime > -1.0) &&
(player->inToOutSampleTimeOffset < 0.0)) {
player->inToOutSampleTimeOffset = player->firstInputSampleTime - player->firstOutputSampleTime;
}
}
//Copy samples out of ring buffer
OSStatus outputProcErr = noErr;
outputProcErr = player->ringBuffer->Fetch(ioData,
inNumberFrames,
inTimeStamp->mSampleTime + player->inToOutSampleTimeOffset);
//BUT THIS IS NOT HOW IT IS SUPPOSED TO WORK
Float32 * data = (Float32 *) ioData->mBuffers[0].mData;
Float32 * data2 = (Float32 *) ioData->mBuffers[1].mData;
for(int frame = 0; frame < inNumberFrames; frame++)
{
Float32 sample = data[frame] + data2[frame];
data[frame] = data2[frame] = sample;
}
return outputProcErr;
}