diff --git a/src/audio/wasapi/SDL_wasapi.c b/src/audio/wasapi/SDL_wasapi.c index ee1f25b7cb..5206c09aac 100644 --- a/src/audio/wasapi/SDL_wasapi.c +++ b/src/audio/wasapi/SDL_wasapi.c @@ -46,6 +46,7 @@ // Some GUIDs we need to know without linking to libraries that aren't available before Vista. static const IID SDL_IID_IAudioRenderClient = { 0xf294acfc, 0x3146, 0x4483, { 0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2 } }; static const IID SDL_IID_IAudioCaptureClient = { 0xc8adbd64, 0xe71e, 0x48a0, { 0xa4, 0xde, 0x18, 0x5c, 0x39, 0x5c, 0xd3, 0x17 } }; +static const IID SDL_IID_IAudioClient3 = { 0x7ed4ee07, 0x8e67, 0x4cd4, { 0x8c, 0x1a, 0x2b, 0x7a, 0x59, 0x87, 0xad, 0x42 } }; // WASAPI is _really_ particular about various things happening on the same thread, for COM and such, @@ -632,7 +633,42 @@ static int mgmtthrtask_PrepDevice(void *userdata) newspec.freq = waveformat->nSamplesPerSec; streamflags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK; - ret = IAudioClient_Initialize(client, sharemode, streamflags, 0, 0, waveformat, NULL); + + int new_sample_frames = 0; + SDL_bool iaudioclient3_initialized = SDL_FALSE; + +#ifdef __IAudioClient3_INTERFACE_DEFINED__ + // Try querying IAudioClient3 if sharemode is AUDCLNT_SHAREMODE_SHARED + if (sharemode == AUDCLNT_SHAREMODE_SHARED) { + IAudioClient3 *client3 = NULL; + ret = IAudioClient_QueryInterface(client, &SDL_IID_IAudioClient3, &client3); + if (SUCCEEDED(ret)) { + UINT32 default_period_in_frames = 0; + UINT32 fundamental_period_in_frames = 0; + UINT32 min_period_in_frames = 0; + UINT32 max_period_in_frames = 0; + ret = IAudioClient3_GetSharedModeEnginePeriod(client3, waveformat, + &default_period_in_frames, &fundamental_period_in_frames, &min_period_in_frames, &max_period_in_frames); + if (SUCCEEDED(ret)) { + // IAudioClient3_InitializeSharedAudioStream only accepts the integral multiple of fundamental_period_in_frames + UINT32 period_in_frames = fundamental_period_in_frames * (UINT32)SDL_round((double)device->sample_frames / fundamental_period_in_frames); + period_in_frames = SDL_clamp(period_in_frames, min_period_in_frames, max_period_in_frames); + + ret = IAudioClient3_InitializeSharedAudioStream(client3, streamflags, period_in_frames, waveformat, NULL); + if (SUCCEEDED(ret)) { + new_sample_frames = (int)period_in_frames; + iaudioclient3_initialized = SDL_TRUE; + } + } + + IAudioClient3_Release(client3); + } + } +#endif + + if (!iaudioclient3_initialized) + ret = IAudioClient_Initialize(client, sharemode, streamflags, 0, 0, waveformat, NULL); + if (FAILED(ret)) { return WIN_SetErrorFromHRESULT("WASAPI can't initialize audio client", ret); } @@ -650,9 +686,11 @@ static int mgmtthrtask_PrepDevice(void *userdata) // Match the callback size to the period size to cut down on the number of // interrupts waited for in each call to WaitDevice - const float period_millis = default_period / 10000.0f; - const float period_frames = period_millis * newspec.freq / 1000.0f; - int new_sample_frames = (int) SDL_ceilf(period_frames); + if (new_sample_frames <= 0) { + const float period_millis = default_period / 10000.0f; + const float period_frames = period_millis * newspec.freq / 1000.0f; + new_sample_frames = (int) SDL_ceilf(period_frames); + } // regardless of what we calculated for the period size, clamp it to the expected hardware buffer size. if (new_sample_frames > (int) bufsize) {