wasapi: Don't crash/hang if transitioning to/from a Remote Desktop Connection.

Fixes #9673.
This commit is contained in:
Ryan C. Gordon 2025-01-05 20:54:15 -05:00
parent 742f2a2fad
commit d16f76e3d4
2 changed files with 13 additions and 6 deletions

View file

@ -353,14 +353,18 @@ static void WASAPI_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDe
static bool mgmtthrtask_DisconnectDevice(void *userdata) static bool mgmtthrtask_DisconnectDevice(void *userdata)
{ {
SDL_AudioDeviceDisconnected((SDL_AudioDevice *)userdata); SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
SDL_AudioDeviceDisconnected(device);
UnrefPhysicalAudioDevice(device);
return true; return true;
} }
void WASAPI_DisconnectDevice(SDL_AudioDevice *device) void WASAPI_DisconnectDevice(SDL_AudioDevice *device)
{ {
bool rc; // block on this; don't disconnect while holding the device lock! if (SDL_CompareAndSwapAtomicInt(&device->hidden->device_disconnecting, 0, 1)) {
WASAPI_ProxyToManagementThread(mgmtthrtask_DisconnectDevice, device, &rc); RefPhysicalAudioDevice(device); // will unref when the task ends.
WASAPI_ProxyToManagementThread(mgmtthrtask_DisconnectDevice, device, NULL);
}
} }
static bool WasapiFailed(SDL_AudioDevice *device, const HRESULT err) static bool WasapiFailed(SDL_AudioDevice *device, const HRESULT err)
@ -503,8 +507,10 @@ static bool RecoverWasapiDevice(SDL_AudioDevice *device)
static bool RecoverWasapiIfLost(SDL_AudioDevice *device) static bool RecoverWasapiIfLost(SDL_AudioDevice *device)
{ {
if (SDL_GetAtomicInt(&device->shutdown)) { if (SDL_GetAtomicInt(&device->shutdown)) {
return false; // already failed. return false; // closing, stop trying.
} else if (device->hidden->device_dead) { // had a fatal error elsewhere, clean up and quit } else if (SDL_GetAtomicInt(&device->hidden->device_disconnecting)) {
return false; // failing via the WASAPI management thread, stop trying.
} else if (device->hidden->device_dead) { // had a fatal error elsewhere, clean up and quit
IAudioClient_Stop(device->hidden->client); IAudioClient_Stop(device->hidden->client);
WASAPI_DisconnectDevice(device); WASAPI_DisconnectDevice(device);
SDL_assert(SDL_GetAtomicInt(&device->shutdown)); // so we don't come back through here. SDL_assert(SDL_GetAtomicInt(&device->shutdown)); // so we don't come back through here.
@ -541,7 +547,7 @@ static Uint8 *WASAPI_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
static bool WASAPI_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen) static bool WASAPI_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{ {
if (device->hidden->render) { // definitely activated? if (device->hidden->render && !SDL_GetAtomicInt(&device->hidden->device_disconnecting)) { // definitely activated?
// WasapiFailed() will mark the device for reacquisition or removal elsewhere. // WasapiFailed() will mark the device for reacquisition or removal elsewhere.
WasapiFailed(device, IAudioRenderClient_ReleaseBuffer(device->hidden->render, device->sample_frames, 0)); WasapiFailed(device, IAudioRenderClient_ReleaseBuffer(device->hidden->render, device->sample_frames, 0));
} }

View file

@ -40,6 +40,7 @@ struct SDL_PrivateAudioData
HANDLE task; HANDLE task;
bool coinitialized; bool coinitialized;
int framesize; int framesize;
SDL_AtomicInt device_disconnecting;
bool device_lost; bool device_lost;
bool device_dead; bool device_dead;
}; };