1 /* Implementation of the Audio Capture Filter (CLSID_AudioRecord) 2 * 3 * Copyright 2015 Damjan Jovanovic 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #include <stdarg.h> 21 22 #define COBJMACROS 23 24 #include "windef.h" 25 #include "winbase.h" 26 #include "wtypes.h" 27 #include "wingdi.h" 28 #include "winuser.h" 29 #include "dshow.h" 30 31 #include "qcap_main.h" 32 33 #include "wine/debug.h" 34 35 WINE_DEFAULT_DEBUG_CHANNEL(qcap); 36 37 typedef struct { 38 IUnknown IUnknown_iface; 39 IUnknown *outerUnknown; 40 BaseFilter filter; 41 IPersistPropertyBag IPersistPropertyBag_iface; 42 BaseOutputPin *output; 43 } AudioRecord; 44 45 static inline AudioRecord *impl_from_IUnknown(IUnknown *iface) 46 { 47 return CONTAINING_RECORD(iface, AudioRecord, IUnknown_iface); 48 } 49 50 static inline AudioRecord *impl_from_BaseFilter(BaseFilter *filter) 51 { 52 return CONTAINING_RECORD(filter, AudioRecord, filter); 53 } 54 55 static inline AudioRecord *impl_from_IBaseFilter(IBaseFilter *iface) 56 { 57 BaseFilter *filter = CONTAINING_RECORD(iface, BaseFilter, IBaseFilter_iface); 58 return impl_from_BaseFilter(filter); 59 } 60 61 static inline AudioRecord *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface) 62 { 63 return CONTAINING_RECORD(iface, AudioRecord, IPersistPropertyBag_iface); 64 } 65 66 static HRESULT WINAPI Unknown_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppv) 67 { 68 AudioRecord *This = impl_from_IUnknown(iface); 69 if (IsEqualIID(riid, &IID_IUnknown)) { 70 TRACE("(%p)->(IID_IUnknown, %p)\n", This, ppv); 71 *ppv = &This->filter.IBaseFilter_iface; 72 } else if (IsEqualIID(riid, &IID_IPersist)) { 73 TRACE("(%p)->(IID_IPersist, %p)\n", This, ppv); 74 *ppv = &This->filter.IBaseFilter_iface; 75 } else if (IsEqualIID(riid, &IID_IMediaFilter)) { 76 TRACE("(%p)->(IID_IMediaFilter, %p)\n", This, ppv); 77 *ppv = &This->filter.IBaseFilter_iface; 78 } else if (IsEqualIID(riid, &IID_IBaseFilter)) { 79 TRACE("(%p)->(IID_IBaseFilter, %p)\n", This, ppv); 80 *ppv = &This->filter.IBaseFilter_iface; 81 } else if (IsEqualIID(riid, &IID_IPersistPropertyBag)) { 82 TRACE("(%p)->(IID_IPersistPropertyBag, %p)\n", This, ppv); 83 *ppv = &This->IPersistPropertyBag_iface; 84 } else { 85 FIXME("(%p): no interface for %s\n", This, debugstr_guid(riid)); 86 *ppv = NULL; 87 return E_NOINTERFACE; 88 } 89 IUnknown_AddRef((IUnknown*)*ppv); 90 return S_OK; 91 } 92 93 static ULONG WINAPI Unknown_AddRef(IUnknown *iface) 94 { 95 AudioRecord *This = impl_from_IUnknown(iface); 96 return BaseFilterImpl_AddRef(&This->filter.IBaseFilter_iface); 97 } 98 99 static ULONG WINAPI Unknown_Release(IUnknown *iface) 100 { 101 AudioRecord *This = impl_from_IUnknown(iface); 102 ULONG ref = BaseFilterImpl_Release(&This->filter.IBaseFilter_iface); 103 TRACE("(%p/%p)->() ref=%d\n", iface, This, ref); 104 if (!ref) { 105 CoTaskMemFree(This); 106 } 107 return ref; 108 } 109 110 static const IUnknownVtbl UnknownVtbl = { 111 Unknown_QueryInterface, 112 Unknown_AddRef, 113 Unknown_Release 114 }; 115 116 static HRESULT WINAPI AudioRecord_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv) 117 { 118 AudioRecord *This = impl_from_IBaseFilter(iface); 119 return IUnknown_QueryInterface(This->outerUnknown, riid, ppv); 120 } 121 122 static ULONG WINAPI AudioRecord_AddRef(IBaseFilter *iface) 123 { 124 AudioRecord *This = impl_from_IBaseFilter(iface); 125 return IUnknown_AddRef(This->outerUnknown); 126 } 127 128 static ULONG WINAPI AudioRecord_Release(IBaseFilter *iface) 129 { 130 AudioRecord *This = impl_from_IBaseFilter(iface); 131 return IUnknown_Release(This->outerUnknown); 132 } 133 134 static HRESULT WINAPI AudioRecord_Stop(IBaseFilter *iface) 135 { 136 AudioRecord *This = impl_from_IBaseFilter(iface); 137 FIXME("(%p): stub\n", This); 138 return E_NOTIMPL; 139 } 140 141 static HRESULT WINAPI AudioRecord_Pause(IBaseFilter *iface) 142 { 143 AudioRecord *This = impl_from_IBaseFilter(iface); 144 FIXME("(%p): stub\n", This); 145 return E_NOTIMPL; 146 } 147 148 static HRESULT WINAPI AudioRecord_Run(IBaseFilter *iface, REFERENCE_TIME tStart) 149 { 150 AudioRecord *This = impl_from_IBaseFilter(iface); 151 FIXME("(%p, %s): stub\n", This, wine_dbgstr_longlong(tStart)); 152 return E_NOTIMPL; 153 } 154 155 static HRESULT WINAPI AudioRecord_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin) 156 { 157 AudioRecord *This = impl_from_IBaseFilter(iface); 158 FIXME("(%p)->(%s, %p): stub\n", This, debugstr_w(Id), ppPin); 159 return E_NOTIMPL; 160 } 161 162 static const IBaseFilterVtbl AudioRecordVtbl = { 163 AudioRecord_QueryInterface, 164 AudioRecord_AddRef, 165 AudioRecord_Release, 166 BaseFilterImpl_GetClassID, 167 AudioRecord_Stop, 168 AudioRecord_Pause, 169 AudioRecord_Run, 170 BaseFilterImpl_GetState, 171 BaseFilterImpl_SetSyncSource, 172 BaseFilterImpl_GetSyncSource, 173 BaseFilterImpl_EnumPins, 174 AudioRecord_FindPin, 175 BaseFilterImpl_QueryFilterInfo, 176 BaseFilterImpl_JoinFilterGraph, 177 BaseFilterImpl_QueryVendorInfo 178 }; 179 180 static IPin* WINAPI AudioRecord_GetPin(BaseFilter *iface, int pos) 181 { 182 AudioRecord *This = impl_from_BaseFilter(iface); 183 FIXME("(%p, %d): stub\n", This, pos); 184 return NULL; 185 } 186 187 static LONG WINAPI AudioRecord_GetPinCount(BaseFilter *iface) 188 { 189 AudioRecord *This = impl_from_BaseFilter(iface); 190 FIXME("(%p): stub\n", This); 191 return 0; 192 } 193 194 static const BaseFilterFuncTable AudioRecordFuncs = { 195 AudioRecord_GetPin, 196 AudioRecord_GetPinCount 197 }; 198 199 static HRESULT WINAPI PPB_QueryInterface(IPersistPropertyBag *iface, REFIID riid, LPVOID *ppv) 200 { 201 AudioRecord *This = impl_from_IPersistPropertyBag(iface); 202 return IUnknown_QueryInterface(This->outerUnknown, riid, ppv); 203 } 204 205 static ULONG WINAPI PPB_AddRef(IPersistPropertyBag *iface) 206 { 207 AudioRecord *This = impl_from_IPersistPropertyBag(iface); 208 return IUnknown_AddRef(This->outerUnknown); 209 } 210 211 static ULONG WINAPI PPB_Release(IPersistPropertyBag *iface) 212 { 213 AudioRecord *This = impl_from_IPersistPropertyBag(iface); 214 return IUnknown_Release(This->outerUnknown); 215 } 216 217 static HRESULT WINAPI PPB_GetClassID(IPersistPropertyBag *iface, CLSID *pClassID) 218 { 219 AudioRecord *This = impl_from_IPersistPropertyBag(iface); 220 TRACE("(%p/%p)->(%p)\n", iface, This, pClassID); 221 return IBaseFilter_GetClassID(&This->filter.IBaseFilter_iface, pClassID); 222 } 223 224 static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag *iface) 225 { 226 AudioRecord *This = impl_from_IPersistPropertyBag(iface); 227 FIXME("(%p/%p)->(): stub\n", iface, This); 228 return E_NOTIMPL; 229 } 230 231 static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *pPropBag, 232 IErrorLog *pErrorLog) 233 { 234 AudioRecord *This = impl_from_IPersistPropertyBag(iface); 235 HRESULT hr; 236 VARIANT var; 237 static const WCHAR WaveInIDW[] = {'W','a','v','e','I','n','I','D',0}; 238 239 TRACE("(%p/%p)->(%p, %p)\n", iface, This, pPropBag, pErrorLog); 240 241 V_VT(&var) = VT_I4; 242 hr = IPropertyBag_Read(pPropBag, WaveInIDW, &var, pErrorLog); 243 if (SUCCEEDED(hr)) 244 { 245 FIXME("FIXME: implement opening waveIn device %d\n", V_I4(&var)); 246 } 247 248 return hr; 249 } 250 251 static HRESULT WINAPI PPB_Save(IPersistPropertyBag *iface, IPropertyBag *pPropBag, 252 BOOL fClearDirty, BOOL fSaveAllProperties) 253 { 254 AudioRecord *This = impl_from_IPersistPropertyBag(iface); 255 FIXME("(%p/%p)->(%p, %u, %u): stub\n", iface, This, pPropBag, fClearDirty, fSaveAllProperties); 256 return E_NOTIMPL; 257 } 258 259 static const IPersistPropertyBagVtbl PersistPropertyBagVtbl = 260 { 261 PPB_QueryInterface, 262 PPB_AddRef, 263 PPB_Release, 264 PPB_GetClassID, 265 PPB_InitNew, 266 PPB_Load, 267 PPB_Save 268 }; 269 270 IUnknown* WINAPI QCAP_createAudioCaptureFilter(IUnknown *outer, HRESULT *phr) 271 { 272 HRESULT hr; 273 AudioRecord *This = NULL; 274 275 FIXME("(%p, %p): the entire CLSID_AudioRecord implementation is just stubs\n", outer, phr); 276 277 This = CoTaskMemAlloc(sizeof(*This)); 278 if (This == NULL) { 279 hr = E_OUTOFMEMORY; 280 goto end; 281 } 282 memset(This, 0, sizeof(*This)); 283 This->IUnknown_iface.lpVtbl = &UnknownVtbl; 284 This->IPersistPropertyBag_iface.lpVtbl = &PersistPropertyBagVtbl; 285 if (outer) 286 This->outerUnknown = outer; 287 else 288 This->outerUnknown = &This->IUnknown_iface; 289 290 hr = BaseFilter_Init(&This->filter, &AudioRecordVtbl, &CLSID_AudioRecord, 291 (DWORD_PTR)(__FILE__ ": AudioRecord.csFilter"), &AudioRecordFuncs); 292 293 end: 294 *phr = hr; 295 if (SUCCEEDED(hr)) { 296 return (IUnknown*)&This->filter.IBaseFilter_iface; 297 } else { 298 if (This) 299 IBaseFilter_Release(&This->filter.IBaseFilter_iface); 300 return NULL; 301 } 302 } 303