diff --git a/macosx/coreaudio/JackCoreAudioAdapter.cpp b/macosx/coreaudio/JackCoreAudioAdapter.cpp index 0ce5a66c..e485888a 100644 --- a/macosx/coreaudio/JackCoreAudioAdapter.cpp +++ b/macosx/coreaudio/JackCoreAudioAdapter.cpp @@ -161,6 +161,22 @@ static void printError(OSStatus err) } } +OSStatus JackCoreAudioAdapter::AudioHardwareNotificationCallback(AudioHardwarePropertyID inPropertyID, void* inClientData) +{ + JackCoreAudioAdapter* driver = (JackCoreAudioAdapter*)inClientData; + + switch (inPropertyID) { + + case kAudioHardwarePropertyDevices: { + jack_log("JackCoreAudioAdapter::AudioHardwareNotificationCallback kAudioHardwarePropertyDevices"); + DisplayDeviceNames(); + break; + } + } + + return noErr; +} + OSStatus JackCoreAudioAdapter::SRNotificationCallback(AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, @@ -222,9 +238,9 @@ int JackCoreAudioAdapter::AddListeners() return -1; } - err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this); + err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, AudioHardwareNotificationCallback, this); if (err != noErr) { - jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices"); + jack_error("Error calling AudioHardwareAddPropertyListener with kAudioHardwarePropertyDevices"); printError(err); return -1; } @@ -263,7 +279,7 @@ int JackCoreAudioAdapter::AddListeners() void JackCoreAudioAdapter::RemoveListeners() { 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, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback); AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback); diff --git a/macosx/coreaudio/JackCoreAudioAdapter.h b/macosx/coreaudio/JackCoreAudioAdapter.h index a276ea39..27d51b56 100644 --- a/macosx/coreaudio/JackCoreAudioAdapter.h +++ b/macosx/coreaudio/JackCoreAudioAdapter.h @@ -79,6 +79,8 @@ class JackCoreAudioAdapter : public JackAudioAdapterInterface UInt32 inNumberFrames, AudioBufferList *ioData); + static OSStatus AudioHardwareNotificationCallback(AudioHardwarePropertyID inPropertyID,void* inClientData); + static OSStatus SRNotificationCallback(AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, diff --git a/macosx/coreaudio/JackCoreAudioDriver.cpp b/macosx/coreaudio/JackCoreAudioDriver.cpp index f3515ae6..5999493f 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.cpp +++ b/macosx/coreaudio/JackCoreAudioDriver.cpp @@ -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() { UInt32 size; @@ -169,7 +239,7 @@ static OSStatus DisplayDeviceNames() 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; @@ -330,6 +400,72 @@ OSStatus JackCoreAudioDriver::BSNotificationCallback(AudioDeviceID inDevice, 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 parsed_chan_in_list; + vector 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) OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice, UInt32 inChannel, @@ -350,6 +486,24 @@ OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice, 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: { jack_error("JackCoreAudioDriver::DeviceNotificationCallback kAudioDeviceProcessorOverload"); 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) { return -1; } - } + + GetDeviceNameFromID(captureID, fCaptureUID); + GetDeviceNameFromID(playbackID, fPlaybackUID); + } // Capture only } 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) { return -1; } + + GetDeviceNameFromID(captureID, fCaptureUID); + GetDeviceNameFromID(playbackID, fPlaybackUID); } } @@ -1628,6 +1788,7 @@ void JackCoreAudioDriver::DisposeBuffers() void JackCoreAudioDriver::CloseAUHAL() { + AudioOutputUnitStop(fAUHAL); AudioUnitUninitialize(fAUHAL); CloseComponent(fAUHAL); } @@ -1644,9 +1805,9 @@ int JackCoreAudioDriver::AddListeners() return -1; } - err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this); + err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, AudioHardwareNotificationCallback, this); if (err != noErr) { - jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices"); + jack_error("Error calling AudioHardwareAddPropertyListener with kAudioHardwarePropertyDevices"); printError(err); return -1; } @@ -1665,6 +1826,20 @@ int JackCoreAudioDriver::AddListeners() 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); if (err != noErr) { jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration"); @@ -1694,9 +1869,11 @@ int JackCoreAudioDriver::AddListeners() void JackCoreAudioDriver::RemoveListeners() { 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, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback); + AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsAlive, DeviceNotificationCallback); + AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceHasChanged, DeviceNotificationCallback); AudioDeviceRemovePropertyListener(fDeviceID, 0, true, 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 playback_driver_name[256]; - // Keep initial state - strcpy(fCaptureUID, capture_driver_uid); - strcpy(fPlaybackUID, playback_driver_uid); fCaptureLatency = capture_latency; fPlaybackLatency = playback_latency; fIOUsage = float(async_output_latency) / 100.f; diff --git a/macosx/coreaudio/JackCoreAudioDriver.h b/macosx/coreaudio/JackCoreAudioDriver.h index 0964dea4..bc5ddb11 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.h +++ b/macosx/coreaudio/JackCoreAudioDriver.h @@ -62,7 +62,7 @@ class JackCoreAudioDriver : public JackAudioDriver AudioDeviceID fDeviceID; // Used "duplex" device AudioObjectID fPluginID; // Used for aggregate device - + AudioUnitRenderActionFlags* fActionFags; const AudioTimeStamp* fCurrentTime; @@ -75,14 +75,17 @@ class JackCoreAudioDriver : public JackAudioDriver float fIOUsage; float fComputationGrain; bool fClockDriftCompensate; - + + static OSStatus Render(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); - + + static OSStatus AudioHardwareNotificationCallback(AudioHardwarePropertyID inPropertyID,void* inClientData); + static OSStatus DeviceNotificationCallback(AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput,