@@ -123,6 +123,8 @@ const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
123123
124124static bool default_output_device_changed = false ;
125125static 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
136138public:
139+ ComPtr<IMMDeviceEnumerator> enumerator = nullptr ;
140+
137141 CMMNotificationClient () {}
138142 virtual ~CMMNotificationClient () {}
139143
@@ -199,6 +203,9 @@ class CMMNotificationClient : public IMMNotificationClient {
199203static CMMNotificationClient notif_client;
200204
201205Error 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 (¬if_client);
286+ notif_client.enumerator = nullptr ;
287+ }
273288 hr = enumerator->RegisterEndpointNotificationCallback (¬if_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
464505Error 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) {
504550Error 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