[PATCH v4 2/2] mmdevapi: Add SpatialAudio tests.

Andrew Eikum aeikum at codeweavers.com
Thu Feb 4 08:18:24 CST 2021


Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>

On Thu, Feb 04, 2021 at 04:09:57PM +0200, Arkadiusz Hiler wrote:
> Signed-off-by: Arkadiusz Hiler <ahiler at codeweavers.com>
> ---
>  dlls/mmdevapi/tests/Makefile.in    |   3 +-
>  dlls/mmdevapi/tests/mmdevenum.c    |   1 +
>  dlls/mmdevapi/tests/spatialaudio.c | 445 +++++++++++++++++++++++++++++
>  3 files changed, 448 insertions(+), 1 deletion(-)
>  create mode 100644 dlls/mmdevapi/tests/spatialaudio.c
> 
> diff --git a/dlls/mmdevapi/tests/Makefile.in b/dlls/mmdevapi/tests/Makefile.in
> index 0f17ea31923..062ad413922 100644
> --- a/dlls/mmdevapi/tests/Makefile.in
> +++ b/dlls/mmdevapi/tests/Makefile.in
> @@ -6,4 +6,5 @@ C_SRCS = \
>  	dependency.c \
>  	mmdevenum.c \
>  	propstore.c \
> -	render.c
> +	render.c \
> +	spatialaudio.c
> diff --git a/dlls/mmdevapi/tests/mmdevenum.c b/dlls/mmdevapi/tests/mmdevenum.c
> index 350d6474a46..1fd1c7d4aca 100644
> --- a/dlls/mmdevapi/tests/mmdevenum.c
> +++ b/dlls/mmdevapi/tests/mmdevenum.c
> @@ -24,6 +24,7 @@
>  #include "endpointvolume.h"
>  #include "mmdeviceapi.h"
>  #include "audioclient.h"
> +#include "spatialaudioclient.h"
>  #include "audiopolicy.h"
>  #include "dshow.h"
>  #include "dsound.h"
> diff --git a/dlls/mmdevapi/tests/spatialaudio.c b/dlls/mmdevapi/tests/spatialaudio.c
> new file mode 100644
> index 00000000000..f2612499350
> --- /dev/null
> +++ b/dlls/mmdevapi/tests/spatialaudio.c
> @@ -0,0 +1,445 @@
> +/*
> + * Copyright 2021 Arkadiusz Hiler for CodeWeavers
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + */
> +
> +#include <math.h>
> +#include <stdio.h>
> +
> +#include "wine/test.h"
> +
> +#define COBJMACROS
> +
> +#ifdef STANDALONE
> +#include "initguid.h"
> +#endif
> +
> +#include "mmdeviceapi.h"
> +#include "spatialaudioclient.h"
> +
> +static IMMDeviceEnumerator *mme = NULL;
> +static IMMDevice *dev = NULL;
> +static ISpatialAudioClient *sac = NULL;
> +static UINT32 max_dyn_count;
> +static HANDLE event;
> +static WAVEFORMATEX format;
> +
> +static void test_formats(void)
> +{
> +    HRESULT hr;
> +    IAudioFormatEnumerator *afe;
> +    UINT32 format_count = 0;
> +    WAVEFORMATEX *fmt = NULL;
> +
> +    hr = ISpatialAudioClient_GetSupportedAudioObjectFormatEnumerator(sac, &afe);
> +    ok(hr == S_OK, "Getting format enumerator failed: 0x%08x\n", hr);
> +
> +    hr = IAudioFormatEnumerator_GetCount(afe, &format_count);
> +    ok(hr == S_OK, "Getting format count failed: 0x%08x\n", hr);
> +    ok(format_count == 1, "Got wrong format count, expected 1 got %u\n", format_count);
> +
> +    hr = IAudioFormatEnumerator_GetFormat(afe, 0, &fmt);
> +    ok(hr == S_OK, "Getting format failed: 0x%08x\n", hr);
> +    ok(fmt != NULL, "Expected to get non-NULL format\n");
> +
> +    ok(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT, "Wrong format, expected WAVE_FORMAT_IEEE_FLOAT got %hx\n", fmt->wFormatTag);
> +    ok(fmt->nChannels == 1, "Wrong number of channels, expected 1 got %hu\n", fmt->nChannels);
> +    ok(fmt->nSamplesPerSec == 48000, "Wrong sample ret, expected 48000 got %u\n", fmt->nSamplesPerSec);
> +    ok(fmt->wBitsPerSample == 32, "Wrong bits per sample, expected 32 got %hu\n", fmt->wBitsPerSample);
> +    ok(fmt->nBlockAlign == 4, "Wrong block align, expected 4 got %hu\n", fmt->nBlockAlign);
> +    ok(fmt->nAvgBytesPerSec == 192000, "Wrong avg bytes per sec, expected 192000 got %u\n", fmt->nAvgBytesPerSec);
> +    ok(fmt->cbSize == 0, "Wrong cbSize for simple format, expected 0, got %hu\n", fmt->cbSize);
> +
> +    memcpy(&format, fmt, sizeof(format));
> +
> +    IAudioFormatEnumerator_Release(afe);
> +}
> +
> +static void fill_activation_params(SpatialAudioObjectRenderStreamActivationParams *activation_params)
> +{
> +    activation_params->StaticObjectTypeMask =  \
> +                AudioObjectType_FrontLeft     |
> +                AudioObjectType_FrontRight    |
> +                AudioObjectType_FrontCenter   |
> +                AudioObjectType_LowFrequency  |
> +                AudioObjectType_SideLeft      |
> +                AudioObjectType_SideRight     |
> +                AudioObjectType_BackLeft      |
> +                AudioObjectType_BackRight     |
> +                AudioObjectType_TopFrontLeft  |
> +                AudioObjectType_TopFrontRight |
> +                AudioObjectType_TopBackLeft   |
> +                AudioObjectType_TopBackRight;
> +
> +    activation_params->MinDynamicObjectCount = 0;
> +    activation_params->MaxDynamicObjectCount = 0;
> +    activation_params->Category = AudioCategory_GameEffects;
> +    activation_params->EventHandle = event;
> +    activation_params->NotifyObject = NULL;
> +
> +    activation_params->ObjectFormat = &format;
> +}
> +
> +typedef struct NotifyObject
> +{
> +    ISpatialAudioObjectRenderStreamNotify ISpatialAudioObjectRenderStreamNotify_iface;
> +    LONG ref;
> +} NotifyObject;
> +
> +static WINAPI HRESULT notifyobj_QueryInterface(
> +        ISpatialAudioObjectRenderStreamNotify *This,
> +        REFIID riid,
> +        void **ppvObject)
> +{
> +    return S_OK;
> +}
> +
> +static WINAPI ULONG notifyobj_AddRef(
> +        ISpatialAudioObjectRenderStreamNotify *This)
> +{
> +    NotifyObject *obj = CONTAINING_RECORD(This, NotifyObject, ISpatialAudioObjectRenderStreamNotify_iface);
> +    ULONG ref = InterlockedIncrement(&obj->ref);
> +    return ref;
> +}
> +
> +static WINAPI ULONG notifyobj_Release(
> +        ISpatialAudioObjectRenderStreamNotify *This)
> +{
> +    NotifyObject *obj = CONTAINING_RECORD(This, NotifyObject, ISpatialAudioObjectRenderStreamNotify_iface);
> +    ULONG ref = InterlockedDecrement(&obj->ref);
> +    return ref;
> +}
> +
> +static WINAPI HRESULT notifyobj_OnAvailableDynamicObjectCountChange(
> +        ISpatialAudioObjectRenderStreamNotify *This,
> +        ISpatialAudioObjectRenderStreamBase *stream,
> +        LONGLONG deadline,
> +        UINT32 object_count)
> +{
> +    ok(FALSE, "Expected to never be notified of dynamic object count change\n");
> +    return S_OK;
> +}
> +
> +static const ISpatialAudioObjectRenderStreamNotifyVtbl notifyobjvtbl =
> +{
> +    notifyobj_QueryInterface,
> +    notifyobj_AddRef,
> +    notifyobj_Release,
> +    notifyobj_OnAvailableDynamicObjectCountChange
> +};
> +
> +static void test_stream_activation(void)
> +{
> +    HRESULT hr;
> +    WAVEFORMATEX wrong_format;
> +    ISpatialAudioObjectRenderStream *sas = NULL;
> +
> +    SpatialAudioObjectRenderStreamActivationParams activation_params;
> +    PROPVARIANT activation_params_prop;
> +    NotifyObject notify_object;
> +
> +    PropVariantInit(&activation_params_prop);
> +    activation_params_prop.vt = VT_BLOB;
> +    activation_params_prop.blob.cbSize = sizeof(activation_params);
> +    activation_params_prop.blob.pBlobData = (BYTE*) &activation_params;
> +
> +    /* correct params */
> +    fill_activation_params(&activation_params);
> +    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);
> +    ok(ISpatialAudioObjectRenderStream_Release(sas) == 0, "Expected to release the last reference\n");
> +
> +    /* event handle */
> +    fill_activation_params(&activation_params);
> +    activation_params.EventHandle = NULL;
> +    hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
> +    ok(hr == E_INVALIDARG, "Expected lack of no EventHandle to be invalid: 0x%08x\n", hr);
> +    ok(sas == NULL, "Expected spatial audio stream to be set to NULL upon failed activation\n");
> +
> +    activation_params.EventHandle = INVALID_HANDLE_VALUE;
> +    hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
> +    ok(hr == E_INVALIDARG, "Expected INVALID_HANDLE_VALUE to be invalid: 0x%08x\n", hr);
> +    ok(sas == NULL, "Expected spatial audio stream to be set to NULL upon failed activation\n");
> +
> +    /* must use only queried sample rate */
> +    fill_activation_params(&activation_params);
> +    memcpy(&wrong_format, &format, sizeof(format));
> +    activation_params.ObjectFormat = &wrong_format;
> +    wrong_format.nSamplesPerSec = 44100;
> +    wrong_format.nAvgBytesPerSec = wrong_format.nSamplesPerSec * wrong_format.nBlockAlign;
> +    hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
> +    ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT, "Expected format to be unsupported: 0x%08x\n", hr);
> +    ok(sas == NULL, "Expected spatial audio stream to be set to NULL upon failed activation\n");
> +
> +    /* dynamic objects are not supported */
> +    if (max_dyn_count == 0)
> +    {
> +        fill_activation_params(&activation_params);
> +        activation_params.StaticObjectTypeMask |= AudioObjectType_Dynamic;
> +        hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
> +        ok(hr == E_INVALIDARG, "Expected dynamic objects type be invalid: 0x%08x\n", hr);
> +        ok(sas == NULL, "Expected spatial audio stream to be set to NULL upon failed activation\n");
> +    }
> +
> +    activation_params.MinDynamicObjectCount = max_dyn_count + 1;
> +    activation_params.MaxDynamicObjectCount = max_dyn_count + 1;
> +    hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
> +    if (max_dyn_count)
> +        ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT, "Expected dynamic object count exceeding max to be unsupported: 0x%08x\n", hr);
> +    else
> +        ok(hr == E_INVALIDARG, "Expected setting dynamic object count to be invalid: 0x%08x\n", hr);
> +
> +    /* ISpatialAudioObjectRenderStreamNotify */
> +    fill_activation_params(&activation_params);
> +    notify_object.ISpatialAudioObjectRenderStreamNotify_iface.lpVtbl = ¬ifyobjvtbl;
> +    notify_object.ref = 0;
> +    activation_params.NotifyObject = &notify_object.ISpatialAudioObjectRenderStreamNotify_iface;
> +    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);
> +    ok(notify_object.ref == 1, "Expected to get increased NotifyObject's ref count\n");
> +    ok(ISpatialAudioObjectRenderStream_Release(sas) == 0, "Expected to release the last reference\n");
> +    ok(notify_object.ref == 0, "Expected to get lowered NotifyObject's ref count\n");
> +}
> +
> +static void test_audio_object_activation(void)
> +{
> +    HRESULT hr;
> +    BOOL is_active;
> +    ISpatialAudioObjectRenderStream *sas = NULL;
> +    ISpatialAudioObject *sao1, *sao2;
> +
> +    SpatialAudioObjectRenderStreamActivationParams activation_params;
> +    PROPVARIANT activation_params_prop;
> +
> +    PropVariantInit(&activation_params_prop);
> +    activation_params_prop.vt = VT_BLOB;
> +    activation_params_prop.blob.cbSize = sizeof(activation_params);
> +    activation_params_prop.blob.pBlobData = (BYTE*) &activation_params;
> +
> +    fill_activation_params(&activation_params);
> +    activation_params.StaticObjectTypeMask &= ~AudioObjectType_FrontRight;
> +    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 = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontLeft, &sao1);
> +    ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08x\n", hr);
> +    hr = ISpatialAudioObject_IsActive(sao1, &is_active);
> +    todo_wine ok(hr == S_OK, "Failed to check if spatial audio object is active: 0x%08x\n", hr);
> +    if (hr == S_OK)
> +        ok(is_active, "Expected spaital audio object to be active\n");
> +
> +    hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontLeft, &sao2);
> +    ok(hr == SPTLAUDCLNT_E_OBJECT_ALREADY_ACTIVE, "Expected audio object to be already active: 0x%08x\n", hr);
> +
> +    hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontRight, &sao2);
> +    ok(hr == SPTLAUDCLNT_E_STATIC_OBJECT_NOT_AVAILABLE, "Expected static object to be not available: 0x%08x\n", hr);
> +
> +    hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_Dynamic, &sao2);
> +    ok(hr == SPTLAUDCLNT_E_NO_MORE_OBJECTS, "Expected to not have no more dynamic objects: 0x%08x\n", hr);
> +
> +    ISpatialAudioObject_Release(sao1);
> +    ISpatialAudioObjectRenderStream_Release(sas);
> +}
> +
> +static BOOL is_buffer_zeroed(const BYTE *buffer, UINT32 buffer_length)
> +{
> +    UINT32 i;
> +
> +    for (i = 0; i < buffer_length; i++)
> +    {
> +        if (buffer[i] != 0)
> +            return FALSE;
> +    }
> +
> +    return TRUE;
> +}
> +
> +static void test_audio_object_buffers(void)
> +{
> +    HRESULT hr;
> +    ISpatialAudioObjectRenderStream *sas = NULL;
> +    ISpatialAudioObject *sao[4];
> +    UINT32 dyn_object_count, frame_count, buffer_length;
> +    BYTE *buffer;
> +    INT i;
> +
> +    SpatialAudioObjectRenderStreamActivationParams activation_params;
> +    PROPVARIANT activation_params_prop;
> +
> +    PropVariantInit(&activation_params_prop);
> +    activation_params_prop.vt = VT_BLOB;
> +    activation_params_prop.blob.cbSize = sizeof(activation_params);
> +    activation_params_prop.blob.pBlobData = (BYTE*) &activation_params;
> +
> +    fill_activation_params(&activation_params);
> +    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 = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontLeft, &sao[0]);
> +    ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08x\n", hr);
> +
> +    hr = ISpatialAudioObjectRenderStream_Start(sas);
> +    ok(hr == S_OK, "Failed to activate spatial audio render stream: 0x%08x\n", hr);
> +
> +    hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontRight, &sao[1]);
> +    ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08x\n", hr);
> +
> +    hr = WaitForSingleObject(event, 200);
> +    ok(hr == WAIT_OBJECT_0, "Expected event to be flagged: 0x%08x\n", hr);
> +
> +    hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_SideLeft, &sao[2]);
> +    ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08x\n", hr);
> +
> +    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");
> +
> +    hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_SideRight, &sao[3]);
> +    ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08x\n", hr);
> +
> +    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\n", hr);
> +        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);
> +        ok(is_buffer_zeroed(buffer, buffer_length), "Expected audio object's buffer to be zeroed\n");
> +    }
> +
> +    hr = ISpatialAudioObjectRenderStream_EndUpdatingAudioObjects(sas);
> +    ok(hr == S_OK, "Failed to end updating audio objects: 0x%08x\n", hr);
> +
> +    hr = WaitForSingleObject(event, 200);
> +    ok(hr == WAIT_OBJECT_0, "Expected event to be flagged: 0x%08x\n", hr);
> +
> +    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");
> +
> +    /* one more iteration but not with every object */
> +    for (i = 0; i < ARRAYSIZE(sao) - 1; 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\n", hr);
> +        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);
> +        ok(is_buffer_zeroed(buffer, buffer_length), "Expected audio object's buffer to be zeroed\n");
> +    }
> +
> +    hr = ISpatialAudioObjectRenderStream_EndUpdatingAudioObjects(sas);
> +    ok(hr == S_OK, "Failed to end updating audio objects: 0x%08x\n", hr);
> +
> +    /* ending the stream */
> +    hr = ISpatialAudioObject_SetEndOfStream(sao[0], 0);
> +    todo_wine ok(hr == SPTLAUDCLNT_E_OUT_OF_ORDER, "Expected that ending the stream at this point won't be allowed: 0x%08x\n", hr);
> +
> +    hr = WaitForSingleObject(event, 200);
> +    ok(hr == WAIT_OBJECT_0, "Expected event to be flagged: 0x%08x\n", hr);
> +
> +    hr = ISpatialAudioObject_SetEndOfStream(sao[0], 0);
> +    todo_wine ok(hr == SPTLAUDCLNT_E_OUT_OF_ORDER, "Expected that ending the stream at this point won't be allowed: 0x%08x\n", hr);
> +
> +    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");
> +
> +    /* expect the object that was not updated last cycle to be invalidated */
> +    hr = ISpatialAudioObject_GetBuffer(sao[ARRAYSIZE(sao) - 1], &buffer, &buffer_length);
> +    todo_wine ok(hr == SPTLAUDCLNT_E_RESOURCES_INVALIDATED, "Expected audio object to be invalidated: 0x%08x\n", hr);
> +
> +    for (i = 0; i < ARRAYSIZE(sao) - 1; 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\n", hr);
> +
> +        hr = ISpatialAudioObject_SetEndOfStream(sao[i], 0);
> +        todo_wine ok(hr == S_OK, "Failed to end the stream: 0x%08x\n", hr);
> +
> +        hr = ISpatialAudioObject_GetBuffer(sao[i], &buffer, &buffer_length);
> +        todo_wine ok(hr == SPTLAUDCLNT_E_RESOURCES_INVALIDATED, "Expected audio object to be invalidated: 0x%08x\n", hr);
> +    }
> +
> +    hr = ISpatialAudioObjectRenderStream_EndUpdatingAudioObjects(sas);
> +    ok(hr == S_OK, "Failed to end updating audio objects: 0x%08x\n", hr);
> +
> +    for (i = 0; i < ARRAYSIZE(sao); i++)
> +    {
> +        ISpatialAudioObject_Release(sao[i]);
> +    }
> +
> +    ISpatialAudioObjectRenderStream_Release(sas);
> +}
> +
> +START_TEST(spatialaudio)
> +{
> +    HRESULT hr;
> +
> +    event = CreateEventA(NULL, FALSE, FALSE, "spatial-audio-test-prog-event");
> +    ok(event != NULL, "Failed to create event, last error: 0x%08x\n", GetLastError());
> +
> +    CoInitializeEx(NULL, COINIT_MULTITHREADED);
> +    hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&mme);
> +    if (FAILED(hr))
> +    {
> +        skip("mmdevapi not available: 0x%08x\n", hr);
> +        goto cleanup;
> +    }
> +
> +    hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(mme, eRender, eMultimedia, &dev);
> +    ok(hr == S_OK || hr == E_NOTFOUND, "GetDefaultAudioEndpoint failed: 0x%08x\n", hr);
> +    if (hr != S_OK || !dev)
> +    {
> +        if (hr == E_NOTFOUND)
> +            skip("No sound card available\n");
> +        else
> +            skip("GetDefaultAudioEndpoint returns 0x%08x\n", hr);
> +        goto cleanup;
> +    }
> +
> +    hr = IMMDevice_Activate(dev, &IID_ISpatialAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)&sac);
> +    ok(hr == S_OK || hr == E_NOINTERFACE, "ISpatialAudioClient Activation failed: 0x%08x\n", hr);
> +    if (hr != S_OK || !dev)
> +    {
> +        if (hr == E_NOINTERFACE)
> +            skip("ISpatialAudioClient interface not found\n");
> +        else
> +            skip("ISpatialAudioClient Activation returns 0x%08x\n", hr);
> +        goto cleanup;
> +    }
> +
> +    hr = ISpatialAudioClient_GetMaxDynamicObjectCount(sac, &max_dyn_count);
> +    ok(hr == S_OK, "Failed to get max dynamic object count: 0x%08x\n", hr);
> +
> +    /* that's the default, after manually enabling Windows Sonic it's possible to have max_dyn_count > 0 */
> +    /* ok(max_dyn_count == 0, "expected max dynamic object count to be 0 got %u\n", max_dyn_count); */
> +
> +    test_formats();
> +    test_stream_activation();
> +    test_audio_object_activation();
> +    test_audio_object_buffers();
> +
> +    ISpatialAudioClient_Release(sac);
> +
> +cleanup:
> +    if (dev)
> +        IMMDevice_Release(dev);
> +    if (mme)
> +        IMMDeviceEnumerator_Release(mme);
> +    CoUninitialize();
> +    CloseHandle(event);
> +}
> -- 
> 2.30.0
> 



More information about the wine-devel mailing list