wasapi: Proxy default device change handling to management thread.
This does a ton of work that can deadlock, because several crucial WASAPI things that we want to do in response to this will block until the notification callback has returned, so we can't call them from the handler directly, or we'll be waiting until the thing that called us returns.main
parent
c45b5121ce
commit
9bec57309c
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue