SDL: wasapi: A few tweaks to buffer management.

From 7a7875c904b74a293d6626d844d25aa07c3c2668 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sat, 27 Jan 2024 14:03:49 -0500
Subject: [PATCH] wasapi: A few tweaks to buffer management.

These were previously applied, in a different form, in SDL2.

Reference Issue #8924.
---
 src/audio/wasapi/SDL_wasapi.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/audio/wasapi/SDL_wasapi.c b/src/audio/wasapi/SDL_wasapi.c
index dda63d0f554f..78cf3f4c85fb 100644
--- a/src/audio/wasapi/SDL_wasapi.c
+++ b/src/audio/wasapi/SDL_wasapi.c
@@ -432,7 +432,11 @@ static Uint8 *WASAPI_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
     BYTE *buffer = NULL;
 
     if (device->hidden->render) {
-        if (WasapiFailed(device, IAudioRenderClient_GetBuffer(device->hidden->render, device->sample_frames, &buffer))) {
+        const HRESULT ret = IAudioRenderClient_GetBuffer(device->hidden->render, device->sample_frames, &buffer);
+        if (ret == AUDCLNT_E_BUFFER_TOO_LARGE) {
+            SDL_assert(buffer == NULL);
+            *buffer_size = 0;  // just go back to WaitDevice and try again after the hardware has consumed some more data.
+        } else if (WasapiFailed(device, ret)) {
             SDL_assert(buffer == NULL);
             if (device->hidden->device_lost) {  // just use an available buffer, we won't be playing it anyhow.
                 *buffer_size = 0;  // we'll recover during WaitDevice and try again.
@@ -642,11 +646,16 @@ static int mgmtthrtask_PrepDevice(void *userdata)
         return WIN_SetErrorFromHRESULT("WASAPI can't determine buffer size", ret);
     }
 
-    /* Match the callback size to the period size to cut down on the number of
-       interrupts waited for in each call to WaitDevice */
+    // 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;
-    const int new_sample_frames = (int) SDL_ceilf(period_frames);
+    int 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) {
+        new_sample_frames = (int) bufsize;
+    }
 
     // Update the fragment size as size in bytes
     if (SDL_AudioDeviceFormatChangedAlreadyLocked(device, &newspec, new_sample_frames) < 0) {