2 * DirectSound renderer filter unit tests
4 * Copyright (C) 2010 Maarten Lankhorst for CodeWeavers
5 * Copyright (C) 2007 Google (Lei Zhang)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "wine/strmbase.h"
30 #include "wine/test.h"
32 static const WCHAR sink_id
[] = L
"Audio Input pin (rendered)";
34 static IBaseFilter
*create_dsound_render(void)
36 IBaseFilter
*filter
= NULL
;
37 HRESULT hr
= CoCreateInstance(&CLSID_DSoundRender
, NULL
, CLSCTX_INPROC_SERVER
,
38 &IID_IBaseFilter
, (void **)&filter
);
39 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
43 static inline BOOL
compare_media_types(const AM_MEDIA_TYPE
*a
, const AM_MEDIA_TYPE
*b
)
45 return !memcmp(a
, b
, offsetof(AM_MEDIA_TYPE
, pbFormat
))
46 && !memcmp(a
->pbFormat
, b
->pbFormat
, a
->cbFormat
);
49 static ULONG
get_refcount(void *iface
)
51 IUnknown
*unknown
= iface
;
52 IUnknown_AddRef(unknown
);
53 return IUnknown_Release(unknown
);
56 static HRESULT WINAPI
property_bag_QueryInterface(IPropertyBag
*iface
, REFIID iid
, void **out
)
58 ok(0, "Unexpected call (iid %s).\n", wine_dbgstr_guid(iid
));
62 static ULONG WINAPI
property_bag_AddRef(IPropertyBag
*iface
)
64 ok(0, "Unexpected call.\n");
68 static ULONG WINAPI
property_bag_Release(IPropertyBag
*iface
)
70 ok(0, "Unexpected call.\n");
74 static HRESULT WINAPI
property_bag_Read(IPropertyBag
*iface
, const WCHAR
*name
, VARIANT
*var
, IErrorLog
*log
)
78 ok(!wcscmp(name
, L
"DSGuid"), "Got unexpected name %s.\n", wine_dbgstr_w(name
));
79 ok(V_VT(var
) == VT_BSTR
, "Got unexpected type %u.\n", V_VT(var
));
80 StringFromGUID2(&DSDEVID_DefaultPlayback
, guidstr
, ARRAY_SIZE(guidstr
));
81 V_BSTR(var
) = SysAllocString(guidstr
);
85 static HRESULT WINAPI
property_bag_Write(IPropertyBag
*iface
, const WCHAR
*name
, VARIANT
*var
)
87 ok(0, "Unexpected call (name %s).\n", wine_dbgstr_w(name
));
91 static const IPropertyBagVtbl property_bag_vtbl
=
93 property_bag_QueryInterface
,
100 static void test_property_bag(void)
102 IPropertyBag property_bag
= {&property_bag_vtbl
};
103 IPersistPropertyBag
*ppb
;
107 hr
= CoCreateInstance(&CLSID_DSoundRender
, NULL
, CLSCTX_INPROC_SERVER
,
108 &IID_IPersistPropertyBag
, (void **)&ppb
);
109 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
110 if (hr
!= S_OK
) return;
112 hr
= IPersistPropertyBag_InitNew(ppb
);
113 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
115 hr
= IPersistPropertyBag_Load(ppb
, &property_bag
, NULL
);
116 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
118 ref
= IPersistPropertyBag_Release(ppb
);
119 ok(!ref
, "Got unexpected refcount %d.\n", ref
);
122 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
123 static void check_interface_(unsigned int line
, void *iface_ptr
, REFIID iid
, BOOL supported
)
125 IUnknown
*iface
= iface_ptr
;
126 HRESULT hr
, expected_hr
;
129 expected_hr
= supported
? S_OK
: E_NOINTERFACE
;
131 hr
= IUnknown_QueryInterface(iface
, iid
, (void **)&unk
);
132 ok_(__FILE__
, line
)(hr
== expected_hr
, "Got hr %#x, expected %#x.\n", hr
, expected_hr
);
134 IUnknown_Release(unk
);
137 static void test_interfaces(void)
139 IBaseFilter
*filter
= create_dsound_render();
142 check_interface(filter
, &IID_IAMDirectSound
, TRUE
);
143 check_interface(filter
, &IID_IBaseFilter
, TRUE
);
144 check_interface(filter
, &IID_IBasicAudio
, TRUE
);
145 todo_wine
check_interface(filter
, &IID_IDirectSound3DBuffer
, TRUE
);
146 check_interface(filter
, &IID_IMediaFilter
, TRUE
);
147 check_interface(filter
, &IID_IMediaPosition
, TRUE
);
148 check_interface(filter
, &IID_IMediaSeeking
, TRUE
);
149 check_interface(filter
, &IID_IPersist
, TRUE
);
150 todo_wine
check_interface(filter
, &IID_IPersistPropertyBag
, TRUE
);
151 check_interface(filter
, &IID_IQualityControl
, TRUE
);
152 check_interface(filter
, &IID_IReferenceClock
, TRUE
);
153 check_interface(filter
, &IID_IUnknown
, TRUE
);
155 check_interface(filter
, &IID_IAMFilterMiscFlags
, FALSE
);
156 check_interface(filter
, &IID_IBasicVideo
, FALSE
);
157 check_interface(filter
, &IID_IDispatch
, FALSE
);
158 check_interface(filter
, &IID_IKsPropertySet
, FALSE
);
159 check_interface(filter
, &IID_IPin
, FALSE
);
160 check_interface(filter
, &IID_IQualProp
, FALSE
);
161 check_interface(filter
, &IID_IVideoWindow
, FALSE
);
163 IBaseFilter_FindPin(filter
, sink_id
, &pin
);
165 check_interface(pin
, &IID_IPin
, TRUE
);
166 check_interface(pin
, &IID_IMemInputPin
, TRUE
);
167 todo_wine
check_interface(pin
, &IID_IQualityControl
, TRUE
);
168 check_interface(pin
, &IID_IUnknown
, TRUE
);
170 check_interface(pin
, &IID_IAsyncReader
, FALSE
);
171 check_interface(pin
, &IID_IMediaPosition
, FALSE
);
172 check_interface(pin
, &IID_IMediaSeeking
, FALSE
);
175 IBaseFilter_Release(filter
);
178 static const GUID test_iid
= {0x33333333};
179 static LONG outer_ref
= 1;
181 static HRESULT WINAPI
outer_QueryInterface(IUnknown
*iface
, REFIID iid
, void **out
)
183 if (IsEqualGUID(iid
, &IID_IUnknown
)
184 || IsEqualGUID(iid
, &IID_IBaseFilter
)
185 || IsEqualGUID(iid
, &test_iid
))
187 *out
= (IUnknown
*)0xdeadbeef;
190 ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid
));
191 return E_NOINTERFACE
;
194 static ULONG WINAPI
outer_AddRef(IUnknown
*iface
)
196 return InterlockedIncrement(&outer_ref
);
199 static ULONG WINAPI
outer_Release(IUnknown
*iface
)
201 return InterlockedDecrement(&outer_ref
);
204 static const IUnknownVtbl outer_vtbl
=
206 outer_QueryInterface
,
211 static IUnknown test_outer
= {&outer_vtbl
};
213 static void test_aggregation(void)
215 IBaseFilter
*filter
, *filter2
;
216 IUnknown
*unk
, *unk2
;
220 filter
= (IBaseFilter
*)0xdeadbeef;
221 hr
= CoCreateInstance(&CLSID_DSoundRender
, &test_outer
, CLSCTX_INPROC_SERVER
,
222 &IID_IBaseFilter
, (void **)&filter
);
223 ok(hr
== E_NOINTERFACE
, "Got hr %#x.\n", hr
);
224 ok(!filter
, "Got interface %p.\n", filter
);
226 hr
= CoCreateInstance(&CLSID_DSoundRender
, &test_outer
, CLSCTX_INPROC_SERVER
,
227 &IID_IUnknown
, (void **)&unk
);
228 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
229 ok(outer_ref
== 1, "Got unexpected refcount %d.\n", outer_ref
);
230 ok(unk
!= &test_outer
, "Returned IUnknown should not be outer IUnknown.\n");
231 ref
= get_refcount(unk
);
232 ok(ref
== 1, "Got unexpected refcount %d.\n", ref
);
234 ref
= IUnknown_AddRef(unk
);
235 ok(ref
== 2, "Got unexpected refcount %d.\n", ref
);
236 ok(outer_ref
== 1, "Got unexpected refcount %d.\n", outer_ref
);
238 ref
= IUnknown_Release(unk
);
239 ok(ref
== 1, "Got unexpected refcount %d.\n", ref
);
240 ok(outer_ref
== 1, "Got unexpected refcount %d.\n", outer_ref
);
242 hr
= IUnknown_QueryInterface(unk
, &IID_IUnknown
, (void **)&unk2
);
243 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
244 ok(unk2
== unk
, "Got unexpected IUnknown %p.\n", unk2
);
245 IUnknown_Release(unk2
);
247 hr
= IUnknown_QueryInterface(unk
, &IID_IBaseFilter
, (void **)&filter
);
248 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
250 hr
= IBaseFilter_QueryInterface(filter
, &IID_IUnknown
, (void **)&unk2
);
251 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
252 ok(unk2
== (IUnknown
*)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2
);
254 hr
= IBaseFilter_QueryInterface(filter
, &IID_IBaseFilter
, (void **)&filter2
);
255 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
256 ok(filter2
== (IBaseFilter
*)0xdeadbeef, "Got unexpected IBaseFilter %p.\n", filter2
);
258 hr
= IUnknown_QueryInterface(unk
, &test_iid
, (void **)&unk2
);
259 ok(hr
== E_NOINTERFACE
, "Got hr %#x.\n", hr
);
260 ok(!unk2
, "Got unexpected IUnknown %p.\n", unk2
);
262 hr
= IBaseFilter_QueryInterface(filter
, &test_iid
, (void **)&unk2
);
263 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
264 ok(unk2
== (IUnknown
*)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2
);
266 IBaseFilter_Release(filter
);
267 ref
= IUnknown_Release(unk
);
268 ok(!ref
, "Got unexpected refcount %d.\n", ref
);
269 ok(outer_ref
== 1, "Got unexpected refcount %d.\n", outer_ref
);
272 static void test_enum_pins(void)
274 IBaseFilter
*filter
= create_dsound_render();
275 IEnumPins
*enum1
, *enum2
;
280 ref
= get_refcount(filter
);
281 ok(ref
== 1, "Got unexpected refcount %d.\n", ref
);
283 hr
= IBaseFilter_EnumPins(filter
, NULL
);
284 ok(hr
== E_POINTER
, "Got hr %#x.\n", hr
);
286 hr
= IBaseFilter_EnumPins(filter
, &enum1
);
287 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
288 ref
= get_refcount(filter
);
289 ok(ref
== 2, "Got unexpected refcount %d.\n", ref
);
290 ref
= get_refcount(enum1
);
291 ok(ref
== 1, "Got unexpected refcount %d.\n", ref
);
293 hr
= IEnumPins_Next(enum1
, 1, NULL
, NULL
);
294 ok(hr
== E_POINTER
, "Got hr %#x.\n", hr
);
296 hr
= IEnumPins_Next(enum1
, 1, pins
, NULL
);
297 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
298 ref
= get_refcount(filter
);
299 ok(ref
== 3, "Got unexpected refcount %d.\n", ref
);
300 ref
= get_refcount(pins
[0]);
301 ok(ref
== 3, "Got unexpected refcount %d.\n", ref
);
302 ref
= get_refcount(enum1
);
303 ok(ref
== 1, "Got unexpected refcount %d.\n", ref
);
304 IPin_Release(pins
[0]);
305 ref
= get_refcount(filter
);
306 ok(ref
== 2, "Got unexpected refcount %d.\n", ref
);
308 hr
= IEnumPins_Next(enum1
, 1, pins
, NULL
);
309 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
311 hr
= IEnumPins_Reset(enum1
);
312 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
314 hr
= IEnumPins_Next(enum1
, 1, pins
, &count
);
315 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
316 ok(count
== 1, "Got count %u.\n", count
);
317 IPin_Release(pins
[0]);
319 hr
= IEnumPins_Next(enum1
, 1, pins
, &count
);
320 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
321 ok(!count
, "Got count %u.\n", count
);
323 hr
= IEnumPins_Reset(enum1
);
324 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
326 hr
= IEnumPins_Next(enum1
, 2, pins
, NULL
);
327 ok(hr
== E_INVALIDARG
, "Got hr %#x.\n", hr
);
329 hr
= IEnumPins_Next(enum1
, 2, pins
, &count
);
330 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
331 ok(count
== 1, "Got count %u.\n", count
);
332 IPin_Release(pins
[0]);
334 hr
= IEnumPins_Reset(enum1
);
335 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
337 hr
= IEnumPins_Clone(enum1
, &enum2
);
338 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
340 hr
= IEnumPins_Skip(enum1
, 2);
341 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
343 hr
= IEnumPins_Skip(enum1
, 1);
344 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
346 hr
= IEnumPins_Skip(enum1
, 1);
347 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
349 hr
= IEnumPins_Next(enum1
, 1, pins
, NULL
);
350 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
352 hr
= IEnumPins_Next(enum2
, 1, pins
, NULL
);
353 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
354 IPin_Release(pins
[0]);
356 IEnumPins_Release(enum2
);
357 IEnumPins_Release(enum1
);
358 ref
= IBaseFilter_Release(filter
);
359 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
362 static void test_find_pin(void)
364 IBaseFilter
*filter
= create_dsound_render();
365 IEnumPins
*enum_pins
;
370 hr
= IBaseFilter_FindPin(filter
, L
"In", &pin
);
371 ok(hr
== VFW_E_NOT_FOUND
, "Got hr %#x.\n", hr
);
373 hr
= IBaseFilter_FindPin(filter
, L
"input pin", &pin
);
374 ok(hr
== VFW_E_NOT_FOUND
, "Got hr %#x.\n", hr
);
376 hr
= IBaseFilter_FindPin(filter
, sink_id
, &pin
);
377 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
379 hr
= IBaseFilter_EnumPins(filter
, &enum_pins
);
380 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
382 hr
= IEnumPins_Next(enum_pins
, 1, &pin2
, NULL
);
383 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
384 ok(pin
== pin2
, "Expected pin %p, got %p.\n", pin2
, pin
);
388 IEnumPins_Release(enum_pins
);
389 ref
= IBaseFilter_Release(filter
);
390 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
393 static void test_pin_info(void)
395 IBaseFilter
*filter
= create_dsound_render();
403 hr
= IBaseFilter_FindPin(filter
, sink_id
, &pin
);
404 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
405 ref
= get_refcount(filter
);
406 ok(ref
== 2, "Got unexpected refcount %d.\n", ref
);
407 ref
= get_refcount(pin
);
408 ok(ref
== 2, "Got unexpected refcount %d.\n", ref
);
410 hr
= IPin_QueryPinInfo(pin
, &info
);
411 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
412 ok(info
.pFilter
== filter
, "Expected filter %p, got %p.\n", filter
, info
.pFilter
);
413 ok(info
.dir
== PINDIR_INPUT
, "Got direction %d.\n", info
.dir
);
414 ok(!wcscmp(info
.achName
, sink_id
), "Got name %s.\n", wine_dbgstr_w(info
.achName
));
415 ref
= get_refcount(filter
);
416 ok(ref
== 3, "Got unexpected refcount %d.\n", ref
);
417 ref
= get_refcount(pin
);
418 ok(ref
== 3, "Got unexpected refcount %d.\n", ref
);
419 IBaseFilter_Release(info
.pFilter
);
421 hr
= IPin_QueryDirection(pin
, &dir
);
422 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
423 ok(dir
== PINDIR_INPUT
, "Got direction %d.\n", dir
);
425 hr
= IPin_QueryId(pin
, &id
);
426 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
427 ok(!wcscmp(id
, sink_id
), "Got id %s.\n", wine_dbgstr_w(id
));
430 hr
= IPin_QueryInternalConnections(pin
, NULL
, NULL
);
431 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
434 ref
= IBaseFilter_Release(filter
);
435 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
438 static void test_basic_audio(void)
440 IBaseFilter
*filter
= create_dsound_render();
441 LONG balance
, volume
;
448 hr
= IBaseFilter_QueryInterface(filter
, &IID_IBasicAudio
, (void **)&audio
);
449 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
451 hr
= IBasicAudio_get_Balance(audio
, NULL
);
452 ok(hr
== E_POINTER
, "Got hr %#x.\n", hr
);
454 hr
= IBasicAudio_get_Balance(audio
, &balance
);
455 if (hr
!= VFW_E_MONO_AUDIO_HW
)
457 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
458 ok(balance
== 0, "Got balance %d.\n", balance
);
460 hr
= IBasicAudio_put_Balance(audio
, DSBPAN_LEFT
- 1);
461 ok(hr
== E_INVALIDARG
, "Got hr %#x.\n", hr
);
463 hr
= IBasicAudio_put_Balance(audio
, DSBPAN_LEFT
);
464 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
466 hr
= IBasicAudio_get_Balance(audio
, &balance
);
467 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
468 ok(balance
== DSBPAN_LEFT
, "Got balance %d.\n", balance
);
471 hr
= IBasicAudio_get_Volume(audio
, &volume
);
472 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
473 ok(volume
== 0, "Got volume %d.\n", volume
);
475 hr
= IBasicAudio_put_Volume(audio
, DSBVOLUME_MIN
- 1);
476 ok(hr
== E_INVALIDARG
, "Got hr %#x.\n", hr
);
478 hr
= IBasicAudio_put_Volume(audio
, DSBVOLUME_MIN
);
479 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
481 hr
= IBasicAudio_get_Volume(audio
, &volume
);
482 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
483 ok(volume
== DSBVOLUME_MIN
, "Got volume %d.\n", volume
);
485 hr
= IBasicAudio_GetTypeInfoCount(audio
, &count
);
486 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
487 ok(count
== 1, "Got count %u.\n", count
);
489 hr
= IBasicAudio_GetTypeInfo(audio
, 0, 0, &typeinfo
);
490 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
491 hr
= ITypeInfo_GetTypeAttr(typeinfo
, &typeattr
);
492 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
493 ok(typeattr
->typekind
== TKIND_DISPATCH
, "Got kind %u.\n", typeattr
->typekind
);
494 ok(IsEqualGUID(&typeattr
->guid
, &IID_IBasicAudio
), "Got IID %s.\n", wine_dbgstr_guid(&typeattr
->guid
));
495 ITypeInfo_ReleaseTypeAttr(typeinfo
, typeattr
);
496 ITypeInfo_Release(typeinfo
);
498 IBasicAudio_Release(audio
);
499 ref
= IBaseFilter_Release(filter
);
500 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
503 static void test_enum_media_types(void)
505 IBaseFilter
*filter
= create_dsound_render();
506 IEnumMediaTypes
*enum1
, *enum2
;
507 AM_MEDIA_TYPE
*mts
[2];
512 IBaseFilter_FindPin(filter
, sink_id
, &pin
);
514 hr
= IPin_EnumMediaTypes(pin
, &enum1
);
515 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
517 hr
= IEnumMediaTypes_Next(enum1
, 1, mts
, NULL
);
518 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
519 if (hr
== S_OK
) CoTaskMemFree(mts
[0]->pbFormat
);
520 if (hr
== S_OK
) CoTaskMemFree(mts
[0]);
522 hr
= IEnumMediaTypes_Next(enum1
, 1, mts
, NULL
);
523 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
525 hr
= IEnumMediaTypes_Reset(enum1
);
526 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
528 hr
= IEnumMediaTypes_Next(enum1
, 1, mts
, &count
);
529 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
530 todo_wine
ok(count
== 1, "Got count %u.\n", count
);
531 if (hr
== S_OK
) CoTaskMemFree(mts
[0]->pbFormat
);
532 if (hr
== S_OK
) CoTaskMemFree(mts
[0]);
534 hr
= IEnumMediaTypes_Next(enum1
, 1, mts
, &count
);
535 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
536 ok(!count
, "Got count %u.\n", count
);
538 hr
= IEnumMediaTypes_Reset(enum1
);
539 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
541 hr
= IEnumMediaTypes_Next(enum1
, 2, mts
, &count
);
542 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
543 todo_wine
ok(count
== 1, "Got count %u.\n", count
);
544 if (count
> 0) CoTaskMemFree(mts
[0]->pbFormat
);
545 if (count
> 0) CoTaskMemFree(mts
[0]);
547 hr
= IEnumMediaTypes_Reset(enum1
);
548 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
550 hr
= IEnumMediaTypes_Clone(enum1
, &enum2
);
551 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
553 hr
= IEnumMediaTypes_Skip(enum1
, 2);
554 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
556 hr
= IEnumMediaTypes_Skip(enum1
, 1);
557 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
559 hr
= IEnumMediaTypes_Reset(enum1
);
560 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
562 hr
= IEnumMediaTypes_Skip(enum1
, 1);
563 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
565 hr
= IEnumMediaTypes_Skip(enum1
, 1);
566 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
568 hr
= IEnumMediaTypes_Next(enum1
, 1, mts
, NULL
);
569 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
571 hr
= IEnumMediaTypes_Next(enum2
, 1, mts
, NULL
);
572 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
573 if (hr
== S_OK
) CoTaskMemFree(mts
[0]->pbFormat
);
574 if (hr
== S_OK
) CoTaskMemFree(mts
[0]);
576 IEnumMediaTypes_Release(enum1
);
577 IEnumMediaTypes_Release(enum2
);
580 ref
= IBaseFilter_Release(filter
);
581 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
586 struct strmbase_filter filter
;
587 struct strmbase_source source
;
590 static inline struct testfilter
*impl_from_strmbase_filter(struct strmbase_filter
*iface
)
592 return CONTAINING_RECORD(iface
, struct testfilter
, filter
);
595 static struct strmbase_pin
*testfilter_get_pin(struct strmbase_filter
*iface
, unsigned int index
)
597 struct testfilter
*filter
= impl_from_strmbase_filter(iface
);
599 return &filter
->source
.pin
;
603 static void testfilter_destroy(struct strmbase_filter
*iface
)
605 struct testfilter
*filter
= impl_from_strmbase_filter(iface
);
606 strmbase_source_cleanup(&filter
->source
);
607 strmbase_filter_cleanup(&filter
->filter
);
610 static const struct strmbase_filter_ops testfilter_ops
=
612 .filter_get_pin
= testfilter_get_pin
,
613 .filter_destroy
= testfilter_destroy
,
616 static HRESULT
testsource_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
618 ok(!IsEqualGUID(iid
, &IID_IQualityControl
), "Unexpected query for IQualityControl.\n");
619 return E_NOINTERFACE
;
622 static HRESULT WINAPI
testsource_DecideAllocator(struct strmbase_source
*iface
,
623 IMemInputPin
*peer
, IMemAllocator
**allocator
)
628 static const struct strmbase_source_ops testsource_ops
=
630 .base
.pin_query_interface
= testsource_query_interface
,
631 .pfnAttemptConnection
= BaseOutputPinImpl_AttemptConnection
,
632 .pfnDecideAllocator
= testsource_DecideAllocator
,
635 static void testfilter_init(struct testfilter
*filter
)
637 static const GUID clsid
= {0xabacab};
638 strmbase_filter_init(&filter
->filter
, NULL
, &clsid
, &testfilter_ops
);
639 strmbase_source_init(&filter
->source
, &filter
->filter
, L
"", &testsource_ops
);
642 static void test_allocator(IMemInputPin
*input
)
644 IMemAllocator
*req_allocator
, *ret_allocator
;
645 ALLOCATOR_PROPERTIES props
;
648 hr
= IMemInputPin_GetAllocatorRequirements(input
, &props
);
649 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
651 hr
= IMemInputPin_GetAllocator(input
, &ret_allocator
);
652 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
656 hr
= IMemAllocator_GetProperties(ret_allocator
, &props
);
657 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
658 ok(!props
.cBuffers
, "Got %d buffers.\n", props
.cBuffers
);
659 ok(!props
.cbBuffer
, "Got size %d.\n", props
.cbBuffer
);
660 ok(!props
.cbAlign
, "Got alignment %d.\n", props
.cbAlign
);
661 ok(!props
.cbPrefix
, "Got prefix %d.\n", props
.cbPrefix
);
663 hr
= IMemInputPin_NotifyAllocator(input
, ret_allocator
, TRUE
);
664 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
665 IMemAllocator_Release(ret_allocator
);
668 hr
= IMemInputPin_NotifyAllocator(input
, NULL
, TRUE
);
669 ok(hr
== E_POINTER
, "Got hr %#x.\n", hr
);
671 CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
,
672 &IID_IMemAllocator
, (void **)&req_allocator
);
674 hr
= IMemInputPin_NotifyAllocator(input
, req_allocator
, TRUE
);
675 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
677 hr
= IMemInputPin_GetAllocator(input
, &ret_allocator
);
678 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
679 ok(ret_allocator
== req_allocator
, "Allocators didn't match.\n");
681 IMemAllocator_Release(req_allocator
);
682 IMemAllocator_Release(ret_allocator
);
685 struct frame_thread_params
688 IMediaSample
*sample
;
691 static DWORD WINAPI
frame_thread(void *arg
)
693 struct frame_thread_params
*params
= arg
;
696 if (winetest_debug
> 1) trace("%04x: Sending frame.\n", GetCurrentThreadId());
697 hr
= IMemInputPin_Receive(params
->sink
, params
->sample
);
698 if (winetest_debug
> 1) trace("%04x: Returned %#x.\n", GetCurrentThreadId(), hr
);
699 IMediaSample_Release(params
->sample
);
704 static HRESULT
send_frame(IMemInputPin
*sink
)
706 struct frame_thread_params
*params
= malloc(sizeof(*params
));
707 REFERENCE_TIME start_time
, end_time
;
708 IMemAllocator
*allocator
;
709 unsigned short *words
;
710 IMediaSample
*sample
;
717 hr
= IMemInputPin_GetAllocator(sink
, &allocator
);
718 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
720 hr
= IMemAllocator_GetBuffer(allocator
, &sample
, NULL
, NULL
, 0);
721 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
723 hr
= IMediaSample_GetPointer(sample
, &data
);
724 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
725 words
= (unsigned short *)data
;
726 for (i
= 0; i
< 44100 * 2; i
+= 2)
727 words
[i
] = words
[i
+1] = sinf(i
/ 20.0f
) * 0x7fff;
729 hr
= IMediaSample_SetActualDataLength(sample
, 44100 * 4);
730 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
733 end_time
= start_time
+ 10000000;
734 hr
= IMediaSample_SetTime(sample
, &start_time
, &end_time
);
735 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
738 params
->sample
= sample
;
739 thread
= CreateThread(NULL
, 0, frame_thread
, params
, 0, NULL
);
740 ret
= WaitForSingleObject(thread
, 500);
741 todo_wine_if (ret
) ok(!ret
, "Wait failed.\n");
742 GetExitCodeThread(thread
, &ret
);
745 IMemAllocator_Release(allocator
);
749 static void test_filter_state(IMemInputPin
*input
, IMediaControl
*control
)
754 hr
= send_frame(input
);
755 ok(hr
== VFW_E_WRONG_STATE
, "Got hr %#x.\n", hr
);
757 /* The renderer is not fully paused until it receives a sample. The
758 * DirectSound renderer never blocks in Receive(), despite returning S_OK
759 * from ReceiveCanBlock(). Instead it holds on to each sample until its
760 * presentation time, then writes it into the buffer. This is more work
761 * than it's worth to emulate, so for now, we'll ignore this behaviour. */
763 hr
= IMediaControl_Pause(control
);
764 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
766 /* It's possible to queue multiple samples while paused. The number of
767 * samples that can be queued depends on the length of each sample, but
768 * it's not particularly clear how. */
770 hr
= IMediaControl_GetState(control
, 0, &state
);
771 ok(hr
== VFW_S_STATE_INTERMEDIATE
, "Got hr %#x.\n", hr
);
773 hr
= send_frame(input
);
774 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
776 hr
= IMediaControl_GetState(control
, 1000, &state
);
777 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
779 hr
= IMediaControl_Stop(control
);
780 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
782 hr
= send_frame(input
);
783 ok(hr
== VFW_E_WRONG_STATE
, "Got hr %#x.\n", hr
);
785 hr
= IMediaControl_Pause(control
);
786 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
788 hr
= IMediaControl_GetState(control
, 0, &state
);
789 ok(hr
== VFW_S_STATE_INTERMEDIATE
, "Got hr %#x.\n", hr
);
791 hr
= send_frame(input
);
792 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
794 hr
= IMediaControl_GetState(control
, 1000, &state
);
795 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
797 hr
= IMediaControl_Run(control
);
798 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
800 hr
= IMediaControl_GetState(control
, 0, &state
);
801 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
803 hr
= send_frame(input
);
804 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
806 hr
= send_frame(input
);
807 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
809 hr
= IMediaControl_GetState(control
, 0, &state
);
810 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
812 hr
= IMediaControl_Run(control
);
813 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
815 hr
= IMediaControl_GetState(control
, 0, &state
);
816 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
818 hr
= IMediaControl_Pause(control
);
819 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
821 hr
= IMediaControl_GetState(control
, 0, &state
);
822 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
824 hr
= IMediaControl_Stop(control
);
825 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
827 hr
= IMediaControl_GetState(control
, 0, &state
);
828 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
830 /* The DirectSound renderer will silently refuse to transition to running
831 * if it hasn't finished pausing yet. Once it does it reports itself as
832 * completely paused. */
835 static void test_flushing(IPin
*pin
, IMemInputPin
*input
, IMediaControl
*control
)
840 hr
= IMediaControl_Pause(control
);
841 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
843 hr
= send_frame(input
);
844 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
846 hr
= IMediaControl_GetState(control
, 0, &state
);
847 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
849 hr
= IPin_BeginFlush(pin
);
850 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
852 hr
= send_frame(input
);
853 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
855 hr
= IPin_EndFlush(pin
);
856 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
858 hr
= IMediaControl_GetState(control
, 0, &state
);
859 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
861 hr
= IMediaControl_Run(control
);
862 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
864 hr
= IPin_BeginFlush(pin
);
865 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
867 hr
= send_frame(input
);
868 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
870 hr
= IPin_EndFlush(pin
);
871 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
873 hr
= send_frame(input
);
874 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
876 hr
= IMediaControl_Stop(control
);
877 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
880 static unsigned int check_ec_complete(IMediaEvent
*eventsrc
, DWORD timeout
)
882 LONG_PTR param1
, param2
;
883 unsigned int ret
= 0;
887 while ((hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, timeout
)) == S_OK
)
889 if (code
== EC_COMPLETE
)
891 ok(param1
== S_OK
, "Got param1 %#lx.\n", param1
);
892 ok(!param2
, "Got param2 %#lx.\n", param2
);
895 IMediaEvent_FreeEventParams(eventsrc
, code
, param1
, param2
);
898 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
903 static void test_eos(IPin
*pin
, IMemInputPin
*input
, IMediaControl
*control
)
905 IMediaEvent
*eventsrc
;
910 IMediaControl_QueryInterface(control
, &IID_IMediaEvent
, (void **)&eventsrc
);
912 hr
= IMediaControl_Pause(control
);
913 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
914 ret
= check_ec_complete(eventsrc
, 0);
915 ok(!ret
, "Got unexpected EC_COMPLETE.\n");
917 hr
= IPin_EndOfStream(pin
);
918 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
920 hr
= IMediaControl_GetState(control
, 1000, &state
);
921 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
922 ret
= check_ec_complete(eventsrc
, 0);
923 ok(!ret
, "Got unexpected EC_COMPLETE.\n");
925 hr
= send_frame(input
);
926 todo_wine
ok(hr
== VFW_E_SAMPLE_REJECTED_EOS
, "Got hr %#x.\n", hr
);
928 hr
= IMediaControl_Run(control
);
929 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
930 ret
= check_ec_complete(eventsrc
, 0);
931 todo_wine
ok(ret
== 1, "Expected EC_COMPLETE.\n");
933 hr
= IMediaControl_Stop(control
);
934 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
935 ret
= check_ec_complete(eventsrc
, 0);
936 ok(!ret
, "Got unexpected EC_COMPLETE.\n");
938 /* We do not receive an EC_COMPLETE notification until the last sample is
941 hr
= IMediaControl_Pause(control
);
942 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
943 hr
= send_frame(input
);
944 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
945 hr
= IMediaControl_GetState(control
, 1000, &state
);
946 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
947 hr
= IMediaControl_Run(control
);
948 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
949 ret
= check_ec_complete(eventsrc
, 0);
950 ok(!ret
, "Got unexpected EC_COMPLETE.\n");
952 hr
= IPin_EndOfStream(pin
);
953 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
954 ret
= check_ec_complete(eventsrc
, 0);
955 ok(!ret
, "Got unexpected EC_COMPLETE.\n");
956 ret
= check_ec_complete(eventsrc
, 2000);
957 todo_wine
ok(ret
== 1, "Expected EC_COMPLETE.\n");
959 hr
= IMediaControl_Stop(control
);
960 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
961 ret
= check_ec_complete(eventsrc
, 0);
962 ok(!ret
, "Got unexpected EC_COMPLETE.\n");
964 /* Test sending EOS while flushing. */
966 hr
= IMediaControl_Run(control
);
967 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
968 hr
= send_frame(input
);
969 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
971 hr
= IPin_BeginFlush(pin
);
972 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
973 hr
= IPin_EndOfStream(pin
);
974 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
975 hr
= IPin_EndFlush(pin
);
976 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
978 hr
= IMediaControl_Stop(control
);
979 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
980 ret
= check_ec_complete(eventsrc
, 0);
981 ok(!ret
, "Got unexpected EC_COMPLETE.\n");
983 /* Test sending EOS and then flushing or stopping. */
985 hr
= IMediaControl_Pause(control
);
986 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
987 hr
= send_frame(input
);
988 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
989 hr
= IMediaControl_GetState(control
, 1000, &state
);
990 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
991 hr
= IMediaControl_Run(control
);
992 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
993 ret
= check_ec_complete(eventsrc
, 0);
994 ok(!ret
, "Got unexpected EC_COMPLETE.\n");
996 hr
= IPin_EndOfStream(pin
);
997 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
998 ret
= check_ec_complete(eventsrc
, 0);
999 ok(!ret
, "Got unexpected EC_COMPLETE.\n");
1001 hr
= IPin_BeginFlush(pin
);
1002 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1003 hr
= IPin_EndFlush(pin
);
1004 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1006 hr
= send_frame(input
);
1007 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1008 hr
= IPin_EndOfStream(pin
);
1009 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1010 ret
= check_ec_complete(eventsrc
, 0);
1011 ok(!ret
, "Got unexpected EC_COMPLETE.\n");
1013 hr
= IMediaControl_Stop(control
);
1014 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1015 ret
= check_ec_complete(eventsrc
, 0);
1016 ok(!ret
, "Got unexpected EC_COMPLETE.\n");
1018 IMediaEvent_Release(eventsrc
);
1021 static void test_connect_pin(void)
1023 ALLOCATOR_PROPERTIES req_props
= {1, 4 * 44100, 1, 0}, ret_props
;
1026 .wFormatTag
= WAVE_FORMAT_PCM
,
1028 .nSamplesPerSec
= 44100,
1029 .nAvgBytesPerSec
= 44100 * 4,
1031 .wBitsPerSample
= 16,
1033 AM_MEDIA_TYPE req_mt
=
1035 .majortype
= MEDIATYPE_Audio
,
1036 .subtype
= MEDIASUBTYPE_PCM
,
1037 .formattype
= FORMAT_WaveFormatEx
,
1038 .cbFormat
= sizeof(wfx
),
1039 .pbFormat
= (BYTE
*)&wfx
,
1041 IBaseFilter
*filter
= create_dsound_render();
1042 struct testfilter source
;
1043 IMemAllocator
*allocator
;
1044 IMediaControl
*control
;
1045 IFilterGraph2
*graph
;
1046 IMemInputPin
*input
;
1052 testfilter_init(&source
);
1054 CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (void **)&graph
);
1055 IFilterGraph2_AddFilter(graph
, &source
.filter
.IBaseFilter_iface
, L
"source");
1056 IFilterGraph2_AddFilter(graph
, filter
, L
"sink");
1057 IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
1059 IBaseFilter_FindPin(filter
, sink_id
, &pin
);
1061 peer
= (IPin
*)0xdeadbeef;
1062 hr
= IPin_ConnectedTo(pin
, &peer
);
1063 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
1064 ok(!peer
, "Got peer %p.\n", peer
);
1066 hr
= IPin_ConnectionMediaType(pin
, &mt
);
1067 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
1069 hr
= IMediaControl_Pause(control
);
1070 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1071 hr
= IFilterGraph2_ConnectDirect(graph
, &source
.source
.pin
.IPin_iface
, pin
, &req_mt
);
1072 ok(hr
== VFW_E_NOT_STOPPED
, "Got hr %#x.\n", hr
);
1073 hr
= IMediaControl_Stop(control
);
1074 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1076 hr
= IFilterGraph2_ConnectDirect(graph
, &source
.source
.pin
.IPin_iface
, pin
, &req_mt
);
1077 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1079 hr
= IPin_ConnectedTo(pin
, &peer
);
1080 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1081 ok(peer
== &source
.source
.pin
.IPin_iface
, "Got peer %p.\n", peer
);
1084 hr
= IPin_ConnectionMediaType(pin
, &mt
);
1085 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1086 ok(compare_media_types(&mt
, &req_mt
), "Media types didn't match.\n");
1088 hr
= IMediaControl_Pause(control
);
1089 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
1090 hr
= IFilterGraph2_Disconnect(graph
, pin
);
1091 ok(hr
== VFW_E_NOT_STOPPED
, "Got hr %#x.\n", hr
);
1092 hr
= IMediaControl_Stop(control
);
1093 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1095 IPin_QueryInterface(pin
, &IID_IMemInputPin
, (void **)&input
);
1097 test_allocator(input
);
1099 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
,
1100 &IID_IMemAllocator
, (void **)&allocator
);
1101 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1102 hr
= IMemAllocator_SetProperties(allocator
, &req_props
, &ret_props
);
1103 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1104 ok(!memcmp(&ret_props
, &req_props
, sizeof(req_props
)), "Properties did not match.\n");
1105 hr
= IMemInputPin_NotifyAllocator(input
, allocator
, TRUE
);
1106 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1107 hr
= IMemAllocator_Commit(allocator
);
1108 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1110 hr
= IMemInputPin_ReceiveCanBlock(input
);
1111 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1113 test_filter_state(input
, control
);
1114 test_flushing(pin
, input
, control
);
1115 test_eos(pin
, input
, control
);
1117 hr
= IFilterGraph2_Disconnect(graph
, pin
);
1118 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1119 hr
= IFilterGraph2_Disconnect(graph
, pin
);
1120 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
1121 ok(source
.source
.pin
.peer
== pin
, "Got peer %p.\n", source
.source
.pin
.peer
);
1122 IFilterGraph2_Disconnect(graph
, &source
.source
.pin
.IPin_iface
);
1124 peer
= (IPin
*)0xdeadbeef;
1125 hr
= IPin_ConnectedTo(pin
, &peer
);
1126 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
1127 ok(!peer
, "Got peer %p.\n", peer
);
1129 hr
= IPin_ConnectionMediaType(pin
, &mt
);
1130 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
1132 ref
= IMemAllocator_Release(allocator
);
1133 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1134 IMemInputPin_Release(input
);
1136 IMediaControl_Release(control
);
1137 ref
= IFilterGraph2_Release(graph
);
1138 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1139 ref
= IBaseFilter_Release(filter
);
1140 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1141 ref
= IBaseFilter_Release(&source
.filter
.IBaseFilter_iface
);
1142 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1145 static void test_unconnected_filter_state(void)
1147 IBaseFilter
*filter
= create_dsound_render();
1152 hr
= IBaseFilter_GetState(filter
, 0, &state
);
1153 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1154 ok(state
== State_Stopped
, "Got state %u.\n", state
);
1156 hr
= IBaseFilter_Pause(filter
);
1157 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1159 hr
= IBaseFilter_GetState(filter
, 0, &state
);
1160 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1161 ok(state
== State_Paused
, "Got state %u.\n", state
);
1163 hr
= IBaseFilter_Run(filter
, 0);
1164 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1166 hr
= IBaseFilter_GetState(filter
, 0, &state
);
1167 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1168 ok(state
== State_Running
, "Got state %u.\n", state
);
1170 hr
= IBaseFilter_Pause(filter
);
1171 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1173 hr
= IBaseFilter_GetState(filter
, 0, &state
);
1174 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1175 ok(state
== State_Paused
, "Got state %u.\n", state
);
1177 hr
= IBaseFilter_Stop(filter
);
1178 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1180 hr
= IBaseFilter_GetState(filter
, 0, &state
);
1181 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1182 ok(state
== State_Stopped
, "Got state %u.\n", state
);
1184 hr
= IBaseFilter_Run(filter
, 0);
1185 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1187 hr
= IBaseFilter_GetState(filter
, 0, &state
);
1188 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1189 ok(state
== State_Running
, "Got state %u.\n", state
);
1191 hr
= IBaseFilter_Stop(filter
);
1192 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1194 hr
= IBaseFilter_GetState(filter
, 0, &state
);
1195 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1196 ok(state
== State_Stopped
, "Got state %u.\n", state
);
1198 ref
= IBaseFilter_Release(filter
);
1199 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1202 static HRESULT
does_dsound_support_format(WAVEFORMATEX
*format
)
1204 const DSBUFFERDESC desc
=
1206 .dwSize
= sizeof(DSBUFFERDESC
),
1207 .dwBufferBytes
= format
->nAvgBytesPerSec
,
1208 .lpwfxFormat
= format
,
1210 IDirectSoundBuffer
*buffer
;
1211 IDirectSound
*dsound
;
1214 hr
= DirectSoundCreate(NULL
, &dsound
, NULL
);
1215 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1217 hr
= IDirectSound_CreateSoundBuffer(dsound
, &desc
, &buffer
, NULL
);
1219 IDirectSoundBuffer_Release(buffer
);
1220 IDirectSound_Release(dsound
);
1222 return hr
== S_OK
? S_OK
: S_FALSE
;
1225 static void test_media_types(void)
1227 IBaseFilter
*filter
= create_dsound_render();
1228 AM_MEDIA_TYPE
*mt
, req_mt
= {{0}};
1229 IEnumMediaTypes
*enummt
;
1230 WAVEFORMATEX wfx
= {0};
1231 HRESULT hr
, expect_hr
;
1237 static const DWORD sample_rates
[] = {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 96000};
1245 {WAVE_FORMAT_PCM
, 8},
1246 {WAVE_FORMAT_PCM
, 16},
1247 {WAVE_FORMAT_PCM
, 24},
1248 {WAVE_FORMAT_PCM
, 32},
1249 {WAVE_FORMAT_IEEE_FLOAT
, 32},
1250 {WAVE_FORMAT_IEEE_FLOAT
, 64},
1253 IBaseFilter_FindPin(filter
, sink_id
, &pin
);
1255 hr
= IPin_EnumMediaTypes(pin
, &enummt
);
1256 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1258 hr
= IEnumMediaTypes_Next(enummt
, 1, &mt
, NULL
);
1259 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1262 ok(IsEqualGUID(&mt
->majortype
, &MEDIATYPE_Audio
), "Got major type %s.\n", wine_dbgstr_guid(&mt
->majortype
));
1263 ok(IsEqualGUID(&mt
->subtype
, &GUID_NULL
), "Got subtype %s.\n", wine_dbgstr_guid(&mt
->subtype
));
1264 ok(mt
->bFixedSizeSamples
== TRUE
, "Got fixed size %d.\n", mt
->bFixedSizeSamples
);
1265 ok(!mt
->bTemporalCompression
, "Got temporal compression %d.\n", mt
->bTemporalCompression
);
1266 ok(mt
->lSampleSize
== 1, "Got sample size %u.\n", mt
->lSampleSize
);
1267 ok(IsEqualGUID(&mt
->formattype
, &GUID_NULL
), "Got format type %s.\n", wine_dbgstr_guid(&mt
->formattype
));
1268 ok(!mt
->pUnk
, "Got pUnk %p.\n", mt
->pUnk
);
1269 ok(!mt
->cbFormat
, "Got format size %u.\n", mt
->cbFormat
);
1270 ok(!mt
->pbFormat
, "Got unexpected format block.\n");
1272 hr
= IPin_QueryAccept(pin
, mt
);
1273 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
1278 hr
= IEnumMediaTypes_Next(enummt
, 1, &mt
, NULL
);
1279 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
1281 req_mt
.majortype
= MEDIATYPE_Audio
;
1282 req_mt
.formattype
= FORMAT_WaveFormatEx
;
1283 req_mt
.cbFormat
= sizeof(WAVEFORMATEX
);
1284 req_mt
.pbFormat
= (BYTE
*)&wfx
;
1286 IEnumMediaTypes_Release(enummt
);
1288 for (channels
= 1; channels
<= 2; ++channels
)
1290 wfx
.nChannels
= channels
;
1292 for (i
= 0; i
< ARRAY_SIZE(formats
); ++i
)
1294 wfx
.wFormatTag
= formats
[i
].tag
;
1295 wfx
.wBitsPerSample
= formats
[i
].depth
;
1296 wfx
.nBlockAlign
= wfx
.nChannels
* wfx
.wBitsPerSample
/ 8;
1297 for (j
= 0; j
< ARRAY_SIZE(sample_rates
); ++j
)
1299 wfx
.nSamplesPerSec
= sample_rates
[j
];
1300 wfx
.nAvgBytesPerSec
= wfx
.nSamplesPerSec
* wfx
.nBlockAlign
;
1302 expect_hr
= does_dsound_support_format(&wfx
);
1304 hr
= IPin_QueryAccept(pin
, &req_mt
);
1305 ok(hr
== expect_hr
, "Expected hr %#x, got %#x, for %d channels, %d-bit %s, %d Hz.\n",
1306 expect_hr
, hr
, channels
, formats
[i
].depth
,
1307 formats
[i
].tag
== WAVE_FORMAT_PCM
? "integer" : "float", sample_rates
[j
]);
1313 ref
= IBaseFilter_Release(filter
);
1314 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1317 START_TEST(dsoundrender
)
1319 IBaseFilter
*filter
;
1324 hr
= CoCreateInstance(&CLSID_DSoundRender
, NULL
, CLSCTX_INPROC_SERVER
,
1325 &IID_IBaseFilter
, (void **)&filter
);
1326 if (hr
== VFW_E_NO_AUDIO_HARDWARE
)
1328 skip("No audio hardware.\n");
1332 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1333 IBaseFilter_Release(filter
);
1335 test_property_bag();
1342 test_enum_media_types();
1343 test_unconnected_filter_state();