audio: Destroy all existing SDL_AudioStreams on shutdown.

main
Ryan C. Gordon 2023-09-20 10:47:11 -04:00
parent 62d4459972
commit f8fdb20d8f
No known key found for this signature in database
GPG Key ID: FA148B892AB48044
3 changed files with 54 additions and 4 deletions

View File

@ -137,6 +137,42 @@ static int GetDefaultSampleFramesFromFreq(const int freq)
} }
} }
void OnAudioStreamCreated(SDL_AudioStream *stream)
{
SDL_assert(SDL_GetCurrentAudioDriver() != NULL);
SDL_assert(stream != NULL);
// this isn't really part of the "device list" but it's a convenient lock to use here.
SDL_LockRWLockForWriting(current_audio.device_list_lock);
if (current_audio.existing_streams) {
current_audio.existing_streams->prev = stream;
}
stream->prev = NULL;
stream->next = current_audio.existing_streams;
current_audio.existing_streams = stream;
SDL_UnlockRWLock(current_audio.device_list_lock);
}
void OnAudioStreamDestroy(SDL_AudioStream *stream)
{
SDL_assert(SDL_GetCurrentAudioDriver() != NULL);
SDL_assert(stream != NULL);
// this isn't really part of the "device list" but it's a convenient lock to use here.
SDL_LockRWLockForWriting(current_audio.device_list_lock);
if (stream->prev) {
stream->prev->next = stream->next;
}
if (stream->next) {
stream->next->prev = stream->prev;
}
if (stream == current_audio.existing_streams) {
current_audio.existing_streams = stream->next;
}
SDL_UnlockRWLock(current_audio.device_list_lock);
}
// device should be locked when calling this. // device should be locked when calling this.
static SDL_bool AudioDeviceCanUseSimpleCopy(SDL_AudioDevice *device) static SDL_bool AudioDeviceCanUseSimpleCopy(SDL_AudioDevice *device)
{ {
@ -657,7 +693,10 @@ void SDL_QuitAudio(void)
return; return;
} }
// !!! FIXME: Destroy all known audio streams, too. // Destroy any audio streams that still exist...
while (current_audio.existing_streams != NULL) {
SDL_DestroyAudioStream(current_audio.existing_streams);
}
// merge device lists so we don't have to duplicate work below. // merge device lists so we don't have to duplicate work below.
SDL_LockRWLockForWriting(current_audio.device_list_lock); SDL_LockRWLockForWriting(current_audio.device_list_lock);

View File

@ -430,6 +430,8 @@ SDL_AudioStream *SDL_CreateAudioStream(const SDL_AudioSpec *src_spec, const SDL_
return NULL; return NULL;
} }
OnAudioStreamCreated(retval);
if (SDL_SetAudioStreamFormat(retval, src_spec, dst_spec) == -1) { if (SDL_SetAudioStreamFormat(retval, src_spec, dst_spec) == -1) {
SDL_DestroyAudioStream(retval); SDL_DestroyAudioStream(retval);
return NULL; return NULL;
@ -1152,6 +1154,8 @@ void SDL_DestroyAudioStream(SDL_AudioStream *stream)
return; return;
} }
OnAudioStreamDestroy(stream);
const SDL_bool simplified = stream->simplified; const SDL_bool simplified = stream->simplified;
if (simplified) { if (simplified) {
SDL_assert(stream->bound_device->simplified); SDL_assert(stream->bound_device->simplified);

View File

@ -102,7 +102,7 @@ extern SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByCallback(SDL_bool (*callbac
extern void SDL_UpdatedAudioDeviceFormat(SDL_AudioDevice *device); extern void SDL_UpdatedAudioDeviceFormat(SDL_AudioDevice *device);
// Backends can call this to get a standardized name for a thread to power a specific audio device. // Backends can call this to get a standardized name for a thread to power a specific audio device.
char *SDL_GetAudioThreadName(SDL_AudioDevice *device, char *buf, size_t buflen); extern char *SDL_GetAudioThreadName(SDL_AudioDevice *device, char *buf, size_t buflen);
// These functions are the heart of the audio threads. Backends can call them directly if they aren't using the SDL-provided thread. // These functions are the heart of the audio threads. Backends can call them directly if they aren't using the SDL-provided thread.
@ -115,9 +115,12 @@ extern void SDL_CaptureAudioThreadShutdown(SDL_AudioDevice *device);
extern void SDL_AudioThreadFinalize(SDL_AudioDevice *device); extern void SDL_AudioThreadFinalize(SDL_AudioDevice *device);
// this gets used from the audio device threads. It has rules, don't use this if you don't know how to use it! // this gets used from the audio device threads. It has rules, don't use this if you don't know how to use it!
void ConvertAudio(int num_frames, const void *src, SDL_AudioFormat src_format, int src_channels, extern void ConvertAudio(int num_frames, const void *src, SDL_AudioFormat src_format, int src_channels,
void *dst, SDL_AudioFormat dst_format, int dst_channels, void* scratch); void *dst, SDL_AudioFormat dst_format, int dst_channels, void* scratch);
// Special case to let something in SDL_audiocvt.c access something in SDL_audio.c. Don't use this.
extern void OnAudioStreamCreated(SDL_AudioStream *stream);
extern void OnAudioStreamDestroy(SDL_AudioStream *stream);
typedef struct SDL_AudioDriverImpl typedef struct SDL_AudioDriverImpl
{ {
@ -151,6 +154,7 @@ typedef struct SDL_AudioDriver
SDL_RWLock *device_list_lock; // A mutex for device detection SDL_RWLock *device_list_lock; // A mutex for device detection
SDL_AudioDevice *output_devices; // the list of currently-available audio output devices. SDL_AudioDevice *output_devices; // the list of currently-available audio output devices.
SDL_AudioDevice *capture_devices; // the list of currently-available audio capture devices. SDL_AudioDevice *capture_devices; // the list of currently-available audio capture devices.
SDL_AudioStream *existing_streams; // a list of all existing SDL_AudioStreams.
SDL_AudioDeviceID default_output_device_id; SDL_AudioDeviceID default_output_device_id;
SDL_AudioDeviceID default_capture_device_id; SDL_AudioDeviceID default_capture_device_id;
SDL_AtomicInt output_device_count; SDL_AtomicInt output_device_count;
@ -191,6 +195,9 @@ struct SDL_AudioStream
SDL_LogicalAudioDevice *bound_device; SDL_LogicalAudioDevice *bound_device;
SDL_AudioStream *next_binding; SDL_AudioStream *next_binding;
SDL_AudioStream *prev_binding; SDL_AudioStream *prev_binding;
SDL_AudioStream *prev; // linked list of all existing streams (so we can free them on shutdown).
SDL_AudioStream *next; // linked list of all existing streams (so we can free them on shutdown).
}; };
/* Logical devices are an abstraction in SDL3; you can open the same physical /* Logical devices are an abstraction in SDL3; you can open the same physical