浏览代码

Fixed issues with audio input on some Macs

Marcelo Fernandez 7 年之前
父节点
当前提交
5e26829118
共有 2 个文件被更改,包括 159 次插入47 次删除
  1. 155 47
      drivers/coreaudio/audio_driver_coreaudio.cpp
  2. 4 0
      drivers/coreaudio/audio_driver_coreaudio.h

+ 155 - 47
drivers/coreaudio/audio_driver_coreaudio.cpp

@@ -95,11 +95,6 @@ Error AudioDriverCoreAudio::init() {
 
 
 	result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this);
 	result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this);
 	ERR_FAIL_COND_V(result != noErr, FAILED);
 	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
 #endif
 
 
 	AudioStreamBasicDescription strdesc;
 	AudioStreamBasicDescription strdesc;
@@ -123,26 +118,6 @@ Error AudioDriverCoreAudio::init() {
 			break;
 			break;
 	}
 	}
 
 
-	zeromem(&strdesc, sizeof(strdesc));
-	size = sizeof(strdesc);
-	result = AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size);
-	ERR_FAIL_COND_V(result != noErr, FAILED);
-
-	switch (strdesc.mChannelsPerFrame) {
-		case 1: // Mono
-			capture_channels = 1;
-			break;
-
-		case 2: // Stereo
-			capture_channels = 2;
-			break;
-
-		default:
-			// Unknown number of channels, default to stereo
-			capture_channels = 2;
-			break;
-	}
-
 	mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
 	mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
 
 
 	zeromem(&strdesc, sizeof(strdesc));
 	zeromem(&strdesc, sizeof(strdesc));
@@ -158,11 +133,6 @@ Error AudioDriverCoreAudio::init() {
 	result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc));
 	result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc));
 	ERR_FAIL_COND_V(result != noErr, FAILED);
 	ERR_FAIL_COND_V(result != noErr, FAILED);
 
 
-	strdesc.mChannelsPerFrame = capture_channels;
-
-	result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, sizeof(strdesc));
-	ERR_FAIL_COND_V(result != noErr, FAILED);
-
 	int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
 	int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
 	// Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
 	// Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
 	buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
 	buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
@@ -189,16 +159,10 @@ Error AudioDriverCoreAudio::init() {
 	result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
 	result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
 	ERR_FAIL_COND_V(result != noErr, FAILED);
 	ERR_FAIL_COND_V(result != noErr, FAILED);
 
 
-	zeromem(&callback, sizeof(AURenderCallbackStruct));
-	callback.inputProc = &AudioDriverCoreAudio::input_callback;
-	callback.inputProcRefCon = this;
-	result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
-	ERR_FAIL_COND_V(result != noErr, FAILED);
-
 	result = AudioUnitInitialize(audio_unit);
 	result = AudioUnitInitialize(audio_unit);
 	ERR_FAIL_COND_V(result != noErr, FAILED);
 	ERR_FAIL_COND_V(result != noErr, FAILED);
 
 
-	return OK;
+	return capture_init();
 }
 }
 
 
 OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon,
 OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon,
@@ -265,7 +229,7 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon,
 	bufferList.mBuffers[0].mNumberChannels = ad->capture_channels;
 	bufferList.mBuffers[0].mNumberChannels = ad->capture_channels;
 	bufferList.mBuffers[0].mDataByteSize = ad->input_buf.size() * sizeof(int16_t);
 	bufferList.mBuffers[0].mDataByteSize = ad->input_buf.size() * sizeof(int16_t);
 
 
-	OSStatus result = AudioUnitRender(ad->audio_unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList);
+	OSStatus result = AudioUnitRender(ad->input_unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList);
 	if (result == noErr) {
 	if (result == noErr) {
 		for (int i = 0; i < inNumberFrames * ad->capture_channels; i++) {
 		for (int i = 0; i < inNumberFrames * ad->capture_channels; i++) {
 			int32_t sample = ad->input_buf[i] << 16;
 			int32_t sample = ad->input_buf[i] << 16;
@@ -332,6 +296,8 @@ bool AudioDriverCoreAudio::try_lock() {
 }
 }
 
 
 void AudioDriverCoreAudio::finish() {
 void AudioDriverCoreAudio::finish() {
+	capture_finish();
+
 	if (audio_unit) {
 	if (audio_unit) {
 		OSStatus result;
 		OSStatus result;
 
 
@@ -375,6 +341,7 @@ void AudioDriverCoreAudio::finish() {
 			ERR_PRINT("AudioComponentInstanceDispose failed");
 			ERR_PRINT("AudioComponentInstanceDispose failed");
 		}
 		}
 
 
+		audio_unit = NULL;
 		unlock();
 		unlock();
 	}
 	}
 
 
@@ -384,20 +351,158 @@ void AudioDriverCoreAudio::finish() {
 	}
 	}
 }
 }
 
 
-Error AudioDriverCoreAudio::capture_start() {
+Error AudioDriverCoreAudio::capture_init() {
+	AudioComponentDescription desc;
+	zeromem(&desc, sizeof(desc));
+	desc.componentType = kAudioUnitType_Output;
+#ifdef OSX_ENABLED
+	desc.componentSubType = kAudioUnitSubType_HALOutput;
+#else
+	desc.componentSubType = kAudioUnitSubType_RemoteIO;
+#endif
+	desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+
+	AudioComponent comp = AudioComponentFindNext(NULL, &desc);
+	ERR_FAIL_COND_V(comp == NULL, FAILED);
+
+	OSStatus result = AudioComponentInstanceNew(comp, &input_unit);
+	ERR_FAIL_COND_V(result != noErr, FAILED);
+
+#ifdef OSX_ENABLED
+	AudioObjectPropertyAddress prop;
+	prop.mSelector = kAudioHardwarePropertyDefaultInputDevice;
+	prop.mScope = kAudioObjectPropertyScopeGlobal;
+	prop.mElement = kAudioObjectPropertyElementMaster;
+
+	result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this);
+	ERR_FAIL_COND_V(result != noErr, FAILED);
+#endif
 
 
 	UInt32 flag = 1;
 	UInt32 flag = 1;
-	OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag));
+	result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag));
+	ERR_FAIL_COND_V(result != noErr, FAILED);
+	flag = 0;
+	result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag));
+	ERR_FAIL_COND_V(result != noErr, FAILED);
+
+	UInt32 size;
+#ifdef OSX_ENABLED
+	AudioDeviceID deviceId;
+	size = sizeof(AudioDeviceID);
+	AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+
+	result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, NULL, &size, &deviceId);
+	ERR_FAIL_COND_V(result != noErr, FAILED);
+
+	result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID));
+	ERR_FAIL_COND_V(result != noErr, FAILED);
+#endif
+
+	AudioStreamBasicDescription strdesc;
+	zeromem(&strdesc, sizeof(strdesc));
+	size = sizeof(strdesc);
+	result = AudioUnitGetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size);
+	ERR_FAIL_COND_V(result != noErr, FAILED);
+
+	switch (strdesc.mChannelsPerFrame) {
+		case 1: // Mono
+			capture_channels = 1;
+			break;
+
+		case 2: // Stereo
+			capture_channels = 2;
+			break;
+
+		default:
+			// Unknown number of channels, default to stereo
+			capture_channels = 2;
+			break;
+	}
+
+	mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
+
+	zeromem(&strdesc, sizeof(strdesc));
+	strdesc.mFormatID = kAudioFormatLinearPCM;
+	strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
+	strdesc.mChannelsPerFrame = capture_channels;
+	strdesc.mSampleRate = mix_rate;
+	strdesc.mFramesPerPacket = 1;
+	strdesc.mBitsPerChannel = 16;
+	strdesc.mBytesPerFrame = strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
+	strdesc.mBytesPerPacket = strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
+
+	result = AudioUnitSetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, sizeof(strdesc));
+	ERR_FAIL_COND_V(result != noErr, FAILED);
+
+	AURenderCallbackStruct callback;
+	zeromem(&callback, sizeof(AURenderCallbackStruct));
+	callback.inputProc = &AudioDriverCoreAudio::input_callback;
+	callback.inputProcRefCon = this;
+	result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callback, sizeof(callback));
+	ERR_FAIL_COND_V(result != noErr, FAILED);
+
+	result = AudioUnitInitialize(input_unit);
 	ERR_FAIL_COND_V(result != noErr, FAILED);
 	ERR_FAIL_COND_V(result != noErr, FAILED);
 
 
 	return OK;
 	return OK;
 }
 }
 
 
+void AudioDriverCoreAudio::capture_finish() {
+	if (input_unit) {
+		lock();
+
+		AURenderCallbackStruct callback;
+		zeromem(&callback, sizeof(AURenderCallbackStruct));
+		OSStatus result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
+		if (result != noErr) {
+			ERR_PRINT("AudioUnitSetProperty failed");
+		}
+
+		result = AudioUnitUninitialize(input_unit);
+		if (result != noErr) {
+			ERR_PRINT("AudioUnitUninitialize failed");
+		}
+
+#ifdef OSX_ENABLED
+		AudioObjectPropertyAddress prop;
+		prop.mSelector = kAudioHardwarePropertyDefaultInputDevice;
+		prop.mScope = kAudioObjectPropertyScopeGlobal;
+		prop.mElement = kAudioObjectPropertyElementMaster;
+
+		result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this);
+		if (result != noErr) {
+			ERR_PRINT("AudioObjectRemovePropertyListener failed");
+		}
+#endif
+
+		result = AudioComponentInstanceDispose(input_unit);
+		if (result != noErr) {
+			ERR_PRINT("AudioComponentInstanceDispose failed");
+		}
+
+		input_unit = NULL;
+		unlock();
+	}
+}
+
+Error AudioDriverCoreAudio::capture_start() {
+
+	OSStatus result = AudioOutputUnitStart(input_unit);
+	if (result != noErr) {
+		ERR_PRINTS("AudioOutputUnitStart failed, code: " + itos(result));
+	}
+
+	return OK;
+}
+
 Error AudioDriverCoreAudio::capture_stop() {
 Error AudioDriverCoreAudio::capture_stop() {
 
 
-	UInt32 flag = 0;
-	OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag));
-	ERR_FAIL_COND_V(result != noErr, FAILED);
+	if (input_unit) {
+		OSStatus result = AudioOutputUnitStop(input_unit);
+		if (result != noErr) {
+			ERR_PRINTS("AudioOutputUnitStop failed, code: " + itos(result));
+		}
+	}
 
 
 	return OK;
 	return OK;
 }
 }
@@ -531,12 +636,14 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
 	}
 	}
 
 
 	if (found) {
 	if (found) {
-		OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, capture ? kInputBus : kOutputBus, &deviceId, sizeof(AudioDeviceID));
+		OSStatus result = AudioUnitSetProperty(capture ? input_unit : audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID));
 		ERR_FAIL_COND(result != noErr);
 		ERR_FAIL_COND(result != noErr);
 
 
-		// Reset audio input to keep synchronisation.
-		input_position = 0;
-		input_size = 0;
+		if (capture) {
+			// Reset audio input to keep synchronisation.
+			input_position = 0;
+			input_size = 0;
+		}
 	}
 	}
 }
 }
 
 
@@ -580,6 +687,7 @@ String AudioDriverCoreAudio::capture_get_device() {
 
 
 AudioDriverCoreAudio::AudioDriverCoreAudio() {
 AudioDriverCoreAudio::AudioDriverCoreAudio() {
 	audio_unit = NULL;
 	audio_unit = NULL;
+	input_unit = NULL;
 	active = false;
 	active = false;
 	mutex = NULL;
 	mutex = NULL;
 
 

+ 4 - 0
drivers/coreaudio/audio_driver_coreaudio.h

@@ -43,6 +43,7 @@
 class AudioDriverCoreAudio : public AudioDriver {
 class AudioDriverCoreAudio : public AudioDriver {
 
 
 	AudioComponentInstance audio_unit;
 	AudioComponentInstance audio_unit;
+	AudioComponentInstance input_unit;
 
 
 	bool active;
 	bool active;
 	Mutex *mutex;
 	Mutex *mutex;
@@ -83,6 +84,9 @@ class AudioDriverCoreAudio : public AudioDriver {
 			UInt32 inBusNumber, UInt32 inNumberFrames,
 			UInt32 inBusNumber, UInt32 inNumberFrames,
 			AudioBufferList *ioData);
 			AudioBufferList *ioData);
 
 
+	Error capture_init();
+	void capture_finish();
+
 public:
 public:
 	const char *get_name() const {
 	const char *get_name() const {
 		return "CoreAudio";
 		return "CoreAudio";