diff options
author | Marcelo Fernandez <marcelofg55@gmail.com> | 2018-03-25 00:43:51 -0300 |
---|---|---|
committer | Marcelo Fernandez <marcelofg55@gmail.com> | 2018-03-26 17:41:05 -0300 |
commit | ecc1b34cbc2375a57afad822218324d8b88fa721 (patch) | |
tree | 7c3272e5609be259398f9bdf3549b4f9a5b84be3 /drivers/coreaudio | |
parent | fd79de01c20168075dbf425831ac44f2b676f275 (diff) |
Added new audio device functions to set/get the audio device
Diffstat (limited to 'drivers/coreaudio')
-rw-r--r-- | drivers/coreaudio/audio_driver_coreaudio.cpp | 212 | ||||
-rw-r--r-- | drivers/coreaudio/audio_driver_coreaudio.h | 20 |
2 files changed, 183 insertions, 49 deletions
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index 0b39f9ebc3..c84469f26f 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -37,16 +37,22 @@ #define kOutputBus 0 #ifdef OSX_ENABLED -static OSStatus outputDeviceAddressCB(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData) { +OSStatus AudioDriverCoreAudio::output_device_address_cb(AudioObjectID inObjectID, + UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, + void *inClientData) { AudioDriverCoreAudio *driver = (AudioDriverCoreAudio *)inClientData; - driver->reopen(); + // If our selected device is the Default call set_device to update the + // kAudioOutputUnitProperty_CurrentDevice property + if (driver->device_name == "Default") { + driver->set_device("Default"); + } return noErr; } #endif -Error AudioDriverCoreAudio::initDevice() { +Error AudioDriverCoreAudio::init_device() { AudioComponentDescription desc; zeromem(&desc, sizeof(desc)); desc.componentType = kAudioUnitType_Output; @@ -129,7 +135,7 @@ Error AudioDriverCoreAudio::initDevice() { return OK; } -Error AudioDriverCoreAudio::finishDevice() { +Error AudioDriverCoreAudio::finish_device() { OSStatus result; if (active) { @@ -153,49 +159,18 @@ Error AudioDriverCoreAudio::init() { channels = 2; #ifdef OSX_ENABLED - outputDeviceAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - outputDeviceAddress.mScope = kAudioObjectPropertyScopeGlobal; - outputDeviceAddress.mElement = kAudioObjectPropertyElementMaster; + AudioObjectPropertyAddress prop; + prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + prop.mScope = kAudioObjectPropertyScopeGlobal; + prop.mElement = kAudioObjectPropertyElementMaster; - result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &outputDeviceAddress, &outputDeviceAddressCB, this); + result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this); ERR_FAIL_COND_V(result != noErr, FAILED); #endif - return initDevice(); + return init_device(); }; -Error AudioDriverCoreAudio::reopen() { - bool restart = false; - - lock(); - - if (active) { - restart = true; - } - - Error err = finishDevice(); - if (err != OK) { - ERR_PRINT("finishDevice failed"); - unlock(); - return err; - } - - err = initDevice(); - if (err != OK) { - ERR_PRINT("initDevice failed"); - unlock(); - return err; - } - - if (restart) { - start(); - } - - unlock(); - - return OK; -} - OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, @@ -257,6 +232,150 @@ 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) { + 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(); @@ -276,10 +395,15 @@ bool AudioDriverCoreAudio::try_lock() { void AudioDriverCoreAudio::finish() { OSStatus result; - finishDevice(); + finish_device(); #ifdef OSX_ENABLED - result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &outputDeviceAddress, &outputDeviceAddressCB, this); + AudioObjectPropertyAddress prop; + prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + prop.mScope = kAudioObjectPropertyScopeGlobal; + prop.mElement = kAudioObjectPropertyElementMaster; + + result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this); if (result != noErr) { ERR_PRINT("AudioObjectRemovePropertyListener failed"); } @@ -309,6 +433,8 @@ AudioDriverCoreAudio::AudioDriverCoreAudio() { buffer_frames = 0; samples_in.clear(); + + device_name = "Default"; }; AudioDriverCoreAudio::~AudioDriverCoreAudio(){}; diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h index 51256085d8..1ef474ac19 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.h +++ b/drivers/coreaudio/audio_driver_coreaudio.h @@ -43,12 +43,12 @@ class AudioDriverCoreAudio : public AudioDriver { AudioComponentInstance audio_unit; -#ifdef OSX_ENABLED - AudioObjectPropertyAddress outputDeviceAddress; -#endif + bool active; Mutex *mutex; + String device_name; + int mix_rate; unsigned int channels; unsigned int buffer_frames; @@ -56,14 +56,18 @@ class AudioDriverCoreAudio : public AudioDriver { Vector<int32_t> samples_in; + static OSStatus output_device_address_cb(AudioObjectID inObjectID, + UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, + void *inClientData); + static OSStatus output_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); - Error initDevice(); - Error finishDevice(); + Error init_device(); + Error finish_device(); public: const char *get_name() const { @@ -74,12 +78,16 @@ 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(); bool try_lock(); - Error reopen(); AudioDriverCoreAudio(); ~AudioDriverCoreAudio(); |