From ab4695f48f2d82b0166af550b916446e8f912fd9 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 13 Dec 2017 14:35:55 -0500 Subject: [PATCH] wasapi: switched to event-driven interface. This reduces latency and improves battery life. --- src/audio/wasapi/SDL_wasapi.c | 41 +++++++++++++++++++++++++++-------- src/audio/wasapi/SDL_wasapi.h | 1 + 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/audio/wasapi/SDL_wasapi.c b/src/audio/wasapi/SDL_wasapi.c index 133f8fe83..f7f04e881 100644 --- a/src/audio/wasapi/SDL_wasapi.c +++ b/src/audio/wasapi/SDL_wasapi.c @@ -321,15 +321,21 @@ WASAPI_PlayDevice(_THIS) static void WASAPI_WaitDevice(_THIS) { - while (RecoverWasapiIfLost(this) && this->hidden->client) { - const UINT32 maxpadding = this->spec.samples; - UINT32 padding = 0; - if (!WasapiFailed(this, IAudioClient_GetCurrentPadding(this->hidden->client, &padding))) { - if (padding <= maxpadding) { - break; + while (RecoverWasapiIfLost(this) && this->hidden->client && this->hidden->event) { + /*SDL_Log("WAITDEVICE");*/ + if (WaitForSingleObject(this->hidden->event, INFINITE) == WAIT_OBJECT_0) { + const UINT32 maxpadding = this->spec.samples; + UINT32 padding = 0; + if (!WasapiFailed(this, IAudioClient_GetCurrentPadding(this->hidden->client, &padding))) { + /*SDL_Log("WASAPI EVENT! padding=%u maxpadding=%u", (unsigned int)padding, (unsigned int)maxpadding);*/ + if (padding <= maxpadding) { + break; + } } - /* Sleep long enough for half the buffer to be free. */ - SDL_Delay(((padding - maxpadding) * 1000) / this->spec.freq); + } else { + /*SDL_Log("WASAPI FAILED EVENT!");*/ + IAudioClient_Stop(this->hidden->client); + SDL_OpenedAudioDeviceDisconnected(this); } } } @@ -429,6 +435,8 @@ ReleaseWasapiDevice(_THIS) { if (this->hidden->client) { IAudioClient_Stop(this->hidden->client); + IAudioClient_SetEventHandle(this->hidden->client, NULL); + IAudioClient_Release(this->hidden->client); this->hidden->client = NULL; } @@ -456,6 +464,11 @@ ReleaseWasapiDevice(_THIS) WASAPI_PlatformDeleteActivationHandler(this->hidden->activation_handler); this->hidden->activation_handler = NULL; } + + if (this->hidden->event) { + CloseHandle(this->hidden->event); + this->hidden->event = NULL; + } } static void @@ -517,6 +530,11 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream) SDL_assert(client != NULL); + this->hidden->event = CreateEventW(NULL, 0, 0, NULL); + if (this->hidden->event == NULL) { + return WIN_SetError("WASAPI can't create an event handle"); + } + ret = IAudioClient_GetMixFormat(client, &waveformat); if (FAILED(ret)) { return WIN_SetErrorFromHRESULT("WASAPI can't determine mix format", ret); @@ -565,11 +583,16 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream) return WIN_SetErrorFromHRESULT("WASAPI can't determine minimum device period", ret); } - ret = IAudioClient_Initialize(client, sharemode, 0, duration, sharemode == AUDCLNT_SHAREMODE_SHARED ? 0 : duration, waveformat, NULL); + ret = IAudioClient_Initialize(client, sharemode, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, duration, sharemode == AUDCLNT_SHAREMODE_SHARED ? 0 : duration, waveformat, NULL); if (FAILED(ret)) { return WIN_SetErrorFromHRESULT("WASAPI can't initialize audio client", ret); } + ret = IAudioClient_SetEventHandle(client, this->hidden->event); + if (FAILED(ret)) { + return WIN_SetErrorFromHRESULT("WASAPI can't set event handle", ret); + } + ret = IAudioClient_GetBufferSize(client, &bufsize); if (FAILED(ret)) { return WIN_SetErrorFromHRESULT("WASAPI can't determine buffer size", ret); diff --git a/src/audio/wasapi/SDL_wasapi.h b/src/audio/wasapi/SDL_wasapi.h index df3546e5b..7967a5499 100644 --- a/src/audio/wasapi/SDL_wasapi.h +++ b/src/audio/wasapi/SDL_wasapi.h @@ -45,6 +45,7 @@ struct SDL_PrivateAudioData IAudioRenderClient *render; IAudioCaptureClient *capture; SDL_AudioStream *capturestream; + HANDLE event; HANDLE task; SDL_bool coinitialized; int framesize;