Skip to content

Commit 9d2798d

Browse files
committed
Merge pull request godotengine#100116 from allenwp/prevent-wasapi-error-spam
Prevent WASAPI error spam when device cannot be initialized.
2 parents 1e1f54e + db63d3e commit 9d2798d

File tree

1 file changed

+78
-15
lines changed

1 file changed

+78
-15
lines changed

drivers/wasapi/audio_driver_wasapi.cpp

Lines changed: 78 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
123123

124124
static bool default_output_device_changed = false;
125125
static bool default_input_device_changed = false;
126+
static int output_reinit_countdown = 0;
127+
static int input_reinit_countdown = 0;
126128

127129
// Silence warning due to a COM API weirdness (GH-35194).
128130
#if defined(__GNUC__) && !defined(__clang__)
@@ -134,6 +136,8 @@ class CMMNotificationClient : public IMMNotificationClient {
134136
LONG _cRef = 1;
135137

136138
public:
139+
ComPtr<IMMDeviceEnumerator> enumerator = nullptr;
140+
137141
CMMNotificationClient() {}
138142
virtual ~CMMNotificationClient() {}
139143

@@ -199,6 +203,9 @@ class CMMNotificationClient : public IMMNotificationClient {
199203
static CMMNotificationClient notif_client;
200204

201205
Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_input, bool p_reinit, bool p_no_audio_client_3) {
206+
// This function can be called recursively, so clean up before starting:
207+
audio_device_finish(p_device);
208+
202209
WAVEFORMATEX *pwfex;
203210
ComPtr<IMMDeviceEnumerator> enumerator = nullptr;
204211
ComPtr<IMMDevice> output_device = nullptr;
@@ -225,21 +232,25 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
225232
ComPtr<IMMDevice> tmp_device = nullptr;
226233

227234
hr = devices->Item(i, &tmp_device);
228-
ERR_BREAK(hr != S_OK);
235+
ERR_BREAK_MSG(hr != S_OK, "Cannot get devices item.");
229236

230237
ComPtr<IPropertyStore> props = nullptr;
231238
hr = tmp_device->OpenPropertyStore(STGM_READ, &props);
232-
ERR_BREAK(hr != S_OK);
239+
ERR_BREAK_MSG(hr != S_OK, "Cannot open property store.");
233240

234241
PROPVARIANT propvar;
235242
PropVariantInit(&propvar);
236243

237244
hr = props->GetValue(PKEY_Device_FriendlyNameGodot, &propvar);
238-
ERR_BREAK(hr != S_OK);
245+
ERR_BREAK_MSG(hr != S_OK, "Cannot get value.");
239246

240247
if (p_device->device_name == String(propvar.pwszVal)) {
241248
hr = tmp_device->GetId(&strId);
242-
ERR_BREAK(hr != S_OK);
249+
if (unlikely(hr != S_OK)) {
250+
PropVariantClear(&propvar);
251+
ERR_PRINT("Cannot get device ID string.");
252+
break;
253+
}
243254

244255
found = true;
245256
}
@@ -270,9 +281,14 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
270281
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
271282
}
272283

284+
if (notif_client.enumerator != nullptr) {
285+
notif_client.enumerator->UnregisterEndpointNotificationCallback(&notif_client);
286+
notif_client.enumerator = nullptr;
287+
}
273288
hr = enumerator->RegisterEndpointNotificationCallback(&notif_client);
274-
275-
if (hr != S_OK) {
289+
if (hr == S_OK) {
290+
notif_client.enumerator = enumerator;
291+
} else {
276292
ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error");
277293
}
278294

@@ -317,6 +333,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
317333

318334
hr = p_device->audio_client->GetMixFormat(&pwfex);
319335
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
336+
// From this point onward, CoTaskMemFree(pwfex) must be called before returning or pwfex will leak!
320337

321338
print_verbose("WASAPI: wFormatTag = " + itos(pwfex->wFormatTag));
322339
print_verbose("WASAPI: nChannels = " + itos(pwfex->nChannels));
@@ -340,6 +357,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
340357
print_verbose("WASAPI: closest->cbSize = " + itos(closest->cbSize));
341358

342359
WARN_PRINT("WASAPI: Using closest match instead");
360+
CoTaskMemFree(pwfex);
343361
pwfex = closest;
344362
}
345363
}
@@ -359,11 +377,13 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
359377
p_device->format_tag = WAVE_FORMAT_IEEE_FLOAT;
360378
} else {
361379
ERR_PRINT("WASAPI: Format not supported");
380+
CoTaskMemFree(pwfex);
362381
ERR_FAIL_V(ERR_CANT_OPEN);
363382
}
364383
} else {
365384
if (p_device->format_tag != WAVE_FORMAT_PCM && p_device->format_tag != WAVE_FORMAT_IEEE_FLOAT) {
366385
ERR_PRINT("WASAPI: Format not supported");
386+
CoTaskMemFree(pwfex);
367387
ERR_FAIL_V(ERR_CANT_OPEN);
368388
}
369389
}
@@ -376,10 +396,28 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
376396
pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nChannels * (pwfex->wBitsPerSample / 8);
377397
}
378398
hr = p_device->audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, p_input ? REFTIMES_PER_SEC : 0, 0, pwfex, nullptr);
379-
ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: Initialize failed with error 0x" + String::num_uint64(hr, 16) + ".");
399+
400+
if (p_reinit) {
401+
// In case we're trying to re-initialize the device, prevent throwing this error on the console,
402+
// otherwise if there is currently no device available this will spam the console.
403+
if (hr != S_OK) {
404+
print_verbose("WASAPI: Initialize failed with error 0x" + String::num_uint64(hr, 16) + ".");
405+
CoTaskMemFree(pwfex);
406+
return ERR_CANT_OPEN;
407+
}
408+
} else {
409+
if (unlikely(hr != S_OK)) {
410+
CoTaskMemFree(pwfex);
411+
ERR_FAIL_V_MSG(ERR_CANT_OPEN, "WASAPI: Initialize failed with error 0x" + String::num_uint64(hr, 16) + ".");
412+
}
413+
}
414+
380415
UINT32 max_frames;
381416
hr = p_device->audio_client->GetBufferSize(&max_frames);
382-
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
417+
if (unlikely(hr != S_OK)) {
418+
CoTaskMemFree(pwfex);
419+
ERR_FAIL_V(ERR_CANT_OPEN);
420+
}
383421

384422
// Due to WASAPI Shared Mode we have no control of the buffer size
385423
if (!p_input) {
@@ -453,7 +491,10 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
453491
} else {
454492
hr = p_device->audio_client->GetService(IID_IAudioRenderClient, (void **)&p_device->render_client);
455493
}
456-
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
494+
if (unlikely(hr != S_OK)) {
495+
CoTaskMemFree(pwfex);
496+
ERR_FAIL_V(ERR_CANT_OPEN);
497+
}
457498

458499
// Free memory
459500
CoTaskMemFree(pwfex);
@@ -464,6 +505,11 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
464505
Error AudioDriverWASAPI::init_output_device(bool p_reinit) {
465506
Error err = audio_device_init(&audio_output, false, p_reinit);
466507
if (err != OK) {
508+
// We've tried to init the device, but have failed. Time to clean up.
509+
Error finish_err = finish_output_device();
510+
if (finish_err != OK) {
511+
ERR_PRINT("WASAPI: finish_output_device error after failed output audio_device_init");
512+
}
467513
return err;
468514
}
469515

@@ -504,6 +550,11 @@ Error AudioDriverWASAPI::init_output_device(bool p_reinit) {
504550
Error AudioDriverWASAPI::init_input_device(bool p_reinit) {
505551
Error err = audio_device_init(&audio_input, true, p_reinit);
506552
if (err != OK) {
553+
// We've tried to init the device, but have failed. Time to clean up.
554+
Error finish_err = finish_input_device();
555+
if (finish_err != OK) {
556+
ERR_PRINT("WASAPI: finish_input_device error after failed input audio_device_init");
557+
}
507558
return err;
508559
}
509560

@@ -826,9 +877,15 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
826877
}
827878

828879
if (!ad->audio_output.audio_client) {
829-
Error err = ad->init_output_device(true);
830-
if (err == OK) {
831-
ad->start();
880+
if (output_reinit_countdown < 1) {
881+
Error err = ad->init_output_device(true);
882+
if (err == OK) {
883+
ad->start();
884+
} else {
885+
output_reinit_countdown = 1000;
886+
}
887+
} else {
888+
output_reinit_countdown--;
832889
}
833890

834891
avail_frames = 0;
@@ -899,9 +956,15 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
899956
}
900957

901958
if (!ad->audio_input.audio_client) {
902-
Error err = ad->init_input_device(true);
903-
if (err == OK) {
904-
ad->input_start();
959+
if (input_reinit_countdown < 1) {
960+
Error err = ad->init_input_device(true);
961+
if (err == OK) {
962+
ad->input_start();
963+
} else {
964+
input_reinit_countdown = 1000;
965+
}
966+
} else {
967+
input_reinit_countdown--;
905968
}
906969
}
907970
}

0 commit comments

Comments
 (0)