From: Zebediah Figura zfigura@codeweavers.com
--- dlls/qcap/audiorecord.c | 42 ++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-)
diff --git a/dlls/qcap/audiorecord.c b/dlls/qcap/audiorecord.c index a6f27cf4f26..53aae9e4fe1 100644 --- a/dlls/qcap/audiorecord.c +++ b/dlls/qcap/audiorecord.c @@ -21,19 +21,20 @@
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
-typedef struct { +struct audio_record +{ struct strmbase_filter filter; IPersistPropertyBag IPersistPropertyBag_iface; -} AudioRecord; +};
-static inline AudioRecord *impl_from_strmbase_filter(struct strmbase_filter *filter) +static struct audio_record *impl_from_strmbase_filter(struct strmbase_filter *filter) { - return CONTAINING_RECORD(filter, AudioRecord, filter); + return CONTAINING_RECORD(filter, struct audio_record, filter); }
-static inline AudioRecord *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface) +static struct audio_record *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface) { - return CONTAINING_RECORD(iface, AudioRecord, IPersistPropertyBag_iface); + return CONTAINING_RECORD(iface, struct audio_record, IPersistPropertyBag_iface); }
static struct strmbase_pin *audio_record_get_pin(struct strmbase_filter *iface, unsigned int index) @@ -44,7 +45,7 @@ static struct strmbase_pin *audio_record_get_pin(struct strmbase_filter *iface,
static void audio_record_destroy(struct strmbase_filter *iface) { - AudioRecord *filter = impl_from_strmbase_filter(iface); + struct audio_record *filter = impl_from_strmbase_filter(iface);
strmbase_filter_cleanup(&filter->filter); free(filter); @@ -52,7 +53,7 @@ static void audio_record_destroy(struct strmbase_filter *iface)
static HRESULT audio_record_query_interface(struct strmbase_filter *iface, REFIID iid, void **out) { - AudioRecord *filter = impl_from_strmbase_filter(iface); + struct audio_record *filter = impl_from_strmbase_filter(iface);
if (IsEqualGUID(iid, &IID_IPersistPropertyBag)) *out = &filter->IPersistPropertyBag_iface; @@ -72,32 +73,35 @@ static const struct strmbase_filter_ops filter_ops =
static HRESULT WINAPI PPB_QueryInterface(IPersistPropertyBag *iface, REFIID riid, LPVOID *ppv) { - AudioRecord *This = impl_from_IPersistPropertyBag(iface); - return IUnknown_QueryInterface(This->filter.outer_unk, riid, ppv); + struct audio_record *filter = impl_from_IPersistPropertyBag(iface); + + return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv); }
static ULONG WINAPI PPB_AddRef(IPersistPropertyBag *iface) { - AudioRecord *This = impl_from_IPersistPropertyBag(iface); - return IUnknown_AddRef(This->filter.outer_unk); + struct audio_record *filter = impl_from_IPersistPropertyBag(iface); + + return IUnknown_AddRef(filter->filter.outer_unk); }
static ULONG WINAPI PPB_Release(IPersistPropertyBag *iface) { - AudioRecord *This = impl_from_IPersistPropertyBag(iface); - return IUnknown_Release(This->filter.outer_unk); + struct audio_record *filter = impl_from_IPersistPropertyBag(iface); + + return IUnknown_Release(filter->filter.outer_unk); }
static HRESULT WINAPI PPB_GetClassID(IPersistPropertyBag *iface, CLSID *pClassID) { - AudioRecord *This = impl_from_IPersistPropertyBag(iface); + struct audio_record *This = impl_from_IPersistPropertyBag(iface); TRACE("(%p/%p)->(%p)\n", iface, This, pClassID); return IBaseFilter_GetClassID(&This->filter.IBaseFilter_iface, pClassID); }
static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag *iface) { - AudioRecord *This = impl_from_IPersistPropertyBag(iface); + struct audio_record *This = impl_from_IPersistPropertyBag(iface); FIXME("(%p/%p)->(): stub\n", iface, This); return E_NOTIMPL; } @@ -105,7 +109,7 @@ static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag *iface) static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *pPropBag, IErrorLog *pErrorLog) { - AudioRecord *This = impl_from_IPersistPropertyBag(iface); + struct audio_record *This = impl_from_IPersistPropertyBag(iface); HRESULT hr; VARIANT var;
@@ -124,7 +128,7 @@ static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *pPropBa static HRESULT WINAPI PPB_Save(IPersistPropertyBag *iface, IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties) { - AudioRecord *This = impl_from_IPersistPropertyBag(iface); + struct audio_record *This = impl_from_IPersistPropertyBag(iface); FIXME("(%p/%p)->(%p, %u, %u): stub\n", iface, This, pPropBag, fClearDirty, fSaveAllProperties); return E_NOTIMPL; } @@ -142,7 +146,7 @@ static const IPersistPropertyBagVtbl PersistPropertyBagVtbl =
HRESULT audio_record_create(IUnknown *outer, IUnknown **out) { - AudioRecord *object; + struct audio_record *object;
if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/qcap/audiorecord.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/dlls/qcap/audiorecord.c b/dlls/qcap/audiorecord.c index 53aae9e4fe1..6dcffb072fc 100644 --- a/dlls/qcap/audiorecord.c +++ b/dlls/qcap/audiorecord.c @@ -1,6 +1,8 @@ -/* Implementation of the Audio Capture Filter (CLSID_AudioRecord) +/* + * Audio capture filter * * Copyright 2015 Damjan Jovanovic + * Copyright 2023 Zeb Figura for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,6 +27,8 @@ struct audio_record { struct strmbase_filter filter; IPersistPropertyBag IPersistPropertyBag_iface; + + struct strmbase_source source; };
static struct audio_record *impl_from_strmbase_filter(struct strmbase_filter *filter) @@ -32,6 +36,21 @@ static struct audio_record *impl_from_strmbase_filter(struct strmbase_filter *fi return CONTAINING_RECORD(filter, struct audio_record, filter); }
+static HRESULT WINAPI audio_record_source_DecideBufferSize(struct strmbase_source *iface, + IMemAllocator *allocator, ALLOCATOR_PROPERTIES *props) +{ + ALLOCATOR_PROPERTIES ret_props; + + return IMemAllocator_SetProperties(allocator, props, &ret_props); +} + +static const struct strmbase_source_ops source_ops = +{ + .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, + .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, + .pfnDecideBufferSize = audio_record_source_DecideBufferSize, +}; + static struct audio_record *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface) { return CONTAINING_RECORD(iface, struct audio_record, IPersistPropertyBag_iface); @@ -39,7 +58,10 @@ static struct audio_record *impl_from_IPersistPropertyBag(IPersistPropertyBag *i
static struct strmbase_pin *audio_record_get_pin(struct strmbase_filter *iface, unsigned int index) { - FIXME("iface %p, index %u, stub!\n", iface, index); + struct audio_record *filter = impl_from_strmbase_filter(iface); + + if (!index) + return &filter->source.pin; return NULL; }
@@ -47,6 +69,7 @@ static void audio_record_destroy(struct strmbase_filter *iface) { struct audio_record *filter = impl_from_strmbase_filter(iface);
+ strmbase_source_cleanup(&filter->source); strmbase_filter_cleanup(&filter->filter); free(filter); } @@ -154,6 +177,8 @@ HRESULT audio_record_create(IUnknown *outer, IUnknown **out) object->IPersistPropertyBag_iface.lpVtbl = &PersistPropertyBagVtbl; strmbase_filter_init(&object->filter, outer, &CLSID_AudioRecord, &filter_ops);
+ strmbase_source_init(&object->source, &object->filter, L"Capture", &source_ops); + TRACE("Created audio recorder %p.\n", object); *out = &object->filter.IUnknown_inner; return S_OK;
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/qcap/tests/audiorecord.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/dlls/qcap/tests/audiorecord.c b/dlls/qcap/tests/audiorecord.c index 5705925a50d..9105ebc8509 100644 --- a/dlls/qcap/tests/audiorecord.c +++ b/dlls/qcap/tests/audiorecord.c @@ -2,6 +2,7 @@ * Audio capture filter unit tests * * Copyright 2018 Zebediah Figura + * Copyright 2023 Zebediah Figura for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -46,6 +47,9 @@ static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOO
static void test_interfaces(IBaseFilter *filter) { + HRESULT hr; + IPin *pin; + todo_wine check_interface(filter, &IID_IAMFilterMiscFlags, TRUE); check_interface(filter, &IID_IBaseFilter, TRUE); check_interface(filter, &IID_IMediaFilter, TRUE); @@ -63,6 +67,20 @@ static void test_interfaces(IBaseFilter *filter) check_interface(filter, &IID_IQualProp, FALSE); check_interface(filter, &IID_IReferenceClock, FALSE); check_interface(filter, &IID_IVideoWindow, FALSE); + + hr = IBaseFilter_FindPin(filter, L"Capture", &pin); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + todo_wine check_interface(pin, &IID_IKsPropertySet, TRUE); + check_interface(pin, &IID_IPin, TRUE); + todo_wine check_interface(pin, &IID_IQualityControl, TRUE); + check_interface(pin, &IID_IUnknown, TRUE); + + check_interface(pin, &IID_IAsyncReader, FALSE); + check_interface(pin, &IID_IMediaPosition, FALSE); + check_interface(pin, &IID_IMediaSeeking, FALSE); + + IPin_Release(pin); }
static const GUID test_iid = {0x33333333};
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/qcap/tests/audiorecord.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/dlls/qcap/tests/audiorecord.c b/dlls/qcap/tests/audiorecord.c index 9105ebc8509..96d06fad431 100644 --- a/dlls/qcap/tests/audiorecord.c +++ b/dlls/qcap/tests/audiorecord.c @@ -312,6 +312,36 @@ static void test_unconnected_filter_state(IBaseFilter *filter) ok(state == State_Stopped, "Got state %u.\n", state); }
+static void test_pin_info(IBaseFilter *filter) +{ + PIN_DIRECTION dir; + PIN_INFO info; + HRESULT hr; + WCHAR *id; + IPin *pin; + + hr = IBaseFilter_FindPin(filter, L"Capture", &pin); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IPin_QueryPinInfo(pin, &info); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter); + ok(info.dir == PINDIR_OUTPUT, "Got direction %d.\n", info.dir); + ok(!wcscmp(info.achName, L"Capture"), "Got name %s.\n", debugstr_w(info.achName)); + IBaseFilter_Release(info.pFilter); + + hr = IPin_QueryDirection(pin, &dir); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(dir == PINDIR_OUTPUT, "Got direction %d.\n", dir); + + hr = IPin_QueryId(pin, &id); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(!wcscmp(id, L"Capture"), "Got id %s.\n", debugstr_w(id)); + CoTaskMemFree(id); + + IPin_Release(pin); +} + START_TEST(audiorecord) { ICreateDevEnum *devenum; @@ -353,6 +383,7 @@ START_TEST(audiorecord)
test_interfaces(filter); test_unconnected_filter_state(filter); + test_pin_info(filter);
ref = IBaseFilter_Release(filter); ok(!ref, "Got outstanding refcount %ld.\n", ref);
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/qcap/tests/audiorecord.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/dlls/qcap/tests/audiorecord.c b/dlls/qcap/tests/audiorecord.c index 96d06fad431..64fc09c49fc 100644 --- a/dlls/qcap/tests/audiorecord.c +++ b/dlls/qcap/tests/audiorecord.c @@ -371,6 +371,8 @@ START_TEST(audiorecord)
while (IEnumMoniker_Next(enummon, 1, &mon, NULL) == S_OK) { + CLSID clsid; + hr = IMoniker_GetDisplayName(mon, NULL, NULL, &name); ok(hr == S_OK, "Got hr %#lx.\n", hr); trace("Testing device %s.\n", wine_dbgstr_w(name)); @@ -381,6 +383,10 @@ START_TEST(audiorecord) hr = IMoniker_BindToObject(mon, NULL, NULL, &IID_IBaseFilter, (void **)&filter); ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ hr = IBaseFilter_GetClassID(filter, &clsid); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(IsEqualGUID(&clsid, &CLSID_AudioRecord), "Got clsid %s.\n", debugstr_guid(&clsid)); + test_interfaces(filter); test_unconnected_filter_state(filter); test_pin_info(filter);