|
@@ -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) {
|