Prechádzať zdrojové kódy

Use COM smart pointers to handle COM objects safely

Use ComPtr to handle COM objects safely

Use COM smart pointers in WASAPI driver

Fix ComPtr handling

Fix crash due to IAudioClient3 type conversion
Lalit Shankar Chowdhury 1 rok pred
rodič
commit
8b8c49703a

+ 15 - 40
drivers/wasapi/audio_driver_wasapi.cpp

@@ -107,12 +107,6 @@ const IID IID_IAudioClient3 = __uuidof(IAudioClient3);
 const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
 const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
 const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
 const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
 
 
-#define SAFE_RELEASE(memory)   \
-	if ((memory) != nullptr) { \
-		(memory)->Release();   \
-		(memory) = nullptr;    \
-	}
-
 #define REFTIMES_PER_SEC 10000000
 #define REFTIMES_PER_SEC 10000000
 #define REFTIMES_PER_MILLISEC 10000
 #define REFTIMES_PER_MILLISEC 10000
 
 
@@ -129,16 +123,10 @@ static bool default_input_device_changed = false;
 
 
 class CMMNotificationClient : public IMMNotificationClient {
 class CMMNotificationClient : public IMMNotificationClient {
 	LONG _cRef = 1;
 	LONG _cRef = 1;
-	IMMDeviceEnumerator *_pEnumerator = nullptr;
 
 
 public:
 public:
 	CMMNotificationClient() {}
 	CMMNotificationClient() {}
-	virtual ~CMMNotificationClient() {
-		if ((_pEnumerator) != nullptr) {
-			(_pEnumerator)->Release();
-			(_pEnumerator) = nullptr;
-		}
-	}
+	virtual ~CMMNotificationClient() {}
 
 
 	ULONG STDMETHODCALLTYPE AddRef() {
 	ULONG STDMETHODCALLTYPE AddRef() {
 		return InterlockedIncrement(&_cRef);
 		return InterlockedIncrement(&_cRef);
@@ -203,8 +191,8 @@ static CMMNotificationClient notif_client;
 
 
 Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_input, bool p_reinit, bool p_no_audio_client_3) {
 Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_input, bool p_reinit, bool p_no_audio_client_3) {
 	WAVEFORMATEX *pwfex;
 	WAVEFORMATEX *pwfex;
-	IMMDeviceEnumerator *enumerator = nullptr;
-	IMMDevice *output_device = nullptr;
+	ComPtr<IMMDeviceEnumerator> enumerator = nullptr;
+	ComPtr<IMMDevice> output_device = nullptr;
 
 
 	HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
 	HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
 	ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
 	ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
@@ -212,7 +200,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
 	if (p_device->device_name == "Default") {
 	if (p_device->device_name == "Default") {
 		hr = enumerator->GetDefaultAudioEndpoint(p_input ? eCapture : eRender, eConsole, &output_device);
 		hr = enumerator->GetDefaultAudioEndpoint(p_input ? eCapture : eRender, eConsole, &output_device);
 	} else {
 	} else {
-		IMMDeviceCollection *devices = nullptr;
+		ComPtr<IMMDeviceCollection> devices = nullptr;
 
 
 		hr = enumerator->EnumAudioEndpoints(p_input ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices);
 		hr = enumerator->EnumAudioEndpoints(p_input ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices);
 		ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
 		ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
@@ -225,12 +213,12 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
 		ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
 		ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
 
 
 		for (ULONG i = 0; i < count && !found; i++) {
 		for (ULONG i = 0; i < count && !found; i++) {
-			IMMDevice *tmp_device = nullptr;
+			ComPtr<IMMDevice> tmp_device = nullptr;
 
 
 			hr = devices->Item(i, &tmp_device);
 			hr = devices->Item(i, &tmp_device);
 			ERR_BREAK(hr != S_OK);
 			ERR_BREAK(hr != S_OK);
 
 
-			IPropertyStore *props = nullptr;
+			ComPtr<IPropertyStore> props = nullptr;
 			hr = tmp_device->OpenPropertyStore(STGM_READ, &props);
 			hr = tmp_device->OpenPropertyStore(STGM_READ, &props);
 			ERR_BREAK(hr != S_OK);
 			ERR_BREAK(hr != S_OK);
 
 
@@ -248,8 +236,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
 			}
 			}
 
 
 			PropVariantClear(&propvar);
 			PropVariantClear(&propvar);
-			props->Release();
-			tmp_device->Release();
 		}
 		}
 
 
 		if (found) {
 		if (found) {
@@ -276,7 +262,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
 	}
 	}
 
 
 	hr = enumerator->RegisterEndpointNotificationCallback(&notif_client);
 	hr = enumerator->RegisterEndpointNotificationCallback(&notif_client);
-	SAFE_RELEASE(enumerator)
 
 
 	if (hr != S_OK) {
 	if (hr != S_OK) {
 		ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error");
 		ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error");
@@ -303,8 +288,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
 		hr = output_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void **)&p_device->audio_client);
 		hr = output_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void **)&p_device->audio_client);
 	}
 	}
 
 
-	SAFE_RELEASE(output_device)
-
 	if (p_reinit) {
 	if (p_reinit) {
 		if (hr != S_OK) {
 		if (hr != S_OK) {
 			return ERR_CANT_OPEN;
 			return ERR_CANT_OPEN;
@@ -319,7 +302,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
 		audioProps.bIsOffload = FALSE;
 		audioProps.bIsOffload = FALSE;
 		audioProps.eCategory = AudioCategory_GameEffects;
 		audioProps.eCategory = AudioCategory_GameEffects;
 
 
-		hr = ((IAudioClient3 *)p_device->audio_client)->SetClientProperties(&audioProps);
+		hr = ((IAudioClient3 *)p_device->audio_client.Get())->SetClientProperties(&audioProps);
 		ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: SetClientProperties failed with error 0x" + String::num_uint64(hr, 16) + ".");
 		ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: SetClientProperties failed with error 0x" + String::num_uint64(hr, 16) + ".");
 	}
 	}
 
 
@@ -402,7 +385,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
 		}
 		}
 
 
 	} else {
 	} else {
-		IAudioClient3 *device_audio_client_3 = (IAudioClient3 *)p_device->audio_client;
+		IAudioClient3 *device_audio_client_3 = (IAudioClient3 *)p_device->audio_client.Get();
 
 
 		// AUDCLNT_STREAMFLAGS_RATEADJUST is an invalid flag with IAudioClient3, therefore we have to use
 		// AUDCLNT_STREAMFLAGS_RATEADJUST is an invalid flag with IAudioClient3, therefore we have to use
 		// the closest supported mix rate supported by the audio driver.
 		// the closest supported mix rate supported by the audio driver.
@@ -419,7 +402,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
 		if (hr != S_OK) {
 		if (hr != S_OK) {
 			print_verbose("WASAPI: GetSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
 			print_verbose("WASAPI: GetSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
 			CoTaskMemFree(pwfex);
 			CoTaskMemFree(pwfex);
-			SAFE_RELEASE(output_device)
 			return audio_device_init(p_device, p_input, p_reinit, true);
 			return audio_device_init(p_device, p_input, p_reinit, true);
 		}
 		}
 
 
@@ -441,7 +423,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
 		if (hr != S_OK) {
 		if (hr != S_OK) {
 			print_verbose("WASAPI: InitializeSharedAudioStream failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
 			print_verbose("WASAPI: InitializeSharedAudioStream failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
 			CoTaskMemFree(pwfex);
 			CoTaskMemFree(pwfex);
-			SAFE_RELEASE(output_device);
 			return audio_device_init(p_device, p_input, p_reinit, true);
 			return audio_device_init(p_device, p_input, p_reinit, true);
 		} else {
 		} else {
 			uint32_t output_latency_in_frames;
 			uint32_t output_latency_in_frames;
@@ -453,7 +434,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
 			} else {
 			} else {
 				print_verbose("WASAPI: GetCurrentSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
 				print_verbose("WASAPI: GetCurrentSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
 				CoTaskMemFree(pwfex);
 				CoTaskMemFree(pwfex);
-				SAFE_RELEASE(output_device);
 				return audio_device_init(p_device, p_input, p_reinit, true);
 				return audio_device_init(p_device, p_input, p_reinit, true);
 			}
 			}
 		}
 		}
@@ -468,7 +448,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
 
 
 	// Free memory
 	// Free memory
 	CoTaskMemFree(pwfex);
 	CoTaskMemFree(pwfex);
-	SAFE_RELEASE(output_device)
 
 
 	return OK;
 	return OK;
 }
 }
@@ -537,9 +516,9 @@ Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) {
 		p_device->active.clear();
 		p_device->active.clear();
 	}
 	}
 
 
-	SAFE_RELEASE(p_device->audio_client)
-	SAFE_RELEASE(p_device->render_client)
-	SAFE_RELEASE(p_device->capture_client)
+	p_device->audio_client.Reset();
+	p_device->render_client.Reset();
+	p_device->capture_client.Reset();
 
 
 	return OK;
 	return OK;
 }
 }
@@ -581,8 +560,8 @@ AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const {
 
 
 PackedStringArray AudioDriverWASAPI::audio_device_get_list(bool p_input) {
 PackedStringArray AudioDriverWASAPI::audio_device_get_list(bool p_input) {
 	PackedStringArray list;
 	PackedStringArray list;
-	IMMDeviceCollection *devices = nullptr;
-	IMMDeviceEnumerator *enumerator = nullptr;
+	ComPtr<IMMDeviceCollection> devices = nullptr;
+	ComPtr<IMMDeviceEnumerator> enumerator = nullptr;
 
 
 	list.push_back(String("Default"));
 	list.push_back(String("Default"));
 
 
@@ -597,12 +576,12 @@ PackedStringArray AudioDriverWASAPI::audio_device_get_list(bool p_input) {
 	ERR_FAIL_COND_V(hr != S_OK, PackedStringArray());
 	ERR_FAIL_COND_V(hr != S_OK, PackedStringArray());
 
 
 	for (ULONG i = 0; i < count; i++) {
 	for (ULONG i = 0; i < count; i++) {
-		IMMDevice *output_device = nullptr;
+		ComPtr<IMMDevice> output_device = nullptr;
 
 
 		hr = devices->Item(i, &output_device);
 		hr = devices->Item(i, &output_device);
 		ERR_BREAK(hr != S_OK);
 		ERR_BREAK(hr != S_OK);
 
 
-		IPropertyStore *props = nullptr;
+		ComPtr<IPropertyStore> props = nullptr;
 		hr = output_device->OpenPropertyStore(STGM_READ, &props);
 		hr = output_device->OpenPropertyStore(STGM_READ, &props);
 		ERR_BREAK(hr != S_OK);
 		ERR_BREAK(hr != S_OK);
 
 
@@ -615,12 +594,8 @@ PackedStringArray AudioDriverWASAPI::audio_device_get_list(bool p_input) {
 		list.push_back(String(propvar.pwszVal));
 		list.push_back(String(propvar.pwszVal));
 
 
 		PropVariantClear(&propvar);
 		PropVariantClear(&propvar);
-		props->Release();
-		output_device->Release();
 	}
 	}
 
 
-	devices->Release();
-	enumerator->Release();
 	return list;
 	return list;
 }
 }
 
 

+ 6 - 3
drivers/wasapi/audio_driver_wasapi.h

@@ -40,15 +40,18 @@
 
 
 #include <audioclient.h>
 #include <audioclient.h>
 #include <mmdeviceapi.h>
 #include <mmdeviceapi.h>
+#include <wrl/client.h>
 #define WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <windows.h>
 
 
+using Microsoft::WRL::ComPtr;
+
 class AudioDriverWASAPI : public AudioDriver {
 class AudioDriverWASAPI : public AudioDriver {
 	class AudioDeviceWASAPI {
 	class AudioDeviceWASAPI {
 	public:
 	public:
-		IAudioClient *audio_client = nullptr;
-		IAudioRenderClient *render_client = nullptr; // Output
-		IAudioCaptureClient *capture_client = nullptr; // Input
+		ComPtr<IAudioClient> audio_client = nullptr;
+		ComPtr<IAudioRenderClient> render_client = nullptr; // Output
+		ComPtr<IAudioCaptureClient> capture_client = nullptr; // Input
 		SafeFlag active;
 		SafeFlag active;
 
 
 		WORD format_tag = 0;
 		WORD format_tag = 0;