mirror of
https://github.com/libretro/RetroArch
synced 2025-04-18 14:42:30 +00:00
Fix issues with some cores in shared mode
This commit is contained in:
parent
4197cfe174
commit
62d9e087c4
@ -84,10 +84,11 @@ typedef struct
|
|||||||
IAudioClient *client;
|
IAudioClient *client;
|
||||||
IAudioRenderClient *renderer;
|
IAudioRenderClient *renderer;
|
||||||
HANDLE write_event;
|
HANDLE write_event;
|
||||||
void *buffer; /* NULL in shared mode */
|
void *buffer; /* NULL in unbuffered shared mode */
|
||||||
size_t buffer_size; /* in shared mode holds WASAPI engine buffer size */
|
size_t buffer_size; /* in unbuffered shared mode holds WASAPI engine buffer size */
|
||||||
size_t buffer_usage; /* valid in exclusive mode only */
|
size_t buffer_usage; /* 0 in unbuffered shared mode */
|
||||||
size_t frame_size; /* 4 or 8 only */
|
size_t frame_size; /* 4 or 8 only */
|
||||||
|
bool exclusive;
|
||||||
bool blocking;
|
bool blocking;
|
||||||
bool running;
|
bool running;
|
||||||
} wasapi_t;
|
} wasapi_t;
|
||||||
@ -260,7 +261,7 @@ static void wasapi_set_format(WAVEFORMATEXTENSIBLE *wf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static IAudioClient *wasapi_init_client_sh(IMMDevice *device,
|
static IAudioClient *wasapi_init_client_sh(IMMDevice *device,
|
||||||
bool *float_fmt, unsigned *rate, double *latency)
|
bool *float_fmt, unsigned *rate, double *latency, bool buffered)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
WAVEFORMATEXTENSIBLE wf;
|
WAVEFORMATEXTENSIBLE wf;
|
||||||
@ -270,6 +271,8 @@ static IAudioClient *wasapi_init_client_sh(IMMDevice *device,
|
|||||||
unsigned rate_res = *rate;
|
unsigned rate_res = *rate;
|
||||||
REFERENCE_TIME default_period = 0;
|
REFERENCE_TIME default_period = 0;
|
||||||
REFERENCE_TIME stream_latency = 0;
|
REFERENCE_TIME stream_latency = 0;
|
||||||
|
UINT32 buffer_length = 0;
|
||||||
|
double buffer_latency = 0.0;
|
||||||
|
|
||||||
hr = device->lpVtbl->Activate(device, &IID_IAudioClient,
|
hr = device->lpVtbl->Activate(device, &IID_IAudioClient,
|
||||||
CLSCTX_ALL, NULL, (void**)&client);
|
CLSCTX_ALL, NULL, (void**)&client);
|
||||||
@ -311,7 +314,7 @@ static IAudioClient *wasapi_init_client_sh(IMMDevice *device,
|
|||||||
|
|
||||||
wasapi_warn("Unsupported format");
|
wasapi_warn("Unsupported format");
|
||||||
rate_res = wasapi_pref_rate(j);
|
rate_res = wasapi_pref_rate(j);
|
||||||
if (rate_res == *rate) /* requested allready tested */
|
if (rate_res == *rate) /* requested rate is allready tested */
|
||||||
rate_res = wasapi_pref_rate(++j); /* skip it */
|
rate_res = wasapi_pref_rate(++j); /* skip it */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,14 +325,23 @@ static IAudioClient *wasapi_init_client_sh(IMMDevice *device,
|
|||||||
*rate = rate_res;
|
*rate = rate_res;
|
||||||
*latency = 0.0;
|
*latency = 0.0;
|
||||||
|
|
||||||
/* next two calls are allowed to fail (we losing latency info only) */
|
/* next three calls are allowed to fail (we losing latency info only) */
|
||||||
hr = client->lpVtbl->GetStreamLatency(client, &stream_latency);
|
hr = client->lpVtbl->GetStreamLatency(client, &stream_latency);
|
||||||
WASAPI_HR_WARN(hr, "IAudioClient::GetStreamLatency", return client);
|
WASAPI_HR_WARN(hr, "IAudioClient::GetStreamLatency", return client);
|
||||||
|
|
||||||
hr = client->lpVtbl->GetDevicePeriod(client, &default_period, NULL);
|
hr = client->lpVtbl->GetDevicePeriod(client, &default_period, NULL);
|
||||||
WASAPI_HR_WARN(hr, "IAudioClient::GetDevicePeriod", return client);
|
WASAPI_HR_WARN(hr, "IAudioClient::GetDevicePeriod", return client);
|
||||||
|
|
||||||
*latency = (double)(stream_latency + default_period) / 10000.0;
|
if (buffered)
|
||||||
|
{
|
||||||
|
hr = client->lpVtbl->GetBufferSize(client, &buffer_length);
|
||||||
|
WASAPI_HR_CHECK(hr, "IAudioClient::GetBufferSize", return client);
|
||||||
|
|
||||||
|
/* buffer size is half of WASAPI internal buffer size */
|
||||||
|
buffer_latency = 1000.0 / rate_res * buffer_length / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*latency = (double)(stream_latency + default_period) / 10000.0 + buffer_latency;
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
|
|
||||||
@ -424,7 +436,7 @@ static IAudioClient *wasapi_init_client_ex(IMMDevice *device,
|
|||||||
|
|
||||||
wasapi_warn("Unsupported format");
|
wasapi_warn("Unsupported format");
|
||||||
rate_res = wasapi_pref_rate(j);
|
rate_res = wasapi_pref_rate(j);
|
||||||
if (rate_res == *rate) /* requested allready tested */
|
if (rate_res == *rate) /* requested rate is allready tested */
|
||||||
rate_res = wasapi_pref_rate(++j); /* skip it */
|
rate_res = wasapi_pref_rate(++j); /* skip it */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -439,6 +451,7 @@ static IAudioClient *wasapi_init_client_ex(IMMDevice *device,
|
|||||||
hr = client->lpVtbl->GetStreamLatency(client, &stream_latency);
|
hr = client->lpVtbl->GetStreamLatency(client, &stream_latency);
|
||||||
WASAPI_HR_WARN(hr, "IAudioClient::GetStreamLatency", return client);
|
WASAPI_HR_WARN(hr, "IAudioClient::GetStreamLatency", return client);
|
||||||
|
|
||||||
|
/* our buffer latency is half of WASAPI internal two-buffer latency */
|
||||||
*latency = (double)stream_latency / 10000.0 * 1.5;
|
*latency = (double)stream_latency / 10000.0 * 1.5;
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
@ -450,7 +463,7 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static IAudioClient *wasapi_init_client(IMMDevice *device, bool *exclusive,
|
static IAudioClient *wasapi_init_client(IMMDevice *device, bool *exclusive,
|
||||||
bool *float_fmt, unsigned *rate, unsigned latency)
|
bool *float_fmt, unsigned *rate, unsigned latency, bool buffered)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
double latency_res = latency;
|
double latency_res = latency;
|
||||||
@ -461,14 +474,16 @@ static IAudioClient *wasapi_init_client(IMMDevice *device, bool *exclusive,
|
|||||||
client = wasapi_init_client_ex(device, float_fmt, rate, &latency_res);
|
client = wasapi_init_client_ex(device, float_fmt, rate, &latency_res);
|
||||||
if (!client)
|
if (!client)
|
||||||
{
|
{
|
||||||
client = wasapi_init_client_sh(device, float_fmt, rate, &latency_res);
|
client = wasapi_init_client_sh(device,
|
||||||
|
float_fmt, rate, &latency_res, buffered);
|
||||||
if (client)
|
if (client)
|
||||||
*exclusive = false;
|
*exclusive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client = wasapi_init_client_sh(device, float_fmt, rate, &latency_res);
|
client = wasapi_init_client_sh(device,
|
||||||
|
float_fmt, rate, &latency_res, buffered);
|
||||||
if (!client)
|
if (!client)
|
||||||
{
|
{
|
||||||
client = wasapi_init_client_ex(device, float_fmt, rate, &latency_res);
|
client = wasapi_init_client_ex(device, float_fmt, rate, &latency_res);
|
||||||
@ -482,7 +497,7 @@ static IAudioClient *wasapi_init_client(IMMDevice *device, bool *exclusive,
|
|||||||
RARCH_LOG("[WASAPI]: Client initialized (%s, %s, %uHz, %.1fms).\n",
|
RARCH_LOG("[WASAPI]: Client initialized (%s, %s, %uHz, %.1fms).\n",
|
||||||
*exclusive ? "exclusive" : "shared",
|
*exclusive ? "exclusive" : "shared",
|
||||||
*float_fmt ? "float" : "pcm",
|
*float_fmt ? "float" : "pcm",
|
||||||
*rate, latency_res);
|
*rate, latency_res + 0.05);
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
@ -491,13 +506,14 @@ static void *wasapi_init(const char *dev_id, unsigned rate, unsigned latency,
|
|||||||
unsigned u, unsigned *new_rate)
|
unsigned u, unsigned *new_rate)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
bool com_initialized = false;
|
bool com_initialized = false;
|
||||||
UINT32 frame_count = 0;
|
UINT32 frame_count = 0;
|
||||||
BYTE *dest = NULL;
|
BYTE *dest = NULL;
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
bool exclusive = settings->audio.wasapi.exclusive_mode;
|
bool float_format = settings->audio.wasapi.float_format;
|
||||||
bool float_format = settings->audio.wasapi.float_format;
|
bool buffered = settings->audio.wasapi.shared_mode_buffering;
|
||||||
wasapi_t *w = (wasapi_t*)calloc(1, sizeof(wasapi_t));
|
wasapi_t *w = (wasapi_t*)calloc(1, sizeof(wasapi_t));
|
||||||
|
w->exclusive = settings->audio.wasapi.exclusive_mode;
|
||||||
|
|
||||||
WASAPI_CHECK(w, "Out of memory", return NULL);
|
WASAPI_CHECK(w, "Out of memory", return NULL);
|
||||||
|
|
||||||
@ -514,7 +530,7 @@ static void *wasapi_init(const char *dev_id, unsigned rate, unsigned latency,
|
|||||||
|
|
||||||
*new_rate = rate;
|
*new_rate = rate;
|
||||||
w->client = wasapi_init_client(w->device,
|
w->client = wasapi_init_client(w->device,
|
||||||
&exclusive, &float_format, new_rate, latency);
|
&w->exclusive, &float_format, new_rate, latency, buffered);
|
||||||
if (!w->client)
|
if (!w->client)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -523,8 +539,15 @@ static void *wasapi_init(const char *dev_id, unsigned rate, unsigned latency,
|
|||||||
|
|
||||||
w->frame_size = float_format ? 8 : 4;
|
w->frame_size = float_format ? 8 : 4;
|
||||||
w->buffer_size = frame_count * w->frame_size;
|
w->buffer_size = frame_count * w->frame_size;
|
||||||
if (exclusive)
|
if (w->exclusive || buffered)
|
||||||
{
|
{
|
||||||
|
/* Buffer size in shared buffered mode
|
||||||
|
* is half of WASAPI internal buffer size.
|
||||||
|
* Size changes here must be followed by changes in functions
|
||||||
|
* wasapi_init_client_sh (latency calculation), and
|
||||||
|
* wasapi_write_sh (WASAPI engine buffer free size comparison). */
|
||||||
|
if (!w->exclusive)
|
||||||
|
w->buffer_size /= 2;
|
||||||
w->buffer = malloc(w->buffer_size);
|
w->buffer = malloc(w->buffer_size);
|
||||||
WASAPI_CHECK(w->buffer, "Out of memory", goto error);
|
WASAPI_CHECK(w->buffer, "Out of memory", goto error);
|
||||||
}
|
}
|
||||||
@ -584,26 +607,61 @@ static ssize_t wasapi_write_sh(wasapi_t *w, const void * data, size_t size)
|
|||||||
size_t buffer_avail;
|
size_t buffer_avail;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
bool br;
|
bool br;
|
||||||
ssize_t result;
|
ssize_t result = -1;
|
||||||
UINT32 padding = 0;
|
UINT32 padding = 0;
|
||||||
|
|
||||||
if (w->blocking)
|
if (w->buffer)
|
||||||
{
|
{
|
||||||
ir = WaitForSingleObject(w->write_event, INFINITE);
|
if (w->buffer_usage == w->buffer_size)
|
||||||
WASAPI_SR_CHECK(ir == WAIT_OBJECT_0, "WaitForSingleObject", return -1);
|
{
|
||||||
|
if (w->blocking)
|
||||||
|
{
|
||||||
|
ir = WaitForSingleObject(w->write_event, INFINITE);
|
||||||
|
WASAPI_SR_CHECK(ir == WAIT_OBJECT_0, "WaitForSingleObject", return -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = w->client->lpVtbl->GetCurrentPadding(w->client, &padding);
|
||||||
|
WASAPI_HR_CHECK(hr, "IAudioClient::GetCurrentPadding", return -1);
|
||||||
|
|
||||||
|
/* this is ok for current buffer size
|
||||||
|
* (half of WASAPI internal buffer size)*/
|
||||||
|
if (padding * w->frame_size > w->buffer_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
br = wasapi_flush(w, w->buffer, w->buffer_size);
|
||||||
|
if (!br)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
w->buffer_usage = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_avail = w->buffer_size - w->buffer_usage;
|
||||||
|
result = size < buffer_avail ? size : buffer_avail;
|
||||||
|
memcpy(w->buffer + w->buffer_usage, data, result);
|
||||||
|
w->buffer_usage += result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (w->blocking)
|
||||||
|
{
|
||||||
|
ir = WaitForSingleObject(w->write_event, INFINITE);
|
||||||
|
WASAPI_SR_CHECK(ir == WAIT_OBJECT_0, "WaitForSingleObject", return -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = w->client->lpVtbl->GetCurrentPadding(w->client, &padding);
|
||||||
|
WASAPI_HR_CHECK(hr, "IAudioClient::GetCurrentPadding", return -1);
|
||||||
|
|
||||||
|
buffer_avail = w->buffer_size - padding * w->frame_size;
|
||||||
|
if (!buffer_avail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
result = size > buffer_avail ? buffer_avail : size;
|
||||||
|
br = wasapi_flush(w, data, result);
|
||||||
|
if (!br)
|
||||||
|
result = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = w->client->lpVtbl->GetCurrentPadding(w->client, &padding);
|
return result;
|
||||||
WASAPI_HR_CHECK(hr, "IAudioClient::GetCurrentPadding", return -1);
|
|
||||||
|
|
||||||
buffer_avail = w->buffer_size - padding * w->frame_size;
|
|
||||||
if (!buffer_avail)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
result = size > buffer_avail ? buffer_avail : size;
|
|
||||||
br = wasapi_flush(w, data, result);
|
|
||||||
|
|
||||||
return br ? result : -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t wasapi_write_ex(wasapi_t *w, const void * data, size_t size)
|
static ssize_t wasapi_write_ex(wasapi_t *w, const void * data, size_t size)
|
||||||
@ -649,7 +707,7 @@ static ssize_t wasapi_write(void *wh, const void *data, size_t size, bool u)
|
|||||||
{
|
{
|
||||||
for (writen = 0, ir = -1; writen < size && ir; writen += ir)
|
for (writen = 0, ir = -1; writen < size && ir; writen += ir)
|
||||||
{
|
{
|
||||||
if (w->buffer)
|
if (w->exclusive)
|
||||||
ir = wasapi_write_ex(w, data + writen, size - writen);
|
ir = wasapi_write_ex(w, data + writen, size - writen);
|
||||||
else
|
else
|
||||||
ir = wasapi_write_sh(w, data + writen, size - writen);
|
ir = wasapi_write_sh(w, data + writen, size - writen);
|
||||||
@ -660,7 +718,7 @@ static ssize_t wasapi_write(void *wh, const void *data, size_t size, bool u)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (w->buffer)
|
else if (w->exclusive)
|
||||||
writen = wasapi_write_ex(w, data, size);
|
writen = wasapi_write_ex(w, data, size);
|
||||||
else
|
else
|
||||||
writen = wasapi_write_sh(w, data, size);
|
writen = wasapi_write_sh(w, data, size);
|
||||||
@ -672,7 +730,6 @@ static bool wasapi_stop(void *wh)
|
|||||||
{
|
{
|
||||||
wasapi_t *w = (wasapi_t*)wh;
|
wasapi_t *w = (wasapi_t*)wh;
|
||||||
HRESULT hr = w->client->lpVtbl->Stop(w->client);
|
HRESULT hr = w->client->lpVtbl->Stop(w->client);
|
||||||
|
|
||||||
WASAPI_HR_CHECK(hr, "IAudioClient::Stop", return !w->running);
|
WASAPI_HR_CHECK(hr, "IAudioClient::Stop", return !w->running);
|
||||||
|
|
||||||
w->running = false;
|
w->running = false;
|
||||||
@ -684,6 +741,8 @@ static bool wasapi_start(void *wh, bool u)
|
|||||||
{
|
{
|
||||||
wasapi_t *w = (wasapi_t*)wh;
|
wasapi_t *w = (wasapi_t*)wh;
|
||||||
HRESULT hr = w->client->lpVtbl->Start(w->client);
|
HRESULT hr = w->client->lpVtbl->Start(w->client);
|
||||||
|
WASAPI_WARN(hr != AUDCLNT_E_NOT_STOPPED, "Already started",
|
||||||
|
return w->running);
|
||||||
|
|
||||||
WASAPI_HR_CHECK(hr, "IAudioClient::Start", return w->running);
|
WASAPI_HR_CHECK(hr, "IAudioClient::Start", return w->running);
|
||||||
|
|
||||||
|
@ -868,8 +868,9 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
|
|||||||
SETTING_BOOL("input_autodetect_enable", &settings->input.autodetect_enable, true, input_autodetect_enable, false);
|
SETTING_BOOL("input_autodetect_enable", &settings->input.autodetect_enable, true, input_autodetect_enable, false);
|
||||||
SETTING_BOOL("audio_rate_control", &settings->audio.rate_control, true, rate_control, false);
|
SETTING_BOOL("audio_rate_control", &settings->audio.rate_control, true, rate_control, false);
|
||||||
#ifdef HAVE_WASAPI
|
#ifdef HAVE_WASAPI
|
||||||
SETTING_BOOL("audio_wasapi_exclusive_mode", &settings->audio.wasapi.exclusive_mode, true, true, false);
|
SETTING_BOOL("audio_wasapi_exclusive_mode", &settings->audio.wasapi.exclusive_mode, true, true, false);
|
||||||
SETTING_BOOL("audio_wasapi_float_format", &settings->audio.wasapi.float_format, true, true, false);
|
SETTING_BOOL("audio_wasapi_float_format", &settings->audio.wasapi.float_format, true, false, false);
|
||||||
|
SETTING_BOOL("audio_wasapi_shared_mode_buffering", &settings->audio.wasapi.shared_mode_buffering, true, true, false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (global)
|
if (global)
|
||||||
|
@ -262,6 +262,7 @@ typedef struct settings
|
|||||||
{
|
{
|
||||||
bool exclusive_mode;
|
bool exclusive_mode;
|
||||||
bool float_format;
|
bool float_format;
|
||||||
|
bool shared_mode_buffering; /* ignored in exclusive mode */
|
||||||
} wasapi;
|
} wasapi;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user