From 077b455b935424148e4b8f139568114fbfbfef56 Mon Sep 17 00:00:00 2001 From: Marcelo Fernandez Date: Sun, 23 Jul 2017 13:40:38 -0300 Subject: [PATCH] Updated OS X audio driver with improvements from 3.0 --- platform/osx/audio_driver_osx.cpp | 121 ++++++++++++++++++++++++------ platform/osx/audio_driver_osx.h | 7 ++ platform/osx/detect.py | 2 +- 3 files changed, 105 insertions(+), 25 deletions(-) diff --git a/platform/osx/audio_driver_osx.cpp b/platform/osx/audio_driver_osx.cpp index 3ff75b506ad..b18c9e1c915 100644 --- a/platform/osx/audio_driver_osx.cpp +++ b/platform/osx/audio_driver_osx.cpp @@ -31,11 +31,15 @@ #include "audio_driver_osx.h" -Error AudioDriverOSX::init() { +static OSStatus outputDeviceAddressCB(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *__nullable inClientData) { + AudioDriverOSX *driver = (AudioDriverOSX *)inClientData; - active = false; - channels = 2; + driver->reopen(); + return noErr; +} + +Error AudioDriverOSX::initDevice() { AudioStreamBasicDescription strdesc; strdesc.mFormatID = kAudioFormatLinearPCM; strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; @@ -43,12 +47,10 @@ Error AudioDriverOSX::init() { strdesc.mSampleRate = 44100; strdesc.mFramesPerPacket = 1; strdesc.mBitsPerChannel = 16; - strdesc.mBytesPerFrame = - strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8; - strdesc.mBytesPerPacket = - strdesc.mBytesPerFrame * strdesc.mFramesPerPacket; + strdesc.mBytesPerFrame = strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8; + strdesc.mBytesPerPacket = strdesc.mBytesPerFrame * strdesc.mFramesPerPacket; - OSStatus result = noErr; + OSStatus result; AURenderCallbackStruct callback; AudioComponentDescription desc; AudioComponent comp = NULL; @@ -58,40 +60,99 @@ Error AudioDriverOSX::init() { zeromem(&desc, sizeof(desc)); desc.componentType = kAudioUnitType_Output; - desc.componentSubType = 0; /* !!! FIXME: ? */ - comp = AudioComponentFindNext(NULL, &desc); + desc.componentSubType = kAudioUnitSubType_HALOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; + comp = AudioComponentFindNext(NULL, &desc); + ERR_FAIL_COND_V(comp == NULL, FAILED); + result = AudioComponentInstanceNew(comp, &audio_unit); ERR_FAIL_COND_V(result != noErr, FAILED); - ERR_FAIL_COND_V(comp == NULL, FAILED); - result = AudioUnitSetProperty(audio_unit, - kAudioUnitProperty_StreamFormat, - scope, bus, &strdesc, sizeof(strdesc)); + result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, scope, bus, &strdesc, sizeof(strdesc)); ERR_FAIL_COND_V(result != noErr, FAILED); zeromem(&callback, sizeof(AURenderCallbackStruct)); callback.inputProc = &AudioDriverOSX::output_callback; callback.inputProcRefCon = this; - result = AudioUnitSetProperty(audio_unit, - kAudioUnitProperty_SetRenderCallback, - scope, bus, &callback, sizeof(callback)); + result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, scope, bus, &callback, sizeof(callback)); ERR_FAIL_COND_V(result != noErr, FAILED); result = AudioUnitInitialize(audio_unit); ERR_FAIL_COND_V(result != noErr, FAILED); - result = AudioOutputUnitStart(audio_unit); + return OK; +} + +Error AudioDriverOSX::finishDevice() { + OSStatus result; + + if (active) { + result = AudioOutputUnitStop(audio_unit); + ERR_FAIL_COND_V(result != noErr, FAILED); + + active = false; + } + + result = AudioUnitUninitialize(audio_unit); + ERR_FAIL_COND_V(result != noErr, FAILED); + + return OK; +} + +Error AudioDriverOSX::init() { + OSStatus result; + + active = false; + channels = 2; + + outputDeviceAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + outputDeviceAddress.mScope = kAudioObjectPropertyScopeGlobal; + outputDeviceAddress.mElement = kAudioObjectPropertyElementMaster; + + result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &outputDeviceAddress, &outputDeviceAddressCB, this); ERR_FAIL_COND_V(result != noErr, FAILED); const int samples = 1024; samples_in = memnew_arr(int32_t, samples); // whatever buffer_frames = samples / channels; - return OK; + return initDevice(); }; +Error AudioDriverOSX::reopen() { + Error err; + bool restart = false; + + lock(); + + if (active) { + restart = true; + } + + 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 AudioDriverOSX::output_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, @@ -149,7 +210,14 @@ OSStatus AudioDriverOSX::output_callback(void *inRefCon, }; void AudioDriverOSX::start() { - active = true; + if (!active) { + OSStatus result = AudioOutputUnitStart(audio_unit); + if (result != noErr) { + ERR_PRINT("AudioOutputUnitStart failed"); + } else { + active = true; + } + } }; int AudioDriverOSX::get_mix_rate() const { @@ -161,18 +229,23 @@ AudioDriverSW::OutputFormat AudioDriverOSX::get_output_format() const { }; void AudioDriverOSX::lock() { - if (active && mutex) + if (mutex) mutex->lock(); }; void AudioDriverOSX::unlock() { - if (active && mutex) + if (mutex) mutex->unlock(); }; void AudioDriverOSX::finish() { + OSStatus result; - if (active) - AudioOutputUnitStop(audio_unit); + finishDevice(); + + result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &outputDeviceAddress, &outputDeviceAddressCB, this); + if (result != noErr) { + ERR_PRINT("AudioObjectRemovePropertyListener failed"); + } memdelete_arr(samples_in); }; diff --git a/platform/osx/audio_driver_osx.h b/platform/osx/audio_driver_osx.h index 0b3a1eea017..f165a2b5edd 100644 --- a/platform/osx/audio_driver_osx.h +++ b/platform/osx/audio_driver_osx.h @@ -35,10 +35,12 @@ #include "servers/audio/audio_server_sw.h" #include +#include class AudioDriverOSX : public AudioDriverSW { AudioComponentInstance audio_unit; + AudioObjectPropertyAddress outputDeviceAddress; bool active; Mutex *mutex; @@ -52,6 +54,9 @@ class AudioDriverOSX : public AudioDriverSW { UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); + Error initDevice(); + Error finishDevice(); + public: const char *get_name() const { return "AudioUnit"; @@ -65,6 +70,8 @@ public: virtual void unlock(); virtual void finish(); + Error reopen(); + AudioDriverOSX(); ~AudioDriverOSX(); }; diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 2dc0eb28082..d60adfd280d 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -84,7 +84,7 @@ def configure(env): env.Append(LIBS=['pthread']) #env.Append(CPPFLAGS=['-F/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-mmacosx-version-min=10.4']) #env.Append(LINKFLAGS=['-mmacosx-version-min=10.4', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk']) - env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) + env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) env.Append(LINKFLAGS=["-mmacosx-version-min=10.9"]) if (env["CXX"] == "clang++"):