wasapi: switched to event-driven interface. This reduces latency and improves battery life.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
diff --git a/src/audio/wasapi/SDL_wasapi.c b/src/audio/wasapi/SDL_wasapi.c
index 133f8fe..f7f04e8 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 df3546e..7967a54 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;