(XAudio) Replicate behavior of WASAPI - selecting the audio

device will set the samplerate set by the OS as well
NOTE: There is still something wrong with the XAudio2 driver
and the 'devices' it enumerates and shows in the menu. It seems
the index is wrong, i.e. the entries seem swapped around. This
was an issue even before this commit. WASAPI seems to work correctly
This commit is contained in:
libretroadmin 2025-08-04 05:31:47 +02:00
parent 780eac62e6
commit cb9ed749db
3 changed files with 98 additions and 16 deletions

View File

@ -184,6 +184,58 @@ char *mmdevice_name(void *data)
return result;
}
void *mmdevice_handle(int id, unsigned data_flow)
{
HRESULT hr;
IMMDeviceEnumerator *enumerator = NULL;
IMMDevice *device = NULL;
IMMDeviceCollection *collection = NULL;
const char *data_flow_name = mmdevice_data_flow_name(data_flow);
#ifdef __cplusplus
hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
IID_IMMDeviceEnumerator, (void **)&enumerator);
#else
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
&IID_IMMDeviceEnumerator, (void **)&enumerator);
#endif
if (FAILED(hr))
return NULL;
hr = _IMMDeviceEnumerator_EnumAudioEndpoints(enumerator,
data_flow, DEVICE_STATE_ACTIVE, &collection);
if (FAILED(hr))
{
RARCH_ERR("[MMDevice] Failed to enumerate audio endpoints: %s.\n", mmdevice_hresult_name(hr));
goto error;
}
hr = _IMMDeviceCollection_Item(collection, id, &device);
if (FAILED(hr))
{
RARCH_ERR("[MMDevice] Failed to get IMMDevice #%d: %s.\n", id, mmdevice_hresult_name(hr));
goto error;
}
return device;
error:
if (collection)
#ifdef __cplusplus
collection->Release();
#else
collection->lpVtbl->Release(collection);
#endif
if (enumerator)
#ifdef __cplusplus
enumerator->Release();
#else
enumerator->lpVtbl->Release(enumerator);
#endif
collection = NULL;
enumerator = NULL;
return NULL;
}
void *mmdevice_init_device(const char *id, unsigned data_flow)
{
HRESULT hr;
@ -225,13 +277,14 @@ void *mmdevice_init_device(const char *id, unsigned data_flow)
if (list->elems)
{
/* If any devices were found... */
size_t d;
/* If any devices were found... */
for (d = 0; d < list->size; d++)
{
if (string_is_equal(id, list->elems[d].data))
{
RARCH_DBG("[MMDevice] Found device #%d: \"%s\".\n", d, list->elems[d].data);
RARCH_DBG("[MMDevice] Found device #%d: \"%s\".\n", d,
list->elems[d].data);
idx_found = d;
break;
}
@ -242,7 +295,8 @@ void *mmdevice_init_device(const char *id, unsigned data_flow)
if (idx_found == -1 && isdigit(id[0]))
{
idx_found = strtoul(id, NULL, 0);
RARCH_LOG("[MMDevice] Fallback, %s device index is a single number index instead: %u.\n", data_flow_name, idx_found);
RARCH_LOG("[MMDevice] Fallback, %s device index is a single number index instead: %u.\n",
data_flow_name, idx_found);
}
}
string_list_free(list);

View File

@ -35,6 +35,11 @@ char* mmdevice_name(void *data);
*/
size_t mmdevice_samplerate(void *data);
/**
* Gets the handle of the IMMDevice.
*/
void *mmdevice_handle(int id, unsigned data_flow);
const char *mmdevice_hresult_name(int hr);

View File

@ -14,8 +14,9 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(_XBOX) && (_MSC_VER == 1310)
#if !defined(_XBOX) && (_MSC_VER == 1310) || defined(_MSC_VER) && (_WIN32_WINNT <= _WIN32_WINNT_WIN2K)
#ifndef _WIN32_DCOM
/* needed for CoInitializeEx */
#define _WIN32_DCOM
#endif
#endif
@ -31,11 +32,6 @@
#include <encodings/utf.h>
#include <lists/string_list.h>
#if defined(_MSC_VER) && (_WIN32_WINNT <= _WIN32_WINNT_WIN2K)
/* needed for CoInitializeEx */
#define _WIN32_DCOM
#endif
#include "xaudio.h"
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600 /*_WIN32_WINNT_VISTA */)
@ -46,6 +42,7 @@
#ifdef HAVE_MMDEVICE
#include "../common/mmdevice_common.h"
#include "../common/mmdevice_common_inline.h"
#endif
#include "../audio_driver.h"
@ -221,6 +218,27 @@ static const char *xaudio2_wave_format_name(WAVEFORMATEX *format)
return "<unknown>";
}
static size_t xa_device_get_samplerate(int id)
{
#ifdef HAVE_MMDEVICE
IMMDevice *device = (IMMDevice*)mmdevice_handle(id, 0 /* eRender */);
if (device)
{
size_t _len = mmdevice_samplerate(device);
#ifdef __cplusplus
device->Release();
#else
device->lpVtbl->Release(device);
#endif
return _len;
}
#else
/* TODO/FIXME - implement */
(void)0;
#endif
return 0;
}
static xaudio2_t *xaudio2_new(unsigned *rate, unsigned channels,
unsigned latency, size_t len, const char *dev_id)
{
@ -277,22 +295,27 @@ static xaudio2_t *xaudio2_new(unsigned *rate, unsigned channels,
{
if (string_is_equal(dev_id, list->elems[i].data))
{
size_t new_rate = 0;
RARCH_DBG("[XAudio2] Found device #%d: \"%s\".\n", i,
list->elems[i].data);
idx_found = i;
idx_found = i;
new_rate = xa_device_get_samplerate(i);
if (new_rate > 0)
{
xaudio2_set_format(&desired_wf, true, channels, new_rate);
*rate = desired_wf.nSamplesPerSec;
}
break;
}
}
/* Index was not found yet based on name string,
* just assume id is a one-character number index. */
if (idx_found == -1)
if (idx_found == -1 && isdigit(dev_id[0]))
{
if (isdigit(dev_id[0]))
{
idx_found = strtoul(dev_id, NULL, 0);
RARCH_LOG("[XAudio2] Fallback, device index is a single number index instead: %d.\n", idx_found);
}
idx_found = strtoul(dev_id, NULL, 0);
RARCH_LOG("[XAudio2] Fallback, device index is a single number index instead: %d.\n",
idx_found);
}
}
}