diff --git a/audio/drivers/wasapi.c b/audio/drivers/wasapi.c index e4425a53c4..9303f5d8a6 100644 --- a/audio/drivers/wasapi.c +++ b/audio/drivers/wasapi.c @@ -40,6 +40,12 @@ typedef struct fifo_buffer_t *buffer; /* NULL in unbuffered shared mode */ } wasapi_t; +/* forward declaration */ +static ssize_t wasapi_write_blocking_exclusive(void *wh, const void *data, size_t size); +static ssize_t wasapi_write_blocking(void *wh, const void *data, size_t size); +static ssize_t wasapi_write_ex(void *wh, const void *data, size_t size); +static ssize_t wasapi_write_sh(void *wh, const void *data, size_t size); + static IMMDevice *wasapi_init_device(const char *id) { HRESULT hr; @@ -577,6 +583,21 @@ static void *wasapi_init(const char *dev_id, unsigned rate, unsigned latency, w->running = true; w->blocking = settings->bools.audio_sync; + if (w->blocking) + { + if (w->exclusive) + audio_wasapi.write = wasapi_write_blocking_exclusive; + else + audio_wasapi.write = wasapi_write_blocking; + } + else + { + if (w->exclusive) + audio_wasapi.write = wasapi_write_ex; + else + audio_wasapi.write = wasapi_write_sh; + } + return w; error: @@ -630,7 +651,7 @@ static bool wasapi_flush_buffer(wasapi_t * w, size_t size) return true; } -static ssize_t wasapi_write_sh(wasapi_t *w, const void * data, size_t size) +static ssize_t wasapi_write_sh_blocking(wasapi_t *w, const void * data, size_t size) { DWORD ir; HRESULT hr; @@ -645,12 +666,9 @@ static ssize_t wasapi_write_sh(wasapi_t *w, const void * data, size_t size) { size_t read_avail = 0; - if (w->blocking) - { - ir = WaitForSingleObject(w->write_event, INFINITE); - if (!(ir == WAIT_OBJECT_0)) - return -1; - } + ir = WaitForSingleObject(w->write_event, INFINITE); + if (!(ir == WAIT_OBJECT_0)) + return -1; hr = _IAudioClient_GetCurrentPadding(w->client, &padding); if (FAILED(hr)) @@ -671,12 +689,9 @@ static ssize_t wasapi_write_sh(wasapi_t *w, const void * data, size_t size) } else { - if (w->blocking) - { - ir = WaitForSingleObject(w->write_event, INFINITE); - if (!(ir == WAIT_OBJECT_0)) - return -1; - } + ir = WaitForSingleObject(w->write_event, INFINITE); + if (!(ir == WAIT_OBJECT_0)) + return -1; hr = _IAudioClient_GetCurrentPadding(w->client, &padding); if (FAILED(hr)) @@ -695,7 +710,59 @@ static ssize_t wasapi_write_sh(wasapi_t *w, const void * data, size_t size) return written; } -static ssize_t wasapi_write_ex(wasapi_t *w, const void * data, size_t size) +static ssize_t wasapi_write_sh(void *_data, const void * data, size_t size) +{ + DWORD ir; + HRESULT hr; + size_t write_avail = 0; + ssize_t written = -1; + UINT32 padding = 0; + wasapi_t *w = (wasapi_t*)_data; + + if (w->buffer) + { + write_avail = fifo_write_avail(w->buffer); + if (!write_avail) + { + size_t read_avail = 0; + + hr = _IAudioClient_GetCurrentPadding(w->client, &padding); + if (FAILED(hr)) + return -1; + + read_avail = fifo_read_avail(w->buffer); + write_avail = w->engine_buffer_size - padding * w->frame_size; + written = read_avail < write_avail ? read_avail : write_avail; + if (written) + if (!wasapi_flush_buffer(w, written)) + return -1; + } + + write_avail = fifo_write_avail(w->buffer); + written = size < write_avail ? size : write_avail; + if (written) + fifo_write(w->buffer, data, written); + } + else + { + hr = _IAudioClient_GetCurrentPadding(w->client, &padding); + if (FAILED(hr)) + return -1; + + write_avail = w->engine_buffer_size - padding * w->frame_size; + if (!write_avail) + return 0; + + written = size < write_avail ? size : write_avail; + if (written) + if (!wasapi_flush(w, data, written)) + return -1; + } + + return written; +} + +static ssize_t wasapi_write_ex_blocking(wasapi_t *w, const void * data, size_t size) { ssize_t written = 0; size_t write_avail = fifo_write_avail(w->buffer); @@ -703,13 +770,9 @@ static ssize_t wasapi_write_ex(wasapi_t *w, const void * data, size_t size) if (!write_avail) { DWORD ir = WaitForSingleObject( - w->write_event, w->blocking ? INFINITE : 0); + w->write_event, INFINITE); if (ir != WAIT_OBJECT_0) - { - if (w->blocking) - return -1; - return 0; - } + return -1; if (!wasapi_flush_buffer(w, w->engine_buffer_size)) return -1; @@ -723,28 +786,59 @@ static ssize_t wasapi_write_ex(wasapi_t *w, const void * data, size_t size) return written; } -static ssize_t wasapi_write(void *wh, const void *data, size_t size) +static ssize_t wasapi_write_ex(void *_data, const void * data, size_t size) { + ssize_t written = 0; + wasapi_t *w = (wasapi_t*)_data; + size_t write_avail = fifo_write_avail(w->buffer); + + if (!write_avail) + { + DWORD ir = WaitForSingleObject( + w->write_event, 0); + if (ir != WAIT_OBJECT_0) + return 0; + + if (!wasapi_flush_buffer(w, w->engine_buffer_size)) + return -1; + + write_avail = w->engine_buffer_size; + } + + written = size < write_avail ? size : write_avail; + fifo_write(w->buffer, data, written); + + return written; +} + +static ssize_t wasapi_write_blocking_exclusive(void *wh, const void *data, size_t size) +{ + ssize_t ir; size_t written; wasapi_t *w = (wasapi_t*)wh; - if (w->blocking) + for (written = 0, ir = -1; written < size; written += ir) { - ssize_t ir; - for (written = 0, ir = -1; written < size; written += ir) - { - if (w->exclusive) - ir = wasapi_write_ex(w, (char*)data + written, size - written); - else - ir = wasapi_write_sh(w, (char*)data + written, size - written); - if (ir == -1) - return -1; - } + ir = wasapi_write_ex_blocking(w, (char*)data + written, size - written); + if (ir == -1) + return -1; + } + + return written; +} + +static ssize_t wasapi_write_blocking(void *wh, const void *data, size_t size) +{ + ssize_t ir; + size_t written; + wasapi_t *w = (wasapi_t*)wh; + + for (written = 0, ir = -1; written < size; written += ir) + { + ir = wasapi_write_sh_blocking(w, (char*)data + written, size - written); + if (ir == -1) + return -1; } - else if (w->exclusive) - written = wasapi_write_ex(w, data, size); - else - written = wasapi_write_sh(w, data, size); return written; } @@ -791,6 +885,20 @@ static void wasapi_set_nonblock_state(void *wh, bool nonblock) RARCH_LOG("[WASAPI]: Sync %s.\n", nonblock ? "off" : "on"); w->blocking = !nonblock; + if (w->blocking) + { + if (w->exclusive) + audio_wasapi.write = wasapi_write_blocking_exclusive; + else + audio_wasapi.write = wasapi_write_blocking; + } + else + { + if (w->exclusive) + audio_wasapi.write = wasapi_write_ex; + else + audio_wasapi.write = wasapi_write_sh; + } } static void wasapi_free(void *wh) @@ -864,7 +972,7 @@ static size_t wasapi_buffer_size(void *wh) audio_driver_t audio_wasapi = { wasapi_init, - wasapi_write, + wasapi_write_sh, wasapi_stop, wasapi_start, wasapi_alive,