QuickTime Audio Output


#1

My app is a standalone synth, that also plays video. I’m on mac so I’m using QuickTimeMovieComponent for the video player.

I’d like to be able to control the audio output of both the synth and movie from within the app. I have no problem doing it with the synth using AudioDeviceSelectorComponent. But I don’t see any JUCE capability for controlling the the movie’s audio output. Is this possible?


#2

No, there’s no control over how QuickTime handles its audio.


#3

Shoot. Thanks for the quick reply.


#4

Here’s my solution, for those interested.

in juce_mac_QuickTimeMovieComponent.mm I added the following method:

void QuickTimeMovieComponent::setAudioDevice(String newDeviceName)
{
	AudioObjectPropertyAddress  propertyAddress;
	AudioObjectID               *deviceIDs;
	UInt32                      propertySize;
	NSInteger                   numDevices;
	
	propertyAddress.mSelector = kAudioHardwarePropertyDevices;
	propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
	propertyAddress.mElement = kAudioObjectPropertyElementMaster;
	
	if (AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize) == noErr) 
	{
		numDevices = propertySize / sizeof(AudioDeviceID);
		deviceIDs = (AudioDeviceID *)calloc(numDevices, sizeof(AudioDeviceID));
		
		if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, deviceIDs) == noErr) 
		{
			AudioObjectPropertyAddress      deviceAddress;
			char                            deviceName[64];
			char                            manufacturerName[64];
			
			for (NSInteger idx=0; idx<numDevices; idx++) 
			{
				propertySize = sizeof(deviceName);
				deviceAddress.mSelector = kAudioDevicePropertyDeviceName;
				deviceAddress.mScope = kAudioObjectPropertyScopeGlobal;
				deviceAddress.mElement = kAudioObjectPropertyElementMaster;
				
				if (AudioObjectGetPropertyData(deviceIDs[idx], &deviceAddress, 0, NULL, &propertySize, deviceName) == noErr) 
				{
					propertySize = sizeof(manufacturerName);
					deviceAddress.mSelector = kAudioDevicePropertyDeviceManufacturer;
					deviceAddress.mScope = kAudioObjectPropertyScopeGlobal;
					deviceAddress.mElement = kAudioObjectPropertyElementMaster;
					
					if (AudioObjectGetPropertyData(deviceIDs[idx], &deviceAddress, 0, NULL, &propertySize, manufacturerName) == noErr) 
					{
						if (String(deviceName) == newDeviceName) 
						{
							CFStringRef uidString;
							
							propertySize = sizeof(uidString);
							deviceAddress.mSelector = kAudioDevicePropertyDeviceUID;
							deviceAddress.mScope = kAudioObjectPropertyScopeGlobal;
							deviceAddress.mElement = kAudioObjectPropertyElementMaster;
							
							if (AudioObjectGetPropertyData(deviceIDs[idx], &deviceAddress, 0, NULL, &propertySize, &uidString) == noErr) 
							{
								NSLog(@"device %s by %s id %@", deviceName, manufacturerName, uidString);
								
								QTAudioContextRef newAudioContext = NULL;
								QTAudioContextCreateForAudioDevice(kCFAllocatorDefault, uidString, /*options*/ NULL, &newAudioContext);
								SetMovieAudioContext([theMovie quickTimeMovie], newAudioContext);
								
								CFRelease(uidString);
							}
						}
						
						
					}
				}
			}
		}

		free(deviceIDs);
	}
}

Whenever the user changes the audio device using the AudioDeviceSelectorComponent, I trigger this method, sending in the name of the new device. Works like a charm.

If you know of a better way to do it I’m all ears. I know next to nothing about Obj C, and pieced this together from examples on internet forums, so hack away!


#5

Argh! Turns out this solution only works on 32 bit systems because QTKit only allows the use of QTAudioContextRef on 32 bit systems. Back to the drawing board.