From e6f91c7a0daac4ff407c1ce1c90ef3ae24227543 Mon Sep 17 00:00:00 2001 From: sletz Date: Sun, 25 Oct 2009 19:24:48 +0000 Subject: [PATCH 1/9] Aggregate device code added to JackCoreAudioAdapter. git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3670 0c269be4-1314-0410-8aa9-9f06e86f4224 --- macosx/coreaudio/JackCoreAudioAdapter.cpp | 212 ++++++++++++++++++++-- macosx/coreaudio/JackCoreAudioAdapter.h | 7 +- macosx/coreaudio/JackCoreAudioDriver.cpp | 12 +- macosx/coreaudio/JackCoreAudioDriver.h | 4 +- 4 files changed, 216 insertions(+), 19 deletions(-) diff --git a/macosx/coreaudio/JackCoreAudioAdapter.cpp b/macosx/coreaudio/JackCoreAudioAdapter.cpp index ead81370..d7e36747 100644 --- a/macosx/coreaudio/JackCoreAudioAdapter.cpp +++ b/macosx/coreaudio/JackCoreAudioAdapter.cpp @@ -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; } diff --git a/macosx/coreaudio/JackCoreAudioAdapter.h b/macosx/coreaudio/JackCoreAudioAdapter.h index b40f7b65..9a6ebd6b 100644 --- a/macosx/coreaudio/JackCoreAudioAdapter.h +++ b/macosx/coreaudio/JackCoreAudioAdapter.h @@ -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, diff --git a/macosx/coreaudio/JackCoreAudioDriver.cpp b/macosx/coreaudio/JackCoreAudioDriver.cpp index 395ddd9f..ec73428e 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.cpp +++ b/macosx/coreaudio/JackCoreAudioDriver.cpp @@ -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 }; diff --git a/macosx/coreaudio/JackCoreAudioDriver.h b/macosx/coreaudio/JackCoreAudioDriver.h index 563e2c0a..3a6a9fe0 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.h +++ b/macosx/coreaudio/JackCoreAudioDriver.h @@ -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; From a76e255132a950fb0f9681b3b7a87b65b71bf5e0 Mon Sep 17 00:00:00 2001 From: sletz Date: Sun, 25 Oct 2009 20:12:53 +0000 Subject: [PATCH 2/9] Cleanup JackSocketServerChannel. git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3671 0c269be4-1314-0410-8aa9-9f06e86f4224 --- ChangeLog | 1 + posix/JackSocketServerChannel.cpp | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8552c5af..0cd91790 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,7 @@ Paul Davis 2009-10-25 Stephane Letz * Improve aggregate device management in JackCoreAudioDriver : now a "private" device only and cleanup properly. + * Aggregate device code added to JackCoreAudioAdapter. 2009-10-23 Stephane Letz diff --git a/posix/JackSocketServerChannel.cpp b/posix/JackSocketServerChannel.cpp index cacaef3d..eb988aef 100644 --- a/posix/JackSocketServerChannel.cpp +++ b/posix/JackSocketServerChannel.cpp @@ -60,10 +60,6 @@ int JackSocketServerChannel::Open(const char* server_name, JackServer* server) BuildPoolTable(); fServer = server; return 0; - -error: - fRequestListenSocket.Close(); - return -1; } void JackSocketServerChannel::Close() From e3ae608f00e959fcbcc016ae954fcc78d140ef69 Mon Sep 17 00:00:00 2001 From: sletz Date: Mon, 26 Oct 2009 06:52:51 +0000 Subject: [PATCH 3/9] Some more cleanup in JackCoreAudioDriver and JackCoreAudioAdapter. git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3672 0c269be4-1314-0410-8aa9-9f06e86f4224 --- macosx/coreaudio/JackCoreAudioAdapter.cpp | 8 ++++++-- macosx/coreaudio/JackCoreAudioDriver.cpp | 12 ++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/macosx/coreaudio/JackCoreAudioAdapter.cpp b/macosx/coreaudio/JackCoreAudioAdapter.cpp index d7e36747..c2f5baad 100644 --- a/macosx/coreaudio/JackCoreAudioAdapter.cpp +++ b/macosx/coreaudio/JackCoreAudioAdapter.cpp @@ -396,7 +396,7 @@ OSStatus JackCoreAudioAdapter::GetDefaultDevice(AudioDeviceID* id) jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault); - // Get the device only if default input and ouput are the same + // Get the device only if default input and output are the same if (inDefault == outDefault) { *id = inDefault; return noErr; @@ -963,7 +963,11 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDevice // 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..."); + char capture_name[256]; + char playback_name[256]; + GetDeviceNameFromID(captureDeviceID, capture_name); + GetDeviceNameFromID(playbackDeviceID, playback_name); + jack_info("Separated input = '%s' and output = '%s' devices, create a private aggregate device to handle them...", capture_name, playback_name); osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable); if (osErr != noErr) diff --git a/macosx/coreaudio/JackCoreAudioDriver.cpp b/macosx/coreaudio/JackCoreAudioDriver.cpp index ec73428e..be7a4e37 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.cpp +++ b/macosx/coreaudio/JackCoreAudioDriver.cpp @@ -321,7 +321,7 @@ OSStatus JackCoreAudioDriver::GetDefaultDevice(AudioDeviceID* id) jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault); - // Get the device only if default input and ouput are the same + // Get the device only if default input and output are the same if (inDefault == outDefault) { *id = inDefault; return noErr; @@ -432,7 +432,11 @@ 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..."); + char capture_name[256]; + char playback_name[256]; + GetDeviceNameFromID(captureDeviceID, capture_name); + GetDeviceNameFromID(playbackDeviceID, playback_name); + jack_info("Separated input = '%s' and output = '%s' devices, create a private aggregate device to handle them...", capture_name, playback_name); osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable); if (osErr != noErr) @@ -1450,7 +1454,7 @@ extern "C" strcpy(desc->params[i].name, "list-devices"); desc->params[i].character = 'l'; desc->params[i].type = JackDriverParamBool; - desc->params[i].value.i = TRUE; + desc->params[i].value.i = FALSE; strcpy(desc->params[i].short_desc, "Display available CoreAudio devices"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); @@ -1459,7 +1463,7 @@ extern "C" desc->params[i].character = 'L'; desc->params[i].type = JackDriverParamUInt; desc->params[i].value.i = 100; - strcpy(desc->params[i].short_desc, "Extra output latency in aynchronous mode (percent)"); + strcpy(desc->params[i].short_desc, "Extra output latency in asynchronous mode (percent)"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); i++; From 5bd1727ab6b6b641eb61d45c611992f0a37b9058 Mon Sep 17 00:00:00 2001 From: sletz Date: Mon, 26 Oct 2009 07:07:43 +0000 Subject: [PATCH 4/9] Hog mode in JackCoreAudioDriver (in progress). git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3673 0c269be4-1314-0410-8aa9-9f06e86f4224 --- macosx/coreaudio/JackCoreAudioDriver.cpp | 25 ++++++++++++++++++++++++ macosx/coreaudio/JackCoreAudioDriver.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/macosx/coreaudio/JackCoreAudioDriver.cpp b/macosx/coreaudio/JackCoreAudioDriver.cpp index be7a4e37..4446f972 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.cpp +++ b/macosx/coreaudio/JackCoreAudioDriver.cpp @@ -1334,6 +1334,31 @@ int JackCoreAudioDriver::SetBufferSize(jack_nframes_t buffer_size) return 0; } + +bool JackCoreAudioDriver::TakeHog(AudioDeviceID deviceID, bool isInput) +{ + pid_t hog_pid; + OSStatus err; + + UInt32 propSize = sizeof(hog_pid); + err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyHogMode, &propSize, &hog_pid); + if (err) { + jack_error("Cannot read hog state..."); + printError(err); + } + + if (hog_pid != getpid()) { + hog_pid = getpid(); + err = AudioDeviceSetProperty(deviceID, 0, 0, isInput, kAudioDevicePropertyHogMode, propSize, &hog_pid); + if (err != noErr) { + jack_error("Can't hog device = %d because it's being hogged by another program", deviceID); + return false; + } + } + + return true; +} + } // end of namespace diff --git a/macosx/coreaudio/JackCoreAudioDriver.h b/macosx/coreaudio/JackCoreAudioDriver.h index 3a6a9fe0..d3dcfa21 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.h +++ b/macosx/coreaudio/JackCoreAudioDriver.h @@ -150,6 +150,8 @@ class JackCoreAudioDriver : public JackAudioDriver int AddListeners(); void RemoveListeners(); + + bool TakeHog(AudioDeviceID deviceID, bool isInput); public: From 96fedf1189a405ee00d80205f828177239aa0fcb Mon Sep 17 00:00:00 2001 From: sletz Date: Mon, 26 Oct 2009 09:45:12 +0000 Subject: [PATCH 5/9] Implement "hog mode" (exclusive access of the audio device) in JackCoreAudioDriver. git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3674 0c269be4-1314-0410-8aa9-9f06e86f4224 --- ChangeLog | 4 ++ macosx/coreaudio/JackCoreAudioDriver.cpp | 64 +++++++++++++++++++++--- macosx/coreaudio/JackCoreAudioDriver.h | 7 ++- 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0cd91790..0f852caf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,6 +25,10 @@ Paul Davis Jackdmp changes log --------------------------- +2009-10-26 Stephane Letz + + * Implement "hog mode" (exclusive access of the audio device) in JackCoreAudioDriver. + 2009-10-25 Stephane Letz * Improve aggregate device management in JackCoreAudioDriver : now a "private" device only and cleanup properly. diff --git a/macosx/coreaudio/JackCoreAudioDriver.cpp b/macosx/coreaudio/JackCoreAudioDriver.cpp index 4446f972..d2edecde 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.cpp +++ b/macosx/coreaudio/JackCoreAudioDriver.cpp @@ -390,7 +390,14 @@ OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, int& channe } JackCoreAudioDriver::JackCoreAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) - : JackAudioDriver(name, alias, engine, table), fJackInputData(NULL), fDriverOutputData(NULL), fPluginID(0), fState(false), fIOUsage(1.f),fComputationGrain(-1.f) + : JackAudioDriver(name, alias, engine, table), + fJackInputData(NULL), + fDriverOutputData(NULL), + fPluginID(0), + fState(false), + fHogged(false), + fIOUsage(1.f), + fComputationGrain(-1.f) {} JackCoreAudioDriver::~JackCoreAudioDriver() @@ -642,6 +649,14 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, const char return -1; } } + + if (fHogged) { + if (TakeHog()) { + jack_info("Device = %ld has been hogged", fDeviceID); + } else { + jack_error("Cannot hog device = %ld", fDeviceID); + } + } return 0; } @@ -1071,7 +1086,8 @@ int JackCoreAudioDriver::Open(jack_nframes_t buffer_size, jack_nframes_t capture_latency, jack_nframes_t playback_latency, int async_output_latency, - int computation_grain) + int computation_grain, + bool hogged) { int in_nChannels = 0; int out_nChannels = 0; @@ -1090,6 +1106,7 @@ int JackCoreAudioDriver::Open(jack_nframes_t buffer_size, fPlaybackLatency = playback_latency; fIOUsage = float(async_output_latency) / 100.f; fComputationGrain = float(computation_grain) / 100.f; + fHogged = hogged; SInt32 major; SInt32 minor; @@ -1334,8 +1351,7 @@ int JackCoreAudioDriver::SetBufferSize(jack_nframes_t buffer_size) return 0; } - -bool JackCoreAudioDriver::TakeHog(AudioDeviceID deviceID, bool isInput) +bool JackCoreAudioDriver::TakeHogAux(AudioDeviceID deviceID, bool isInput) { pid_t hog_pid; OSStatus err; @@ -1358,6 +1374,29 @@ bool JackCoreAudioDriver::TakeHog(AudioDeviceID deviceID, bool isInput) return true; } + +bool JackCoreAudioDriver::TakeHog() +{ + OSStatus err = noErr; + AudioObjectID sub_device[32]; + UInt32 outSize = sizeof(sub_device); + err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioAggregateDevicePropertyActiveSubDeviceList, &outSize, sub_device); + + if (err != noErr) { + jack_log("Device does not have subdevices"); + return TakeHogAux(fDeviceID, true); + } else { + int num_devices = outSize / sizeof(AudioObjectID); + jack_log("Device does has %d subdevices", num_devices); + for (int i = 0; i < num_devices; i++) { + if (!TakeHogAux(sub_device[i], true)) { + return false; + } + } + return true; + } +} + } // end of namespace @@ -1376,7 +1415,7 @@ extern "C" strcpy(desc->name, "coreaudio"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 strcpy(desc->desc, "Apple CoreAudio API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 - desc->nparams = 15; + desc->nparams = 16; desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); i = 0; @@ -1483,6 +1522,14 @@ extern "C" strcpy(desc->params[i].short_desc, "Display available CoreAudio devices"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + i++; + strcpy(desc->params[i].name, "hog"); + desc->params[i].character = 'H'; + desc->params[i].type = JackDriverParamBool; + desc->params[i].value.i = FALSE; + strcpy(desc->params[i].short_desc, "Take exclusive access of the audio device"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + i++; strcpy(desc->params[i].name, "async-latency"); desc->params[i].character = 'L'; @@ -1519,6 +1566,7 @@ extern "C" jack_nframes_t systemic_output_latency = 0; int async_output_latency = 100; int computation_grain = -1; + bool hogged = false; for (node = params; node; node = jack_slist_next(node)) { param = (const jack_driver_param_t *) node->data; @@ -1585,6 +1633,10 @@ extern "C" Jack::DisplayDeviceNames(); break; + case 'H': + hogged = true; + break; + case 'L': async_output_latency = param->value.ui; break; @@ -1603,7 +1655,7 @@ extern "C" Jack::JackCoreAudioDriver* driver = new Jack::JackCoreAudioDriver("system", "coreaudio", engine, table); if (driver->Open(frames_per_interrupt, srate, capture, playback, chan_in, chan_out, monitor, capture_driver_uid, - playback_driver_uid, systemic_input_latency, systemic_output_latency, async_output_latency, computation_grain) == 0) { + playback_driver_uid, systemic_input_latency, systemic_output_latency, async_output_latency, computation_grain, hogged) == 0) { return driver; } else { delete driver; diff --git a/macosx/coreaudio/JackCoreAudioDriver.h b/macosx/coreaudio/JackCoreAudioDriver.h index d3dcfa21..273dabdd 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.h +++ b/macosx/coreaudio/JackCoreAudioDriver.h @@ -60,6 +60,7 @@ class JackCoreAudioDriver : public JackAudioDriver AudioTimeStamp* fCurrentTime; bool fState; + bool fHogged; // Initial state bool fCapturing; @@ -151,7 +152,8 @@ class JackCoreAudioDriver : public JackAudioDriver int AddListeners(); void RemoveListeners(); - bool TakeHog(AudioDeviceID deviceID, bool isInput); + bool TakeHogAux(AudioDeviceID deviceID, bool isInput); + bool TakeHog(); public: @@ -170,7 +172,8 @@ class JackCoreAudioDriver : public JackAudioDriver jack_nframes_t capture_latency, jack_nframes_t playback_latency, int async_output_latency, - int computation_grain); + int computation_grain, + bool hogged); int Close(); int Attach(); From 832907c9a9608eec640e934e5859e06edf13dac3 Mon Sep 17 00:00:00 2001 From: sletz Date: Mon, 26 Oct 2009 13:37:06 +0000 Subject: [PATCH 6/9] More debug code in JackCoreAudioDriver. git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3675 0c269be4-1314-0410-8aa9-9f06e86f4224 --- macosx/coreaudio/JackCoreAudioDriver.cpp | 36 ++++++++++++++++++------ 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/macosx/coreaudio/JackCoreAudioDriver.cpp b/macosx/coreaudio/JackCoreAudioDriver.cpp index d2edecde..55268edf 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.cpp +++ b/macosx/coreaudio/JackCoreAudioDriver.cpp @@ -446,8 +446,11 @@ OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceI jack_info("Separated input = '%s' and output = '%s' devices, create a private aggregate device to handle them...", capture_name, playback_name); osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable); - if (osErr != noErr) + if (osErr != noErr) { + jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error"); + printError(osErr); return osErr; + } AudioValueTranslation pluginAVT; @@ -459,8 +462,11 @@ OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceI pluginAVT.mOutputDataSize = sizeof(fPluginID); osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT); - if (osErr != noErr) + if (osErr != noErr) { + jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error"); + printError(osErr); return osErr; + } //------------------------------------------------- // Create a CFDictionary for our aggregate device @@ -510,12 +516,18 @@ OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceI UInt32 outDataSize; osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); - if (osErr != noErr) + if (osErr != noErr) { + jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyDataSize error"); + printError(osErr); return osErr; - + } + osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice); - if (osErr != noErr) + if (osErr != noErr) { + jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyData error"); + printError(osErr); 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 @@ -530,9 +542,12 @@ OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceI pluginAOPA.mElement = kAudioObjectPropertyElementMaster; outDataSize = sizeof(CFMutableArrayRef); osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray); - if (osErr != noErr) + if (osErr != noErr) { + jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error"); + printError(osErr); return osErr; - + } + // pause again to give the changes time to take effect CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); @@ -547,9 +562,12 @@ OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceI pluginAOPA.mElement = kAudioObjectPropertyElementMaster; outDataSize = sizeof(CFStringRef); osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID); // capture is master... - if (osErr != noErr) + if (osErr != noErr) { + jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for master device error"); + printError(osErr); return osErr; - + } + // pause again to give the changes time to take effect CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); From 801541e04d3c15591ca1f3f088e465892f53fc8b Mon Sep 17 00:00:00 2001 From: sletz Date: Mon, 26 Oct 2009 19:25:09 +0000 Subject: [PATCH 7/9] Internal aggregate devices can be used only after 10.5.4 systems, otherwise use public one. git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3676 0c269be4-1314-0410-8aa9-9f06e86f4224 --- macosx/coreaudio/JackCoreAudioDriver.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/macosx/coreaudio/JackCoreAudioDriver.cpp b/macosx/coreaudio/JackCoreAudioDriver.cpp index 55268edf..d5ba8f85 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.cpp +++ b/macosx/coreaudio/JackCoreAudioDriver.cpp @@ -484,9 +484,21 @@ OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceI 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); + + SInt32 major; + SInt32 minor; + SInt32 bugfix; + Gestalt(gestaltSystemVersionMajor, &major); + Gestalt(gestaltSystemVersionMinor, &minor); + Gestalt(gestaltSystemVersionBugFix, &bugfix); + + // Starting with 10.5.4 systems, the AD can be internal... (better) + if (major == 10 && minor >= 5 && bugfix >= 4) { + CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef); + } //------------------------------------------------- // Create a CFMutableArray for our sub-device list @@ -1132,7 +1144,7 @@ int JackCoreAudioDriver::Open(jack_nframes_t buffer_size, Gestalt(gestaltSystemVersionMinor, &minor); // Starting with 10.6 systems, the HAL notification thread is created internally - if (major == 10 && minor >=6) { + if (major == 10 && minor >= 6) { CFRunLoopRef theRunLoop = NULL; AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; OSStatus theError = AudioObjectSetPropertyData (kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop); From d85cb284c770112e013b4ac917439ff26ca42018 Mon Sep 17 00:00:00 2001 From: sletz Date: Mon, 26 Oct 2009 21:54:51 +0000 Subject: [PATCH 8/9] Fix jack_set_sample_rate_callback to have he same bevahior as in JACK1. git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3677 0c269be4-1314-0410-8aa9-9f06e86f4224 --- ChangeLog | 1 + common/JackClient.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/ChangeLog b/ChangeLog index 0f852caf..fa8264dd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,7 @@ Paul Davis 2009-10-26 Stephane Letz * Implement "hog mode" (exclusive access of the audio device) in JackCoreAudioDriver. + * Fix jack_set_sample_rate_callback to have he same bevahior as in JACK1. 2009-10-25 Stephane Letz diff --git a/common/JackClient.cpp b/common/JackClient.cpp index eae5f7a2..7cfb50ef 100644 --- a/common/JackClient.cpp +++ b/common/JackClient.cpp @@ -874,6 +874,9 @@ int JackClient::SetSampleRateCallback(JackSampleRateCallback callback, void *arg GetClientControl()->fCallback[kSampleRateCallback] = (callback != NULL); fSampleRateArg = arg; fSampleRate = callback; + // Now invoke it + if (callback) + callback(GetEngineControl()->fSampleRate, arg); return 0; } } From 350215e21798d6ae08a7700f5b0f0d6ddd15b422 Mon Sep 17 00:00:00 2001 From: sletz Date: Tue, 27 Oct 2009 09:53:18 +0000 Subject: [PATCH 9/9] Dynamic system version detection in JackCoreAudioDriver to either create public or private aggregate device. git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3678 0c269be4-1314-0410-8aa9-9f06e86f4224 --- ChangeLog | 6 +++++- macosx/coreaudio/JackCoreAudioAdapter.cpp | 14 +++++++++++++- macosx/coreaudio/JackCoreAudioDriver.cpp | 17 +++++++++-------- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index fa8264dd..0e577f9f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,10 +25,14 @@ Paul Davis Jackdmp changes log --------------------------- +2009-10-27 Stephane Letz + + * Dynamic system version detection in JackCoreAudioDriver to either create public or private aggregate device. + 2009-10-26 Stephane Letz * Implement "hog mode" (exclusive access of the audio device) in JackCoreAudioDriver. - * Fix jack_set_sample_rate_callback to have he same bevahior as in JACK1. + * Fix jack_set_sample_rate_callback to have he same behavior as in JACK1. 2009-10-25 Stephane Letz diff --git a/macosx/coreaudio/JackCoreAudioAdapter.cpp b/macosx/coreaudio/JackCoreAudioAdapter.cpp index c2f5baad..1c0121ab 100644 --- a/macosx/coreaudio/JackCoreAudioAdapter.cpp +++ b/macosx/coreaudio/JackCoreAudioAdapter.cpp @@ -1004,7 +1004,19 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDevice(AudioDeviceID captureDevice // add a "private aggregate key" to the dictionary int value = 1; CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value); - CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef); + + SInt32 system; + Gestalt(gestaltSystemVersion, &system); + + jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054); + + // Starting with 10.5.4 systems, the AD can be internal... (better) + if (system < 0x00001054) { + jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device...."); + } else { + jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device...."); + CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef); + } //------------------------------------------------- // Create a CFMutableArray for our sub-device list diff --git a/macosx/coreaudio/JackCoreAudioDriver.cpp b/macosx/coreaudio/JackCoreAudioDriver.cpp index d5ba8f85..45bd29fa 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.cpp +++ b/macosx/coreaudio/JackCoreAudioDriver.cpp @@ -484,19 +484,19 @@ OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceI CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceUIDKey), AggregateDeviceUIDRef); // add a "private aggregate key" to the dictionary - int value = 1; CFNumberRef AggregateDeviceNumberRef = CFNumberCreate(NULL, kCFNumberIntType, &value); - SInt32 major; - SInt32 minor; - SInt32 bugfix; - Gestalt(gestaltSystemVersionMajor, &major); - Gestalt(gestaltSystemVersionMinor, &minor); - Gestalt(gestaltSystemVersionBugFix, &bugfix); + SInt32 system; + Gestalt(gestaltSystemVersion, &system); + + jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054); // Starting with 10.5.4 systems, the AD can be internal... (better) - if (major == 10 && minor >= 5 && bugfix >= 4) { + if (system < 0x00001054) { + jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device...."); + } else { + jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device...."); CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef); } @@ -587,6 +587,7 @@ OSStatus JackCoreAudioDriver::CreateAggregateDevice(AudioDeviceID captureDeviceI // Clean up //---------- + // release the private AD key CFRelease(AggregateDeviceNumberRef); // release the CF objects we have created - we don't need them any more