diff --git a/src/audio/directsound/SDL_directsound.c b/src/audio/directsound/SDL_directsound.c index 432e740f80..74fc522be4 100644 --- a/src/audio/directsound/SDL_directsound.c +++ b/src/audio/directsound/SDL_directsound.c @@ -647,7 +647,7 @@ static SDL_bool DSOUND_Init(SDL_AudioDriverImpl *impl) } #ifdef HAVE_MMDEVICEAPI_H - SupportsIMMDevice = !(SDL_IMMDevice_Init() < 0); + SupportsIMMDevice = !(SDL_IMMDevice_Init(NULL) < 0); #endif impl->DetectDevices = DSOUND_DetectDevices; diff --git a/src/audio/wasapi/SDL_wasapi_win32.c b/src/audio/wasapi/SDL_wasapi_win32.c index 19dfbd4d9b..b695154518 100644 --- a/src/audio/wasapi/SDL_wasapi_win32.c +++ b/src/audio/wasapi/SDL_wasapi_win32.c @@ -48,11 +48,22 @@ 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 } }; +static int mgmtthrtask_DefaultAudioDeviceChanged(void *userdata) +{ + SDL_DefaultAudioDeviceChanged((SDL_AudioDevice *) userdata); + return 0; +} + +static void WASAPI_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device) +{ + WASAPI_ProxyToManagementThread(mgmtthrtask_DetectDevices, new_default_device, NULL); // don't wait on this, IMMDevice's own thread needs to return or everything will deadlock. +} + int WASAPI_PlatformInit(void) { if (FAILED(WIN_CoInitialize())) { return SDL_SetError("CoInitialize() failed"); - } else if (SDL_IMMDevice_Init() < 0) { + } else if (SDL_IMMDevice_Init(WASAPI_DefaultAudioDeviceChanged) < 0) { return -1; // Error string is set by SDL_IMMDevice_Init } diff --git a/src/core/windows/SDL_immdevice.c b/src/core/windows/SDL_immdevice.c index 780eff40dd..583c71ff2e 100644 --- a/src/core/windows/SDL_immdevice.c +++ b/src/core/windows/SDL_immdevice.c @@ -37,6 +37,7 @@ static const ERole SDL_IMMDevice_role = eConsole; /* !!! FIXME: should this be e /* This is global to the WASAPI target, to handle hotplug and default device lookup. */ static IMMDeviceEnumerator *enumerator = NULL; +static SDL_IMMDevice_DefaultAudioDeviceChanged devchangecallback = NULL; /* PropVariantInit() is an inline function/macro in PropIdl.h that calls the C runtime's memset() directly. Use ours instead, to avoid dependency. */ #ifdef PropVariantInit @@ -204,7 +205,9 @@ static ULONG STDMETHODCALLTYPE SDLMMNotificationClient_Release(IMMNotificationCl static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDefaultDeviceChanged(IMMNotificationClient *iclient, EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) { if (role == SDL_IMMDevice_role) { - SDL_DefaultAudioDeviceChanged(SDL_IMMDevice_FindByDevID(pwstrDeviceId)); + if (devchangecallback) { + devchangecallback(SDL_IMMDevice_FindByDevID(pwstrDeviceId)); + } } return S_OK; } @@ -273,7 +276,7 @@ static const IMMNotificationClientVtbl notification_client_vtbl = { static SDLMMNotificationClient notification_client = { ¬ification_client_vtbl, { 1 } }; -int SDL_IMMDevice_Init(void) +int SDL_IMMDevice_Init(SDL_IMMDevice_DefaultAudioDeviceChanged devchanged) { HRESULT ret; @@ -291,6 +294,9 @@ int SDL_IMMDevice_Init(void) WIN_CoUninitialize(); return WIN_SetErrorFromHRESULT("IMMDevice CoCreateInstance(MMDeviceEnumerator)", ret); } + + devchangecallback = devchanged ? devchanged : SDL_DefaultAudioDeviceChanged; + return 0; } @@ -302,6 +308,8 @@ void SDL_IMMDevice_Quit(void) enumerator = NULL; } + devchangecallback = NULL; + WIN_CoUninitialize(); } diff --git a/src/core/windows/SDL_immdevice.h b/src/core/windows/SDL_immdevice.h index a190a7cf84..0b64d2f556 100644 --- a/src/core/windows/SDL_immdevice.h +++ b/src/core/windows/SDL_immdevice.h @@ -28,7 +28,9 @@ typedef struct SDL_AudioDevice SDL_AudioDevice; // this is defined in src/audio/SDL_sysaudio.h -int SDL_IMMDevice_Init(void); +typedef void (*SDL_IMMDevice_DefaultAudioDeviceChanged)(SDL_AudioDevice *new_default_device); + +int SDL_IMMDevice_Init(SDL_IMMDevice_DefaultAudioDeviceChanged devchanged); void SDL_IMMDevice_Quit(void); int SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, SDL_bool iscapture); void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture);