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.
|
// 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 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)
|
static int mgmtthrtask_DefaultAudioDeviceChanged(void *userdata)
|
||||||
{
|
{
|
||||||
SDL_DefaultAudioDeviceChanged((SDL_AudioDevice *) userdata);
|
SDL_DefaultAudioDeviceChanged((SDL_AudioDevice *) userdata);
|
||||||
@@ -62,9 +74,10 @@ static void WASAPI_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device
|
|||||||
|
|
||||||
int WASAPI_PlatformInit(void)
|
int WASAPI_PlatformInit(void)
|
||||||
{
|
{
|
||||||
|
const SDL_IMMDevice_callbacks callbacks = { WASAPI_AudioDeviceDisconnected, WASAPI_DefaultAudioDeviceChanged };
|
||||||
if (FAILED(WIN_CoInitialize())) {
|
if (FAILED(WIN_CoInitialize())) {
|
||||||
return SDL_SetError("CoInitialize() failed");
|
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
|
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. */
|
/* This is global to the WASAPI target, to handle hotplug and default device lookup. */
|
||||||
static IMMDeviceEnumerator *enumerator = NULL;
|
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. */
|
/* 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
|
#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)
|
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDefaultDeviceChanged(IMMNotificationClient *iclient, EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId)
|
||||||
{
|
{
|
||||||
if (role == SDL_IMMDevice_role) {
|
if (role == SDL_IMMDevice_role) {
|
||||||
if (devchangecallback) {
|
immcallbacks.default_audio_device_changed(SDL_IMMDevice_FindByDevID(pwstrDeviceId));
|
||||||
devchangecallback(SDL_IMMDevice_FindByDevID(pwstrDeviceId));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
@@ -247,7 +245,7 @@ static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceStateChanged(IM
|
|||||||
SDL_free(utf8dev);
|
SDL_free(utf8dev);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SDL_AudioDeviceDisconnected(SDL_IMMDevice_FindByDevID(pwstrDeviceId));
|
immcallbacks.audio_device_disconnected(SDL_IMMDevice_FindByDevID(pwstrDeviceId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IMMEndpoint_Release(endpoint);
|
IMMEndpoint_Release(endpoint);
|
||||||
@@ -276,7 +274,7 @@ static const IMMNotificationClientVtbl notification_client_vtbl = {
|
|||||||
|
|
||||||
static SDLMMNotificationClient notification_client = { ¬ification_client_vtbl, { 1 } };
|
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;
|
HRESULT ret;
|
||||||
|
|
||||||
@@ -295,7 +293,18 @@ int SDL_IMMDevice_Init(SDL_IMMDevice_DefaultAudioDeviceChanged devchanged)
|
|||||||
return WIN_SetErrorFromHRESULT("IMMDevice CoCreateInstance(MMDeviceEnumerator)", ret);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -308,7 +317,7 @@ void SDL_IMMDevice_Quit(void)
|
|||||||
enumerator = NULL;
|
enumerator = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
devchangecallback = NULL;
|
SDL_zero(immcallbacks);
|
||||||
|
|
||||||
WIN_CoUninitialize();
|
WIN_CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,13 @@
|
|||||||
|
|
||||||
typedef struct SDL_AudioDevice SDL_AudioDevice; // this is defined in src/audio/SDL_sysaudio.h
|
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);
|
void SDL_IMMDevice_Quit(void);
|
||||||
int SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, SDL_bool iscapture);
|
int SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, SDL_bool iscapture);
|
||||||
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture);
|
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture);
|
||||||
|
|||||||
Reference in New Issue
Block a user