diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index 261ba7809cf..cbd5fbe7432 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -38,6 +38,20 @@ #define kInputBus 1 #ifdef OSX_ENABLED +OSStatus AudioDriverCoreAudio::input_device_address_cb(AudioObjectID inObjectID, + UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, + void *inClientData) { + AudioDriverCoreAudio *driver = (AudioDriverCoreAudio *)inClientData; + + // If our selected device is the Default call set_device to update the + // kAudioOutputUnitProperty_CurrentDevice property + if (driver->capture_device_name == "Default") { + driver->capture_set_device("Default"); + } + + return noErr; +} + OSStatus AudioDriverCoreAudio::output_device_address_cb(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData) { @@ -80,6 +94,11 @@ Error AudioDriverCoreAudio::init() { result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this); ERR_FAIL_COND_V(result != noErr, FAILED); + + prop.mSelector = kAudioHardwarePropertyDefaultInputDevice; + + result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this); + ERR_FAIL_COND_V(result != noErr, FAILED); #endif AudioStreamBasicDescription strdesc; @@ -276,151 +295,6 @@ AudioDriver::SpeakerMode AudioDriverCoreAudio::get_speaker_mode() const { return get_speaker_mode_by_total_channels(channels); }; -#ifdef OSX_ENABLED - -Array AudioDriverCoreAudio::get_device_list() { - - Array list; - - list.push_back("Default"); - - AudioObjectPropertyAddress prop; - - prop.mSelector = kAudioHardwarePropertyDevices; - prop.mScope = kAudioObjectPropertyScopeGlobal; - prop.mElement = kAudioObjectPropertyElementMaster; - - UInt32 size = 0; - AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, NULL, &size); - AudioDeviceID *audioDevices = (AudioDeviceID *)malloc(size); - AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, NULL, &size, audioDevices); - - UInt32 deviceCount = size / sizeof(AudioDeviceID); - for (UInt32 i = 0; i < deviceCount; i++) { - prop.mScope = kAudioDevicePropertyScopeOutput; - prop.mSelector = kAudioDevicePropertyStreamConfiguration; - - AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, NULL, &size); - AudioBufferList *bufferList = (AudioBufferList *)malloc(size); - AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, bufferList); - - UInt32 outputChannelCount = 0; - for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++) - outputChannelCount += bufferList->mBuffers[j].mNumberChannels; - - free(bufferList); - - if (outputChannelCount >= 1) { - CFStringRef cfname; - - size = sizeof(CFStringRef); - prop.mSelector = kAudioObjectPropertyName; - - AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, &cfname); - - CFIndex length = CFStringGetLength(cfname); - CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; - char *buffer = (char *)malloc(maxSize); - if (CFStringGetCString(cfname, buffer, maxSize, kCFStringEncodingUTF8)) { - // Append the ID to the name in case we have devices with duplicate name - list.push_back(String(buffer) + " (" + itos(audioDevices[i]) + ")"); - } - - free(buffer); - } - } - - free(audioDevices); - - return list; -} - -String AudioDriverCoreAudio::get_device() { - - return device_name; -} - -void AudioDriverCoreAudio::set_device(String device) { - - device_name = device; - if (!active) { - return; - } - - AudioDeviceID deviceId; - bool found = false; - if (device_name != "Default") { - AudioObjectPropertyAddress prop; - - prop.mSelector = kAudioHardwarePropertyDevices; - prop.mScope = kAudioObjectPropertyScopeGlobal; - prop.mElement = kAudioObjectPropertyElementMaster; - - UInt32 size = 0; - AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, NULL, &size); - AudioDeviceID *audioDevices = (AudioDeviceID *)malloc(size); - AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, NULL, &size, audioDevices); - - UInt32 deviceCount = size / sizeof(AudioDeviceID); - for (UInt32 i = 0; i < deviceCount && !found; i++) { - prop.mScope = kAudioDevicePropertyScopeOutput; - prop.mSelector = kAudioDevicePropertyStreamConfiguration; - - AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, NULL, &size); - AudioBufferList *bufferList = (AudioBufferList *)malloc(size); - AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, bufferList); - - UInt32 outputChannelCount = 0; - for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++) - outputChannelCount += bufferList->mBuffers[j].mNumberChannels; - - free(bufferList); - - if (outputChannelCount >= 1) { - CFStringRef cfname; - - size = sizeof(CFStringRef); - prop.mSelector = kAudioObjectPropertyName; - - AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, &cfname); - - CFIndex length = CFStringGetLength(cfname); - CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; - char *buffer = (char *)malloc(maxSize); - if (CFStringGetCString(cfname, buffer, maxSize, kCFStringEncodingUTF8)) { - String name = String(buffer) + " (" + itos(audioDevices[i]) + ")"; - if (name == device_name) { - deviceId = audioDevices[i]; - found = true; - } - } - - free(buffer); - } - } - - free(audioDevices); - } - - if (!found) { - // If we haven't found the desired device get the system default one - UInt32 size = sizeof(AudioDeviceID); - AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; - - OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, NULL, &size, &deviceId); - ERR_FAIL_COND(result != noErr); - - found = true; - } - - if (found) { - OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID)); - ERR_FAIL_COND(result != noErr); - } -} - -#endif - void AudioDriverCoreAudio::lock() { if (mutex) mutex->lock(); @@ -506,6 +380,178 @@ Error AudioDriverCoreAudio::capture_stop() { return OK; } +#ifdef OSX_ENABLED + +Array AudioDriverCoreAudio::_get_device_list(bool capture) { + + Array list; + + list.push_back("Default"); + + AudioObjectPropertyAddress prop; + + prop.mSelector = kAudioHardwarePropertyDevices; + prop.mScope = kAudioObjectPropertyScopeGlobal; + prop.mElement = kAudioObjectPropertyElementMaster; + + UInt32 size = 0; + AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, NULL, &size); + AudioDeviceID *audioDevices = (AudioDeviceID *)malloc(size); + AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, NULL, &size, audioDevices); + + UInt32 deviceCount = size / sizeof(AudioDeviceID); + for (UInt32 i = 0; i < deviceCount; i++) { + prop.mScope = capture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; + prop.mSelector = kAudioDevicePropertyStreamConfiguration; + + AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, NULL, &size); + AudioBufferList *bufferList = (AudioBufferList *)malloc(size); + AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, bufferList); + + UInt32 channelCount = 0; + for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++) + channelCount += bufferList->mBuffers[j].mNumberChannels; + + free(bufferList); + + if (channelCount >= 1) { + CFStringRef cfname; + + size = sizeof(CFStringRef); + prop.mSelector = kAudioObjectPropertyName; + + AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, &cfname); + + CFIndex length = CFStringGetLength(cfname); + CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; + char *buffer = (char *)malloc(maxSize); + if (CFStringGetCString(cfname, buffer, maxSize, kCFStringEncodingUTF8)) { + // Append the ID to the name in case we have devices with duplicate name + list.push_back(String(buffer) + " (" + itos(audioDevices[i]) + ")"); + } + + free(buffer); + } + } + + free(audioDevices); + + return list; +} + +void AudioDriverCoreAudio::_set_device(const String &device, bool capture) { + + AudioDeviceID deviceId; + bool found = false; + if (device != "Default") { + AudioObjectPropertyAddress prop; + + prop.mSelector = kAudioHardwarePropertyDevices; + prop.mScope = kAudioObjectPropertyScopeGlobal; + prop.mElement = kAudioObjectPropertyElementMaster; + + UInt32 size = 0; + AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, NULL, &size); + AudioDeviceID *audioDevices = (AudioDeviceID *)malloc(size); + AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, NULL, &size, audioDevices); + + UInt32 deviceCount = size / sizeof(AudioDeviceID); + for (UInt32 i = 0; i < deviceCount && !found; i++) { + prop.mScope = capture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; + prop.mSelector = kAudioDevicePropertyStreamConfiguration; + + AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, NULL, &size); + AudioBufferList *bufferList = (AudioBufferList *)malloc(size); + AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, bufferList); + + UInt32 channelCount = 0; + for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++) + channelCount += bufferList->mBuffers[j].mNumberChannels; + + free(bufferList); + + if (channelCount >= 1) { + CFStringRef cfname; + + size = sizeof(CFStringRef); + prop.mSelector = kAudioObjectPropertyName; + + AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, &cfname); + + CFIndex length = CFStringGetLength(cfname); + CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; + char *buffer = (char *)malloc(maxSize); + if (CFStringGetCString(cfname, buffer, maxSize, kCFStringEncodingUTF8)) { + String name = String(buffer) + " (" + itos(audioDevices[i]) + ")"; + if (name == device) { + deviceId = audioDevices[i]; + found = true; + } + } + + free(buffer); + } + } + + free(audioDevices); + } + + if (!found) { + // If we haven't found the desired device get the system default one + UInt32 size = sizeof(AudioDeviceID); + UInt32 elem = capture ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice; + AudioObjectPropertyAddress property = { elem, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; + + OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, NULL, &size, &deviceId); + ERR_FAIL_COND(result != noErr); + + found = true; + } + + if (found) { + OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, capture ? kInputBus : kOutputBus, &deviceId, sizeof(AudioDeviceID)); + ERR_FAIL_COND(result != noErr); + } +} + +Array AudioDriverCoreAudio::get_device_list() { + + return _get_device_list(); +} + +String AudioDriverCoreAudio::get_device() { + + return device_name; +} + +void AudioDriverCoreAudio::set_device(String device) { + + device_name = device; + if (active) { + _set_device(device_name); + } +} + +void AudioDriverCoreAudio::capture_set_device(const String &p_name) { + + capture_device_name = p_name; + if (active) { + _set_device(capture_device_name, true); + } +} + +Array AudioDriverCoreAudio::capture_get_device_list() { + + return _get_device_list(true); +} + +String AudioDriverCoreAudio::capture_get_device() { + + return capture_device_name; +} + +#endif + AudioDriverCoreAudio::AudioDriverCoreAudio() { active = false; mutex = NULL; @@ -518,7 +564,8 @@ AudioDriverCoreAudio::AudioDriverCoreAudio() { samples_in.clear(); device_name = "Default"; -}; + capture_device_name = "Default"; +} AudioDriverCoreAudio::~AudioDriverCoreAudio(){}; diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h index 7629e566860..a416a162b36 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.h +++ b/drivers/coreaudio/audio_driver_coreaudio.h @@ -48,6 +48,7 @@ class AudioDriverCoreAudio : public AudioDriver { Mutex *mutex; String device_name; + String capture_device_name; int mix_rate; unsigned int channels; @@ -57,6 +58,13 @@ class AudioDriverCoreAudio : public AudioDriver { Vector input_buf; #ifdef OSX_ENABLED + Array _get_device_list(bool capture = false); + void _set_device(const String &device, bool capture = false); + + static OSStatus input_device_address_cb(AudioObjectID inObjectID, + UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, + void *inClientData); + static OSStatus output_device_address_cb(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData); @@ -83,11 +91,7 @@ public: virtual void start(); virtual int get_mix_rate() const; virtual SpeakerMode get_speaker_mode() const; -#ifdef OSX_ENABLED - virtual Array get_device_list(); - virtual String get_device(); - virtual void set_device(String device); -#endif + virtual void lock(); virtual void unlock(); virtual void finish(); @@ -98,6 +102,16 @@ public: bool try_lock(); void stop(); +#ifdef OSX_ENABLED + virtual Array get_device_list(); + virtual String get_device(); + virtual void set_device(String device); + + virtual Array capture_get_device_list(); + virtual void capture_set_device(const String &p_name); + virtual String capture_get_device(); +#endif + AudioDriverCoreAudio(); ~AudioDriverCoreAudio(); }; diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index f8d7516f1f6..7113a777355 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -786,7 +786,7 @@ Error AudioDriverWASAPI::capture_stop() { return FAILED; } -void AudioDriverWASAPI::capture_set_device(StringName p_name) { +void AudioDriverWASAPI::capture_set_device(const String &p_name) { lock(); audio_input.new_device = p_name; diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h index a131eb5dae2..3d94f3ba490 100644 --- a/drivers/wasapi/audio_driver_wasapi.h +++ b/drivers/wasapi/audio_driver_wasapi.h @@ -120,8 +120,8 @@ public: virtual Error capture_start(); virtual Error capture_stop(); virtual Array capture_get_device_list(); - virtual void capture_set_device(StringName p_name); - virtual StringName capture_get_device(); + virtual void capture_set_device(const String &p_name); + virtual String capture_get_device(); AudioDriverWASAPI(); }; diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index eb034fa615f..7c8d61f5456 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -1215,14 +1215,14 @@ Array AudioServer::capture_get_device_list() { return AudioDriver::get_singleton()->capture_get_device_list(); } -StringName AudioServer::capture_get_device() { +String AudioServer::capture_get_device() { return AudioDriver::get_singleton()->capture_get_device(); } -void AudioServer::capture_set_device(StringName device) { +void AudioServer::capture_set_device(const String &p_name) { - AudioDriver::get_singleton()->capture_set_device(device); + AudioDriver::get_singleton()->capture_set_device(p_name); } void AudioServer::_bind_methods() { @@ -1275,6 +1275,10 @@ void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_device"), &AudioServer::get_device); ClassDB::bind_method(D_METHOD("set_device"), &AudioServer::set_device); + ClassDB::bind_method(D_METHOD("capture_get_device_list"), &AudioServer::capture_get_device_list); + ClassDB::bind_method(D_METHOD("capture_get_device"), &AudioServer::capture_get_device); + ClassDB::bind_method(D_METHOD("capture_set_device"), &AudioServer::capture_set_device); + ClassDB::bind_method(D_METHOD("set_bus_layout", "bus_layout"), &AudioServer::set_bus_layout); ClassDB::bind_method(D_METHOD("generate_bus_layout"), &AudioServer::generate_bus_layout); diff --git a/servers/audio_server.h b/servers/audio_server.h index 035942cf896..c199a337eb8 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -98,8 +98,8 @@ public: virtual Error capture_start() { return FAILED; } virtual Error capture_stop() { return FAILED; } - virtual void capture_set_device(StringName p_name) {} - virtual StringName capture_get_device() { return "Default"; } + virtual void capture_set_device(const String &p_name) {} + virtual String capture_get_device() { return "Default"; } virtual Array capture_get_device_list(); // TODO: convert this and get_device_list to PoolStringArray virtual float get_latency() { return 0; } @@ -362,8 +362,8 @@ public: void set_device(String device); Array capture_get_device_list(); - StringName capture_get_device(); - void capture_set_device(StringName device); + String capture_get_device(); + void capture_set_device(const String &p_name); float get_output_latency() { return output_latency; } AudioServer();