• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Programmatic Aggregate Device issue on Intel Mac, not always completing initialisation?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Programmatic Aggregate Device issue on Intel Mac, not always completing initialisation?


  • Subject: Re: Programmatic Aggregate Device issue on Intel Mac, not always completing initialisation?
  • From: Jeff Moore <email@hidden>
  • Date: Tue, 08 Jul 2008 12:00:13 -0700


On Jul 8, 2008, at 2:32 AM, Dan Stowell wrote:

Hi -

Thanks for the response, and sorry for my omissions. To clarify:

2008/7/7 Jeff Moore <email@hidden>:
- Is the aggregate device you are creating private?

Yes. Situation doesn't seem to change if I don't make it private.

Interesting. The other folks that have had problems generally had them with their private devices. It would seem then that your issues may be something different entirely.



- You say that it works fine in the case where you are using two separate
processes, but you get the problem when you are using a single process. Can
you elaborate on what the differences are between the environments?

I wish I could pin down the relevant differences for you. Both versions use the same code to connect to the audio drivers. The "separate process" version is a command-line executable so the audio setup is triggered from the call to main(), while the in-process version is triggered from some other function called by the user. But both use the same structs and method calls to initialise, and as far as I can tell there's no difference in the options received by the CoreAudio code.

Not to belabor the obvious, but something has to be different. Given everything I've heard so far, figuring this out seems to me to be the most important thing you can do to learn about this problem. There's not much more I can do for you until you nail this down I think.


- Can you walk through how you are creating the aggregate device? The honest
truth is that I don't have time to wade through your code and debug your
problems for you so it is always much more helpful if you can boil down your
code into snippets that you can post.

Here's the main snippet:


count = sizeof(mOutputDevice);

if(mOutputDevice == kAudioDeviceUnknown) {
//get the output device:
err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
&count, (void *) & mOutputDevice);
if (err != kAudioHardwareNoError) {
scprintf("get kAudioHardwarePropertyDefaultOutputDevice error
%4.4s\n", (char*)&err);
return false;
}
}


if (mInputDevice == kAudioDeviceUnknown) {
//get the input device
err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
&count, (void *) & mInputDevice);
if (err != kAudioHardwareNoError) {
scprintf("get kAudioHardwarePropertyDefaultInputDevice error
%4.4s\n", (char*)&err);
return false;
}
}

Getting the default input and output devices. Seems fine. About the only comment I'd make is that you really should stop using the older APIs and should switch over to using the AudioObject-based APIs. Not that it will change anything about this problem, but it will help future-proof your code.



// create aggregate from default input and default output
if (mInputDevice!=mOutputDevice)
{
scprintf("creating Aggregate Device : SCAggregate\n");
CFStringRef s = CFStringCreateWithCString(NULL,
"com.apple.audio.CoreAudio", kCFStringEncodingUTF8);
AudioValueTranslation translation = {&s, sizeof(s), &coreaudioPlugin,
sizeof(coreaudioPlugin)};
unsigned long size = sizeof(translation);
err = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID,
&size, &translation);
CFRelease(s);
if (err != kAudioHardwareNoError)
{
scprintf("get kAudioHardwarePropertyPlugInForBundleID error
%4.4s\n", (char*)&err);
return false;
}


	CFStringRef inputUID;
	CFStringRef outputUID;
	unsigned long UIDsize = sizeof(inputUID);
	AudioDeviceGetProperty(mInputDevice, 0, 0,
kAudioDevicePropertyDeviceUID, &UIDsize, &inputUID);
	AudioDeviceGetProperty(mOutputDevice, 0, 0,
kAudioDevicePropertyDeviceUID, &UIDsize, &outputUID);

CFMutableDictionaryRef dict =
CFDictionaryCreateMutable(kCFAllocatorDefault,0,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(dict, CFSTR("uid"), CFSTR("SCAggregate"));
CFDictionarySetValue(dict, CFSTR("name"), CFSTR("SCAggregate"));
int privateness = 1;
CFNumberRef privatenessRef = CFNumberCreate(kCFAllocatorDefault,
kCFNumberIntType, & privateness);
CFDictionarySetValue(dict, CFSTR("private"), privatenessRef);
CFRelease(privatenessRef);

unsigned long aggregateSize = sizeof(aggregateID);
AudioObjectPropertyAddress address = {
kAudioPlugInCreateAggregateDevice, kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
err = AudioObjectGetPropertyData(coreaudioPlugin, &address,
sizeof(CFDictionaryRef), &dict, &aggregateSize, &aggregateID);
CFRelease(dict);
if (err != kAudioHardwareNoError)
{
scprintf("get kAudioPlugInCreateAggregateDevice error %4.4s\n", (char*)&err);
return false;
}


// point at which to add the delay?

The preceding code looks OK, although I'd really advise you to use the constants in AudioHardware.h for the dictionary keys.


And this is also where you'd put the delay and the re-fetching of the newly created aggregate device's AudioOjbectID that I mentioned in my previous email. Note that you'd be using the re-fetched ID from this point on.

	address.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList;
	CFMutableArrayRef subdevices = CFArrayCreateMutable(NULL,0,NULL);
	CFArrayAppendValue(subdevices, (void *) inputUID);
	CFArrayAppendValue(subdevices, (void *) outputUID);
	err = AudioObjectSetPropertyData(aggregateID, &address, 0, NULL,
sizeof(subdevices), &subdevices);
	CFRelease(subdevices);
	if (err != kAudioHardwareNoError)
	{
		scprintf("get kAudioAggregateDevicePropertyFullSubDeviceList error
%4.4s\n", (char*)&err);
		return false;
	}

Setting the sub-device list can be done in either as part of the creation dictionary or done after the fact.



	address.mSelector = kAudioAggregateDevicePropertyMasterSubDevice;
	err = AudioObjectSetPropertyData(aggregateID, &address, 0, NULL,
sizeof(outputUID), &outputUID);
	if (err != kAudioHardwareNoError)
	{
		scprintf("get kAudioAggregateDevicePropertyMasterSubDevice error
%4.4s\n", (char*)&err);
		return false;
	}

	mOutputDevice = mInputDevice = aggregateID;
}
Finally, as you say there have been issues in the past with programmatically
created aggregate devices. The usual way this has manifested is that a newly
created aggregate device will seem to disappear for a moment after it is
created. The way I've seen folks work around this issue is to do add some
code to pause after creating the aggregate and then to look up the
aggregate's AudioObjectID again using kAudioHardwarePropertyDeviceForUID.
It's not a cure all by any means but it has helped a few developers.

OK, thanks. I added the following to the above code, at the point marked "point at which to add the delay":


CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
address.mSelector = kAudioHardwarePropertyDeviceForUID;
err = AudioObjectGetPropertyData(coreaudioPlugin, &address,
sizeof(CFStringRef), CFSTR("SCAggregate"), &aggregateSize, &aggregateID);
if (err != kAudioHardwareNoError)
{
scprintf("get kAudioHardwarePropertyDeviceForUID error %s\n", (char*)&err);
return false;
}



It results in the following error in all configurations:

 get kAudioHardwarePropertyDeviceForUID error ?ohw

so I guess I'm doing something wrong...? Thanks for any further advice.

As it's name implies, kAudioHardwarePropertyDeviceForUID is a property of the system object, not the plug-in object. That's why you are getting the error here.



At any rate, here's what the pseudo-code would look like:

// create the aggregate device
<... make a bunch of HAL calls ending with a new aggregate device getting
created ...>


// task the thread's run loop for 100 milliseconds to make sure that things
got done
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);


// use the UID of the aggregate device to look up it's AudioObjectID
<... make a call to AudioObjectGetPropertyData on the system object using
kAudioHardwarePropertyDeviceForUID ...>


On Jul 3, 2008, at 7:42 AM, Dan wrote:

We're trying to add automatic creation of an Aggregate Device to an
open-source audio software called SuperCollider. The audio engine has
two ways of running: either as a separate process, or launched within
the main application process.


Now, we have a patch for the Aggregate Device issue, and it works fine
in the first case (audio engine is separate). But in the second case
(audio engine "internal" to application) there seems to be a problem
on Intel Macs, where the IOProc callback for the audio device is never
called. It's the same code being called in each case, so maybe
something subtle is going on.


If using a "real" device, or a user-created aggregate, there is no
problem starting the audio callback.

I've seen in the archives of this list discussion of the occasional
bug in the programmatic interaction with Aggregate Device creation
etc. If you can suggest whether this is a bug or our own fault that
would be extremely helpful!



--

Jeff Moore
Core Audio
Apple


_______________________________________________ Do not post admin requests to the list. They will be ignored. Coreaudio-api mailing list (email@hidden) Help/Unsubscribe/Update your Subscription: This email sent to email@hidden
References: 
 >Programmatic Aggregate Device issue on Intel Mac, not always completing initialisation? (From: Dan <email@hidden>)
 >Re: Programmatic Aggregate Device issue on Intel Mac, not always completing initialisation? (From: Jeff Moore <email@hidden>)

  • Prev by Date: Re: Saving a MIDI/SMF file: How?
  • Next by Date: Re: A simple 'Device Through' app (need some help).
  • Previous by thread: Re: Programmatic Aggregate Device issue on Intel Mac, not always completing initialisation?
  • Next by thread: Re: Programmatic Aggregate Device issue on Intel Mac, not always completing initialisation?
  • Index(es):
    • Date
    • Thread