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 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.
Fully committing to it...!
This left SDL_wave.* alone for now, since there's a ton of comments in there
and this code hasn't changed much from SDL2 so far. But as SDL2 ages out a
little more, I'll likely switch this over, too.
First stage happens before we destroy objects, and is generally used to
shut down hotplug. The second stage is the usual deinit, which cleans up
the lowlevel API, unloads shared libraries, etc.
- No more tapdance to either join the audio device thread or have it detach
itself. Significant simplication of and fixes to the locking code to prevent
deadlocks.
- Physical devices now keep a refcount. Each logical device increments it,
as does the existence of a device thread, etc. Last unref destroys the
device and takes it out of the device_hash. Since there's a lot of moving
parts that might be holding a reference to a physical device, this seemed
like a safer way to protect the object.
- Disconnected devices now continue to function as zombie devices. Playback
devices will still consume data (and just throw it away), and capture devices
will continue to produce data (which always be silence). This helps apps
that don't handle disconnect events; the device still stops playing/capturing,
but bound audio streams will still consume data so they don't allocate more
data infinitely, and apps that depend on an audio callback firing regularly
to make progress won't hang.
Please note that disconnected audio devices must now be explicitly closed!
They always _should_ have been, but before this commit, SDL3 would destroy the
disconnected device for you (and manually closing afterwards was a safe no-op).
Reference Issue #8331.
Fixes#8386.
(and probably others).
All devices are in a single hash, whether playback or capture, or physical
or logical. Lookups are keyed on device ID and map to either
`SDL_AudioDevice *` for physical devices or `SDL_LogicalAudioDevice *` for
logical devices (as an implementation detail, you can determine which object
type you have by checking a specific bit in the device ID).
This simplifies a bunch of code, makes some cases significantly more
efficient, and solves the problem of having to lock each physical
device while the device list rwlock is held to find logical devices by ID.
Device IDs hash perfectly evenly, too, being incrementing integers.
The following objects now have properties that can be user modified:
* SDL_AudioStream
* SDL_Gamepad
* SDL_Joystick
* SDL_RWops
* SDL_Renderer
* SDL_Sensor
* SDL_Surface
* SDL_Texture
* SDL_Window
We need to do this early in the file, so that it will be taken into
account when deciding whether to define NEED_SCALAR_CONVERTER_FALLBACKS
and therefore provide a non-SIMD fallback.
Mitigates: https://github.com/libsdl-org/SDL/issues/8352
Signed-off-by: Simon McVittie <smcv@collabora.com>
This is an attempt to centralize all the error handling, instead of
implicitly counting on WaitDevice implementations to disconnect the device
to report an error.
This should retry until GetCurrentPosition succeeds. Otherwise, we would be
going on to the next iteration too soon.
Also generally streamlined the code while I was in here.
This prevents catastrophe if someone tries to close the device in an event
filter in response to the event.
Note that this means SDL_GetAudioStreamDevice() for any stream on this
device will return 0 during the event filter!
Fixes#8331.