Skip to content

Commit 641deb9

Browse files
playmericculus
authored andcommitted
Initial port to SDL3 audio subsystem
1 parent 05ce978 commit 641deb9

File tree

5 files changed

+56
-11
lines changed

5 files changed

+56
-11
lines changed

src/audio/directsound/SDL_directsound.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ static void DSOUND_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDe
206206
{
207207
#ifdef HAVE_MMDEVICEAPI_H
208208
if (SupportsIMMDevice) {
209-
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording, SDL_AUDIO_UNKNOWN);
209+
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording, SDL_AUDIO_UNKNOWN, false);
210210
} else
211211
#endif
212212
{

src/audio/wasapi/SDL_wasapi.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ static const IID SDL_IID_IAudioClient3 = { 0x7ed4ee07, 0x8e67, 0x4cd4, { 0x8c, 0
6262
#endif //
6363

6464
static bool immdevice_initialized = false;
65+
static bool supports_recording_on_playback_devices = false;
6566

6667
// WASAPI is _really_ particular about various things happening on the same thread, for COM and such,
6768
// so we proxy various stuff to a single background thread to manage.
@@ -329,7 +330,7 @@ typedef struct
329330
static bool mgmtthrtask_DetectDevices(void *userdata)
330331
{
331332
mgmtthrtask_DetectDevicesData *data = (mgmtthrtask_DetectDevicesData *)userdata;
332-
SDL_IMMDevice_EnumerateEndpoints(data->default_playback, data->default_recording, SDL_AUDIO_F32);
333+
SDL_IMMDevice_EnumerateEndpoints(data->default_playback, data->default_recording, SDL_AUDIO_F32, supports_recording_on_playback_devices);
333334
return true;
334335
}
335336

@@ -446,6 +447,8 @@ static bool mgmtthrtask_ActivateDevice(void *userdata)
446447
return false; // This is already set by SDL_IMMDevice_Get
447448
}
448449

450+
device->hidden->isplayback = !SDL_IMMDevice_GetIsCapture(immdevice);
451+
449452
// this is _not_ async in standard win32, yay!
450453
HRESULT ret = IMMDevice_Activate(immdevice, &SDL_IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&device->hidden->client);
451454
IMMDevice_Release(immdevice);
@@ -725,6 +728,11 @@ static bool mgmtthrtask_PrepDevice(void *userdata)
725728

726729
newspec.freq = waveformat->nSamplesPerSec;
727730

731+
if (device->recording && device->hidden->isplayback)
732+
{
733+
streamflags |= AUDCLNT_STREAMFLAGS_LOOPBACK;
734+
}
735+
728736
streamflags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
729737

730738
int new_sample_frames = 0;
@@ -978,6 +986,7 @@ static bool WASAPI_Init(SDL_AudioDriverImpl *impl)
978986
impl->FreeDeviceHandle = WASAPI_FreeDeviceHandle;
979987

980988
impl->HasRecordingSupport = true;
989+
supports_recording_on_playback_devices = SDL_GetHintBoolean(SDL_HINT_AUDIO_INCLUDE_MONITORS, false);
981990

982991
return true;
983992
}

src/audio/wasapi/SDL_wasapi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct SDL_PrivateAudioData
4343
SDL_AtomicInt device_disconnecting;
4444
bool device_lost;
4545
bool device_dead;
46+
bool isplayback;
4647
};
4748

4849
// win32 implementation calls into these.

src/core/windows/SDL_immdevice.c

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ void SDL_IMMDevice_FreeDeviceHandle(SDL_AudioDevice *device)
120120
}
121121
}
122122

123-
static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid, GUID *dsoundguid, SDL_AudioFormat force_format)
123+
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)
124124
{
125125
/* You can have multiple endpoints on a device that are mutually exclusive ("Speakers" vs "Line Out" or whatever).
126126
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
165165
spec.format = (force_format != SDL_AUDIO_UNKNOWN) ? force_format : SDL_WaveFormatExToSDLFormat((WAVEFORMATEX *)fmt);
166166

167167
device = SDL_AddAudioDevice(recording, devname, &spec, handle);
168+
169+
if (!recording && supports_recording_playback_devices) {
170+
// handle is freed by SDL_IMMDevice_FreeDeviceHandle!
171+
SDL_IMMDevice_HandleData *recording_handle = (SDL_IMMDevice_HandleData *)SDL_malloc(sizeof(SDL_IMMDevice_HandleData));
172+
if (!recording_handle) {
173+
return NULL;
174+
}
175+
176+
SDL_memcpy(&recording_handle->directsound_guid, dsoundguid, sizeof(GUID));
177+
recording_handle->immdevice_id = SDL_wcsdup(devid);
178+
179+
if (!recording_handle->immdevice_id || !SDL_AddAudioDevice(true, devname, &spec, recording_handle)) {
180+
SDL_free(recording_handle);
181+
}
182+
}
183+
168184
if (!device) {
169185
SDL_free(handle->immdevice_id);
170186
SDL_free(handle);
@@ -184,6 +200,7 @@ typedef struct SDLMMNotificationClient
184200
const IMMNotificationClientVtbl *lpVtbl;
185201
SDL_AtomicInt refcount;
186202
SDL_AudioFormat force_format;
203+
bool supports_recording_playback_devices;
187204
} SDLMMNotificationClient;
188205

189206
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_QueryInterface(IMMNotificationClient *client, REFIID iid, void **ppv)
@@ -257,7 +274,7 @@ static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceStateChanged(IM
257274
GUID dsoundguid;
258275
GetMMDeviceInfo(device, &utf8dev, &fmt, &dsoundguid);
259276
if (utf8dev) {
260-
SDL_IMMDevice_Add(recording, utf8dev, &fmt, pwstrDeviceId, &dsoundguid, client->force_format);
277+
SDL_IMMDevice_Add(recording, utf8dev, &fmt, pwstrDeviceId, &dsoundguid, client->force_format, client->supports_recording_playback_devices);
261278
SDL_free(utf8dev);
262279
}
263280
} else {
@@ -288,7 +305,7 @@ static const IMMNotificationClientVtbl notification_client_vtbl = {
288305
SDLMMNotificationClient_OnPropertyValueChanged
289306
};
290307

291-
static SDLMMNotificationClient notification_client = { &notification_client_vtbl, { 1 }, SDL_AUDIO_UNKNOWN };
308+
static SDLMMNotificationClient notification_client = { &notification_client_vtbl, { 1 }, SDL_AUDIO_UNKNOWN, false };
292309

293310
bool SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks)
294311
{
@@ -365,7 +382,23 @@ bool SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, bool reco
365382
return true;
366383
}
367384

368-
static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **default_device, SDL_AudioFormat force_format)
385+
bool SDL_IMMDevice_GetIsCapture(IMMDevice *device)
386+
{
387+
bool iscapture = false;
388+
IMMEndpoint *endpoint = NULL;
389+
if (SUCCEEDED(IMMDevice_QueryInterface(device, &SDL_IID_IMMEndpoint, (void **)&endpoint))) {
390+
EDataFlow flow;
391+
392+
if (SUCCEEDED(IMMEndpoint_GetDataFlow(endpoint, &flow))) {
393+
iscapture = (flow == eCapture);
394+
}
395+
}
396+
397+
IMMEndpoint_Release(endpoint);
398+
return iscapture;
399+
}
400+
401+
static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **default_device, SDL_AudioFormat force_format, bool supports_recording_playback_devices)
369402
{
370403
/* Note that WASAPI separates "adapter devices" from "audio endpoint devices"
371404
...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
407440
SDL_zero(dsoundguid);
408441
GetMMDeviceInfo(immdevice, &devname, &fmt, &dsoundguid);
409442
if (devname) {
410-
SDL_AudioDevice *sdldevice = SDL_IMMDevice_Add(recording, devname, &fmt, devid, &dsoundguid, force_format);
443+
SDL_AudioDevice *sdldevice = SDL_IMMDevice_Add(recording, devname, &fmt, devid, &dsoundguid, force_format, supports_recording_playback_devices);
411444
if (default_device && default_devid && SDL_wcscmp(default_devid, devid) == 0) {
412445
*default_device = sdldevice;
413446
}
@@ -424,12 +457,13 @@ static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **de
424457
IMMDeviceCollection_Release(collection);
425458
}
426459

427-
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording, SDL_AudioFormat force_format)
460+
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording, SDL_AudioFormat force_format, bool supports_recording_playback_devices)
428461
{
429-
EnumerateEndpointsForFlow(false, default_playback, force_format);
430-
EnumerateEndpointsForFlow(true, default_recording, force_format);
462+
EnumerateEndpointsForFlow(false, default_playback, force_format, supports_recording_playback_devices);
463+
EnumerateEndpointsForFlow(true, default_recording, force_format, supports_recording_playback_devices);
431464

432465
notification_client.force_format = force_format;
466+
notification_client.supports_recording_playback_devices = supports_recording_playback_devices;
433467

434468
// if this fails, we just won't get hotplug events. Carry on anyhow.
435469
IMMDeviceEnumerator_RegisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *)&notification_client);

src/core/windows/SDL_immdevice.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ typedef struct SDL_IMMDevice_callbacks
3737
bool SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks);
3838
void SDL_IMMDevice_Quit(void);
3939
bool SDL_IMMDevice_Get(struct SDL_AudioDevice *device, IMMDevice **immdevice, bool recording);
40-
void SDL_IMMDevice_EnumerateEndpoints(struct SDL_AudioDevice **default_playback, struct SDL_AudioDevice **default_recording, SDL_AudioFormat force_format);
40+
bool SDL_IMMDevice_GetIsCapture(IMMDevice* device);
41+
void SDL_IMMDevice_EnumerateEndpoints(struct SDL_AudioDevice **default_playback, struct SDL_AudioDevice **default_recording, SDL_AudioFormat force_format, bool supports_recording_playback_devices);
4142
LPGUID SDL_IMMDevice_GetDirectSoundGUID(struct SDL_AudioDevice *device);
4243
LPCWSTR SDL_IMMDevice_GetDevID(struct SDL_AudioDevice *device);
4344
void SDL_IMMDevice_FreeDeviceHandle(struct SDL_AudioDevice *device);

0 commit comments

Comments
 (0)