Paul Gofman : mmdevapi: Make spatial audio objects buffer update size constant.

Alexandre Julliard julliard at winehq.org
Fri Mar 19 16:42:02 CDT 2021


Module: wine
Branch: master
Commit: 1d66a108b901ebfb11b134e9a6895b1d87333638
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=1d66a108b901ebfb11b134e9a6895b1d87333638

Author: Paul Gofman <pgofman at codeweavers.com>
Date:   Wed Mar 17 19:41:52 2021 +0300

mmdevapi: Make spatial audio objects buffer update size constant.

Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/mmdevapi/spatialaudio.c       | 22 +++---------
 dlls/mmdevapi/tests/Makefile.in    |  2 +-
 dlls/mmdevapi/tests/spatialaudio.c | 73 ++++++++++++++++++++++++++++++++++----
 3 files changed, 72 insertions(+), 25 deletions(-)

diff --git a/dlls/mmdevapi/spatialaudio.c b/dlls/mmdevapi/spatialaudio.c
index cbca57b4890..7ec09b663aa 100644
--- a/dlls/mmdevapi/spatialaudio.c
+++ b/dlls/mmdevapi/spatialaudio.c
@@ -41,8 +41,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
 
-#define MAX_PERIODS 3
-
 static UINT32 AudioObjectType_to_index(AudioObjectType type)
 {
     UINT32 o = 0;
@@ -361,7 +359,6 @@ static HRESULT WINAPI SAORS_BeginUpdatingAudioObjects(ISpatialAudioObjectRenderS
     static BOOL fixme_once = FALSE;
     SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface);
     SpatialAudioObjectImpl *object;
-    UINT32 pad;
     HRESULT hr;
 
     TRACE("(%p)->(%p, %p)\n", This, dyn_count, frames);
@@ -373,18 +370,7 @@ static HRESULT WINAPI SAORS_BeginUpdatingAudioObjects(ISpatialAudioObjectRenderS
         return SPTLAUDCLNT_E_OUT_OF_ORDER;
     }
 
-    hr = IAudioClient_GetCurrentPadding(This->client, &pad);
-    if(FAILED(hr)){
-        WARN("GetCurrentPadding failed: %08x\n", hr);
-        LeaveCriticalSection(&This->lock);
-        return hr;
-    }
-
-    if(pad < This->period_frames * MAX_PERIODS){
-        This->update_frames = This->period_frames * MAX_PERIODS - pad;
-    }else{
-        This->update_frames = 0;
-    }
+    This->update_frames = This->period_frames;
 
     if(This->update_frames > 0){
         hr = IAudioRenderClient_GetBuffer(This->render, This->update_frames, (BYTE **)&This->buf);
@@ -496,7 +482,7 @@ static HRESULT WINAPI SAORS_ActivateSpatialAudioObject(ISpatialAudioObjectRender
     obj->sa_stream = This;
     SAORS_AddRef(&This->ISpatialAudioObjectRenderStream_iface);
 
-    obj->buf = heap_alloc_zero(This->period_frames * MAX_PERIODS * This->sa_client->object_fmtex.Format.nBlockAlign);
+    obj->buf = heap_alloc_zero(This->period_frames * This->sa_client->object_fmtex.Format.nBlockAlign);
 
     EnterCriticalSection(&This->lock);
 
@@ -616,7 +602,7 @@ static HRESULT WINAPI SAC_GetMaxFrameCount(ISpatialAudioClient *iface,
 
     TRACE("(%p)->(%p, %p)\n", This, format, count);
 
-    *count = MulDiv(period, format->nSamplesPerSec, 10000000) * MAX_PERIODS;
+    *count = MulDiv(period, format->nSamplesPerSec, 10000000);
 
     return S_OK;
 }
@@ -731,7 +717,7 @@ static HRESULT activate_stream(SpatialAudioStreamImpl *stream)
 
     hr = IAudioClient_Initialize(stream->client, AUDCLNT_SHAREMODE_SHARED,
             AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
-            period * MAX_PERIODS, 0, &stream->stream_fmtex.Format, NULL);
+            period, 0, &stream->stream_fmtex.Format, NULL);
     if(FAILED(hr)){
         WARN("Initialize failed: %08x\n", hr);
         IAudioClient_Release(stream->client);
diff --git a/dlls/mmdevapi/tests/Makefile.in b/dlls/mmdevapi/tests/Makefile.in
index 062ad413922..dd180a253b9 100644
--- a/dlls/mmdevapi/tests/Makefile.in
+++ b/dlls/mmdevapi/tests/Makefile.in
@@ -1,5 +1,5 @@
 TESTDLL   = mmdevapi.dll
-IMPORTS   = ole32 version user32 advapi32
+IMPORTS   = ole32 version user32 advapi32 winmm
 
 C_SRCS = \
 	capture.c \
diff --git a/dlls/mmdevapi/tests/spatialaudio.c b/dlls/mmdevapi/tests/spatialaudio.c
index f2612499350..d9ccc429ce8 100644
--- a/dlls/mmdevapi/tests/spatialaudio.c
+++ b/dlls/mmdevapi/tests/spatialaudio.c
@@ -29,6 +29,7 @@
 
 #include "mmdeviceapi.h"
 #include "spatialaudioclient.h"
+#include "mmsystem.h"
 
 static IMMDeviceEnumerator *mme = NULL;
 static IMMDevice *dev = NULL;
@@ -269,15 +270,14 @@ static BOOL is_buffer_zeroed(const BYTE *buffer, UINT32 buffer_length)
 
 static void test_audio_object_buffers(void)
 {
-    HRESULT hr;
+    UINT32 dyn_object_count, frame_count, max_frame_count, buffer_length;
+    SpatialAudioObjectRenderStreamActivationParams activation_params;
     ISpatialAudioObjectRenderStream *sas = NULL;
+    PROPVARIANT activation_params_prop;
     ISpatialAudioObject *sao[4];
-    UINT32 dyn_object_count, frame_count, buffer_length;
     BYTE *buffer;
-    INT i;
-
-    SpatialAudioObjectRenderStreamActivationParams activation_params;
-    PROPVARIANT activation_params_prop;
+    INT i, j, k;
+    HRESULT hr;
 
     PropVariantInit(&activation_params_prop);
     activation_params_prop.vt = VT_BLOB;
@@ -288,6 +288,17 @@ static void test_audio_object_buffers(void)
     hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
     ok(hr == S_OK, "Failed to activate spatial audio stream: 0x%08x\n", hr);
 
+    hr = ISpatialAudioClient_GetMaxFrameCount(sac, &format, &max_frame_count);
+    ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+    frame_count = format.nSamplesPerSec / 100; /* 10ms */
+    /* Most of the time the frame count matches the 10ms interval exactly.
+     * However (seen on some Testbot machines) it might be a bit higher for some reason. */
+    ok(max_frame_count <= frame_count + frame_count / 4, "Got unexpected frame count %u.\n", frame_count);
+
+    /* The tests below which check frame count from _BeginUpdatingAudioObjects fail on some Testbot machines
+     * with max_frame_count from _GetMaxFrameCount(). */
+    max_frame_count = frame_count + frame_count / 4;
+
     hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontLeft, &sao[0]);
     ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08x\n", hr);
 
@@ -306,6 +317,7 @@ static void test_audio_object_buffers(void)
     hr = ISpatialAudioObjectRenderStream_BeginUpdatingAudioObjects(sas, &dyn_object_count, &frame_count);
     ok(hr == S_OK, "Failed to beging updating audio objects: 0x%08x\n", hr);
     ok(dyn_object_count == 0, "Unexpected dynamic objects\n");
+    ok(frame_count <= max_frame_count, "Got unexpected frame count %u.\n", frame_count);
 
     hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_SideRight, &sao[3]);
     ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08x\n", hr);
@@ -323,6 +335,55 @@ static void test_audio_object_buffers(void)
     hr = ISpatialAudioObjectRenderStream_EndUpdatingAudioObjects(sas);
     ok(hr == S_OK, "Failed to end updating audio objects: 0x%08x\n", hr);
 
+    /* Emulate underrun and test frame count approximate limit. */
+
+    /* Force 1ms Sleep() timer resolution. */
+    timeBeginPeriod(1);
+    for (j = 0; j < 20; ++j)
+    {
+        hr = WaitForSingleObject(event, 200);
+        ok(hr == WAIT_OBJECT_0, "Expected event to be flagged: 0x%08x, j %u.\n", hr, j);
+
+        hr = ISpatialAudioObjectRenderStream_BeginUpdatingAudioObjects(sas, &dyn_object_count, &frame_count);
+        ok(hr == S_OK, "Failed to beging updating audio objects: 0x%08x\n", hr);
+        ok(dyn_object_count == 0, "Unexpected dynamic objects\n");
+        ok(frame_count <= max_frame_count, "Got unexpected frame_count %u.\n", frame_count);
+
+        /* Audio starts crackling with delays 10ms and above. However, setting such delay (that is, the delay
+         * which skips the whole quantum) breaks SA on some Testbot machines: _BeginUpdatingAudioObjects fails
+         * with SPTLAUDCLNT_E_INTERNAL starting from some iteration or WaitForSingleObject timeouts. That seems
+         * to work on the real hardware though. */
+        Sleep(5);
+
+        for (i = 0; i < ARRAYSIZE(sao); i++)
+        {
+            hr = ISpatialAudioObject_GetBuffer(sao[i], &buffer, &buffer_length);
+            ok(hr == S_OK, "Expected to be able to get buffers for audio object: 0x%08x, i %d\n", hr, i);
+            ok(buffer != NULL, "Expected to get a non-NULL buffer\n");
+            ok(buffer_length == frame_count * format.wBitsPerSample / 8,
+                    "Expected buffer length to be sample_size * frame_count = %hu but got %u\n",
+                    frame_count * format.wBitsPerSample / 8, buffer_length);
+
+            /* Enable to hear the test sound. */
+            if (0)
+            {
+                if (format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
+                {
+                    for (k = 0; k < frame_count; ++k)
+                    {
+                        float time_sec = 10.0f / 1000.0f * (j + (float)k / frame_count);
+
+                        /* 440Hz tone. */
+                        ((float *)buffer)[k] = sinf(2.0f * M_PI * time_sec * 440.0f);
+                    }
+                }
+            }
+        }
+        hr = ISpatialAudioObjectRenderStream_EndUpdatingAudioObjects(sas);
+        ok(hr == S_OK, "Failed to end updating audio objects: 0x%08x\n", hr);
+    }
+    timeEndPeriod(1);
+
     hr = WaitForSingleObject(event, 200);
     ok(hr == WAIT_OBJECT_0, "Expected event to be flagged: 0x%08x\n", hr);
 




More information about the wine-cvs mailing list