diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 331e57c7ee..a5dac4b673 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -570,6 +570,7 @@ static int SDL_AudioPlayDevice_Default(SDL_AudioDevice *device, const Uint8 *buf static int SDL_AudioWaitCaptureDevice_Default(SDL_AudioDevice *device) { return 0; /* no-op. */ } static void SDL_AudioFlushCapture_Default(SDL_AudioDevice *device) { /* no-op. */ } static void SDL_AudioCloseDevice_Default(SDL_AudioDevice *device) { /* no-op. */ } +static void SDL_AudioDeinitializeStart_Default(void) { /* no-op. */ } static void SDL_AudioDeinitialize_Default(void) { /* no-op. */ } static void SDL_AudioFreeDeviceHandle_Default(SDL_AudioDevice *device) { /* no-op. */ } @@ -622,6 +623,7 @@ static void CompleteAudioEntryPoints(void) FILL_STUB(FlushCapture); FILL_STUB(CloseDevice); FILL_STUB(FreeDeviceHandle); + FILL_STUB(DeinitializeStart); FILL_STUB(Deinitialize); #undef FILL_STUB } @@ -808,6 +810,8 @@ void SDL_QuitAudio(void) return; } + current_audio.impl.DeinitializeStart(); + // Destroy any audio streams that still exist... while (current_audio.existing_streams != NULL) { SDL_DestroyAudioStream(current_audio.existing_streams); diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index c33ac9ce08..0d3ec6305a 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -141,6 +141,7 @@ typedef struct SDL_AudioDriverImpl void (*FlushCapture)(SDL_AudioDevice *device); void (*CloseDevice)(SDL_AudioDevice *device); void (*FreeDeviceHandle)(SDL_AudioDevice *device); // SDL is done with this device; free the handle from SDL_AddAudioDevice() + void (*DeinitializeStart)(void); // SDL calls this, then starts destroying objects, then calls Deinitialize. This is a good place to stop hotplug detection. void (*Deinitialize)(void); // Some flags to push duplicate code into the core and reduce #ifdefs. diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index c6f86d8460..ebc2b604c5 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -923,7 +923,7 @@ static void ALSA_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice #endif } -static void ALSA_Deinitialize(void) +static void ALSA_DeinitializeStart(void) { ALSA_Device *dev; ALSA_Device *next; @@ -944,7 +944,10 @@ static void ALSA_Deinitialize(void) SDL_free(dev); } hotplug_devices = NULL; +} +static void ALSA_Deinitialize(void) +{ UnloadALSALibrary(); } @@ -960,6 +963,7 @@ static SDL_bool ALSA_Init(SDL_AudioDriverImpl *impl) impl->GetDeviceBuf = ALSA_GetDeviceBuf; impl->PlayDevice = ALSA_PlayDevice; impl->CloseDevice = ALSA_CloseDevice; + impl->DeinitializeStart = ALSA_DeinitializeStart; impl->Deinitialize = ALSA_Deinitialize; impl->WaitCaptureDevice = ALSA_WaitDevice; impl->CaptureFromDevice = ALSA_CaptureFromDevice; diff --git a/src/audio/android/SDL_androidaudio.c b/src/audio/android/SDL_androidaudio.c index c0dade8acb..9d49ce9b8c 100644 --- a/src/audio/android/SDL_androidaudio.c +++ b/src/audio/android/SDL_androidaudio.c @@ -172,7 +172,7 @@ static SDL_bool ANDROIDAUDIO_Init(SDL_AudioDriverImpl *impl) // !!! FIXME: if on Android API < 24, DetectDevices and Deinitialize should be NULL and OnlyHasDefaultOutputDevice and OnlyHasDefaultCaptureDevice should be SDL_TRUE, since audio device enum and hotplug appears to require Android 7.0+. impl->ThreadInit = Android_AudioThreadInit; impl->DetectDevices = Android_StartAudioHotplug; - impl->Deinitialize = Android_StopAudioHotplug; + impl->DeinitializeStart = Android_StopAudioHotplug; impl->OpenDevice = ANDROIDAUDIO_OpenDevice; impl->PlayDevice = ANDROIDAUDIO_PlayDevice; impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf; diff --git a/src/audio/coreaudio/SDL_coreaudio.m b/src/audio/coreaudio/SDL_coreaudio.m index bbe37161bf..998bda154f 100644 --- a/src/audio/coreaudio/SDL_coreaudio.m +++ b/src/audio/coreaudio/SDL_coreaudio.m @@ -940,7 +940,7 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *device) return (device->hidden->thread != NULL) ? 0 : -1; } -static void COREAUDIO_Deinitialize(void) +static void COREAUDIO_DeinitializeStart(void) { #ifdef MACOSX_COREAUDIO AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &devlist_address, DeviceListChangedNotification, NULL); @@ -958,7 +958,7 @@ static SDL_bool COREAUDIO_Init(SDL_AudioDriverImpl *impl) impl->CaptureFromDevice = COREAUDIO_CaptureFromDevice; impl->FlushCapture = COREAUDIO_FlushCapture; impl->CloseDevice = COREAUDIO_CloseDevice; - impl->Deinitialize = COREAUDIO_Deinitialize; + impl->DeinitializeStart = COREAUDIO_DeinitializeStart; #ifdef MACOSX_COREAUDIO impl->DetectDevices = COREAUDIO_DetectDevices; diff --git a/src/audio/directsound/SDL_directsound.c b/src/audio/directsound/SDL_directsound.c index ad0d9db375..2a6bb47e7c 100644 --- a/src/audio/directsound/SDL_directsound.c +++ b/src/audio/directsound/SDL_directsound.c @@ -623,15 +623,21 @@ static int DSOUND_OpenDevice(SDL_AudioDevice *device) return 0; // good to go. } -static void DSOUND_Deinitialize(void) +static void DSOUND_DeinitializeStart(void) { #ifdef HAVE_MMDEVICEAPI_H if (SupportsIMMDevice) { SDL_IMMDevice_Quit(); - SupportsIMMDevice = SDL_FALSE; } #endif +} + +static void DSOUND_Deinitialize(void) +{ DSOUND_Unload(); +#ifdef HAVE_MMDEVICEAPI_H + SupportsIMMDevice = SDL_FALSE; +#endif } static SDL_bool DSOUND_Init(SDL_AudioDriverImpl *impl) @@ -654,6 +660,7 @@ static SDL_bool DSOUND_Init(SDL_AudioDriverImpl *impl) impl->FlushCapture = DSOUND_FlushCapture; impl->CloseDevice = DSOUND_CloseDevice; impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle; + impl->DeinitializeStart = DSOUND_DeinitializeStart; impl->Deinitialize = DSOUND_Deinitialize; impl->HasCaptureSupport = SDL_TRUE; diff --git a/src/audio/pipewire/SDL_pipewire.c b/src/audio/pipewire/SDL_pipewire.c index 0dda0d8cae..b5cbbe74c1 100644 --- a/src/audio/pipewire/SDL_pipewire.c +++ b/src/audio/pipewire/SDL_pipewire.c @@ -1234,10 +1234,16 @@ static void PIPEWIRE_CloseDevice(SDL_AudioDevice *device) SDL_AudioThreadFinalize(device); } -static void PIPEWIRE_Deinitialize(void) +static void PIPEWIRE_DeinitializeStart(void) { if (pipewire_initialized) { hotplug_loop_destroy(); + } +} + +static void PIPEWIRE_Deinitialize(void) +{ + if (pipewire_initialized) { deinit_pipewire_library(); pipewire_initialized = SDL_FALSE; } @@ -1261,6 +1267,7 @@ static SDL_bool PIPEWIRE_Init(SDL_AudioDriverImpl *impl) /* Set the function pointers */ impl->DetectDevices = PIPEWIRE_DetectDevices; impl->OpenDevice = PIPEWIRE_OpenDevice; + impl->DeinitializeStart = PIPEWIRE_DeinitializeStart; impl->Deinitialize = PIPEWIRE_Deinitialize; impl->PlayDevice = PIPEWIRE_PlayDevice; impl->GetDeviceBuf = PIPEWIRE_GetDeviceBuf; diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index 1ab099baa0..0703fc7401 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -968,7 +968,7 @@ static void PULSEAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_Audio SDL_DestroySemaphore(ready_sem); } -static void PULSEAUDIO_Deinitialize(void) +static void PULSEAUDIO_DeinitializeStart(void) { if (pulseaudio_hotplug_thread) { PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop); @@ -978,7 +978,10 @@ static void PULSEAUDIO_Deinitialize(void) SDL_WaitThread(pulseaudio_hotplug_thread, NULL); pulseaudio_hotplug_thread = NULL; } +} +static void PULSEAUDIO_Deinitialize(void) +{ DisconnectFromPulseServer(); SDL_free(default_sink_path); @@ -1010,6 +1013,7 @@ static SDL_bool PULSEAUDIO_Init(SDL_AudioDriverImpl *impl) impl->WaitDevice = PULSEAUDIO_WaitDevice; impl->GetDeviceBuf = PULSEAUDIO_GetDeviceBuf; impl->CloseDevice = PULSEAUDIO_CloseDevice; + impl->DeinitializeStart = PULSEAUDIO_DeinitializeStart; impl->Deinitialize = PULSEAUDIO_Deinitialize; impl->WaitCaptureDevice = PULSEAUDIO_WaitCaptureDevice; impl->CaptureFromDevice = PULSEAUDIO_CaptureFromDevice; diff --git a/src/audio/wasapi/SDL_wasapi.c b/src/audio/wasapi/SDL_wasapi.c index 42aa8ef577..86f504387b 100644 --- a/src/audio/wasapi/SDL_wasapi.c +++ b/src/audio/wasapi/SDL_wasapi.c @@ -714,6 +714,18 @@ static void WASAPI_FreeDeviceHandle(SDL_AudioDevice *device) WASAPI_ProxyToManagementThread(mgmtthrtask_FreeDeviceHandle, device, &rc); } +static int mgmtthrtask_DeinitializeStart(void *userdata) +{ + WASAPI_PlatformDeinitializeStart(void); + return 0; +} + +static void WASAPI_DeinitializeStart(void) +{ + int rc; + WASAPI_ProxyToManagementThread(mgmtthrtask_DeinitializeStart, NULL, &rc); +} + static void WASAPI_Deinitialize(void) { DeinitManagementThread(); @@ -736,6 +748,7 @@ static SDL_bool WASAPI_Init(SDL_AudioDriverImpl *impl) impl->CaptureFromDevice = WASAPI_CaptureFromDevice; impl->FlushCapture = WASAPI_FlushCapture; impl->CloseDevice = WASAPI_CloseDevice; + impl->DeinitializeStart = WASAPI_DeinitializeStart; impl->Deinitialize = WASAPI_Deinitialize; impl->FreeDeviceHandle = WASAPI_FreeDeviceHandle; diff --git a/src/audio/wasapi/SDL_wasapi.h b/src/audio/wasapi/SDL_wasapi.h index ba2870801b..00f80a08a3 100644 --- a/src/audio/wasapi/SDL_wasapi.h +++ b/src/audio/wasapi/SDL_wasapi.h @@ -58,6 +58,7 @@ int WASAPI_ProxyToManagementThread(ManagementThreadTask task, void *userdata, in // UNLESS OTHERWISE NOTED THESE ALL HAPPEN ON THE MANAGEMENT THREAD. int WASAPI_PlatformInit(void); void WASAPI_PlatformDeinit(void); +void WASAPI_PlatformDeinitializeStart(void); void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture); int WASAPI_ActivateDevice(SDL_AudioDevice *device); void WASAPI_PlatformThreadInit(SDL_AudioDevice *device); // this happens on the audio device thread, not the management thread. diff --git a/src/audio/wasapi/SDL_wasapi_win32.c b/src/audio/wasapi/SDL_wasapi_win32.c index 719ac94a3b..b43e07941c 100644 --- a/src/audio/wasapi/SDL_wasapi_win32.c +++ b/src/audio/wasapi/SDL_wasapi_win32.c @@ -44,15 +44,21 @@ typedef BOOL(WINAPI *pfnAvRevertMmThreadCharacteristics)(HANDLE); static pfnAvSetMmThreadCharacteristicsW pAvSetMmThreadCharacteristicsW = NULL; static pfnAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL; +static SDL_bool immdevice_initialized = SDL_FALSE; + /* Some GUIDs we need to know without linking to libraries that aren't available before Vista. */ static const IID SDL_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32, { 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2 } }; int WASAPI_PlatformInit(void) { - if (SDL_IMMDevice_Init() < 0) { // this will call WIN_CoInitialize for us! - return -1; /* This is set by SDL_IMMDevice_Init */ + if (FAILED(WIN_CoInitialize())) { + return SDL_SetError("CoInitialize() failed"); + } else if (SDL_IMMDevice_Init() < 0) { + return -1; // Error string is set by SDL_IMMDevice_Init } + immdevice_initialized = SDL_TRUE; + libavrt = LoadLibrary(TEXT("avrt.dll")); /* this library is available in Vista and later. No WinXP, so have to LoadLibrary to use it for now! */ if (libavrt) { pAvSetMmThreadCharacteristicsW = (pfnAvSetMmThreadCharacteristicsW)GetProcAddress(libavrt, "AvSetMmThreadCharacteristicsW"); @@ -62,6 +68,14 @@ int WASAPI_PlatformInit(void) return 0; } +static void StopWasapiHotplug(void) +{ + if (immdevice_initialized) { + SDL_IMMDevice_Quit(); + immdevice_initialized = SDL_FALSE; + } +} + void WASAPI_PlatformDeinit(void) { if (libavrt) { @@ -72,7 +86,14 @@ void WASAPI_PlatformDeinit(void) pAvSetMmThreadCharacteristicsW = NULL; pAvRevertMmThreadCharacteristics = NULL; - SDL_IMMDevice_Quit(); // This will call WIN_CoUninitialize for us! + StopWasapiHotplug(); + + WIN_CoUninitialize(); +} + +void WASAPI_PlatformDeinitializeStart(void) +{ + StopWasapiHotplug(); } void WASAPI_PlatformThreadInit(SDL_AudioDevice *device) diff --git a/src/audio/wasapi/SDL_wasapi_winrt.cpp b/src/audio/wasapi/SDL_wasapi_winrt.cpp index a4030f39c2..c3701a8a5f 100644 --- a/src/audio/wasapi/SDL_wasapi_winrt.cpp +++ b/src/audio/wasapi/SDL_wasapi_winrt.cpp @@ -220,7 +220,7 @@ int WASAPI_PlatformInit(void) return 0; } -void WASAPI_PlatformDeinit(void) +static void StopWasapiHotplug(void) { delete playback_device_event_handler; playback_device_event_handler = nullptr; @@ -228,6 +228,17 @@ void WASAPI_PlatformDeinit(void) capture_device_event_handler = nullptr; } +void WASAPI_PlatformDeinit(void) +{ + StopWasapiHotplug(); +} + +void WASAPI_PlatformDeinitializeStart(void) +{ + StopWasapiHotplug(); +} + + void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture) { Platform::String ^ defdevid;