rasapi32: Update spec file.
[wine/zf.git] / dlls / mmdevapi / tests / spatialaudio.c
blobd9ccc429ce828ec4f646a3ce770229f4c3d9c4de
1 /*
2 * Copyright 2021 Arkadiusz Hiler for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <math.h>
20 #include <stdio.h>
22 #include "wine/test.h"
24 #define COBJMACROS
26 #ifdef STANDALONE
27 #include "initguid.h"
28 #endif
30 #include "mmdeviceapi.h"
31 #include "spatialaudioclient.h"
32 #include "mmsystem.h"
34 static IMMDeviceEnumerator *mme = NULL;
35 static IMMDevice *dev = NULL;
36 static ISpatialAudioClient *sac = NULL;
37 static UINT32 max_dyn_count;
38 static HANDLE event;
39 static WAVEFORMATEX format;
41 static void test_formats(void)
43 HRESULT hr;
44 IAudioFormatEnumerator *afe;
45 UINT32 format_count = 0;
46 WAVEFORMATEX *fmt = NULL;
48 hr = ISpatialAudioClient_GetSupportedAudioObjectFormatEnumerator(sac, &afe);
49 ok(hr == S_OK, "Getting format enumerator failed: 0x%08x\n", hr);
51 hr = IAudioFormatEnumerator_GetCount(afe, &format_count);
52 ok(hr == S_OK, "Getting format count failed: 0x%08x\n", hr);
53 ok(format_count == 1, "Got wrong format count, expected 1 got %u\n", format_count);
55 hr = IAudioFormatEnumerator_GetFormat(afe, 0, &fmt);
56 ok(hr == S_OK, "Getting format failed: 0x%08x\n", hr);
57 ok(fmt != NULL, "Expected to get non-NULL format\n");
59 ok(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT, "Wrong format, expected WAVE_FORMAT_IEEE_FLOAT got %hx\n", fmt->wFormatTag);
60 ok(fmt->nChannels == 1, "Wrong number of channels, expected 1 got %hu\n", fmt->nChannels);
61 ok(fmt->nSamplesPerSec == 48000, "Wrong sample ret, expected 48000 got %u\n", fmt->nSamplesPerSec);
62 ok(fmt->wBitsPerSample == 32, "Wrong bits per sample, expected 32 got %hu\n", fmt->wBitsPerSample);
63 ok(fmt->nBlockAlign == 4, "Wrong block align, expected 4 got %hu\n", fmt->nBlockAlign);
64 ok(fmt->nAvgBytesPerSec == 192000, "Wrong avg bytes per sec, expected 192000 got %u\n", fmt->nAvgBytesPerSec);
65 ok(fmt->cbSize == 0, "Wrong cbSize for simple format, expected 0, got %hu\n", fmt->cbSize);
67 memcpy(&format, fmt, sizeof(format));
69 IAudioFormatEnumerator_Release(afe);
72 static void fill_activation_params(SpatialAudioObjectRenderStreamActivationParams *activation_params)
74 activation_params->StaticObjectTypeMask = \
75 AudioObjectType_FrontLeft |
76 AudioObjectType_FrontRight |
77 AudioObjectType_FrontCenter |
78 AudioObjectType_LowFrequency |
79 AudioObjectType_SideLeft |
80 AudioObjectType_SideRight |
81 AudioObjectType_BackLeft |
82 AudioObjectType_BackRight |
83 AudioObjectType_TopFrontLeft |
84 AudioObjectType_TopFrontRight |
85 AudioObjectType_TopBackLeft |
86 AudioObjectType_TopBackRight;
88 activation_params->MinDynamicObjectCount = 0;
89 activation_params->MaxDynamicObjectCount = 0;
90 activation_params->Category = AudioCategory_GameEffects;
91 activation_params->EventHandle = event;
92 activation_params->NotifyObject = NULL;
94 activation_params->ObjectFormat = &format;
97 typedef struct NotifyObject
99 ISpatialAudioObjectRenderStreamNotify ISpatialAudioObjectRenderStreamNotify_iface;
100 LONG ref;
101 } NotifyObject;
103 static WINAPI HRESULT notifyobj_QueryInterface(
104 ISpatialAudioObjectRenderStreamNotify *This,
105 REFIID riid,
106 void **ppvObject)
108 return S_OK;
111 static WINAPI ULONG notifyobj_AddRef(
112 ISpatialAudioObjectRenderStreamNotify *This)
114 NotifyObject *obj = CONTAINING_RECORD(This, NotifyObject, ISpatialAudioObjectRenderStreamNotify_iface);
115 ULONG ref = InterlockedIncrement(&obj->ref);
116 return ref;
119 static WINAPI ULONG notifyobj_Release(
120 ISpatialAudioObjectRenderStreamNotify *This)
122 NotifyObject *obj = CONTAINING_RECORD(This, NotifyObject, ISpatialAudioObjectRenderStreamNotify_iface);
123 ULONG ref = InterlockedDecrement(&obj->ref);
124 return ref;
127 static WINAPI HRESULT notifyobj_OnAvailableDynamicObjectCountChange(
128 ISpatialAudioObjectRenderStreamNotify *This,
129 ISpatialAudioObjectRenderStreamBase *stream,
130 LONGLONG deadline,
131 UINT32 object_count)
133 ok(FALSE, "Expected to never be notified of dynamic object count change\n");
134 return S_OK;
137 static const ISpatialAudioObjectRenderStreamNotifyVtbl notifyobjvtbl =
139 notifyobj_QueryInterface,
140 notifyobj_AddRef,
141 notifyobj_Release,
142 notifyobj_OnAvailableDynamicObjectCountChange
145 static void test_stream_activation(void)
147 HRESULT hr;
148 WAVEFORMATEX wrong_format;
149 ISpatialAudioObjectRenderStream *sas = NULL;
151 SpatialAudioObjectRenderStreamActivationParams activation_params;
152 PROPVARIANT activation_params_prop;
153 NotifyObject notify_object;
155 PropVariantInit(&activation_params_prop);
156 activation_params_prop.vt = VT_BLOB;
157 activation_params_prop.blob.cbSize = sizeof(activation_params);
158 activation_params_prop.blob.pBlobData = (BYTE*) &activation_params;
160 /* correct params */
161 fill_activation_params(&activation_params);
162 hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
163 ok(hr == S_OK, "Failed to activate spatial audio stream: 0x%08x\n", hr);
164 ok(ISpatialAudioObjectRenderStream_Release(sas) == 0, "Expected to release the last reference\n");
166 /* event handle */
167 fill_activation_params(&activation_params);
168 activation_params.EventHandle = NULL;
169 hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
170 ok(hr == E_INVALIDARG, "Expected lack of no EventHandle to be invalid: 0x%08x\n", hr);
171 ok(sas == NULL, "Expected spatial audio stream to be set to NULL upon failed activation\n");
173 activation_params.EventHandle = INVALID_HANDLE_VALUE;
174 hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
175 ok(hr == E_INVALIDARG, "Expected INVALID_HANDLE_VALUE to be invalid: 0x%08x\n", hr);
176 ok(sas == NULL, "Expected spatial audio stream to be set to NULL upon failed activation\n");
178 /* must use only queried sample rate */
179 fill_activation_params(&activation_params);
180 memcpy(&wrong_format, &format, sizeof(format));
181 activation_params.ObjectFormat = &wrong_format;
182 wrong_format.nSamplesPerSec = 44100;
183 wrong_format.nAvgBytesPerSec = wrong_format.nSamplesPerSec * wrong_format.nBlockAlign;
184 hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
185 ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT, "Expected format to be unsupported: 0x%08x\n", hr);
186 ok(sas == NULL, "Expected spatial audio stream to be set to NULL upon failed activation\n");
188 /* dynamic objects are not supported */
189 if (max_dyn_count == 0)
191 fill_activation_params(&activation_params);
192 activation_params.StaticObjectTypeMask |= AudioObjectType_Dynamic;
193 hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
194 ok(hr == E_INVALIDARG, "Expected dynamic objects type be invalid: 0x%08x\n", hr);
195 ok(sas == NULL, "Expected spatial audio stream to be set to NULL upon failed activation\n");
198 activation_params.MinDynamicObjectCount = max_dyn_count + 1;
199 activation_params.MaxDynamicObjectCount = max_dyn_count + 1;
200 hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
201 if (max_dyn_count)
202 ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT, "Expected dynamic object count exceeding max to be unsupported: 0x%08x\n", hr);
203 else
204 ok(hr == E_INVALIDARG, "Expected setting dynamic object count to be invalid: 0x%08x\n", hr);
206 /* ISpatialAudioObjectRenderStreamNotify */
207 fill_activation_params(&activation_params);
208 notify_object.ISpatialAudioObjectRenderStreamNotify_iface.lpVtbl = &notifyobjvtbl;
209 notify_object.ref = 0;
210 activation_params.NotifyObject = &notify_object.ISpatialAudioObjectRenderStreamNotify_iface;
211 hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
212 ok(hr == S_OK, "Failed to activate spatial audio stream: 0x%08x\n", hr);
213 ok(notify_object.ref == 1, "Expected to get increased NotifyObject's ref count\n");
214 ok(ISpatialAudioObjectRenderStream_Release(sas) == 0, "Expected to release the last reference\n");
215 ok(notify_object.ref == 0, "Expected to get lowered NotifyObject's ref count\n");
218 static void test_audio_object_activation(void)
220 HRESULT hr;
221 BOOL is_active;
222 ISpatialAudioObjectRenderStream *sas = NULL;
223 ISpatialAudioObject *sao1, *sao2;
225 SpatialAudioObjectRenderStreamActivationParams activation_params;
226 PROPVARIANT activation_params_prop;
228 PropVariantInit(&activation_params_prop);
229 activation_params_prop.vt = VT_BLOB;
230 activation_params_prop.blob.cbSize = sizeof(activation_params);
231 activation_params_prop.blob.pBlobData = (BYTE*) &activation_params;
233 fill_activation_params(&activation_params);
234 activation_params.StaticObjectTypeMask &= ~AudioObjectType_FrontRight;
235 hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
236 ok(hr == S_OK, "Failed to activate spatial audio stream: 0x%08x\n", hr);
238 hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontLeft, &sao1);
239 ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08x\n", hr);
240 hr = ISpatialAudioObject_IsActive(sao1, &is_active);
241 todo_wine ok(hr == S_OK, "Failed to check if spatial audio object is active: 0x%08x\n", hr);
242 if (hr == S_OK)
243 ok(is_active, "Expected spaital audio object to be active\n");
245 hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontLeft, &sao2);
246 ok(hr == SPTLAUDCLNT_E_OBJECT_ALREADY_ACTIVE, "Expected audio object to be already active: 0x%08x\n", hr);
248 hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontRight, &sao2);
249 ok(hr == SPTLAUDCLNT_E_STATIC_OBJECT_NOT_AVAILABLE, "Expected static object to be not available: 0x%08x\n", hr);
251 hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_Dynamic, &sao2);
252 ok(hr == SPTLAUDCLNT_E_NO_MORE_OBJECTS, "Expected to not have no more dynamic objects: 0x%08x\n", hr);
254 ISpatialAudioObject_Release(sao1);
255 ISpatialAudioObjectRenderStream_Release(sas);
258 static BOOL is_buffer_zeroed(const BYTE *buffer, UINT32 buffer_length)
260 UINT32 i;
262 for (i = 0; i < buffer_length; i++)
264 if (buffer[i] != 0)
265 return FALSE;
268 return TRUE;
271 static void test_audio_object_buffers(void)
273 UINT32 dyn_object_count, frame_count, max_frame_count, buffer_length;
274 SpatialAudioObjectRenderStreamActivationParams activation_params;
275 ISpatialAudioObjectRenderStream *sas = NULL;
276 PROPVARIANT activation_params_prop;
277 ISpatialAudioObject *sao[4];
278 BYTE *buffer;
279 INT i, j, k;
280 HRESULT hr;
282 PropVariantInit(&activation_params_prop);
283 activation_params_prop.vt = VT_BLOB;
284 activation_params_prop.blob.cbSize = sizeof(activation_params);
285 activation_params_prop.blob.pBlobData = (BYTE*) &activation_params;
287 fill_activation_params(&activation_params);
288 hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas);
289 ok(hr == S_OK, "Failed to activate spatial audio stream: 0x%08x\n", hr);
291 hr = ISpatialAudioClient_GetMaxFrameCount(sac, &format, &max_frame_count);
292 ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
293 frame_count = format.nSamplesPerSec / 100; /* 10ms */
294 /* Most of the time the frame count matches the 10ms interval exactly.
295 * However (seen on some Testbot machines) it might be a bit higher for some reason. */
296 ok(max_frame_count <= frame_count + frame_count / 4, "Got unexpected frame count %u.\n", frame_count);
298 /* The tests below which check frame count from _BeginUpdatingAudioObjects fail on some Testbot machines
299 * with max_frame_count from _GetMaxFrameCount(). */
300 max_frame_count = frame_count + frame_count / 4;
302 hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontLeft, &sao[0]);
303 ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08x\n", hr);
305 hr = ISpatialAudioObjectRenderStream_Start(sas);
306 ok(hr == S_OK, "Failed to activate spatial audio render stream: 0x%08x\n", hr);
308 hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontRight, &sao[1]);
309 ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08x\n", hr);
311 hr = WaitForSingleObject(event, 200);
312 ok(hr == WAIT_OBJECT_0, "Expected event to be flagged: 0x%08x\n", hr);
314 hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_SideLeft, &sao[2]);
315 ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08x\n", hr);
317 hr = ISpatialAudioObjectRenderStream_BeginUpdatingAudioObjects(sas, &dyn_object_count, &frame_count);
318 ok(hr == S_OK, "Failed to beging updating audio objects: 0x%08x\n", hr);
319 ok(dyn_object_count == 0, "Unexpected dynamic objects\n");
320 ok(frame_count <= max_frame_count, "Got unexpected frame count %u.\n", frame_count);
322 hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_SideRight, &sao[3]);
323 ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08x\n", hr);
325 for (i = 0; i < ARRAYSIZE(sao); i++)
327 hr = ISpatialAudioObject_GetBuffer(sao[i], &buffer, &buffer_length);
328 ok(hr == S_OK, "Expected to be able to get buffers for audio object: 0x%08x\n", hr);
329 ok(buffer != NULL, "Expected to get a non-NULL buffer\n");
330 ok(buffer_length == frame_count * format.wBitsPerSample / 8, "Expected buffer length to be sample_size * frame_count = %hu but got %u\n",
331 frame_count * format.wBitsPerSample / 8, buffer_length);
332 ok(is_buffer_zeroed(buffer, buffer_length), "Expected audio object's buffer to be zeroed\n");
335 hr = ISpatialAudioObjectRenderStream_EndUpdatingAudioObjects(sas);
336 ok(hr == S_OK, "Failed to end updating audio objects: 0x%08x\n", hr);
338 /* Emulate underrun and test frame count approximate limit. */
340 /* Force 1ms Sleep() timer resolution. */
341 timeBeginPeriod(1);
342 for (j = 0; j < 20; ++j)
344 hr = WaitForSingleObject(event, 200);
345 ok(hr == WAIT_OBJECT_0, "Expected event to be flagged: 0x%08x, j %u.\n", hr, j);
347 hr = ISpatialAudioObjectRenderStream_BeginUpdatingAudioObjects(sas, &dyn_object_count, &frame_count);
348 ok(hr == S_OK, "Failed to beging updating audio objects: 0x%08x\n", hr);
349 ok(dyn_object_count == 0, "Unexpected dynamic objects\n");
350 ok(frame_count <= max_frame_count, "Got unexpected frame_count %u.\n", frame_count);
352 /* Audio starts crackling with delays 10ms and above. However, setting such delay (that is, the delay
353 * which skips the whole quantum) breaks SA on some Testbot machines: _BeginUpdatingAudioObjects fails
354 * with SPTLAUDCLNT_E_INTERNAL starting from some iteration or WaitForSingleObject timeouts. That seems
355 * to work on the real hardware though. */
356 Sleep(5);
358 for (i = 0; i < ARRAYSIZE(sao); i++)
360 hr = ISpatialAudioObject_GetBuffer(sao[i], &buffer, &buffer_length);
361 ok(hr == S_OK, "Expected to be able to get buffers for audio object: 0x%08x, i %d\n", hr, i);
362 ok(buffer != NULL, "Expected to get a non-NULL buffer\n");
363 ok(buffer_length == frame_count * format.wBitsPerSample / 8,
364 "Expected buffer length to be sample_size * frame_count = %hu but got %u\n",
365 frame_count * format.wBitsPerSample / 8, buffer_length);
367 /* Enable to hear the test sound. */
368 if (0)
370 if (format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
372 for (k = 0; k < frame_count; ++k)
374 float time_sec = 10.0f / 1000.0f * (j + (float)k / frame_count);
376 /* 440Hz tone. */
377 ((float *)buffer)[k] = sinf(2.0f * M_PI * time_sec * 440.0f);
382 hr = ISpatialAudioObjectRenderStream_EndUpdatingAudioObjects(sas);
383 ok(hr == S_OK, "Failed to end updating audio objects: 0x%08x\n", hr);
385 timeEndPeriod(1);
387 hr = WaitForSingleObject(event, 200);
388 ok(hr == WAIT_OBJECT_0, "Expected event to be flagged: 0x%08x\n", hr);
390 hr = ISpatialAudioObjectRenderStream_BeginUpdatingAudioObjects(sas, &dyn_object_count, &frame_count);
391 ok(hr == S_OK, "Failed to beging updating audio objects: 0x%08x\n", hr);
392 ok(dyn_object_count == 0, "Unexpected dynamic objects\n");
394 /* one more iteration but not with every object */
395 for (i = 0; i < ARRAYSIZE(sao) - 1; i++)
397 hr = ISpatialAudioObject_GetBuffer(sao[i], &buffer, &buffer_length);
398 ok(hr == S_OK, "Expected to be able to get buffers for audio object: 0x%08x\n", hr);
399 ok(buffer != NULL, "Expected to get a non-NULL buffer\n");
400 ok(buffer_length == frame_count * format.wBitsPerSample / 8, "Expected buffer length to be sample_size * frame_count = %hu but got %u\n",
401 frame_count * format.wBitsPerSample / 8, buffer_length);
402 ok(is_buffer_zeroed(buffer, buffer_length), "Expected audio object's buffer to be zeroed\n");
405 hr = ISpatialAudioObjectRenderStream_EndUpdatingAudioObjects(sas);
406 ok(hr == S_OK, "Failed to end updating audio objects: 0x%08x\n", hr);
408 /* ending the stream */
409 hr = ISpatialAudioObject_SetEndOfStream(sao[0], 0);
410 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);
412 hr = WaitForSingleObject(event, 200);
413 ok(hr == WAIT_OBJECT_0, "Expected event to be flagged: 0x%08x\n", hr);
415 hr = ISpatialAudioObject_SetEndOfStream(sao[0], 0);
416 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);
418 hr = ISpatialAudioObjectRenderStream_BeginUpdatingAudioObjects(sas, &dyn_object_count, &frame_count);
419 ok(hr == S_OK, "Failed to beging updating audio objects: 0x%08x\n", hr);
420 ok(dyn_object_count == 0, "Unexpected dynamic objects\n");
422 /* expect the object that was not updated last cycle to be invalidated */
423 hr = ISpatialAudioObject_GetBuffer(sao[ARRAYSIZE(sao) - 1], &buffer, &buffer_length);
424 todo_wine ok(hr == SPTLAUDCLNT_E_RESOURCES_INVALIDATED, "Expected audio object to be invalidated: 0x%08x\n", hr);
426 for (i = 0; i < ARRAYSIZE(sao) - 1; i++)
428 hr = ISpatialAudioObject_GetBuffer(sao[i], &buffer, &buffer_length);
429 ok(hr == S_OK, "Expected to be able to get buffers for audio object: 0x%08x\n", hr);
431 hr = ISpatialAudioObject_SetEndOfStream(sao[i], 0);
432 todo_wine ok(hr == S_OK, "Failed to end the stream: 0x%08x\n", hr);
434 hr = ISpatialAudioObject_GetBuffer(sao[i], &buffer, &buffer_length);
435 todo_wine ok(hr == SPTLAUDCLNT_E_RESOURCES_INVALIDATED, "Expected audio object to be invalidated: 0x%08x\n", hr);
438 hr = ISpatialAudioObjectRenderStream_EndUpdatingAudioObjects(sas);
439 ok(hr == S_OK, "Failed to end updating audio objects: 0x%08x\n", hr);
441 for (i = 0; i < ARRAYSIZE(sao); i++)
443 ISpatialAudioObject_Release(sao[i]);
446 ISpatialAudioObjectRenderStream_Release(sas);
449 START_TEST(spatialaudio)
451 HRESULT hr;
453 event = CreateEventA(NULL, FALSE, FALSE, "spatial-audio-test-prog-event");
454 ok(event != NULL, "Failed to create event, last error: 0x%08x\n", GetLastError());
456 CoInitializeEx(NULL, COINIT_MULTITHREADED);
457 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&mme);
458 if (FAILED(hr))
460 skip("mmdevapi not available: 0x%08x\n", hr);
461 goto cleanup;
464 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(mme, eRender, eMultimedia, &dev);
465 ok(hr == S_OK || hr == E_NOTFOUND, "GetDefaultAudioEndpoint failed: 0x%08x\n", hr);
466 if (hr != S_OK || !dev)
468 if (hr == E_NOTFOUND)
469 skip("No sound card available\n");
470 else
471 skip("GetDefaultAudioEndpoint returns 0x%08x\n", hr);
472 goto cleanup;
475 hr = IMMDevice_Activate(dev, &IID_ISpatialAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)&sac);
476 ok(hr == S_OK || hr == E_NOINTERFACE, "ISpatialAudioClient Activation failed: 0x%08x\n", hr);
477 if (hr != S_OK || !dev)
479 if (hr == E_NOINTERFACE)
480 skip("ISpatialAudioClient interface not found\n");
481 else
482 skip("ISpatialAudioClient Activation returns 0x%08x\n", hr);
483 goto cleanup;
486 hr = ISpatialAudioClient_GetMaxDynamicObjectCount(sac, &max_dyn_count);
487 ok(hr == S_OK, "Failed to get max dynamic object count: 0x%08x\n", hr);
489 /* that's the default, after manually enabling Windows Sonic it's possible to have max_dyn_count > 0 */
490 /* ok(max_dyn_count == 0, "expected max dynamic object count to be 0 got %u\n", max_dyn_count); */
492 test_formats();
493 test_stream_activation();
494 test_audio_object_activation();
495 test_audio_object_buffers();
497 ISpatialAudioClient_Release(sac);
499 cleanup:
500 if (dev)
501 IMMDevice_Release(dev);
502 if (mme)
503 IMMDeviceEnumerator_Release(mme);
504 CoUninitialize();
505 CloseHandle(event);