Merge pull request #91975 from lalitshankarchowdhury/wasapi-use-smart-pointers

Use COM smart pointers in WASAPI driver
This commit is contained in:
Rémi Verschelde 2024-05-17 11:14:04 +02:00
commit 04a8cfbb74
No known key found for this signature in database
GPG Key ID: C3336907360768E1
2 changed files with 21 additions and 43 deletions

View File

@ -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() { virtual ~CMMNotificationClient() {}
if ((_pEnumerator) != nullptr) {
(_pEnumerator)->Release();
(_pEnumerator) = nullptr;
}
}
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; ComPtr<IMMDeviceEnumerator> enumerator = nullptr;
IMMDevice *output_device = 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) p_device->audio_client.Reset();
SAFE_RELEASE(p_device->render_client) p_device->render_client.Reset();
SAFE_RELEASE(p_device->capture_client) 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; ComPtr<IMMDeviceCollection> devices = nullptr;
IMMDeviceEnumerator *enumerator = 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;
} }

View File

@ -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; ComPtr<IAudioClient> audio_client = nullptr;
IAudioRenderClient *render_client = nullptr; // Output ComPtr<IAudioRenderClient> render_client = nullptr; // Output
IAudioCaptureClient *capture_client = nullptr; // Input ComPtr<IAudioCaptureClient> capture_client = nullptr; // Input
SafeFlag active; SafeFlag active;
WORD format_tag = 0; WORD format_tag = 0;