SDL: audio: Report SDL_AUDIODEVICEREMOVED for unopened devices.

From 8ff738f234bd0150639a4fd07e5a53d2d9068bd2 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Tue, 26 Jul 2022 12:40:47 -0400
Subject: [PATCH] audio: Report SDL_AUDIODEVICEREMOVED for unopened devices.

Unopened devices, if removed, now send SDL_AUDIODEVICEREMOVED events with
a `which` field set to zero. Apps can use this to decide if they need to
refresh a list of devices being shown in an options menu, etc.

It's safe to call SDL_CloseAudioDevice(0), so even if they try to clean
up this bogus id, it should be safe.

Fixes #5199.
---
 src/audio/SDL_audio.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 949d650f8ce..e2f7412c994 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -527,6 +527,7 @@ SDL_RemoveAudioDevice(const SDL_bool iscapture, void *handle)
 {
     int device_index;
     SDL_AudioDevice *device = NULL;
+    SDL_bool device_was_opened = SDL_FALSE;
 
     SDL_LockMutex(current_audio.detectionLock);
     if (iscapture) {
@@ -539,10 +540,29 @@ SDL_RemoveAudioDevice(const SDL_bool iscapture, void *handle)
         device = open_devices[device_index];
         if (device != NULL && device->handle == handle)
         {
+            device_was_opened = SDL_TRUE;
             SDL_OpenedAudioDeviceDisconnected(device);
             break;
         }
     }
+
+    /* Devices that aren't opened, as of 2.24.0, will post an
+       SDL_AUDIODEVICEREMOVED event with the `which` field set to zero.
+       Apps can use this to decide if they need to refresh a list of
+       available devices instead of closing an opened one.
+       Note that opened devices will send the non-zero event in
+       SDL_OpenedAudioDeviceDisconnected(). */
+    if (!device_was_opened) {
+        if (SDL_GetEventState(SDL_AUDIODEVICEREMOVED) == SDL_ENABLE) {
+            SDL_Event event;
+            SDL_zero(event);
+            event.adevice.type = SDL_AUDIODEVICEREMOVED;
+            event.adevice.which = 0;
+            event.adevice.iscapture = iscapture ? 1 : 0;
+            SDL_PushEvent(&event);
+        }
+    }
+
     SDL_UnlockMutex(current_audio.detectionLock);
 
     current_audio.impl.FreeDeviceHandle(handle);