@@ -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
189206static 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
293310bool 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 );
0 commit comments