I am trying to aggregate my USB 6 in 6 out sound card so that instead
of being regarded as two separate devices (in and out), it shows up as
one device.
Courtesy of a previous question to the mailing list
(http://lists.apple.com/archives/coreaudio-api/2006/Apr/msg00103.html)
I am able to create an aggregate device in the code so that it shows
up in Audio MIDI Setup, unfortunately though, my input/output
callbacks never start.
I have had some success though.
- I can use the two USB devices (in and out) so that it uses the input
callback and output callback.
- I can create the aggregate device in the code, close my application
so that the aggregate device remains in Audio MIDI setup, then restart
the program using the name of the aggregate device to identify an
input/output device that requires only one callback. This works too.
What I can't do is create my aggregate device in the code, 'then'
use it.
Here's the steps I've done:
- Identified the two separate USB devices (in and out) and set the
sample rate and frame size.
- Created a public aggregate device using the input and output ids of
the USB device.
- Tried to start the callbacks using AudioDeviceAddIOProc and
AudioDeviceStart using the id of the newly created aggregate device.
Unfortunately, the callbacks never start and I've noticed that while
running my application, Audio MIDI Setup shows zero input channels but
6 output channels for the device. When I close my application, it
changes to 6 in 6 out, which is what the card is supposed to be.
Is that the problem? Should all 6 in and 6 outs be visible when I
create the aggregate device. I'm assuming there is a problem with the
way I have created the aggregate device, code which is unashamedly
copied from numerous sources. Unfortunately though, I can't identify
why it would drop access to the inputs, if that is indeed the problem.
Any help would be great.
OSStatus CCoreAudioHost::CreateAggregateDevice(AudioDeviceID
inputDeviceID, AudioDeviceID outputDeviceID, AudioDeviceID
&aggregateID)
{
OSStatus status = noErr;
UInt32 size;
CFStringRef s;
AudioDeviceID coreaudioPlugin;
size = sizeof(AudioValueTranslation);
AudioValueTranslation translation = { &s, sizeof(s),
&coreaudioPlugin, sizeof(coreaudioPlugin) };
s = CFStringCreateWithCString(NULL, "com.apple.audio.CoreAudio",
kCFStringEncodingUTF8);
status =
AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID,
&size, &translation);
CFRelease(s);
if (status != kAudioHardwareNoError)
{
DEBUGSTR("Get kAudioHardwarePropertyPlugInForBundleID error
%4.4s\n", (char*)&status);
return status;
}
CFStringRef inputUID;
CFStringRef outputUID;
unsigned long UIDsize = sizeof(inputUID);
AudioDeviceGetProperty(inputDeviceID, 0, 0,
kAudioDevicePropertyDeviceUID, &UIDsize, &inputUID);
AudioDeviceGetProperty(outputDeviceID, 0, 0,
kAudioDevicePropertyDeviceUID, &UIDsize, &outputUID);
CFMutableDictionaryRef dict =
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(dict, CFSTR(kAudioAggregateDeviceUIDKey),
CFSTR("AggregateDevice")); //Set the UID of the aggregate device
CFDictionarySetValue(dict, CFSTR(kAudioAggregateDeviceNameKey),
CFSTR("AggregateDevice")); //Set the name of the aggregate device
int privateness = 0; //0 is global, 1 is private
CFNumberRef privatenessRef =
CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType, &privateness);
CFDictionarySetValue(dict, CFSTR(kAudioAggregateDeviceIsPrivateKey),
privatenessRef);
CFRelease(privatenessRef);
UInt32 aggregateSize = sizeof(aggregateID);
AudioObjectPropertyAddress address = {
kAudioPlugInCreateAggregateDevice, kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
status = AudioObjectGetPropertyData( coreaudioPlugin, &address,
sizeof(CFDictionaryRef), &dict, &aggregateSize, &aggregateID);
CFRelease(dict);
if (status != kAudioHardwareNoError)
{
PrintError(status);
DEBUGSTR("Get kAudioPlugInCreateAggregateDevice error %4.4s\n",
(char*)&status);
return false;
}
address.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList;
CFMutableArrayRef subdevices = CFArrayCreateMutable(NULL, 0, NULL);
CFArrayAppendValue(subdevices, (void *) inputUID);
CFArrayAppendValue(subdevices, (void *) outputUID);
status = AudioObjectSetPropertyData(aggregateID, &address, 0, NULL,
sizeof(subdevices), &subdevices);
CFRelease(subdevices);
if (status != kAudioHardwareNoError)
{
DEBUGSTR("Get kAudioAggregateDevicePropertyFullSubDeviceList error
%4.4s\n", (char*)&status);
return false;
}
address.mSelector = kAudioAggregateDevicePropertyMasterSubDevice;
status = AudioObjectSetPropertyData(aggregateID, &address, 0, NULL,
sizeof(outputUID), &outputUID);
if (status != kAudioHardwareNoError)
{
DEBUGSTR("Get kAudioAggregateDevicePropertyMasterSubDevice error
%4.4s\n", (char*)&status);
return false;
}
return noErr;
}