mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-05 19:08:12 +00:00
wasapi: Handle disconnect notifications from the management thread, too.
These are also pretty heavyweight, don't do them from the notification thread, which can deadlock everything.
This commit is contained in:
@@ -48,6 +48,18 @@ 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_AudioDeviceDisconnected(void *userdata)
|
||||
{
|
||||
SDL_AudioDeviceDisconnected((SDL_AudioDevice *)userdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void WASAPI_AudioDeviceDisconnected(SDL_AudioDevice *device)
|
||||
{
|
||||
// don't wait on this, IMMDevice's own thread needs to return or everything will deadlock.
|
||||
WASAPI_ProxyToManagementThread(mgmtthrtask_AudioDeviceDisconnected, device, NULL);
|
||||
}
|
||||
|
||||
static int mgmtthrtask_DefaultAudioDeviceChanged(void *userdata)
|
||||
{
|
||||
SDL_DefaultAudioDeviceChanged((SDL_AudioDevice *) userdata);
|
||||
@@ -62,9 +74,10 @@ static void WASAPI_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device
|
||||
|
||||
int WASAPI_PlatformInit(void)
|
||||
{
|
||||
const SDL_IMMDevice_callbacks callbacks = { WASAPI_AudioDeviceDisconnected, WASAPI_DefaultAudioDeviceChanged };
|
||||
if (FAILED(WIN_CoInitialize())) {
|
||||
return SDL_SetError("CoInitialize() failed");
|
||||
} else if (SDL_IMMDevice_Init(WASAPI_DefaultAudioDeviceChanged) < 0) {
|
||||
} else if (SDL_IMMDevice_Init(&callbacks) < 0) {
|
||||
return -1; // Error string is set by SDL_IMMDevice_Init
|
||||
}
|
||||
|
||||
|
@@ -37,7 +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;
|
||||
static SDL_IMMDevice_callbacks immcallbacks;
|
||||
|
||||
/* 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
|
||||
@@ -205,9 +205,7 @@ static ULONG STDMETHODCALLTYPE SDLMMNotificationClient_Release(IMMNotificationCl
|
||||
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDefaultDeviceChanged(IMMNotificationClient *iclient, EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId)
|
||||
{
|
||||
if (role == SDL_IMMDevice_role) {
|
||||
if (devchangecallback) {
|
||||
devchangecallback(SDL_IMMDevice_FindByDevID(pwstrDeviceId));
|
||||
}
|
||||
immcallbacks.default_audio_device_changed(SDL_IMMDevice_FindByDevID(pwstrDeviceId));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
@@ -247,7 +245,7 @@ static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceStateChanged(IM
|
||||
SDL_free(utf8dev);
|
||||
}
|
||||
} else {
|
||||
SDL_AudioDeviceDisconnected(SDL_IMMDevice_FindByDevID(pwstrDeviceId));
|
||||
immcallbacks.audio_device_disconnected(SDL_IMMDevice_FindByDevID(pwstrDeviceId));
|
||||
}
|
||||
}
|
||||
IMMEndpoint_Release(endpoint);
|
||||
@@ -276,7 +274,7 @@ static const IMMNotificationClientVtbl notification_client_vtbl = {
|
||||
|
||||
static SDLMMNotificationClient notification_client = { ¬ification_client_vtbl, { 1 } };
|
||||
|
||||
int SDL_IMMDevice_Init(SDL_IMMDevice_DefaultAudioDeviceChanged devchanged)
|
||||
int SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks)
|
||||
{
|
||||
HRESULT ret;
|
||||
|
||||
@@ -295,7 +293,18 @@ int SDL_IMMDevice_Init(SDL_IMMDevice_DefaultAudioDeviceChanged devchanged)
|
||||
return WIN_SetErrorFromHRESULT("IMMDevice CoCreateInstance(MMDeviceEnumerator)", ret);
|
||||
}
|
||||
|
||||
devchangecallback = devchanged ? devchanged : SDL_DefaultAudioDeviceChanged;
|
||||
if (callbacks) {
|
||||
SDL_copyp(&immcallbacks, callbacks);
|
||||
} else {
|
||||
SDL_zero(immcallbacks);
|
||||
}
|
||||
|
||||
if (!immcallbacks.audio_device_disconnected) {
|
||||
immcallbacks.audio_device_disconnected = SDL_AudioDeviceDisconnected;
|
||||
}
|
||||
if (!immcallbacks.default_audio_device_changed) {
|
||||
immcallbacks.default_audio_device_changed = SDL_DefaultAudioDeviceChanged;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -308,7 +317,7 @@ void SDL_IMMDevice_Quit(void)
|
||||
enumerator = NULL;
|
||||
}
|
||||
|
||||
devchangecallback = NULL;
|
||||
SDL_zero(immcallbacks);
|
||||
|
||||
WIN_CoUninitialize();
|
||||
}
|
||||
|
@@ -28,9 +28,13 @@
|
||||
|
||||
typedef struct SDL_AudioDevice SDL_AudioDevice; // this is defined in src/audio/SDL_sysaudio.h
|
||||
|
||||
typedef void (*SDL_IMMDevice_DefaultAudioDeviceChanged)(SDL_AudioDevice *new_default_device);
|
||||
typedef struct SDL_IMMDevice_callbacks
|
||||
{
|
||||
void (*audio_device_disconnected)(SDL_AudioDevice *device);
|
||||
void (*default_audio_device_changed)(SDL_AudioDevice *new_default_device);
|
||||
} SDL_IMMDevice_callbacks;
|
||||
|
||||
int SDL_IMMDevice_Init(SDL_IMMDevice_DefaultAudioDeviceChanged devchanged);
|
||||
int SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks);
|
||||
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);
|
||||
|
Reference in New Issue
Block a user