Add CreateAggregateDevice method in JackCoreAudioDriver (in progress).
git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3505 0c269be4-1314-0410-8aa9-9f06e86f4224
This commit is contained in:
parent
642006c445
commit
ff2b38bc8a
|
@ -236,6 +236,7 @@ void JackEngine::NotifyClients(int event, int sync, int value1, int value2)
|
|||
|
||||
int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* name, int refnum)
|
||||
{
|
||||
jack_log("JackEngine::NotifyAddClient: name = %s", name);
|
||||
// Notify existing clients of the new client and new client of existing clients.
|
||||
for (int i = 0; i < CLIENT_NUM; i++) {
|
||||
JackClientInterface* old_client = fClientTable[i];
|
||||
|
|
|
@ -67,7 +67,7 @@ SERVER_EXPORT void* audio_acquire(int num)
|
|||
NULL,
|
||||
&error)) < 0) {
|
||||
|
||||
jack_error ("Failed to acquire device: %s\n", error.message ? error.message : strerror(-e));
|
||||
jack_error("Failed to acquire device: %s", error.message ? error.message : strerror(-e));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -89,5 +89,7 @@ SERVER_EXPORT void audio_release(void* dev)
|
|||
if (device) {
|
||||
jack_info("Release audio card");
|
||||
rd_release(device);
|
||||
} else {
|
||||
jack_info("No audio card to release...");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,6 +157,14 @@ error:
|
|||
return err;
|
||||
}
|
||||
|
||||
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 JackCoreAudioDriver::Render(void *inRefCon,
|
||||
AudioUnitRenderActionFlags *ioActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
|
@ -434,6 +442,136 @@ JackCoreAudioDriver::JackCoreAudioDriver(const char* name, const char* alias, Ja
|
|||
JackCoreAudioDriver::~JackCoreAudioDriver()
|
||||
{}
|
||||
|
||||
OSStatus JackCoreAudioDriver::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
|
||||
//-----------------------
|
||||
|
||||
osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
|
||||
if (osErr != noErr)
|
||||
return osErr;
|
||||
|
||||
AudioValueTranslation pluginAVT;
|
||||
|
||||
CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio");
|
||||
AudioObjectID pluginID;
|
||||
|
||||
pluginAVT.mInputData = &inBundleRef;
|
||||
pluginAVT.mInputDataSize = sizeof(inBundleRef);
|
||||
pluginAVT.mOutputData = &pluginID;
|
||||
pluginAVT.mOutputDataSize = sizeof(pluginID);
|
||||
|
||||
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);
|
||||
|
||||
//-------------------------------------------------
|
||||
// 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(pluginID, &pluginAOPA, 0, NULL, &outDataSize);
|
||||
if (osErr != noErr)
|
||||
return osErr;
|
||||
|
||||
osErr = AudioObjectGetPropertyData(pluginID, &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
|
||||
//----------
|
||||
|
||||
// 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\n", *outAggregateDevice);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, const char* playback_driver_uid, char* capture_driver_name, char* playback_driver_name)
|
||||
{
|
||||
capture_driver_name[0] = 0;
|
||||
|
@ -442,16 +580,42 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, const char
|
|||
// Duplex
|
||||
if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) {
|
||||
jack_log("JackCoreAudioDriver::Open duplex");
|
||||
if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
|
||||
jack_log("Will take default in/out");
|
||||
if (GetDefaultDevice(&fDeviceID) != noErr) {
|
||||
jack_error("Cannot open default 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;
|
||||
*/
|
||||
|
||||
// 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 agregate 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
|
||||
|
|
|
@ -115,6 +115,7 @@ class JackCoreAudioDriver : public JackAudioDriver
|
|||
OSStatus GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput);
|
||||
|
||||
// Setup
|
||||
OSStatus CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, AudioDeviceID* outAggregateDevice);
|
||||
int SetupDevices(const char* capture_driver_uid,
|
||||
const char* playback_driver_uid,
|
||||
char* capture_driver_name,
|
||||
|
|
|
@ -119,7 +119,7 @@ JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient()
|
|||
fOverlap.hEvent = CreateEvent(NULL, // default security attribute
|
||||
TRUE, // manual-reset event
|
||||
TRUE, // initial state = signaled
|
||||
NULL); // unnamed event object
|
||||
NULL); // unnamed event object
|
||||
}
|
||||
|
||||
JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient(HANDLE pipe, bool pending)
|
||||
|
|
Loading…
Reference in New Issue