diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h index f21e25161f..a3c5cced02 100644 --- a/include/SDL3/SDL_events.h +++ b/include/SDL3/SDL_events.h @@ -185,8 +185,9 @@ typedef enum SDL_EVENT_DROP_POSITION, /**< Position while moving over the window */ /* Audio hotplug events */ - SDL_EVENT_AUDIO_DEVICE_ADDED = 0x1100, /**< A new audio device is available */ - SDL_EVENT_AUDIO_DEVICE_REMOVED, /**< An audio device has been removed. */ + SDL_EVENT_AUDIO_DEVICE_ADDED = 0x1100, /**< A new audio device is available */ + SDL_EVENT_AUDIO_DEVICE_REMOVED, /**< An audio device has been removed. */ + SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED, /**< An audio device's format has been changed by the system. */ /* Sensor events */ SDL_EVENT_SENSOR_UPDATE = 0x1200, /**< A sensor was updated */ @@ -491,9 +492,9 @@ typedef struct SDL_GamepadSensorEvent */ typedef struct SDL_AudioDeviceEvent { - Uint32 type; /**< ::SDL_EVENT_AUDIO_DEVICE_ADDED, or ::SDL_EVENT_AUDIO_DEVICE_REMOVED */ + Uint32 type; /**< ::SDL_EVENT_AUDIO_DEVICE_ADDED, or ::SDL_EVENT_AUDIO_DEVICE_REMOVED, or ::SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED */ Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ - SDL_AudioDeviceID which; /**< SDL_AudioDeviceID for the device being added or removed */ + SDL_AudioDeviceID which; /**< SDL_AudioDeviceID for the device being added or removed or changing */ Uint8 iscapture; /**< zero if an output device, non-zero if a capture device. */ Uint8 padding1; Uint8 padding2; diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 52ee69d26a..f2a2e4d17e 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -1797,6 +1797,7 @@ void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device) SDL_AudioSpec spec; SDL_bool needs_migration = SDL_FALSE; SDL_zero(spec); + for (SDL_LogicalAudioDevice *logdev = current_default_device->logical_devices; logdev != NULL; logdev = logdev->next) { if (logdev->opened_as_default) { needs_migration = SDL_TRUE; @@ -1824,6 +1825,8 @@ void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device) } if (needs_migration) { + const SDL_bool spec_changed = !AUDIO_SPECS_EQUAL(current_default_device->spec, new_default_device->spec); + const SDL_bool post_fmt_event = (spec_changed && SDL_EventEnabled(SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED)) ? SDL_TRUE : SDL_FALSE; SDL_LogicalAudioDevice *next = NULL; for (SDL_LogicalAudioDevice *logdev = current_default_device->logical_devices; logdev != NULL; logdev = next) { next = logdev->next; @@ -1852,6 +1855,17 @@ void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device) logdev->prev = NULL; logdev->next = new_default_device->logical_devices; new_default_device->logical_devices = logdev; + + // Post an event for each logical device we moved. + if (post_fmt_event) { + SDL_Event event; + SDL_zero(event); + event.type = SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED; + event.common.timestamp = 0; + event.adevice.iscapture = iscapture ? 1 : 0; + event.adevice.which = logdev->instance_id; + SDL_PushEvent(&event); + } } current_default_device->simple_copy = AudioDeviceCanUseSimpleCopy(current_default_device); @@ -1883,13 +1897,15 @@ int SDL_AudioDeviceFormatChangedAlreadyLocked(SDL_AudioDevice *device, const SDL const int orig_work_buffer_size = device->work_buffer_size; const SDL_bool iscapture = device->iscapture; - if ((device->spec.format != newspec->format) || (device->spec.channels != newspec->channels) || (device->spec.freq != newspec->freq)) { - SDL_memcpy(&device->spec, newspec, sizeof (*newspec)); - for (SDL_LogicalAudioDevice *logdev = device->logical_devices; !kill_device && (logdev != NULL); logdev = logdev->next) { - for (SDL_AudioStream *stream = logdev->bound_streams; !kill_device && (stream != NULL); stream = stream->next_binding) { - if (SDL_SetAudioStreamFormat(stream, iscapture ? &device->spec : NULL, iscapture ? NULL : &device->spec) == -1) { - kill_device = SDL_TRUE; - } + if (AUDIO_SPECS_EQUAL(device->spec, *newspec)) { + return 0; // we're already in that format. + } + + SDL_memcpy(&device->spec, newspec, sizeof (*newspec)); + for (SDL_LogicalAudioDevice *logdev = device->logical_devices; !kill_device && (logdev != NULL); logdev = logdev->next) { + for (SDL_AudioStream *stream = logdev->bound_streams; !kill_device && (stream != NULL); stream = stream->next_binding) { + if (SDL_SetAudioStreamFormat(stream, iscapture ? &device->spec : NULL, iscapture ? NULL : &device->spec) == -1) { + kill_device = SDL_TRUE; } } } @@ -1923,6 +1939,21 @@ int SDL_AudioDeviceFormatChangedAlreadyLocked(SDL_AudioDevice *device, const SDL } } + // Post an event for the physical device, and each logical device on this physical device. + if (!kill_device && SDL_EventEnabled(SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED)) { + SDL_Event event; + SDL_zero(event); + event.type = SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED; + event.common.timestamp = 0; + event.adevice.iscapture = device->iscapture ? 1 : 0; + event.adevice.which = device->instance_id; + SDL_PushEvent(&event); + for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev != NULL; logdev = logdev->next) { + event.adevice.which = logdev->instance_id; + SDL_PushEvent(&event); + } + } + return kill_device ? -1 : 0; } diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c index fa680974dc..eefc61101a 100644 --- a/src/audio/SDL_audiocvt.c +++ b/src/audio/SDL_audiocvt.c @@ -29,8 +29,6 @@ #define SDL_INT_MAX ((int)(~0u>>1)) #endif -#define AUDIO_SPECS_EQUAL(x, y) (((x).format == (y).format) && ((x).channels == (y).channels) && ((x).freq == (y).freq)) - /* * CHANNEL LAYOUTS AS SDL EXPECTS THEM: * diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 3c859d83cd..6563978314 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -56,6 +56,8 @@ extern void (*SDL_Convert_F32_to_S32)(Sint32 *dst, const float *src, int num_sam #define DEFAULT_AUDIO_CAPTURE_CHANNELS 1 #define DEFAULT_AUDIO_CAPTURE_FREQUENCY 44100 +#define AUDIO_SPECS_EQUAL(x, y) (((x).format == (y).format) && ((x).channels == (y).channels) && ((x).freq == (y).freq)) + typedef struct SDL_AudioDevice SDL_AudioDevice; typedef struct SDL_LogicalAudioDevice SDL_LogicalAudioDevice; diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c index ac692faad7..24f40c6d55 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -440,6 +440,9 @@ static void SDL_LogEvent(const SDL_Event *event) SDL_EVENT_CASE(SDL_EVENT_AUDIO_DEVICE_REMOVED) PRINT_AUDIODEV_EVENT(event); break; + SDL_EVENT_CASE(SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED) + PRINT_AUDIODEV_EVENT(event); + break; #undef PRINT_AUDIODEV_EVENT SDL_EVENT_CASE(SDL_EVENT_SENSOR_UPDATE)