The device ID strings don't change between connects, so we need to move the
old device object out of the way if it still exists as a zombie, and let
the reconnected device get itself a fresh object.
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.
Almost nothing checks these return values, and there's no reason a valid
lock should fail to operate. The cases where a lock isn't valid (it's a
bogus pointer, it was previously destroyed, a thread is unlocking a lock it
doesn't own, etc) are undefined behavior and always were, and should be
treated as an application bug.
Reference Issue #8096.
ALSA expects handles to be of type ALSA_Device, and passing the handle for the default device as a plain string causes a crash as it attempts to deference the string contents itself as a pointer to a string.
Create immutable static ALSA_Device structs for the default devices and pass those as the handles. They are not placed in the hotplug list, and the audio layer doesn't attempt to free ALSA handles, so there is no need to worry about them being erroneously freed.
The string has a number after it, so a basic SDL_strcmp() will never match.
Reference PR #8346.
(cherry picked from commit cba6090398f581415938aa53c232142c85d23009)
(cherry picked from commit 62266dbd4fa79090025317a71473eb764b2e1abe)
(SDL3 audio backends don't have the LockDevice interfaces, so this just
ended up being a comment.)
It needs to be SDL_RELEASE_GENERIC, because it releases both exclusive
(writer) and shared (reader) locks.
Without this fix, clang's `-Wthread-safety` tests generate incorrect warnings.
Reference Issue #8096.
Both strings are _right there_ for comparing, so we can just set a flag to
note the device definitely changed.
Also simplified string management further; hotplug thread now makes a copy
of the string before releasing the lock if there was a change event, so when
the lock releases further events don't see a NULL and assume it's a new
device, causing a lot of work to ripple out and decide nothing has changed,
until the system stabilizes again. Now, it just does the right thing once.
We don't match dev->name by string, since we might use the same string for both capture and output devices. Instead use the device pointer itself as the handle.
@icculus, are we guaranteed the device pointer is valid in ALSA_OpenDevice()?
This fixes problems where Pulse callbacks don't fire in the order we expect,
or fail to fire at all, and avoids extra round trips to the Pulse server to
lookup information we could have trivially obtained already.
The end result is we would occasionally miss default device changes, etc, and
this resolves that better.
This ensures that we don't accidentally interpret an ID from one system as an ID in another system.
Audio device IDs are not covered here, since they have a unique numbering system.
This patch reverts the previous reversion, and then adds code to queue up
events to be sent the next time SDL pumps the event queue. This guarantees
that the event watcher/filter _never_ runs from an SDL audio device thread
or some other backend-specific internal thread.
This reverts commit 76f81797b7.
This worked in the normal cases, but:
A device thread that calls SDL_DisconnectAudioDevice due to failure will fire
the disconnect event from the device thread...and if there's an event watcher
that uses that moment to close the device, we still end up in the same
situation, where the device thread tries to join on itself.
Better solutions are still pending.
Otherwise, they risk the device thread joining on itself.
Now we make sure the reference is held at the logical device level until
the physical device is closed, so it can't destroy the device in normal
usage until the thread is joined, etc.