|
@@ -129,6 +129,76 @@ static void printError(OSStatus err) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool CheckAvailableDeviceName(const char* device_name, AudioDeviceID* device_id) |
|
|
|
|
|
{ |
|
|
|
|
|
UInt32 size; |
|
|
|
|
|
Boolean isWritable; |
|
|
|
|
|
int i, deviceNum; |
|
|
|
|
|
OSStatus err; |
|
|
|
|
|
|
|
|
|
|
|
err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable); |
|
|
|
|
|
if (err != noErr) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
deviceNum = size / sizeof(AudioDeviceID); |
|
|
|
|
|
AudioDeviceID devices[deviceNum]; |
|
|
|
|
|
|
|
|
|
|
|
err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices); |
|
|
|
|
|
if (err != noErr) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < deviceNum; i++) { |
|
|
|
|
|
char device_name_aux[256]; |
|
|
|
|
|
|
|
|
|
|
|
size = 256; |
|
|
|
|
|
err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name_aux); |
|
|
|
|
|
if (err != noErr) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (strcmp(device_name_aux, device_name) == 0) { |
|
|
|
|
|
*device_id = devices[i]; |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool CheckAvailableDevice(AudioDeviceID device_id) |
|
|
|
|
|
{ |
|
|
|
|
|
UInt32 size; |
|
|
|
|
|
Boolean isWritable; |
|
|
|
|
|
int i, deviceNum; |
|
|
|
|
|
OSStatus err; |
|
|
|
|
|
|
|
|
|
|
|
err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable); |
|
|
|
|
|
if (err != noErr) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
deviceNum = size / sizeof(AudioDeviceID); |
|
|
|
|
|
AudioDeviceID devices[deviceNum]; |
|
|
|
|
|
|
|
|
|
|
|
err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices); |
|
|
|
|
|
if (err != noErr) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < deviceNum; i++) { |
|
|
|
|
|
if (device_id == devices[i]) { |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static OSStatus DisplayDeviceNames() |
|
|
static OSStatus DisplayDeviceNames() |
|
|
{ |
|
|
{ |
|
|
UInt32 size; |
|
|
UInt32 size; |
|
@@ -169,7 +239,7 @@ static OSStatus DisplayDeviceNames() |
|
|
return err; |
|
|
return err; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
jack_info("Device name = \'%s\', internal name = \'%s\' (to be used as -C, -P, or -d parameter)", device_name, internal_name); |
|
|
|
|
|
|
|
|
jack_info("Device ID = \'%d\' name = \'%s\', internal name = \'%s\' (to be used as -C, -P, or -d parameter)", devices[i], device_name, internal_name); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return noErr; |
|
|
return noErr; |
|
@@ -330,6 +400,72 @@ OSStatus JackCoreAudioDriver::BSNotificationCallback(AudioDeviceID inDevice, |
|
|
return noErr; |
|
|
return noErr; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
OSStatus JackCoreAudioDriver::AudioHardwareNotificationCallback(AudioHardwarePropertyID inPropertyID, void* inClientData) |
|
|
|
|
|
{ |
|
|
|
|
|
JackCoreAudioDriver* driver = (JackCoreAudioDriver*)inClientData; |
|
|
|
|
|
|
|
|
|
|
|
switch (inPropertyID) { |
|
|
|
|
|
|
|
|
|
|
|
case kAudioHardwarePropertyDevices: { |
|
|
|
|
|
jack_log("JackCoreAudioDriver::AudioHardwareNotificationCallback kAudioHardwarePropertyDevices"); |
|
|
|
|
|
DisplayDeviceNames(); |
|
|
|
|
|
|
|
|
|
|
|
AudioDeviceID captureID, playbackID; |
|
|
|
|
|
|
|
|
|
|
|
jack_log("JackCoreAudioDriver::AudioHardwareNotificationCallback %s %d %s %d", |
|
|
|
|
|
driver->fCaptureUID, CheckAvailableDeviceName(driver->fCaptureUID, &captureID), |
|
|
|
|
|
driver->fPlaybackUID, CheckAvailableDeviceName(driver->fPlaybackUID, &playbackID)); |
|
|
|
|
|
jack_log("JackCoreAudioDriver::AudioHardwareNotificationCallback %d %d", driver->fDeviceID, CheckAvailableDevice(driver->fDeviceID)); |
|
|
|
|
|
driver->CloseAUHAL(); |
|
|
|
|
|
|
|
|
|
|
|
if (CheckAvailableDevice(driver->fDeviceID) || |
|
|
|
|
|
(CheckAvailableDeviceName(driver->fCaptureUID, &captureID) && CheckAvailableDeviceName(driver->fPlaybackUID, &playbackID))) { |
|
|
|
|
|
|
|
|
|
|
|
vector<int> parsed_chan_in_list; |
|
|
|
|
|
vector<int> parsed_chan_out_list; |
|
|
|
|
|
|
|
|
|
|
|
if (driver->OpenAUHAL(true, true, 2, 2, 2, 2, |
|
|
|
|
|
parsed_chan_in_list, |
|
|
|
|
|
parsed_chan_out_list, |
|
|
|
|
|
driver->fEngineControl->fBufferSize, |
|
|
|
|
|
driver->fEngineControl->fSampleRate) < 0) { |
|
|
|
|
|
jack_log("JackCoreAudioDriver::OpenAUHAL fails"); |
|
|
|
|
|
return -1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Waiting for Render callback to be called (= driver has started) |
|
|
|
|
|
driver->fState = false; |
|
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
|
|
OSStatus err = AudioOutputUnitStart(driver->fAUHAL); |
|
|
|
|
|
if (err == noErr) { |
|
|
|
|
|
|
|
|
|
|
|
while (!driver->fState && count++ < WAIT_COUNTER) { |
|
|
|
|
|
usleep(100000); |
|
|
|
|
|
jack_log("JackCoreAudioDriver::Start wait count = %d", count); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (count < WAIT_COUNTER) { |
|
|
|
|
|
jack_info("CoreAudio driver is running..."); |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
jack_error("CoreAudio driver cannot start..."); |
|
|
|
|
|
return -1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
driver->CloseAUHAL(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return noErr; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// A better implementation would possibly try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code) |
|
|
// A better implementation would possibly try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code) |
|
|
OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice, |
|
|
OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice, |
|
|
UInt32 inChannel, |
|
|
UInt32 inChannel, |
|
@@ -350,6 +486,24 @@ OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice, |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
case kAudioDevicePropertyDeviceIsAlive: { |
|
|
|
|
|
UInt32 isalive = 0; |
|
|
|
|
|
UInt32 outsize = sizeof(UInt32); |
|
|
|
|
|
if (AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyDeviceIsAlive, &outsize, &isalive) == noErr) { |
|
|
|
|
|
jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceIsAlive = %d", isalive); |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
case kAudioDevicePropertyDeviceHasChanged: { |
|
|
|
|
|
UInt32 hachanged = 0; |
|
|
|
|
|
UInt32 outsize = sizeof(UInt32); |
|
|
|
|
|
if (AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyDeviceHasChanged, &outsize, &hachanged) == noErr) { |
|
|
|
|
|
jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyDeviceHasChanged = %d", hachanged); |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
case kAudioDeviceProcessorOverload: { |
|
|
case kAudioDeviceProcessorOverload: { |
|
|
jack_error("JackCoreAudioDriver::DeviceNotificationCallback kAudioDeviceProcessorOverload"); |
|
|
jack_error("JackCoreAudioDriver::DeviceNotificationCallback kAudioDeviceProcessorOverload"); |
|
|
jack_time_t cur_time = GetMicroSeconds(); |
|
|
jack_time_t cur_time = GetMicroSeconds(); |
|
@@ -1057,7 +1211,10 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, |
|
|
if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) { |
|
|
if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) { |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GetDeviceNameFromID(captureID, fCaptureUID); |
|
|
|
|
|
GetDeviceNameFromID(playbackID, fPlaybackUID); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Capture only |
|
|
// Capture only |
|
|
} else if (strcmp(capture_driver_uid, "") != 0) { |
|
|
} else if (strcmp(capture_driver_uid, "") != 0) { |
|
@@ -1117,6 +1274,9 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, |
|
|
if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) { |
|
|
if (CreateAggregateDevice(captureID, playbackID, samplerate, &fDeviceID) != noErr) { |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
GetDeviceNameFromID(captureID, fCaptureUID); |
|
|
|
|
|
GetDeviceNameFromID(playbackID, fPlaybackUID); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -1628,6 +1788,7 @@ void JackCoreAudioDriver::DisposeBuffers() |
|
|
|
|
|
|
|
|
void JackCoreAudioDriver::CloseAUHAL() |
|
|
void JackCoreAudioDriver::CloseAUHAL() |
|
|
{ |
|
|
{ |
|
|
|
|
|
AudioOutputUnitStop(fAUHAL); |
|
|
AudioUnitUninitialize(fAUHAL); |
|
|
AudioUnitUninitialize(fAUHAL); |
|
|
CloseComponent(fAUHAL); |
|
|
CloseComponent(fAUHAL); |
|
|
} |
|
|
} |
|
@@ -1644,9 +1805,9 @@ int JackCoreAudioDriver::AddListeners() |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this); |
|
|
|
|
|
|
|
|
err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, AudioHardwareNotificationCallback, this); |
|
|
if (err != noErr) { |
|
|
if (err != noErr) { |
|
|
jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices"); |
|
|
|
|
|
|
|
|
jack_error("Error calling AudioHardwareAddPropertyListener with kAudioHardwarePropertyDevices"); |
|
|
printError(err); |
|
|
printError(err); |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
@@ -1665,6 +1826,20 @@ int JackCoreAudioDriver::AddListeners() |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsAlive, DeviceNotificationCallback, this); |
|
|
|
|
|
if (err != noErr) { |
|
|
|
|
|
jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsAlive"); |
|
|
|
|
|
printError(err); |
|
|
|
|
|
return -1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceHasChanged, DeviceNotificationCallback, this); |
|
|
|
|
|
if (err != noErr) { |
|
|
|
|
|
jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceHasChanged"); |
|
|
|
|
|
printError(err); |
|
|
|
|
|
return -1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this); |
|
|
err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this); |
|
|
if (err != noErr) { |
|
|
if (err != noErr) { |
|
|
jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration"); |
|
|
jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration"); |
|
@@ -1694,9 +1869,11 @@ int JackCoreAudioDriver::AddListeners() |
|
|
void JackCoreAudioDriver::RemoveListeners() |
|
|
void JackCoreAudioDriver::RemoveListeners() |
|
|
{ |
|
|
{ |
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback); |
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDeviceProcessorOverload, DeviceNotificationCallback); |
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback); |
|
|
|
|
|
|
|
|
AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, AudioHardwareNotificationCallback); |
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback); |
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback); |
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback); |
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback); |
|
|
|
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsAlive, DeviceNotificationCallback); |
|
|
|
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceHasChanged, DeviceNotificationCallback); |
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback); |
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback); |
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback); |
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback); |
|
|
} |
|
|
} |
|
@@ -1724,9 +1901,6 @@ int JackCoreAudioDriver::Open(jack_nframes_t buffer_size, |
|
|
char capture_driver_name[256]; |
|
|
char capture_driver_name[256]; |
|
|
char playback_driver_name[256]; |
|
|
char playback_driver_name[256]; |
|
|
|
|
|
|
|
|
// Keep initial state |
|
|
|
|
|
strcpy(fCaptureUID, capture_driver_uid); |
|
|
|
|
|
strcpy(fPlaybackUID, playback_driver_uid); |
|
|
|
|
|
fCaptureLatency = capture_latency; |
|
|
fCaptureLatency = capture_latency; |
|
|
fPlaybackLatency = playback_latency; |
|
|
fPlaybackLatency = playback_latency; |
|
|
fIOUsage = float(async_output_latency) / 100.f; |
|
|
fIOUsage = float(async_output_latency) / 100.f; |
|
|