mirror of
https://github.com/libretro/RetroArch
synced 2025-01-29 18:32:44 +00:00
(WASAPI) Shared buffer refactor + cleanup (#15929)
This commit is contained in:
parent
ee417c0f75
commit
598a0c0d37
@ -151,7 +151,35 @@ static const char* wasapi_data_flow_name(EDataFlow data_flow)
|
||||
}
|
||||
|
||||
static void wasapi_set_format(WAVEFORMATEXTENSIBLE *wf,
|
||||
bool float_fmt, unsigned rate, unsigned channels);
|
||||
bool float_fmt, unsigned rate, unsigned channels)
|
||||
{
|
||||
WORD wBitsPerSample = float_fmt ? 32 : 16;
|
||||
WORD nBlockAlign = (channels * wBitsPerSample) / 8;
|
||||
DWORD nAvgBytesPerSec = rate * nBlockAlign;
|
||||
|
||||
wf->Format.nChannels = channels;
|
||||
wf->Format.nSamplesPerSec = rate;
|
||||
wf->Format.nAvgBytesPerSec = nAvgBytesPerSec;
|
||||
wf->Format.nBlockAlign = nBlockAlign;
|
||||
wf->Format.wBitsPerSample = wBitsPerSample;
|
||||
|
||||
if (float_fmt)
|
||||
{
|
||||
wf->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
wf->Format.cbSize = sizeof(WORD) + sizeof(DWORD) + sizeof(GUID);
|
||||
wf->Samples.wValidBitsPerSample = wBitsPerSample;
|
||||
wf->dwChannelMask = channels == 1 ? KSAUDIO_SPEAKER_MONO : KSAUDIO_SPEAKER_STEREO;
|
||||
wf->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
wf->Format.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wf->Format.cbSize = 0;
|
||||
wf->Samples.wValidBitsPerSample = 0;
|
||||
wf->dwChannelMask = 0;
|
||||
memset(&wf->SubFormat, 0, sizeof(wf->SubFormat));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param[in] format The format to check.
|
||||
@ -186,6 +214,7 @@ static bool wasapi_is_format_suitable(const WAVEFORMATEXTENSIBLE *format)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects a sample format suitable for the given device.
|
||||
* @param[in,out] format The place where the chosen format will be written,
|
||||
@ -201,7 +230,7 @@ static bool wasapi_select_device_format(WAVEFORMATEXTENSIBLE *format, IAudioClie
|
||||
{
|
||||
static const unsigned preferred_rates[] = { 48000, 44100, 96000, 192000, 32000 };
|
||||
const bool preferred_formats[] = {format->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE, format->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE};
|
||||
/* Try the requested sample format first, then try the other one */
|
||||
/* Try the requested sample format first, then try the other one. */
|
||||
WAVEFORMATEXTENSIBLE *suggested_format = NULL;
|
||||
bool result = false;
|
||||
HRESULT hr = _IAudioClient_IsFormatSupported(
|
||||
@ -213,15 +242,13 @@ static bool wasapi_select_device_format(WAVEFORMATEXTENSIBLE *format, IAudioClie
|
||||
switch (hr)
|
||||
{
|
||||
case S_OK:
|
||||
/* The requested format is okay without any changes */
|
||||
RARCH_DBG("[WASAPI]: Desired format (%s, %u-channel, %uHz) can be used as-is.\n",
|
||||
wave_format_name(format), format->Format.nChannels, format->Format.nSamplesPerSec);
|
||||
/* The requested format is okay without any changes. */
|
||||
result = true;
|
||||
break;
|
||||
case S_FALSE:
|
||||
/* The requested format is unsupported, but Windows has suggested a similar one. */
|
||||
RARCH_DBG("[WASAPI]: Windows suggests a format of (%s, %u-channel, %uHz).\n",
|
||||
wave_format_name(suggested_format), suggested_format->Format.nChannels, suggested_format->Format.nSamplesPerSec);
|
||||
wave_format_name(suggested_format), suggested_format->Format.nChannels, suggested_format->Format.nSamplesPerSec);
|
||||
if (wasapi_is_format_suitable(suggested_format))
|
||||
{
|
||||
*format = *suggested_format;
|
||||
@ -234,10 +261,11 @@ static bool wasapi_select_device_format(WAVEFORMATEXTENSIBLE *format, IAudioClie
|
||||
}
|
||||
break;
|
||||
case AUDCLNT_E_UNSUPPORTED_FORMAT:
|
||||
{ /* The requested format is unsupported
|
||||
* and Windows was unable to suggest another.
|
||||
* Usually happens with exclusive mode.
|
||||
* RetroArch will try selecting a format. */
|
||||
{
|
||||
/* The requested format is unsupported
|
||||
* and Windows was unable to suggest another.
|
||||
* Usually happens with exclusive mode.
|
||||
* RetroArch will try selecting a format. */
|
||||
size_t i, j;
|
||||
WAVEFORMATEXTENSIBLE possible_format;
|
||||
HRESULT format_check_hr;
|
||||
@ -253,60 +281,29 @@ static bool wasapi_select_device_format(WAVEFORMATEXTENSIBLE *format, IAudioClie
|
||||
*format = possible_format;
|
||||
result = true;
|
||||
RARCH_DBG("[WASAPI]: RetroArch suggests a format of (%s, %u-channel, %uHz).\n",
|
||||
wave_format_name(format), format->Format.nChannels, format->Format.nSamplesPerSec);
|
||||
wave_format_name(format), format->Format.nChannels, format->Format.nSamplesPerSec);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
RARCH_ERR("[WASAPI]: Failed to select client format: No suitable format available\n");
|
||||
RARCH_ERR("[WASAPI]: Failed to select client format: No suitable format available.\n");
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Something else went wrong. */
|
||||
RARCH_ERR("[WASAPI]: Failed to select client format: %s\n", hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI]: Failed to select client format: %s.\n", hresult_name(hr));
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
done:
|
||||
/* IAudioClient::IsFormatSupported allocates a format object */
|
||||
/* IAudioClient::IsFormatSupported allocates a format object. */
|
||||
if (suggested_format)
|
||||
CoTaskMemFree(suggested_format);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void wasapi_set_format(WAVEFORMATEXTENSIBLE *wf,
|
||||
bool float_fmt, unsigned rate, unsigned channels)
|
||||
{
|
||||
WORD wBitsPerSample = float_fmt ? 32 : 16;
|
||||
WORD nBlockAlign = (channels * wBitsPerSample) / 8;
|
||||
DWORD nAvgBytesPerSec = rate * nBlockAlign;
|
||||
|
||||
wf->Format.nChannels = channels;
|
||||
wf->Format.nSamplesPerSec = rate;
|
||||
wf->Format.nAvgBytesPerSec = nAvgBytesPerSec;
|
||||
wf->Format.nBlockAlign = nBlockAlign;
|
||||
wf->Format.wBitsPerSample = wBitsPerSample;
|
||||
|
||||
if (float_fmt)
|
||||
{
|
||||
wf->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
wf->Format.cbSize = sizeof(WORD) + sizeof(DWORD) + sizeof(GUID);
|
||||
wf->Samples.wValidBitsPerSample = wBitsPerSample;
|
||||
wf->dwChannelMask = channels == 1 ? KSAUDIO_SPEAKER_MONO : KSAUDIO_SPEAKER_STEREO;
|
||||
wf->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
wf->Format.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wf->Format.cbSize = 0;
|
||||
wf->Samples.wValidBitsPerSample = 0;
|
||||
wf->dwChannelMask = 0;
|
||||
memset(&wf->SubFormat, 0, sizeof(wf->SubFormat));
|
||||
}
|
||||
}
|
||||
|
||||
static IAudioClient *wasapi_init_client_ex(IMMDevice *device,
|
||||
bool *float_fmt, unsigned *rate, unsigned latency, unsigned channels)
|
||||
{
|
||||
@ -320,59 +317,54 @@ static IAudioClient *wasapi_init_client_ex(IMMDevice *device,
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s\n", hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s.\n", hresult_name(hr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hr = _IAudioClient_GetDevicePeriod(client, NULL, &minimum_period);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to get device period of exclusive-mode client: %s\n", hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI]: Failed to get minimum device period of exclusive client: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* buffer_duration is in 100ns units */
|
||||
/* Buffer_duration is in 100ns units. */
|
||||
buffer_duration = latency * 10000.0;
|
||||
if (buffer_duration < minimum_period)
|
||||
buffer_duration = minimum_period;
|
||||
|
||||
wasapi_set_format(&wf, *float_fmt, *rate, channels);
|
||||
RARCH_DBG("[WASAPI]: Requesting format: %u-bit %u-channel client with %s samples at %uHz\n",
|
||||
wf.Format.wBitsPerSample,
|
||||
wf.Format.nChannels, wave_format_name(&wf), wf.Format.nSamplesPerSec);
|
||||
|
||||
if (wasapi_select_device_format(&wf, client, AUDCLNT_SHAREMODE_EXCLUSIVE, channels))
|
||||
{
|
||||
RARCH_DBG("[WASAPI]: Using format: %u-bit %u-channel client with %s samples at %uHz\n",
|
||||
RARCH_DBG("[WASAPI]: Requesting exclusive %u-bit %u-channel client with %s samples at %uHz %ums.\n",
|
||||
wf.Format.wBitsPerSample,
|
||||
wf.Format.nChannels, wave_format_name(&wf), wf.Format.nSamplesPerSec);
|
||||
}
|
||||
else
|
||||
wf.Format.nChannels, wave_format_name(&wf), wf.Format.nSamplesPerSec, latency);
|
||||
|
||||
if (!wasapi_select_device_format(&wf, client, AUDCLNT_SHAREMODE_EXCLUSIVE, channels))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to select a suitable device format\n");
|
||||
RARCH_ERR("[WASAPI]: Failed to select a suitable device format.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = _IAudioClient_Initialize(client, AUDCLNT_SHAREMODE_EXCLUSIVE,
|
||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
|
||||
buffer_duration, buffer_duration, (WAVEFORMATEX*)&wf, NULL);
|
||||
|
||||
if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
|
||||
{
|
||||
RARCH_WARN("[WASAPI]: Unaligned buffer size: %s\n", hresult_name(hr));
|
||||
RARCH_WARN("[WASAPI]: Unaligned buffer size: %s.\n", hresult_name(hr));
|
||||
hr = _IAudioClient_GetBufferSize(client, &buffer_length);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to get buffer size of client: %s\n", hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI]: Failed to get buffer size of client: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
IFACE_RELEASE(client);
|
||||
hr = _IMMDevice_Activate(device,
|
||||
hr = _IMMDevice_Activate(device,
|
||||
IID_IAudioClient,
|
||||
CLSCTX_ALL, NULL, (void**)&client);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s\n", hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s.\n", hresult_name(hr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -384,12 +376,12 @@ static IAudioClient *wasapi_init_client_ex(IMMDevice *device,
|
||||
if (hr == AUDCLNT_E_ALREADY_INITIALIZED)
|
||||
{
|
||||
IFACE_RELEASE(client);
|
||||
hr = _IMMDevice_Activate(device,
|
||||
hr = _IMMDevice_Activate(device,
|
||||
IID_IAudioClient,
|
||||
CLSCTX_ALL, NULL, (void**)&client);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI] IMMDevice::Activate failed: %s\n", hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI] IMMDevice::Activate failed: %s.\n", hresult_name(hr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -408,16 +400,13 @@ static IAudioClient *wasapi_init_client_ex(IMMDevice *device,
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to create exclusive-mode client: %s\n", hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI]: IAudioClient::Initialize failed: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
*float_fmt = wf.Format.wFormatTag != WAVE_FORMAT_PCM;
|
||||
*rate = wf.Format.nSamplesPerSec;
|
||||
|
||||
RARCH_DBG("[WASAPI]: Initialized exclusive %s client at %uHz, latency %ums\n",
|
||||
*float_fmt ? "float" : "pcm", *rate, latency);
|
||||
|
||||
return client;
|
||||
|
||||
error:
|
||||
@ -430,27 +419,43 @@ static IAudioClient *wasapi_init_client_sh(IMMDevice *device,
|
||||
bool *float_fmt, unsigned *rate, unsigned latency, unsigned channels)
|
||||
{
|
||||
WAVEFORMATEXTENSIBLE wf;
|
||||
IAudioClient *client = NULL;
|
||||
bool float_fmt_res = *float_fmt;
|
||||
unsigned rate_res = *rate;
|
||||
HRESULT hr = _IMMDevice_Activate(device,
|
||||
IID_IAudioClient,
|
||||
CLSCTX_ALL, NULL, (void**)&client);
|
||||
IAudioClient *client = NULL;
|
||||
settings_t *settings = config_get_ptr();
|
||||
unsigned sh_buffer_length = settings->uints.audio_wasapi_sh_buffer_length;
|
||||
REFERENCE_TIME default_period = 0;
|
||||
REFERENCE_TIME buffer_duration = 0;
|
||||
HRESULT hr = _IMMDevice_Activate(device,
|
||||
IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&client);
|
||||
|
||||
if (FAILED(hr))
|
||||
{ /* If we couldn't create the IAudioClient... */
|
||||
RARCH_ERR("[WASAPI]: Failed to create %s IAudioClient: %s\n", hresult_name(hr));
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s.\n", hresult_name(hr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wasapi_set_format(&wf, float_fmt_res, rate_res, channels);
|
||||
|
||||
if (wasapi_select_device_format(&wf, client, AUDCLNT_SHAREMODE_SHARED, channels))
|
||||
hr = _IAudioClient_GetDevicePeriod(client, &default_period, NULL);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_DBG("[WASAPI]: Requesting %u-channel shared-mode client with %s samples at %uHz.\n",
|
||||
wf.Format.nChannels, wave_format_name(&wf), wf.Format.nSamplesPerSec);
|
||||
RARCH_ERR("[WASAPI]: Failed to get default device period of shared client: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
|
||||
/* Use audio latency setting for buffer size if allowed */
|
||||
if ( sh_buffer_length < WASAPI_SH_BUFFER_DEVICE_PERIOD
|
||||
|| sh_buffer_length > WASAPI_SH_BUFFER_CLIENT_BUFFER)
|
||||
{
|
||||
/* Buffer_duration is in 100ns units. */
|
||||
buffer_duration = latency * 10000.0;
|
||||
if (buffer_duration < default_period)
|
||||
buffer_duration = default_period;
|
||||
}
|
||||
|
||||
wasapi_set_format(&wf, *float_fmt, *rate, channels);
|
||||
RARCH_DBG("[WASAPI]: Requesting shared %u-bit %u-channel client with %s samples at %uHz %ums.\n",
|
||||
wf.Format.wBitsPerSample,
|
||||
wf.Format.nChannels, wave_format_name(&wf), wf.Format.nSamplesPerSec, latency);
|
||||
|
||||
if (!wasapi_select_device_format(&wf, client, AUDCLNT_SHAREMODE_SHARED, channels))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to select a suitable device format.\n");
|
||||
goto error;
|
||||
@ -458,37 +463,34 @@ static IAudioClient *wasapi_init_client_sh(IMMDevice *device,
|
||||
|
||||
hr = _IAudioClient_Initialize(client, AUDCLNT_SHAREMODE_SHARED,
|
||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
|
||||
0, 0, (WAVEFORMATEX*)&wf, NULL);
|
||||
buffer_duration, 0, (WAVEFORMATEX*)&wf, NULL);
|
||||
|
||||
if (hr == AUDCLNT_E_ALREADY_INITIALIZED)
|
||||
{
|
||||
IFACE_RELEASE(client);
|
||||
hr = _IMMDevice_Activate(device,
|
||||
hr = _IMMDevice_Activate(device,
|
||||
IID_IAudioClient,
|
||||
CLSCTX_ALL, NULL, (void**)&client);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s\n", hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s.\n", hresult_name(hr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hr = _IAudioClient_Initialize(client, AUDCLNT_SHAREMODE_SHARED,
|
||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
|
||||
0, 0, (WAVEFORMATEX*)&wf, NULL);
|
||||
buffer_duration, 0, (WAVEFORMATEX*)&wf, NULL);
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: IAudioClient::Initialize failed: %s\n", hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI]: IAudioClient::Initialize failed: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
*float_fmt = wf.Format.wFormatTag != WAVE_FORMAT_PCM;
|
||||
*rate = wf.Format.nSamplesPerSec;
|
||||
|
||||
RARCH_DBG("[WASAPI]: Initialized shared %s client at %uHz.\n",
|
||||
wave_format_name(&wf), *rate);
|
||||
|
||||
return client;
|
||||
|
||||
error:
|
||||
@ -516,16 +518,17 @@ IMMDevice *wasapi_init_device(const char *id, EDataFlow data_flow)
|
||||
IID_IMMDeviceEnumerator, (void **)&enumerator);
|
||||
#else
|
||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
|
||||
&IID_IMMDeviceEnumerator, (void **)&enumerator);
|
||||
&IID_IMMDeviceEnumerator, (void **)&enumerator);
|
||||
#endif
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to create device enumerator: %s\n", hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI]: Failed to create device enumerator: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (id)
|
||||
{ /* If a specific device was requested... */
|
||||
{
|
||||
/* If a specific device was requested... */
|
||||
int32_t idx_found = -1;
|
||||
struct string_list *list = (struct string_list*)mmdevice_list_new(NULL, data_flow);
|
||||
|
||||
@ -536,20 +539,21 @@ IMMDevice *wasapi_init_device(const char *id, EDataFlow data_flow)
|
||||
}
|
||||
|
||||
if (list->elems)
|
||||
{ /* If any devices were found... */
|
||||
{
|
||||
/* If any devices were found... */
|
||||
unsigned d;
|
||||
for (d = 0; d < list->size; d++)
|
||||
{
|
||||
if (string_is_equal(id, list->elems[d].data))
|
||||
{
|
||||
RARCH_DBG("[WASAPI]: Found device #%d: \"%s\"\n", d, list->elems[d].data);
|
||||
RARCH_DBG("[WASAPI]: Found device #%d: \"%s\".\n", d, list->elems[d].data);
|
||||
idx_found = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Index was not found yet based on name string,
|
||||
* just assume id is a one-character number index. */
|
||||
|
||||
if (idx_found == -1 && isdigit(id[0]))
|
||||
{
|
||||
idx_found = strtoul(id, NULL, 0);
|
||||
@ -565,14 +569,14 @@ IMMDevice *wasapi_init_device(const char *id, EDataFlow data_flow)
|
||||
data_flow, DEVICE_STATE_ACTIVE, &collection);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to enumerate audio endpoints: %s\n", hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI]: Failed to enumerate audio endpoints: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = _IMMDeviceCollection_GetCount(collection, &dev_count);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to count IMMDevices: %s\n", hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI]: Failed to count IMMDevices: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -581,7 +585,7 @@ IMMDevice *wasapi_init_device(const char *id, EDataFlow data_flow)
|
||||
hr = _IMMDeviceCollection_Item(collection, i, &device);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to get IMMDevice #%d: %s\n", i, hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI]: Failed to get IMMDevice #%d: %s.\n", i, hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -597,7 +601,7 @@ IMMDevice *wasapi_init_device(const char *id, EDataFlow data_flow)
|
||||
enumerator, data_flow, eConsole, &device);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to get default audio endpoint: %s\n", hresult_name(hr));
|
||||
RARCH_ERR("[WASAPI]: Failed to get default audio endpoint: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
@ -615,13 +619,9 @@ error:
|
||||
IFACE_RELEASE(enumerator);
|
||||
|
||||
if (id)
|
||||
{
|
||||
RARCH_WARN("[WASAPI]: Failed to initialize %s device \"%s\".\n", data_flow_name, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to initialize default %s device.\n", data_flow_name);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -631,14 +631,11 @@ IAudioClient *wasapi_init_client(IMMDevice *device, bool *exclusive,
|
||||
{
|
||||
HRESULT hr;
|
||||
IAudioClient *client;
|
||||
double latency_res;
|
||||
REFERENCE_TIME device_period = 0;
|
||||
REFERENCE_TIME stream_latency = 0;
|
||||
UINT32 buffer_length = 0;
|
||||
|
||||
RARCH_DBG("[WASAPI]: Requesting %s %s client (rate=%uHz, latency=%ums).\n",
|
||||
*exclusive ? "exclusive" : "shared",
|
||||
*float_fmt ? "float" : "pcm", *rate, latency);
|
||||
float latency_res;
|
||||
REFERENCE_TIME device_period = 0;
|
||||
REFERENCE_TIME device_period_min = 0;
|
||||
REFERENCE_TIME stream_latency = 0;
|
||||
UINT32 buffer_length = 0;
|
||||
|
||||
if (*exclusive)
|
||||
{
|
||||
@ -666,45 +663,24 @@ IAudioClient *wasapi_init_client(IMMDevice *device, bool *exclusive,
|
||||
if (!client)
|
||||
return NULL;
|
||||
|
||||
/* next calls are allowed to fail (we losing info only) */
|
||||
/* Remaining calls are for logging purposes. */
|
||||
|
||||
if (*exclusive)
|
||||
hr = _IAudioClient_GetDevicePeriod(client, &device_period, &device_period_min);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = _IAudioClient_GetDevicePeriod(client, NULL, &device_period);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
RARCH_DBG("[WASAPI]: Minimum exclusive-mode device period is %uns (%.1fms).\n",
|
||||
device_period * 100, (double)device_period * 100 / 1e6);
|
||||
}
|
||||
/* device_period is in 100ns units */
|
||||
RARCH_DBG("[WASAPI]: Default device period is %.1fms.\n", (float)device_period * 100 / 1e6);
|
||||
RARCH_DBG("[WASAPI]: Minimum device period is %.1fms.\n", (float)device_period_min * 100 / 1e6);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = _IAudioClient_GetDevicePeriod(client, &device_period, NULL);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
RARCH_DBG("[WASAPI]: Default shared-mode device period is %uns (%.1fms).\n",
|
||||
device_period * 100, (double)device_period * 100 / 1e6);
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_WARN("[WASAPI]: IAudioClient::GetDevicePeriod failed: %s\n", hresult_name(hr));
|
||||
}
|
||||
RARCH_WARN("[WASAPI]: IAudioClient::GetDevicePeriod failed: %s.\n", hresult_name(hr));
|
||||
|
||||
if (!*exclusive)
|
||||
{
|
||||
hr = _IAudioClient_GetStreamLatency(client, &stream_latency);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
RARCH_DBG("[WASAPI]: Shared stream latency is %uns (%.1fms).\n",
|
||||
stream_latency * 100, (double)stream_latency * 100 / 1e6);
|
||||
}
|
||||
RARCH_DBG("[WASAPI]: Shared stream latency is %.1fms.\n", (float)stream_latency * 100 / 1e6);
|
||||
else
|
||||
{
|
||||
RARCH_WARN("[WASAPI]: IAudioClient::GetStreamLatency failed: %s\n", hresult_name(hr));
|
||||
}
|
||||
RARCH_WARN("[WASAPI]: IAudioClient::GetStreamLatency failed: %s.\n", hresult_name(hr));
|
||||
}
|
||||
|
||||
hr = _IAudioClient_GetBufferSize(client, &buffer_length);
|
||||
@ -712,45 +688,38 @@ IAudioClient *wasapi_init_client(IMMDevice *device, bool *exclusive,
|
||||
{
|
||||
size_t num_samples = buffer_length * channels;
|
||||
size_t num_bytes = num_samples * (*float_fmt ? sizeof(float) : sizeof(int16_t));
|
||||
RARCH_DBG("[WASAPI]: Endpoint buffer size is %u frames (%u samples, %u bytes).\n",
|
||||
buffer_length, num_samples, num_bytes);
|
||||
RARCH_DBG("[WASAPI]: Endpoint buffer size is %u frames (%u samples, %u bytes, %.1f ms).\n",
|
||||
buffer_length, num_samples, num_bytes, (float)buffer_length * 1000.0 / *rate);
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_WARN("[WASAPI]: IAudioClient::GetBufferSize failed: %s.\n", hresult_name(hr));
|
||||
}
|
||||
|
||||
if (*exclusive)
|
||||
latency_res = (double)buffer_length * 1000.0 / (*rate);
|
||||
latency_res = (float)buffer_length * 1000.0 / (*rate);
|
||||
else
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
int sh_buffer_length = settings->ints.audio_wasapi_sh_buffer_length;
|
||||
settings_t *settings = config_get_ptr();
|
||||
unsigned sh_buffer_length = settings->uints.audio_wasapi_sh_buffer_length;
|
||||
|
||||
if (sh_buffer_length < 0)
|
||||
switch (sh_buffer_length)
|
||||
{
|
||||
#ifdef USE_CLIENT_BUFFER
|
||||
latency_res = (double)buffer_length * 1000.0 / (*rate);
|
||||
#else
|
||||
latency_res = (double)(stream_latency + device_period) / 10000.0;
|
||||
#endif
|
||||
case WASAPI_SH_BUFFER_AUDIO_LATENCY:
|
||||
case WASAPI_SH_BUFFER_CLIENT_BUFFER:
|
||||
latency_res = (float)buffer_length * 1000.0 / (*rate);
|
||||
break;
|
||||
case WASAPI_SH_BUFFER_DEVICE_PERIOD:
|
||||
latency_res = (float)(stream_latency + device_period) / 10000.0;
|
||||
break;
|
||||
default:
|
||||
latency_res = (float)sh_buffer_length * 1000.0 / (*rate);
|
||||
break;
|
||||
}
|
||||
else if (sh_buffer_length > 0)
|
||||
latency_res = sh_buffer_length * 1000.0 / (*rate);
|
||||
else
|
||||
latency_res = 0;
|
||||
}
|
||||
|
||||
RARCH_LOG("[WASAPI]: Client initialized (%s, %s, %uHz, %.1fms).\n",
|
||||
*exclusive ? "exclusive" : "shared",
|
||||
*float_fmt ? "float" : "pcm",
|
||||
*float_fmt ? "FLOAT" : "PCM",
|
||||
*rate, latency_res);
|
||||
|
||||
RARCH_LOG("[WASAPI]: Client buffer length is %u frames (%.1fms).\n",
|
||||
buffer_length, (double)buffer_length * 1000.0 / (*rate));
|
||||
|
||||
RARCH_LOG("[WASAPI]: Device period is %lld frames (%.1fms).\n",
|
||||
device_period * (*rate) / 10000000, (double)device_period / 10000.0);
|
||||
|
||||
return client;
|
||||
}
|
||||
|
@ -26,8 +26,10 @@
|
||||
#include "../common/mmdevice_common_inline.h"
|
||||
#include "boolean.h"
|
||||
|
||||
/* Get automatic buffer size from client buffer instead of device period */
|
||||
#define USE_CLIENT_BUFFER
|
||||
/* Shared buffer size replacement placeholders */
|
||||
#define WASAPI_SH_BUFFER_AUDIO_LATENCY 0
|
||||
#define WASAPI_SH_BUFFER_DEVICE_PERIOD 32
|
||||
#define WASAPI_SH_BUFFER_CLIENT_BUFFER 64
|
||||
|
||||
const char *hresult_name(HRESULT hr);
|
||||
const char* wasapi_error(DWORD error);
|
||||
|
@ -33,9 +33,9 @@ typedef struct
|
||||
IMMDevice *device;
|
||||
IAudioClient *client;
|
||||
IAudioRenderClient *renderer;
|
||||
fifo_buffer_t *buffer; /* NULL in unbuffered shared mode */
|
||||
size_t frame_size; /* 4 or 8 only */
|
||||
fifo_buffer_t *buffer;
|
||||
size_t engine_buffer_size;
|
||||
unsigned char frame_size; /* 4 or 8 only */
|
||||
bool exclusive;
|
||||
bool nonblock;
|
||||
bool running;
|
||||
@ -51,7 +51,7 @@ static void *wasapi_init(const char *dev_id, unsigned rate, unsigned latency,
|
||||
settings_t *settings = config_get_ptr();
|
||||
bool float_format = settings->bools.audio_wasapi_float_format;
|
||||
bool exclusive_mode = settings->bools.audio_wasapi_exclusive_mode;
|
||||
int sh_buffer_length = settings->ints.audio_wasapi_sh_buffer_length;
|
||||
unsigned sh_buffer_length = settings->uints.audio_wasapi_sh_buffer_length;
|
||||
wasapi_t *w = (wasapi_t*)calloc(1, sizeof(wasapi_t));
|
||||
|
||||
if (!w)
|
||||
@ -73,43 +73,39 @@ static void *wasapi_init(const char *dev_id, unsigned rate, unsigned latency,
|
||||
if (FAILED(hr))
|
||||
goto error;
|
||||
|
||||
w->frame_size = float_format ? 8 : 4;
|
||||
w->engine_buffer_size = frame_count * w->frame_size;
|
||||
w->frame_size = float_format ? 8 : 4;
|
||||
w->engine_buffer_size = frame_count * w->frame_size;
|
||||
|
||||
if (w->exclusive)
|
||||
{
|
||||
w->buffer = fifo_new(w->engine_buffer_size);
|
||||
if (!w->buffer)
|
||||
goto error;
|
||||
|
||||
RARCH_LOG("[WASAPI]: Intermediate buffer length is %u frames (%.1fms).\n",
|
||||
frame_count, (double)frame_count * 1000.0 / rate);
|
||||
}
|
||||
else if (sh_buffer_length)
|
||||
else
|
||||
{
|
||||
if (sh_buffer_length < 0)
|
||||
switch (sh_buffer_length)
|
||||
{
|
||||
#ifdef USE_CLIENT_BUFFER
|
||||
sh_buffer_length = frame_count;
|
||||
#else
|
||||
hr = _IAudioClient_GetDevicePeriod(w->client, &dev_period, NULL);
|
||||
case WASAPI_SH_BUFFER_AUDIO_LATENCY:
|
||||
case WASAPI_SH_BUFFER_CLIENT_BUFFER:
|
||||
sh_buffer_length = frame_count;
|
||||
break;
|
||||
case WASAPI_SH_BUFFER_DEVICE_PERIOD:
|
||||
hr = _IAudioClient_GetDevicePeriod(w->client, &dev_period, NULL);
|
||||
|
||||
if (FAILED(hr))
|
||||
goto error;
|
||||
if (FAILED(hr))
|
||||
goto error;
|
||||
|
||||
sh_buffer_length = dev_period * rate / 10000000;
|
||||
#endif
|
||||
sh_buffer_length = dev_period * rate / 10000000;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
w->buffer = fifo_new(sh_buffer_length * w->frame_size);
|
||||
if (!w->buffer)
|
||||
goto error;
|
||||
|
||||
RARCH_LOG("[WASAPI]: Intermediate buffer length is %u frames (%.1fms).\n",
|
||||
sh_buffer_length, (double)sh_buffer_length * 1000.0 / rate);
|
||||
}
|
||||
else
|
||||
RARCH_LOG("[WASAPI]: Intermediate buffer is off. \n");
|
||||
|
||||
w->write_event = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
if (!w->write_event)
|
||||
@ -203,7 +199,7 @@ static ssize_t wasapi_write_sh_buffer(wasapi_t *w, const void * data, size_t siz
|
||||
|
||||
if (!write_avail)
|
||||
{
|
||||
size_t read_avail = 0;
|
||||
size_t read_avail = 0;
|
||||
if (!(WaitForSingleObject(w->write_event, INFINITE) == WAIT_OBJECT_0))
|
||||
return -1;
|
||||
|
||||
@ -252,9 +248,9 @@ static ssize_t wasapi_write_sh(wasapi_t *w, const void * data, size_t size)
|
||||
|
||||
static ssize_t wasapi_write_sh_nonblock(wasapi_t *w, const void * data, size_t size)
|
||||
{
|
||||
ssize_t written = -1;
|
||||
size_t write_avail = 0;
|
||||
UINT32 padding = 0;
|
||||
ssize_t written = -1;
|
||||
size_t write_avail = 0;
|
||||
UINT32 padding = 0;
|
||||
|
||||
if (w->buffer)
|
||||
{
|
||||
@ -320,6 +316,7 @@ static ssize_t wasapi_write_ex(wasapi_t *w, const void * data, size_t size, DWOR
|
||||
static ssize_t wasapi_write(void *wh, const void *data, size_t size)
|
||||
{
|
||||
size_t written = 0;
|
||||
ssize_t ir = 0;
|
||||
wasapi_t *w = (wasapi_t*)wh;
|
||||
|
||||
if (w->nonblock)
|
||||
@ -331,7 +328,6 @@ static ssize_t wasapi_write(void *wh, const void *data, size_t size)
|
||||
|
||||
if (w->exclusive)
|
||||
{
|
||||
ssize_t ir;
|
||||
for (ir = -1; written < size; written += ir)
|
||||
{
|
||||
ir = wasapi_write_ex(w, (char*)data + written, size - written, INFINITE);
|
||||
@ -341,7 +337,6 @@ static ssize_t wasapi_write(void *wh, const void *data, size_t size)
|
||||
}
|
||||
else
|
||||
{
|
||||
ssize_t ir;
|
||||
if (w->buffer)
|
||||
{
|
||||
for (ir = -1; written < size; written += ir)
|
||||
@ -426,7 +421,6 @@ static void wasapi_free(void *wh)
|
||||
if (ir == WAIT_FAILED)
|
||||
RARCH_ERR("[WASAPI]: WaitForSingleObject failed with error %d.\n", GetLastError());
|
||||
|
||||
/* If event isn't signaled log and leak */
|
||||
if (!(ir == WAIT_OBJECT_0))
|
||||
return;
|
||||
|
||||
|
@ -1147,7 +1147,7 @@
|
||||
#define DEFAULT_WASAPI_EXCLUSIVE_MODE false
|
||||
#define DEFAULT_WASAPI_FLOAT_FORMAT false
|
||||
/* Automatic shared mode buffer */
|
||||
#define DEFAULT_WASAPI_SH_BUFFER_LENGTH -16
|
||||
#define DEFAULT_WASAPI_SH_BUFFER_LENGTH 0
|
||||
#endif
|
||||
|
||||
/* Automatically mute audio when fast forward
|
||||
|
@ -1783,7 +1783,6 @@ static struct config_bool_setting *populate_settings_bool(
|
||||
|
||||
#ifdef HAVE_MICROPHONE
|
||||
SETTING_BOOL("microphone_enable", &settings->bools.microphone_enable, true, DEFAULT_MICROPHONE_ENABLE, false);
|
||||
|
||||
#ifdef HAVE_WASAPI
|
||||
SETTING_BOOL("microphone_wasapi_exclusive_mode", &settings->bools.microphone_wasapi_exclusive_mode, true, DEFAULT_WASAPI_EXCLUSIVE_MODE, false);
|
||||
SETTING_BOOL("microphone_wasapi_float_format", &settings->bools.microphone_wasapi_float_format, true, DEFAULT_WASAPI_FLOAT_FORMAT, false);
|
||||
@ -2335,6 +2334,11 @@ static struct config_uint_setting *populate_settings_uint(
|
||||
SETTING_UINT("audio_resampler_quality", &settings->uints.audio_resampler_quality, true, DEFAULT_AUDIO_RESAMPLER_QUALITY_LEVEL, false);
|
||||
SETTING_UINT("audio_block_frames", &settings->uints.audio_block_frames, true, 0, false);
|
||||
SETTING_UINT("midi_volume", &settings->uints.midi_volume, true, DEFAULT_MIDI_VOLUME, false);
|
||||
|
||||
#ifdef HAVE_WASAPI
|
||||
SETTING_UINT("audio_wasapi_sh_buffer_length", &settings->uints.audio_wasapi_sh_buffer_length, true, DEFAULT_WASAPI_SH_BUFFER_LENGTH, false);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MICROPHONE
|
||||
SETTING_UINT("microphone_latency", &settings->uints.microphone_latency, false, 0 /* TODO */, false);
|
||||
SETTING_UINT("microphone_resampler_quality", &settings->uints.microphone_resampler_quality, true, DEFAULT_AUDIO_RESAMPLER_QUALITY_LEVEL, false);
|
||||
@ -2549,9 +2553,6 @@ static struct config_int_setting *populate_settings_int(
|
||||
SETTING_INT("menu_xmb_title_margin_horizontal_offset", &settings->ints.menu_xmb_title_margin_horizontal_offset, true, DEFAULT_XMB_TITLE_MARGIN_HORIZONTAL_OFFSET, false);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WASAPI
|
||||
SETTING_INT("audio_wasapi_sh_buffer_length", &settings->ints.audio_wasapi_sh_buffer_length, true, DEFAULT_WASAPI_SH_BUFFER_LENGTH, false);
|
||||
#endif
|
||||
SETTING_INT("crt_switch_center_adjust", &settings->ints.crt_switch_center_adjust, false, DEFAULT_CRT_SWITCH_CENTER_ADJUST, false);
|
||||
SETTING_INT("crt_switch_porch_adjust", &settings->ints.crt_switch_porch_adjust, false, DEFAULT_CRT_SWITCH_PORCH_ADJUST, false);
|
||||
#ifdef HAVE_WINDOW_OFFSET
|
||||
@ -3770,6 +3771,16 @@ static bool config_load_file(global_t *global,
|
||||
audio_set_float(AUDIO_ACTION_MIXER_VOLUME_GAIN, settings->floats.audio_mixer_volume);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WASAPI
|
||||
{
|
||||
/* Migrate from old deprecated negative value */
|
||||
int wasapi_sh_buffer_length = settings->uints.audio_wasapi_sh_buffer_length;
|
||||
|
||||
if (wasapi_sh_buffer_length < 0)
|
||||
settings->uints.audio_wasapi_sh_buffer_length = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* MIDI fallback for old OFF-string */
|
||||
if (string_is_equal(settings->arrays.midi_input, "Off"))
|
||||
configuration_set_string(settings,
|
||||
|
@ -106,7 +106,6 @@ typedef struct settings
|
||||
int location_update_interval_distance;
|
||||
int state_slot;
|
||||
int replay_slot;
|
||||
int audio_wasapi_sh_buffer_length;
|
||||
int crt_switch_center_adjust;
|
||||
int crt_switch_porch_adjust;
|
||||
#ifdef HAVE_VULKAN
|
||||
@ -161,12 +160,18 @@ typedef struct settings
|
||||
unsigned audio_block_frames;
|
||||
unsigned audio_latency;
|
||||
|
||||
#ifdef HAVE_WASAPI
|
||||
unsigned audio_wasapi_sh_buffer_length;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MICROPHONE
|
||||
unsigned microphone_sample_rate;
|
||||
unsigned microphone_block_frames;
|
||||
unsigned microphone_latency;
|
||||
unsigned microphone_wasapi_sh_buffer_length;
|
||||
unsigned microphone_resampler_quality;
|
||||
#ifdef HAVE_WASAPI
|
||||
unsigned microphone_wasapi_sh_buffer_length;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
unsigned fps_update_interval;
|
||||
@ -623,11 +628,14 @@ typedef struct settings
|
||||
bool audio_enable_menu_scroll;
|
||||
bool audio_sync;
|
||||
bool audio_rate_control;
|
||||
bool audio_wasapi_exclusive_mode;
|
||||
bool audio_wasapi_float_format;
|
||||
bool audio_fastforward_mute;
|
||||
bool audio_fastforward_speedup;
|
||||
|
||||
#ifdef HAVE_WASAPI
|
||||
bool audio_wasapi_exclusive_mode;
|
||||
bool audio_wasapi_float_format;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MICROPHONE
|
||||
/* Microphone */
|
||||
bool microphone_enable;
|
||||
|
@ -7184,6 +7184,7 @@ unsigned menu_displaylist_build_list(
|
||||
MENU_ENUM_LABEL_AUDIO_BLOCK_FRAMES,
|
||||
PARSE_ONLY_UINT, false) == 0)
|
||||
count++;
|
||||
#ifdef HAVE_WASAPI
|
||||
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
|
||||
MENU_ENUM_LABEL_AUDIO_WASAPI_EXCLUSIVE_MODE,
|
||||
PARSE_ONLY_BOOL, false) == 0)
|
||||
@ -7194,8 +7195,9 @@ unsigned menu_displaylist_build_list(
|
||||
count++;
|
||||
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
|
||||
MENU_ENUM_LABEL_AUDIO_WASAPI_SH_BUFFER_LENGTH,
|
||||
PARSE_ONLY_INT, false) == 0)
|
||||
PARSE_ONLY_UINT, false) == 0)
|
||||
count++;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_MICROPHONE
|
||||
@ -7235,6 +7237,7 @@ unsigned menu_displaylist_build_list(
|
||||
MENU_ENUM_LABEL_MICROPHONE_BLOCK_FRAMES,
|
||||
PARSE_ONLY_UINT, false) == 0)
|
||||
count++;
|
||||
#ifdef HAVE_WASAPI
|
||||
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
|
||||
MENU_ENUM_LABEL_MICROPHONE_WASAPI_EXCLUSIVE_MODE,
|
||||
PARSE_ONLY_BOOL, false) == 0)
|
||||
@ -7247,6 +7250,7 @@ unsigned menu_displaylist_build_list(
|
||||
MENU_ENUM_LABEL_MICROPHONE_WASAPI_SH_BUFFER_LENGTH,
|
||||
PARSE_ONLY_UINT, false) == 0)
|
||||
count++;
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
case DISPLAYLIST_AUDIO_SYNCHRONIZATION_SETTINGS_LIST:
|
||||
|
@ -51,6 +51,10 @@
|
||||
#include <vfs/vfs_implementation_cdrom.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WASAPI
|
||||
#include "../audio/common/wasapi.h"
|
||||
#endif
|
||||
|
||||
#include "../config.def.h"
|
||||
#include "../config.def.keybinds.h"
|
||||
|
||||
@ -4941,29 +4945,52 @@ static void setting_get_string_representation_uint_custom_viewport_height(rarch_
|
||||
}
|
||||
|
||||
#ifdef HAVE_WASAPI
|
||||
static void setting_get_string_representation_int_audio_wasapi_sh_buffer_length(rarch_setting_t *setting,
|
||||
static void setting_get_string_representation_uint_audio_wasapi_sh_buffer_length(rarch_setting_t *setting,
|
||||
char *s, size_t len)
|
||||
{
|
||||
if (!setting)
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
if (!setting || !settings)
|
||||
return;
|
||||
|
||||
if (*setting->value.target.integer > 0)
|
||||
snprintf(s, len, "%d", *setting->value.target.integer);
|
||||
else if (*setting->value.target.integer == 0)
|
||||
strlcpy(s, "0 (Off)", len);
|
||||
else
|
||||
strlcpy(s, "Auto", len);
|
||||
switch (*setting->value.target.integer)
|
||||
{
|
||||
case WASAPI_SH_BUFFER_AUDIO_LATENCY:
|
||||
snprintf(s, len, "%u (%s)",
|
||||
*setting->value.target.integer,
|
||||
"Audio Latency");
|
||||
break;
|
||||
case WASAPI_SH_BUFFER_DEVICE_PERIOD:
|
||||
snprintf(s, len, "%u (%s)",
|
||||
*setting->value.target.integer,
|
||||
"Device Period");
|
||||
break;
|
||||
case WASAPI_SH_BUFFER_CLIENT_BUFFER:
|
||||
snprintf(s, len, "%u (%s)",
|
||||
*setting->value.target.integer,
|
||||
"Client Buffer");
|
||||
break;
|
||||
default:
|
||||
snprintf(s, len, "%u (%.1f ms)",
|
||||
*setting->value.target.integer,
|
||||
(float)*setting->value.target.integer * 1000 / settings->uints.audio_output_sample_rate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_MICROPHONE
|
||||
static void setting_get_string_representation_uint_microphone_wasapi_sh_buffer_length(rarch_setting_t *setting,
|
||||
char *s, size_t len)
|
||||
{
|
||||
if (!setting)
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
if (!setting || !settings)
|
||||
return;
|
||||
|
||||
if (*setting->value.target.unsigned_integer > 0)
|
||||
snprintf(s, len, "%u", *setting->value.target.unsigned_integer);
|
||||
if (*setting->value.target.integer > 0)
|
||||
snprintf(s, len, "%u (%.1f ms)",
|
||||
*setting->value.target.integer,
|
||||
(float)*setting->value.target.integer * 1000 / settings->uints.audio_output_sample_rate);
|
||||
else
|
||||
strlcpy(s, "Auto", len);
|
||||
}
|
||||
@ -8315,9 +8342,11 @@ static void general_write_handler(rarch_setting_t *setting)
|
||||
break;
|
||||
case MENU_ENUM_LABEL_AUDIO_LATENCY:
|
||||
case MENU_ENUM_LABEL_AUDIO_OUTPUT_RATE:
|
||||
#ifdef HAVE_WASAPI
|
||||
case MENU_ENUM_LABEL_AUDIO_WASAPI_EXCLUSIVE_MODE:
|
||||
case MENU_ENUM_LABEL_AUDIO_WASAPI_FLOAT_FORMAT:
|
||||
case MENU_ENUM_LABEL_AUDIO_WASAPI_SH_BUFFER_LENGTH:
|
||||
#endif
|
||||
rarch_cmd = CMD_EVENT_AUDIO_REINIT;
|
||||
break;
|
||||
#ifdef HAVE_MICROPHONE
|
||||
@ -14107,9 +14136,9 @@ static bool setting_append_list(
|
||||
SD_FLAG_NONE
|
||||
);
|
||||
|
||||
CONFIG_INT(
|
||||
CONFIG_UINT(
|
||||
list, list_info,
|
||||
&settings->ints.audio_wasapi_sh_buffer_length,
|
||||
&settings->uints.audio_wasapi_sh_buffer_length,
|
||||
MENU_ENUM_LABEL_AUDIO_WASAPI_SH_BUFFER_LENGTH,
|
||||
MENU_ENUM_LABEL_VALUE_AUDIO_WASAPI_SH_BUFFER_LENGTH,
|
||||
DEFAULT_WASAPI_SH_BUFFER_LENGTH,
|
||||
@ -14118,11 +14147,12 @@ static bool setting_append_list(
|
||||
parent_group,
|
||||
general_write_handler,
|
||||
general_read_handler);
|
||||
menu_settings_list_current_add_range(list, list_info, -16.0f, 0.0f, 16.0f, true, false);
|
||||
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_ADVANCED);
|
||||
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint_special;
|
||||
(*list)[list_info->index - 1].get_string_representation =
|
||||
&setting_get_string_representation_int_audio_wasapi_sh_buffer_length;
|
||||
}
|
||||
&setting_get_string_representation_uint_audio_wasapi_sh_buffer_length;
|
||||
menu_settings_list_current_add_range(list, list_info, 0, 32.0f * 200, 32.0f, true, true);
|
||||
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_ADVANCED);
|
||||
}
|
||||
#endif
|
||||
|
||||
END_SUB_GROUP(list, list_info, parent_group);
|
||||
@ -14302,11 +14332,12 @@ static bool setting_append_list(
|
||||
parent_group,
|
||||
general_write_handler,
|
||||
general_read_handler);
|
||||
menu_settings_list_current_add_range(list, list_info, 0.0f, 0.0f, 16.0f, true, false);
|
||||
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_ADVANCED);
|
||||
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint_special;
|
||||
(*list)[list_info->index - 1].get_string_representation =
|
||||
&setting_get_string_representation_uint_microphone_wasapi_sh_buffer_length;
|
||||
}
|
||||
menu_settings_list_current_add_range(list, list_info, 0, 32.0f * 200, 32.0f, true, true);
|
||||
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_ADVANCED);
|
||||
}
|
||||
#endif
|
||||
|
||||
END_SUB_GROUP(list, list_info, parent_group);
|
||||
|
Loading…
x
Reference in New Issue
Block a user