/* Implementation of the Audio Capture Filter (CLSID_AudioRecord) * * Copyright 2015 Damjan Jovanovic * * 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 <stdarg.h> #define COBJMACROS #include "windef.h" #include "winbase.h" #include "wtypes.h" #include "wingdi.h" #include "winuser.h" #include "dshow.h" #include "qcap_main.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(qcap); typedef struct { IUnknown IUnknown_iface; IUnknown *outerUnknown; BaseFilter filter; IPersistPropertyBag IPersistPropertyBag_iface; BaseOutputPin *output; } AudioRecord; static inline AudioRecord *impl_from_IUnknown(IUnknown *iface) { return CONTAINING_RECORD(iface, AudioRecord, IUnknown_iface); } static inline AudioRecord *impl_from_BaseFilter(BaseFilter *filter) { return CONTAINING_RECORD(filter, AudioRecord, filter); } static inline AudioRecord *impl_from_IBaseFilter(IBaseFilter *iface) { BaseFilter *filter = CONTAINING_RECORD(iface, BaseFilter, IBaseFilter_iface); return impl_from_BaseFilter(filter); } static inline AudioRecord *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface) { return CONTAINING_RECORD(iface, AudioRecord, IPersistPropertyBag_iface); } static HRESULT WINAPI Unknown_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppv) { AudioRecord *This = impl_from_IUnknown(iface); if (IsEqualIID(riid, &IID_IUnknown)) { TRACE("(%p)->(IID_IUnknown, %p)\n", This, ppv); *ppv = &This->filter.IBaseFilter_iface; } else if (IsEqualIID(riid, &IID_IPersist)) { TRACE("(%p)->(IID_IPersist, %p)\n", This, ppv); *ppv = &This->filter.IBaseFilter_iface; } else if (IsEqualIID(riid, &IID_IMediaFilter)) { TRACE("(%p)->(IID_IMediaFilter, %p)\n", This, ppv); *ppv = &This->filter.IBaseFilter_iface; } else if (IsEqualIID(riid, &IID_IBaseFilter)) { TRACE("(%p)->(IID_IBaseFilter, %p)\n", This, ppv); *ppv = &This->filter.IBaseFilter_iface; } else if (IsEqualIID(riid, &IID_IPersistPropertyBag)) { TRACE("(%p)->(IID_IPersistPropertyBag, %p)\n", This, ppv); *ppv = &This->IPersistPropertyBag_iface; } else { FIXME("(%p): no interface for %s\n", This, debugstr_guid(riid)); *ppv = NULL; return E_NOINTERFACE; } IUnknown_AddRef((IUnknown*)*ppv); return S_OK; } static ULONG WINAPI Unknown_AddRef(IUnknown *iface) { AudioRecord *This = impl_from_IUnknown(iface); return BaseFilterImpl_AddRef(&This->filter.IBaseFilter_iface); } static ULONG WINAPI Unknown_Release(IUnknown *iface) { AudioRecord *This = impl_from_IUnknown(iface); ULONG ref = BaseFilterImpl_Release(&This->filter.IBaseFilter_iface); TRACE("(%p/%p)->() ref=%d\n", iface, This, ref); if (!ref) { CoTaskMemFree(This); } return ref; } static const IUnknownVtbl UnknownVtbl = { Unknown_QueryInterface, Unknown_AddRef, Unknown_Release }; static HRESULT WINAPI AudioRecord_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv) { AudioRecord *This = impl_from_IBaseFilter(iface); return IUnknown_QueryInterface(This->outerUnknown, riid, ppv); } static ULONG WINAPI AudioRecord_AddRef(IBaseFilter *iface) { AudioRecord *This = impl_from_IBaseFilter(iface); return IUnknown_AddRef(This->outerUnknown); } static ULONG WINAPI AudioRecord_Release(IBaseFilter *iface) { AudioRecord *This = impl_from_IBaseFilter(iface); return IUnknown_Release(This->outerUnknown); } static HRESULT WINAPI AudioRecord_Stop(IBaseFilter *iface) { AudioRecord *This = impl_from_IBaseFilter(iface); FIXME("(%p): stub\n", This); return E_NOTIMPL; } static HRESULT WINAPI AudioRecord_Pause(IBaseFilter *iface) { AudioRecord *This = impl_from_IBaseFilter(iface); FIXME("(%p): stub\n", This); return E_NOTIMPL; } static HRESULT WINAPI AudioRecord_Run(IBaseFilter *iface, REFERENCE_TIME tStart) { AudioRecord *This = impl_from_IBaseFilter(iface); FIXME("(%p, %x%08x): stub\n", This, (ULONG)(tStart >> 32), (ULONG)tStart); return E_NOTIMPL; } static HRESULT WINAPI AudioRecord_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin) { AudioRecord *This = impl_from_IBaseFilter(iface); FIXME("(%p)->(%s, %p): stub\n", This, debugstr_w(Id), ppPin); return E_NOTIMPL; } static const IBaseFilterVtbl AudioRecordVtbl = { AudioRecord_QueryInterface, AudioRecord_AddRef, AudioRecord_Release, BaseFilterImpl_GetClassID, AudioRecord_Stop, AudioRecord_Pause, AudioRecord_Run, BaseFilterImpl_GetState, BaseFilterImpl_SetSyncSource, BaseFilterImpl_GetSyncSource, BaseFilterImpl_EnumPins, AudioRecord_FindPin, BaseFilterImpl_QueryFilterInfo, BaseFilterImpl_JoinFilterGraph, BaseFilterImpl_QueryVendorInfo }; static IPin* WINAPI AudioRecord_GetPin(BaseFilter *iface, int pos) { AudioRecord *This = impl_from_BaseFilter(iface); FIXME("(%p, %d): stub\n", This, pos); return NULL; } static LONG WINAPI AudioRecord_GetPinCount(BaseFilter *iface) { AudioRecord *This = impl_from_BaseFilter(iface); FIXME("(%p): stub\n", This); return 0; } static const BaseFilterFuncTable AudioRecordFuncs = { AudioRecord_GetPin, AudioRecord_GetPinCount }; static HRESULT WINAPI PPB_QueryInterface(IPersistPropertyBag *iface, REFIID riid, LPVOID *ppv) { AudioRecord *This = impl_from_IPersistPropertyBag(iface); return IUnknown_QueryInterface(This->outerUnknown, riid, ppv); } static ULONG WINAPI PPB_AddRef(IPersistPropertyBag *iface) { AudioRecord *This = impl_from_IPersistPropertyBag(iface); return IUnknown_AddRef(This->outerUnknown); } static ULONG WINAPI PPB_Release(IPersistPropertyBag *iface) { AudioRecord *This = impl_from_IPersistPropertyBag(iface); return IUnknown_Release(This->outerUnknown); } static HRESULT WINAPI PPB_GetClassID(IPersistPropertyBag *iface, CLSID *pClassID) { AudioRecord *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); FIXME("(%p/%p)->(): stub\n", iface, This); return E_NOTIMPL; } static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *pPropBag, IErrorLog *pErrorLog) { AudioRecord *This = impl_from_IPersistPropertyBag(iface); HRESULT hr; VARIANT var; static const WCHAR WaveInIDW[] = {'W','a','v','e','I','n','I','D',0}; TRACE("(%p/%p)->(%p, %p)\n", iface, This, pPropBag, pErrorLog); V_VT(&var) = VT_I4; hr = IPropertyBag_Read(pPropBag, WaveInIDW, &var, pErrorLog); if (SUCCEEDED(hr)) { FIXME("FIXME: implement opening waveIn device %d\n", V_I4(&var)); } return hr; } static HRESULT WINAPI PPB_Save(IPersistPropertyBag *iface, IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties) { AudioRecord *This = impl_from_IPersistPropertyBag(iface); FIXME("(%p/%p)->(%p, %u, %u): stub\n", iface, This, pPropBag, fClearDirty, fSaveAllProperties); return E_NOTIMPL; } static const IPersistPropertyBagVtbl PersistPropertyBagVtbl = { PPB_QueryInterface, PPB_AddRef, PPB_Release, PPB_GetClassID, PPB_InitNew, PPB_Load, PPB_Save }; IUnknown* WINAPI QCAP_createAudioCaptureFilter(IUnknown *outer, HRESULT *phr) { HRESULT hr; AudioRecord *This = NULL; FIXME("(%p, %p): the entire CLSID_AudioRecord implementation is just stubs\n", outer, phr); This = CoTaskMemAlloc(sizeof(*This)); if (This == NULL) { hr = E_OUTOFMEMORY; goto end; } memset(This, 0, sizeof(*This)); This->IUnknown_iface.lpVtbl = &UnknownVtbl; This->IPersistPropertyBag_iface.lpVtbl = &PersistPropertyBagVtbl; if (outer) This->outerUnknown = outer; else This->outerUnknown = &This->IUnknown_iface; hr = BaseFilter_Init(&This->filter, &AudioRecordVtbl, &CLSID_AudioRecord, (DWORD_PTR)(__FILE__ ": AudioRecord.csFilter"), &AudioRecordFuncs); end: *phr = hr; if (SUCCEEDED(hr)) { return (IUnknown*)&This->filter.IBaseFilter_iface; } else { if (This) IBaseFilter_Release(&This->filter.IBaseFilter_iface); return NULL; } }