Browse Source

Aggregate device code added to JackCoreAudioAdapter.

git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3670 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/v1.9.4
sletz 15 years ago
parent
commit
e6f91c7a0d
4 changed files with 216 additions and 19 deletions
  1. +201
    -11
      macosx/coreaudio/JackCoreAudioAdapter.cpp
  2. +6
    -1
      macosx/coreaudio/JackCoreAudioAdapter.h
  3. +7
    -5
      macosx/coreaudio/JackCoreAudioDriver.cpp
  4. +2
    -2
      macosx/coreaudio/JackCoreAudioDriver.h

+ 201
- 11
macosx/coreaudio/JackCoreAudioAdapter.cpp View File

@@ -491,19 +491,35 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,

// Duplex
if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) {
jack_log("JackCoreAudioAdapter::Open duplex");
if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
if (GetDefaultDevice(&fDeviceID) != noErr) {
jack_error("Cannot open default device");
// Same device for capture and playback...
if (strcmp(capture_driver_uid, playback_driver_uid) == 0) {
if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
jack_log("Will take default in/out");
if (GetDefaultDevice(&fDeviceID) != noErr) {
jack_error("Cannot open default device");
return -1;
}
}
if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
jack_error("Cannot get device name from device ID");
return -1;
}
}
if (GetDeviceNameFromID(fDeviceID, capture_driver_name) != noErr || GetDeviceNameFromID(fDeviceID, playback_driver_name) != noErr) {
jack_error("Cannot get device name from device ID");
return -1;
} else {
// Creates aggregate device
AudioDeviceID captureID, playbackID;
if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr)
return -1;
if (GetDeviceIDFromUID(playback_driver_uid, &playbackID) != noErr)
return -1;
if (CreateAggregateDevice(captureID, playbackID, &fDeviceID) != noErr)
return -1;
}

// Capture only
// Capture only
} else if (strcmp(capture_driver_uid, "") != 0) {
jack_log("JackCoreAudioAdapter::Open capture only");
if (GetDeviceIDFromUID(capture_driver_uid, &fDeviceID) != noErr) {
@@ -517,7 +533,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
return -1;
}

// Playback only
// Playback only
} else if (strcmp(playback_driver_uid, "") != 0) {
jack_log("JackCoreAudioAdapter::Open playback only");
if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
@@ -531,7 +547,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
return -1;
}

// Use default driver in duplex mode
// Use default driver in duplex mode
} else {
jack_log("JackCoreAudioAdapter::Open default driver");
if (GetDefaultDevice(&fDeviceID) != noErr) {
@@ -903,6 +919,178 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
return 0;
}

OSStatus JackCoreAudioAdapter::DestroyAggregateDevice()
{
OSStatus osErr = noErr;
AudioObjectPropertyAddress pluginAOPA;
pluginAOPA.mSelector = kAudioPlugInDestroyAggregateDevice;
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
UInt32 outDataSize;
osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
if (osErr != noErr) {
jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error");
printError(osErr);
return osErr;
}
osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID);
if (osErr != noErr) {
jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyData error");
printError(osErr);
return osErr;
}
return noErr;
}

static CFStringRef GetDeviceName(AudioDeviceID id)
{
UInt32 size = sizeof(CFStringRef);
CFStringRef UIname;
OSStatus err = AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
return (err == noErr) ? UIname : NULL;
}

OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, AudioDeviceID* outAggregateDevice)
{
OSStatus osErr = noErr;
UInt32 outSize;
Boolean outWritable;

//---------------------------------------------------------------------------
// Start to create a new aggregate by getting the base audio hardware plugin
//---------------------------------------------------------------------------
jack_info("Separated input and output devices, so create a private aggregate device to handle them...");
osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
if (osErr != noErr)
return osErr;

AudioValueTranslation pluginAVT;

CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio");
pluginAVT.mInputData = &inBundleRef;
pluginAVT.mInputDataSize = sizeof(inBundleRef);
pluginAVT.mOutputData = &fPluginID;
pluginAVT.mOutputDataSize = sizeof(fPluginID);

osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT);
if (osErr != noErr)
return osErr;

//-------------------------------------------------
// Create a CFDictionary for our aggregate device
//-------------------------------------------------

CFMutableDictionaryRef aggDeviceDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

CFStringRef AggregateDeviceNameRef = CFSTR("JackDuplex");
CFStringRef AggregateDeviceUIDRef = CFSTR("com.grame.JackDuplex");
// add the name of the device to the dictionary
CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceNameKey), AggregateDeviceNameRef);

// add our choice of UID for the aggregate device to the dictionary
CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef);
// add a "private aggregate key" to the dictionary
int value = 1;
CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value);
CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef);
//-------------------------------------------------
// Create a CFMutableArray for our sub-device list
//-------------------------------------------------
CFStringRef captureDeviceUID = GetDeviceName(captureDeviceID);
CFStringRef playbackDeviceUID = GetDeviceName(playbackDeviceID);
if (captureDeviceUID == NULL || playbackDeviceUID == NULL)
return -1;
// we need to append the UID for each device to a CFMutableArray, so create one here
CFMutableArrayRef subDevicesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);

// two sub-devices in this example, so append the sub-device's UID to the CFArray
CFArrayAppendValue(subDevicesArray, captureDeviceUID);
CFArrayAppendValue(subDevicesArray, playbackDeviceUID);

//-----------------------------------------------------------------------
// Feed the dictionary to the plugin, to create a blank aggregate device
//-----------------------------------------------------------------------
AudioObjectPropertyAddress pluginAOPA;
pluginAOPA.mSelector = kAudioPlugInCreateAggregateDevice;
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
UInt32 outDataSize;

osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize);
if (osErr != noErr)
return osErr;

osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice);
if (osErr != noErr)
return osErr;

// pause for a bit to make sure that everything completed correctly
// this is to work around a bug in the HAL where a new aggregate device seems to disappear briefly after it is created
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);

//-------------------------
// Set the sub-device list
//-------------------------

pluginAOPA.mSelector = kAudioAggregateDevicePropertyFullSubDeviceList;
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
outDataSize = sizeof(CFMutableArrayRef);
osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray);
if (osErr != noErr)
return osErr;

// pause again to give the changes time to take effect
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);

//-----------------------
// Set the master device
//-----------------------

// set the master device manually (this is the device which will act as the master clock for the aggregate device)
// pass in the UID of the device you want to use
pluginAOPA.mSelector = kAudioAggregateDevicePropertyMasterSubDevice;
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
pluginAOPA.mElement = kAudioObjectPropertyElementMaster;
outDataSize = sizeof(CFStringRef);
osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID); // capture is master...
if (osErr != noErr)
return osErr;

// pause again to give the changes time to take effect
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);

//----------
// Clean up
//----------
CFRelease(AggregateDeviceNumberRef);

// release the CF objects we have created - we don't need them any more
CFRelease(aggDeviceDict);
CFRelease(subDevicesArray);

// release the device UID
CFRelease(captureDeviceUID);
CFRelease(playbackDeviceUID);
jack_log("New aggregate device %ld", *outAggregateDevice);
return noErr;
}

void JackCoreAudioAdapter::CloseAUHAL()
{
AudioUnitUninitialize(fAUHAL);
@@ -923,6 +1111,8 @@ int JackCoreAudioAdapter::Close()
DisposeBuffers();
CloseAUHAL();
RemoveListeners();
if (fPluginID > 0)
DestroyAggregateDevice();
return 0;
}



+ 6
- 1
macosx/coreaudio/JackCoreAudioAdapter.h View File

@@ -54,7 +54,9 @@ class JackCoreAudioAdapter : public JackAudioAdapterInterface
bool fCapturing;
bool fPlaying;

AudioDeviceID fDeviceID;
AudioDeviceID fDeviceID; // Used "duplex" device
AudioObjectID fPluginID; // Used for aggregate device

bool fState;

AudioUnitRenderActionFlags* fActionFags;
@@ -86,6 +88,9 @@ class JackCoreAudioAdapter : public JackAudioAdapterInterface
OSStatus GetDeviceNameFromID(AudioDeviceID id, char* name);

// Setup
OSStatus CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, AudioDeviceID* outAggregateDevice);
OSStatus DestroyAggregateDevice();
int SetupDevices(const char* capture_driver_uid,
const char* playback_driver_uid,
char* capture_driver_name,


+ 7
- 5
macosx/coreaudio/JackCoreAudioDriver.cpp View File

@@ -431,6 +431,8 @@ OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceI
//---------------------------------------------------------------------------
// Start to create a new aggregate by getting the base audio hardware plugin
//---------------------------------------------------------------------------
jack_info("Separated input and output devices, so create a private aggregate device to handle them...");
osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
if (osErr != noErr)
@@ -584,7 +586,7 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, const char
} else {
// Creates agregate device
// Creates aggregate device
AudioDeviceID captureID, playbackID;
if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr)
return -1;
@@ -594,7 +596,7 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, const char
return -1;
}

// Capture only
// Capture only
} else if (strcmp(capture_driver_uid, "") != 0) {
jack_log("JackCoreAudioDriver::Open capture only");
if (GetDeviceIDFromUID(capture_driver_uid, &fDeviceID) != noErr) {
@@ -609,7 +611,7 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, const char
return -1;
}

// Playback only
// Playback only
} else if (strcmp(playback_driver_uid, "") != 0) {
jack_log("JackCoreAudioDriver::Open playback only");
if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
@@ -624,7 +626,7 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, const char
return -1;
}

// Use default driver in duplex mode
// Use default driver in duplex mode
} else {
jack_log("JackCoreAudioDriver::Open default driver");
if (GetDefaultDevice(&fDeviceID) != noErr) {
@@ -1090,7 +1092,7 @@ int JackCoreAudioDriver::Open(jack_nframes_t buffer_size,
Gestalt(gestaltSystemVersionMajor, &major);
Gestalt(gestaltSystemVersionMinor, &minor);
// Starting with 10.6 systems...
// Starting with 10.6 systems, the HAL notification thread is created internally
if (major == 10 && minor >=6) {
CFRunLoopRef theRunLoop = NULL;
AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };


+ 2
- 2
macosx/coreaudio/JackCoreAudioDriver.h View File

@@ -53,8 +53,8 @@ class JackCoreAudioDriver : public JackAudioDriver
AudioBufferList* fJackInputData;
AudioBufferList* fDriverOutputData;

AudioDeviceID fDeviceID;
AudioObjectID fPluginID;
AudioDeviceID fDeviceID; // Used "duplex" device
AudioObjectID fPluginID; // Used for aggregate device

AudioUnitRenderActionFlags* fActionFags;
AudioTimeStamp* fCurrentTime;


Loading…
Cancel
Save