Преглед изворни кода

Merge pull request #9796 from marcelofg55/2.1

[2.1] Updated OS X audio driver with improvements from 3.0
Rémi Verschelde пре 8 година
родитељ
комит
48007d8ec6
3 измењених фајлова са 105 додато и 25 уклоњено
  1. 97 24
      platform/osx/audio_driver_osx.cpp
  2. 7 0
      platform/osx/audio_driver_osx.h
  3. 1 1
      platform/osx/detect.py

+ 97 - 24
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;
+
+	finishDevice();
 
-	if (active)
-		AudioOutputUnitStop(audio_unit);
+	result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &outputDeviceAddress, &outputDeviceAddressCB, this);
+	if (result != noErr) {
+		ERR_PRINT("AudioObjectRemovePropertyListener failed");
+	}
 
 	memdelete_arr(samples_in);
 };

+ 7 - 0
platform/osx/audio_driver_osx.h

@@ -35,10 +35,12 @@
 #include "servers/audio/audio_server_sw.h"
 
 #include <AudioUnit/AudioUnit.h>
+#include <CoreAudio/AudioHardware.h>
 
 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();
 };

+ 1 - 1
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++"):