Initial port to SDL3 audio subsystem

This commit is contained in:
Joshua T. Fisher
2025-11-02 21:29:58 -08:00
committed by Ryan C. Gordon
parent 05ce978e18
commit 641deb9c0e
5 changed files with 56 additions and 11 deletions
+42 -8
View File
@@ -120,7 +120,7 @@ void SDL_IMMDevice_FreeDeviceHandle(SDL_AudioDevice *device)
}
}
static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid, GUID *dsoundguid, SDL_AudioFormat force_format)
static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid, GUID *dsoundguid, SDL_AudioFormat force_format, bool supports_recording_playback_devices)
{
/* You can have multiple endpoints on a device that are mutually exclusive ("Speakers" vs "Line Out" or whatever).
In a perfect world, things that are unplugged won't be in this collection. The only gotcha is probably for
@@ -165,6 +165,22 @@ static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devn
spec.format = (force_format != SDL_AUDIO_UNKNOWN) ? force_format : SDL_WaveFormatExToSDLFormat((WAVEFORMATEX *)fmt);
device = SDL_AddAudioDevice(recording, devname, &spec, handle);
if (!recording && supports_recording_playback_devices) {
// handle is freed by SDL_IMMDevice_FreeDeviceHandle!
SDL_IMMDevice_HandleData *recording_handle = (SDL_IMMDevice_HandleData *)SDL_malloc(sizeof(SDL_IMMDevice_HandleData));
if (!recording_handle) {
return NULL;
}
SDL_memcpy(&recording_handle->directsound_guid, dsoundguid, sizeof(GUID));
recording_handle->immdevice_id = SDL_wcsdup(devid);
if (!recording_handle->immdevice_id || !SDL_AddAudioDevice(true, devname, &spec, recording_handle)) {
SDL_free(recording_handle);
}
}
if (!device) {
SDL_free(handle->immdevice_id);
SDL_free(handle);
@@ -184,6 +200,7 @@ typedef struct SDLMMNotificationClient
const IMMNotificationClientVtbl *lpVtbl;
SDL_AtomicInt refcount;
SDL_AudioFormat force_format;
bool supports_recording_playback_devices;
} SDLMMNotificationClient;
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_QueryInterface(IMMNotificationClient *client, REFIID iid, void **ppv)
@@ -257,7 +274,7 @@ static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceStateChanged(IM
GUID dsoundguid;
GetMMDeviceInfo(device, &utf8dev, &fmt, &dsoundguid);
if (utf8dev) {
SDL_IMMDevice_Add(recording, utf8dev, &fmt, pwstrDeviceId, &dsoundguid, client->force_format);
SDL_IMMDevice_Add(recording, utf8dev, &fmt, pwstrDeviceId, &dsoundguid, client->force_format, client->supports_recording_playback_devices);
SDL_free(utf8dev);
}
} else {
@@ -288,7 +305,7 @@ static const IMMNotificationClientVtbl notification_client_vtbl = {
SDLMMNotificationClient_OnPropertyValueChanged
};
static SDLMMNotificationClient notification_client = { &notification_client_vtbl, { 1 }, SDL_AUDIO_UNKNOWN };
static SDLMMNotificationClient notification_client = { &notification_client_vtbl, { 1 }, SDL_AUDIO_UNKNOWN, false };
bool SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks)
{
@@ -365,7 +382,23 @@ bool SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, bool reco
return true;
}
static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **default_device, SDL_AudioFormat force_format)
bool SDL_IMMDevice_GetIsCapture(IMMDevice *device)
{
bool iscapture = false;
IMMEndpoint *endpoint = NULL;
if (SUCCEEDED(IMMDevice_QueryInterface(device, &SDL_IID_IMMEndpoint, (void **)&endpoint))) {
EDataFlow flow;
if (SUCCEEDED(IMMEndpoint_GetDataFlow(endpoint, &flow))) {
iscapture = (flow == eCapture);
}
}
IMMEndpoint_Release(endpoint);
return iscapture;
}
static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **default_device, SDL_AudioFormat force_format, bool supports_recording_playback_devices)
{
/* Note that WASAPI separates "adapter devices" from "audio endpoint devices"
...one adapter device ("SoundBlaster Pro") might have multiple endpoint devices ("Speakers", "Line-Out"). */
@@ -407,7 +440,7 @@ static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **de
SDL_zero(dsoundguid);
GetMMDeviceInfo(immdevice, &devname, &fmt, &dsoundguid);
if (devname) {
SDL_AudioDevice *sdldevice = SDL_IMMDevice_Add(recording, devname, &fmt, devid, &dsoundguid, force_format);
SDL_AudioDevice *sdldevice = SDL_IMMDevice_Add(recording, devname, &fmt, devid, &dsoundguid, force_format, supports_recording_playback_devices);
if (default_device && default_devid && SDL_wcscmp(default_devid, devid) == 0) {
*default_device = sdldevice;
}
@@ -424,12 +457,13 @@ static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **de
IMMDeviceCollection_Release(collection);
}
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording, SDL_AudioFormat force_format)
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording, SDL_AudioFormat force_format, bool supports_recording_playback_devices)
{
EnumerateEndpointsForFlow(false, default_playback, force_format);
EnumerateEndpointsForFlow(true, default_recording, force_format);
EnumerateEndpointsForFlow(false, default_playback, force_format, supports_recording_playback_devices);
EnumerateEndpointsForFlow(true, default_recording, force_format, supports_recording_playback_devices);
notification_client.force_format = force_format;
notification_client.supports_recording_playback_devices = supports_recording_playback_devices;
// if this fails, we just won't get hotplug events. Carry on anyhow.
IMMDeviceEnumerator_RegisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *)&notification_client);
+2 -1
View File
@@ -37,7 +37,8 @@ typedef struct SDL_IMMDevice_callbacks
bool SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks);
void SDL_IMMDevice_Quit(void);
bool SDL_IMMDevice_Get(struct SDL_AudioDevice *device, IMMDevice **immdevice, bool recording);
void SDL_IMMDevice_EnumerateEndpoints(struct SDL_AudioDevice **default_playback, struct SDL_AudioDevice **default_recording, SDL_AudioFormat force_format);
bool SDL_IMMDevice_GetIsCapture(IMMDevice* device);
void SDL_IMMDevice_EnumerateEndpoints(struct SDL_AudioDevice **default_playback, struct SDL_AudioDevice **default_recording, SDL_AudioFormat force_format, bool supports_recording_playback_devices);
LPGUID SDL_IMMDevice_GetDirectSoundGUID(struct SDL_AudioDevice *device);
LPCWSTR SDL_IMMDevice_GetDevID(struct SDL_AudioDevice *device);
void SDL_IMMDevice_FreeDeviceHandle(struct SDL_AudioDevice *device);