wined3d: Register map cleanups.
[wine] / dlls / dsound / capture.c
1 /*              DirectSoundCapture
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998 Rob Riggs
5  * Copyright 2000-2001 TransGaming Technologies, Inc.
6  *
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.
11  *
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.
16  *
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
20  */
21 /*
22  * TODO:
23  *      Implement FX support.
24  *      Implement both IDirectSoundCaptureBuffer and IDirectSoundCaptureBuffer8
25  *      Make DirectSoundCaptureCreate and DirectSoundCaptureCreate8 behave differently
26  */
27
28 #include <stdarg.h>
29
30 #define NONAMELESSSTRUCT
31 #define NONAMELESSUNION
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winuser.h"
35 #include "mmsystem.h"
36 #include "mmddk.h"
37 #include "winreg.h"
38 #include "winternl.h"
39 #include "winnls.h"
40 #include "wine/debug.h"
41 #include "dsound.h"
42 #include "dsdriver.h"
43 #include "dsound_private.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
46
47 DirectSoundCaptureDevice * DSOUND_capture[MAXWAVEDRIVERS];
48
49 static HRESULT DirectSoundCaptureDevice_Create(DirectSoundCaptureDevice ** ppDevice);
50
51 static const char * captureStateString[] = {
52     "STATE_STOPPED",
53     "STATE_STARTING",
54     "STATE_CAPTURING",
55     "STATE_STOPPING"
56 };
57
58 static HRESULT DSOUND_CaptureCreate(
59     LPDIRECTSOUNDCAPTURE *ppDSC,
60     IUnknown *pUnkOuter)
61 {
62     LPDIRECTSOUNDCAPTURE pDSC;
63     HRESULT hr;
64     TRACE("(%p,%p)\n",ppDSC,pUnkOuter);
65
66     /* Get dsound configuration */
67     setup_dsound_options();
68
69     hr = IDirectSoundCaptureImpl_Create(&pDSC);
70     if (hr == DS_OK) {
71         IDirectSoundCapture_AddRef(pDSC);
72         *ppDSC = pDSC;
73     } else {
74         WARN("IDirectSoundCaptureImpl_Create failed\n");
75         *ppDSC = 0;
76     }
77
78     return hr;
79 }
80
81 static HRESULT DSOUND_CaptureCreate8(
82     LPDIRECTSOUNDCAPTURE8 *ppDSC8,
83     IUnknown *pUnkOuter)
84 {
85     LPDIRECTSOUNDCAPTURE8 pDSC8;
86     HRESULT hr;
87     TRACE("(%p,%p)\n",ppDSC8,pUnkOuter);
88
89     /* Get dsound configuration */
90     setup_dsound_options();
91
92     hr = IDirectSoundCaptureImpl_Create(&pDSC8);
93     if (hr == DS_OK) {
94         IDirectSoundCapture_AddRef(pDSC8);
95         *ppDSC8 = pDSC8;
96     } else {
97         WARN("IDirectSoundCaptureImpl_Create failed\n");
98         *ppDSC8 = 0;
99     }
100
101     return hr;
102 }
103
104 /***************************************************************************
105  * DirectSoundCaptureCreate [DSOUND.6]
106  *
107  * Create and initialize a DirectSoundCapture interface.
108  *
109  * PARAMS
110  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
111  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
112  *    pUnkOuter [I] Must be NULL.
113  *
114  * RETURNS
115  *    Success: DS_OK
116  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
117  *             DSERR_OUTOFMEMORY
118  *
119  * NOTES
120  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
121  *    or NULL for the default device or DSDEVID_DefaultCapture or
122  *    DSDEVID_DefaultVoiceCapture.
123  *
124  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
125  */
126 HRESULT WINAPI DirectSoundCaptureCreate(
127     LPCGUID lpcGUID,
128     LPDIRECTSOUNDCAPTURE *ppDSC,
129     LPUNKNOWN pUnkOuter)
130 {
131     HRESULT hr;
132     LPDIRECTSOUNDCAPTURE pDSC;
133     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
134
135     if (ppDSC == NULL) {
136         WARN("invalid parameter: ppDSC == NULL\n");
137         return DSERR_INVALIDPARAM;
138     }
139
140     if (pUnkOuter) {
141         WARN("invalid parameter: pUnkOuter != NULL\n");
142         *ppDSC = NULL;
143         return DSERR_NOAGGREGATION;
144     }
145
146     hr = DSOUND_CaptureCreate(&pDSC, (IUnknown *)pUnkOuter);
147     if (hr == DS_OK) {
148         hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
149         if (hr != DS_OK) {
150             IDirectSoundCapture_Release(pDSC);
151             pDSC = 0;
152         }
153     }
154
155     *ppDSC = pDSC;
156
157     return hr;
158 }
159
160 /***************************************************************************
161  * DirectSoundCaptureCreate8 [DSOUND.12]
162  *
163  * Create and initialize a DirectSoundCapture interface.
164  *
165  * PARAMS
166  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
167  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
168  *    pUnkOuter [I] Must be NULL.
169  *
170  * RETURNS
171  *    Success: DS_OK
172  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
173  *             DSERR_OUTOFMEMORY
174  *
175  * NOTES
176  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
177  *    or NULL for the default device or DSDEVID_DefaultCapture or
178  *    DSDEVID_DefaultVoiceCapture.
179  *
180  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
181  */
182 HRESULT WINAPI DirectSoundCaptureCreate8(
183     LPCGUID lpcGUID,
184     LPDIRECTSOUNDCAPTURE8 *ppDSC8,
185     LPUNKNOWN pUnkOuter)
186 {
187     HRESULT hr;
188     LPDIRECTSOUNDCAPTURE8 pDSC8;
189     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
190
191     if (ppDSC8 == NULL) {
192         WARN("invalid parameter: ppDSC8 == NULL\n");
193         return DSERR_INVALIDPARAM;
194     }
195
196     if (pUnkOuter) {
197         WARN("invalid parameter: pUnkOuter != NULL\n");
198         *ppDSC8 = NULL;
199         return DSERR_NOAGGREGATION;
200     }
201
202     hr = DSOUND_CaptureCreate8(&pDSC8, (IUnknown *)pUnkOuter);
203     if (hr == DS_OK) {
204         hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
205         if (hr != DS_OK) {
206             IDirectSoundCapture_Release(pDSC8);
207             pDSC8 = 0;
208         }
209     }
210
211     *ppDSC8 = pDSC8;
212
213     return hr;
214 }
215
216 /***************************************************************************
217  * DirectSoundCaptureEnumerateA [DSOUND.7]
218  *
219  * Enumerate all DirectSound drivers installed in the system.
220  *
221  * PARAMS
222  *    lpDSEnumCallback  [I] Address of callback function.
223  *    lpContext         [I] Address of user defined context passed to callback function.
224  *
225  * RETURNS
226  *    Success: DS_OK
227  *    Failure: DSERR_INVALIDPARAM
228  */
229 HRESULT WINAPI
230 DirectSoundCaptureEnumerateA(
231     LPDSENUMCALLBACKA lpDSEnumCallback,
232     LPVOID lpContext)
233 {
234     unsigned devs, wid;
235     DSDRIVERDESC desc;
236     GUID guid;
237     int err;
238
239     TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
240
241     if (lpDSEnumCallback == NULL) {
242         WARN("invalid parameter: lpDSEnumCallback == NULL\n");
243         return DSERR_INVALIDPARAM;
244     }
245
246     devs = waveInGetNumDevs();
247     if (devs > 0) {
248         if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) {
249             for (wid = 0; wid < devs; ++wid) {
250                 if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) {
251                     err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
252                     if (err == DS_OK) {
253                         TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
254                               "Primary Sound Capture Driver",desc.szDrvname,lpContext);
255                         if (lpDSEnumCallback(NULL, "Primary Sound Capture Driver", desc.szDrvname, lpContext) == FALSE)
256                             return DS_OK;
257                     }
258                 }
259             }
260         }
261     }
262
263     for (wid = 0; wid < devs; ++wid) {
264         err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
265         if (err == DS_OK) {
266             TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
267                   debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext);
268             if (lpDSEnumCallback(&DSOUND_capture_guids[wid], desc.szDesc, desc.szDrvname, lpContext) == FALSE)
269                 return DS_OK;
270         }
271     }
272
273     return DS_OK;
274 }
275
276 /***************************************************************************
277  * DirectSoundCaptureEnumerateW [DSOUND.8]
278  *
279  * Enumerate all DirectSound drivers installed in the system.
280  *
281  * PARAMS
282  *    lpDSEnumCallback  [I] Address of callback function.
283  *    lpContext         [I] Address of user defined context passed to callback function.
284  *
285  * RETURNS
286  *    Success: DS_OK
287  *    Failure: DSERR_INVALIDPARAM
288  */
289 HRESULT WINAPI
290 DirectSoundCaptureEnumerateW(
291     LPDSENUMCALLBACKW lpDSEnumCallback,
292     LPVOID lpContext)
293 {
294     unsigned devs, wid;
295     DSDRIVERDESC desc;
296     GUID guid;
297     int err;
298     WCHAR wDesc[MAXPNAMELEN];
299     WCHAR wName[MAXPNAMELEN];
300
301     TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
302
303     if (lpDSEnumCallback == NULL) {
304         WARN("invalid parameter: lpDSEnumCallback == NULL\n");
305         return DSERR_INVALIDPARAM;
306     }
307
308     devs = waveInGetNumDevs();
309     if (devs > 0) {
310         if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) {
311             for (wid = 0; wid < devs; ++wid) {
312                 if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) {
313                     err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
314                     if (err == DS_OK) {
315                         TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
316                               "Primary Sound Capture Driver",desc.szDrvname,lpContext);
317                         MultiByteToWideChar( CP_ACP, 0, "Primary Sound Capture Driver", -1,
318                                              wDesc, sizeof(wDesc)/sizeof(WCHAR) );
319                         MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1,
320                                              wName, sizeof(wName)/sizeof(WCHAR) );
321                         if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE)
322                             return DS_OK;
323                     }
324                 }
325             }
326         }
327     }
328
329     for (wid = 0; wid < devs; ++wid) {
330         err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
331         if (err == DS_OK) {
332             TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
333                   debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext);
334             MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1,
335                                  wDesc, sizeof(wDesc)/sizeof(WCHAR) );
336             MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1,
337                                  wName, sizeof(wName)/sizeof(WCHAR) );
338             if (lpDSEnumCallback((LPGUID)&DSOUND_capture_guids[wid], wDesc, wName, lpContext) == FALSE)
339                 return DS_OK;
340         }
341     }
342
343     return DS_OK;
344 }
345
346 static void CALLBACK
347 DSOUND_capture_callback(
348     HWAVEIN hwi,
349     UINT msg,
350     DWORD dwUser,
351     DWORD dw1,
352     DWORD dw2 )
353 {
354     DirectSoundCaptureDevice * This = (DirectSoundCaptureDevice*)dwUser;
355     TRACE("(%p,%08x(%s),%08lx,%08lx,%08lx) entering at %ld\n",hwi,msg,
356         msg == MM_WIM_OPEN ? "MM_WIM_OPEN" : msg == MM_WIM_CLOSE ? "MM_WIM_CLOSE" :
357         msg == MM_WIM_DATA ? "MM_WIM_DATA" : "UNKNOWN",dwUser,dw1,dw2,GetTickCount());
358
359     if (msg == MM_WIM_DATA) {
360         LPWAVEHDR pHdr = (LPWAVEHDR)dw1;
361         EnterCriticalSection( &(This->lock) );
362         TRACE("DirectSoundCapture msg=MM_WIM_DATA, old This->state=%s, old This->index=%d\n",
363             captureStateString[This->state],This->index);
364         if (This->state != STATE_STOPPED) {
365             int index = This->index;
366             if (This->state == STATE_STARTING) {
367                 This->read_position = pHdr->dwBytesRecorded;
368                 This->state = STATE_CAPTURING;
369             }
370             if (This->capture_buffer->nrofnotifies)
371                 SetEvent(This->capture_buffer->notifies[This->index].hEventNotify);
372             This->index = (This->index + 1) % This->nrofpwaves;
373             if ( (This->index == 0) && !(This->capture_buffer->flags & DSCBSTART_LOOPING) ) {
374                 TRACE("end of buffer\n");
375                 This->state = STATE_STOPPED;
376             } else {
377                 if (This->state == STATE_CAPTURING) {
378                     waveInAddBuffer(hwi, &(This->pwave[index]), sizeof(WAVEHDR));
379                 } else if (This->state == STATE_STOPPING) {
380                     TRACE("stopping\n");
381                     This->state = STATE_STOPPED;
382                 }
383             }
384         }
385         TRACE("DirectSoundCapture new This->state=%s, new This->index=%d\n",
386             captureStateString[This->state],This->index);
387         LeaveCriticalSection( &(This->lock) );
388     }
389
390     TRACE("completed\n");
391 }
392
393 /***************************************************************************
394  * IDirectSoundCaptureImpl
395  */
396 static HRESULT WINAPI
397 IDirectSoundCaptureImpl_QueryInterface(
398     LPDIRECTSOUNDCAPTURE iface,
399     REFIID riid,
400     LPVOID* ppobj )
401 {
402     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
403     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
404
405     if (ppobj == NULL) {
406         WARN("invalid parameter\n");
407         return E_INVALIDARG;
408     }
409
410     *ppobj = NULL;
411
412     if (IsEqualIID(riid, &IID_IUnknown)) {
413         IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This);
414         *ppobj = This;
415         return DS_OK;
416     } else if (IsEqualIID(riid, &IID_IDirectSoundCapture)) {
417         IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This);
418         *ppobj = This;
419         return DS_OK;
420     }
421
422     WARN("unsupported riid: %s\n", debugstr_guid(riid));
423     return E_NOINTERFACE;
424 }
425
426 static ULONG WINAPI
427 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface )
428 {
429     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
430     ULONG ref = InterlockedIncrement(&(This->ref));
431     TRACE("(%p) ref was %ld\n", This, ref - 1);
432     return ref;
433 }
434
435 static ULONG WINAPI
436 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface )
437 {
438     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
439     ULONG ref = InterlockedDecrement(&(This->ref));
440     TRACE("(%p) ref was %ld\n", This, ref + 1);
441
442     if (!ref) {
443         if (This->device)
444             DirectSoundCaptureDevice_Release(This->device);
445
446         HeapFree( GetProcessHeap(), 0, This );
447         TRACE("(%p) released\n", This);
448     }
449     return ref;
450 }
451
452 HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(
453     LPDIRECTSOUNDCAPTURE iface,
454     LPCDSCBUFFERDESC lpcDSCBufferDesc,
455     LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
456     LPUNKNOWN pUnk )
457 {
458     HRESULT hr;
459     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
460
461     TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
462
463     if (lpcDSCBufferDesc == NULL) {
464         WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
465         return DSERR_INVALIDPARAM;
466     }
467
468     if (lplpDSCaptureBuffer == NULL) {
469         WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
470         return DSERR_INVALIDPARAM;
471     }
472
473     if (pUnk != NULL) {
474         WARN("invalid parameter: pUnk != NULL\n");
475         return DSERR_INVALIDPARAM;
476     }
477
478     /* FIXME: We can only have one buffer so what do we do here? */
479     if (This->device->capture_buffer) {
480         WARN("lnvalid parameter: already has buffer\n");
481         return DSERR_INVALIDPARAM;    /* DSERR_GENERIC ? */
482     }
483
484     hr = IDirectSoundCaptureBufferImpl_Create(This->device,
485         (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
486
487     if (hr != DS_OK)
488         WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
489
490     return hr;
491 }
492
493 HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(
494     LPDIRECTSOUNDCAPTURE iface,
495     LPDSCCAPS lpDSCCaps )
496 {
497     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
498     TRACE("(%p,%p)\n",This,lpDSCCaps);
499
500     if (This->device == NULL) {
501         WARN("not initialized\n");
502         return DSERR_UNINITIALIZED;
503     }
504
505     if (lpDSCCaps== NULL) {
506         WARN("invalid parameter: lpDSCCaps== NULL\n");
507         return DSERR_INVALIDPARAM;
508     }
509
510     if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
511         WARN("invalid parameter: lpDSCCaps->dwSize = %ld < %d\n",
512             lpDSCCaps->dwSize, sizeof(*lpDSCCaps));
513         return DSERR_INVALIDPARAM;
514     }
515
516     lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
517     lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
518     lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
519
520     TRACE("(flags=0x%08lx,format=0x%08lx,channels=%ld)\n",lpDSCCaps->dwFlags,
521         lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
522
523     return DS_OK;
524 }
525
526 HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(
527     LPDIRECTSOUNDCAPTURE iface,
528     LPCGUID lpcGUID )
529 {
530     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
531     TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
532
533     if (This->device != NULL) {
534         WARN("already initialized\n");
535         return DSERR_ALREADYINITIALIZED;
536     }
537
538     return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
539 }
540
541 static const IDirectSoundCaptureVtbl dscvt =
542 {
543     /* IUnknown methods */
544     IDirectSoundCaptureImpl_QueryInterface,
545     IDirectSoundCaptureImpl_AddRef,
546     IDirectSoundCaptureImpl_Release,
547
548     /* IDirectSoundCapture methods */
549     IDirectSoundCaptureImpl_CreateCaptureBuffer,
550     IDirectSoundCaptureImpl_GetCaps,
551     IDirectSoundCaptureImpl_Initialize
552 };
553
554 HRESULT IDirectSoundCaptureImpl_Create(
555     LPDIRECTSOUNDCAPTURE8 * ppDSC)
556 {
557     IDirectSoundCaptureImpl *pDSC;
558     TRACE("(%p)\n", ppDSC);
559
560     /* Allocate memory */
561     pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
562     if (pDSC == NULL) {
563         WARN("out of memory\n");
564         *ppDSC = NULL;
565         return DSERR_OUTOFMEMORY;
566     }
567
568     pDSC->lpVtbl = &dscvt;
569     pDSC->ref    = 0;
570     pDSC->device = NULL;
571
572     *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
573
574     return DS_OK;
575 }
576
577 /*******************************************************************************
578  *              IDirectSoundCaptureNotify
579  */
580 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface(
581     LPDIRECTSOUNDNOTIFY iface,
582     REFIID riid,
583     LPVOID *ppobj)
584 {
585     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
586     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
587
588     if (This->dscb == NULL) {
589         WARN("invalid parameter\n");
590         return E_INVALIDARG;
591     }
592
593     return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
594 }
595
596 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
597 {
598     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
599     ULONG ref = InterlockedIncrement(&(This->ref));
600     TRACE("(%p) ref was %ld\n", This, ref - 1);
601     return ref;
602 }
603
604 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
605 {
606     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
607     ULONG ref = InterlockedDecrement(&(This->ref));
608     TRACE("(%p) ref was %ld\n", This, ref + 1);
609
610     if (!ref) {
611         if (This->dscb->hwnotify)
612             IDsDriverNotify_Release(This->dscb->hwnotify);
613         This->dscb->notify=NULL;
614         IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb);
615         HeapFree(GetProcessHeap(),0,This);
616         TRACE("(%p) released\n", This);
617     }
618     return ref;
619 }
620
621 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions(
622     LPDIRECTSOUNDNOTIFY iface,
623     DWORD howmuch,
624     LPCDSBPOSITIONNOTIFY notify)
625 {
626     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
627     TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
628
629     if (howmuch > 0 && notify == NULL) {
630         WARN("invalid parameter: notify == NULL\n");
631         return DSERR_INVALIDPARAM;
632     }
633
634     if (TRACE_ON(dsound)) {
635         unsigned int i;
636         for (i=0;i<howmuch;i++)
637             TRACE("notify at %ld to %p\n",
638             notify[i].dwOffset,notify[i].hEventNotify);
639     }
640
641     if (This->dscb->hwnotify) {
642         HRESULT hres;
643         hres = IDsDriverNotify_SetNotificationPositions(This->dscb->hwnotify, howmuch, notify);
644         if (hres != DS_OK)
645             WARN("IDsDriverNotify_SetNotificationPositions failed\n");
646         return hres;
647     } else if (howmuch > 0) {
648         /* Make an internal copy of the caller-supplied array.
649          * Replace the existing copy if one is already present. */
650         if (This->dscb->notifies)
651             This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
652                 This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
653         else
654             This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
655                 howmuch * sizeof(DSBPOSITIONNOTIFY));
656
657         if (This->dscb->notifies == NULL) {
658             WARN("out of memory\n");
659             return DSERR_OUTOFMEMORY;
660         }
661         CopyMemory(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
662         This->dscb->nrofnotifies = howmuch;
663     } else {
664         HeapFree(GetProcessHeap(), 0, This->dscb->notifies);
665         This->dscb->notifies = NULL;
666         This->dscb->nrofnotifies = 0;
667     }
668
669     return S_OK;
670 }
671
672 static const IDirectSoundNotifyVtbl dscnvt =
673 {
674     IDirectSoundCaptureNotifyImpl_QueryInterface,
675     IDirectSoundCaptureNotifyImpl_AddRef,
676     IDirectSoundCaptureNotifyImpl_Release,
677     IDirectSoundCaptureNotifyImpl_SetNotificationPositions,
678 };
679
680 HRESULT IDirectSoundCaptureNotifyImpl_Create(
681     IDirectSoundCaptureBufferImpl *dscb,
682     IDirectSoundCaptureNotifyImpl **pdscn)
683 {
684     IDirectSoundCaptureNotifyImpl * dscn;
685     TRACE("(%p,%p)\n",dscb,pdscn);
686
687     dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscn));
688
689     if (dscn == NULL) {
690         WARN("out of memory\n");
691         return DSERR_OUTOFMEMORY;
692     }
693
694     dscn->ref = 0;
695     dscn->lpVtbl = &dscnvt;
696     dscn->dscb = dscb;
697     dscb->notify = dscn;
698     IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb);
699
700     *pdscn = dscn;
701     return DS_OK;
702 }
703
704 /*******************************************************************************
705  *              IDirectSoundCaptureBuffer
706  */
707 static HRESULT WINAPI
708 IDirectSoundCaptureBufferImpl_QueryInterface(
709     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
710     REFIID riid,
711     LPVOID* ppobj )
712 {
713     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
714     HRESULT hres;
715     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
716
717     if (ppobj == NULL) {
718         WARN("invalid parameter\n");
719         return E_INVALIDARG;
720     }
721
722     *ppobj = NULL;
723
724     if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
725         if (!This->notify)
726             hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify);
727         if (This->notify) {
728             if (This->device->hwbuf) {
729                 hres = IDsCaptureDriverBuffer_QueryInterface(This->device->hwbuf,
730                     &IID_IDsDriverNotify, (LPVOID*)&(This->hwnotify));
731                 if (hres != DS_OK) {
732                     WARN("IDsCaptureDriverBuffer_QueryInterface failed\n");
733                     *ppobj = 0;
734                     return hres;
735                 }
736             }
737
738             IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
739             *ppobj = (LPVOID)This->notify;
740             return DS_OK;
741         }
742
743         WARN("IID_IDirectSoundNotify\n");
744         return E_FAIL;
745     }
746
747     if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
748          IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
749         IDirectSoundCaptureBuffer8_AddRef(iface);
750         *ppobj = This;
751         return NO_ERROR;
752     }
753
754     FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
755     return E_NOINTERFACE;
756 }
757
758 static ULONG WINAPI
759 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
760 {
761     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
762     ULONG ref = InterlockedIncrement(&(This->ref));
763     TRACE("(%p) ref was %ld\n", This, ref - 1);
764     return ref;
765 }
766
767 static ULONG WINAPI
768 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
769 {
770     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
771     ULONG ref = InterlockedDecrement(&(This->ref));
772     TRACE("(%p) ref was %ld\n", This, ref + 1);
773
774     if (!ref) {
775         TRACE("deleting object\n");
776         if (This->device->state == STATE_CAPTURING)
777             This->device->state = STATE_STOPPING;
778
779         HeapFree(GetProcessHeap(),0, This->pdscbd);
780
781         if (This->device->hwi) {
782             waveInReset(This->device->hwi);
783             waveInClose(This->device->hwi);
784             HeapFree(GetProcessHeap(),0, This->device->pwave);
785             This->device->pwave = 0;
786             This->device->hwi = 0;
787         }
788
789         if (This->device->hwbuf)
790             IDsCaptureDriverBuffer_Release(This->device->hwbuf);
791
792         /* remove from DirectSoundCaptureDevice */
793         This->device->capture_buffer = NULL;
794
795         if (This->notify)
796             IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
797
798         HeapFree(GetProcessHeap(), 0, This->notifies);
799         HeapFree( GetProcessHeap(), 0, This );
800         TRACE("(%p) released\n", This);
801     }
802     return ref;
803 }
804
805 static HRESULT WINAPI
806 IDirectSoundCaptureBufferImpl_GetCaps(
807     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
808     LPDSCBCAPS lpDSCBCaps )
809 {
810     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
811     TRACE( "(%p,%p)\n", This, lpDSCBCaps );
812
813     if (lpDSCBCaps == NULL) {
814         WARN("invalid parameter: lpDSCBCaps == NULL\n");
815         return DSERR_INVALIDPARAM;
816     }
817
818     if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
819         WARN("invalid parameter: lpDSCBCaps->dwSize = %ld < %d\n",
820             lpDSCBCaps->dwSize, sizeof(DSCBCAPS));
821         return DSERR_INVALIDPARAM;
822     }
823
824     if (This->device == NULL) {
825         WARN("invalid parameter: This->device == NULL\n");
826         return DSERR_INVALIDPARAM;
827     }
828
829     lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
830     lpDSCBCaps->dwFlags = This->flags;
831     lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
832     lpDSCBCaps->dwReserved = 0;
833
834     TRACE("returning DS_OK\n");
835     return DS_OK;
836 }
837
838 static HRESULT WINAPI
839 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
840     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
841     LPDWORD lpdwCapturePosition,
842     LPDWORD lpdwReadPosition )
843 {
844     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
845     HRESULT hres = DS_OK;
846     TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
847
848     if (This->device == NULL) {
849         WARN("invalid parameter: This->device == NULL\n");
850         return DSERR_INVALIDPARAM;
851     }
852
853     if (This->device->driver) {
854         hres = IDsCaptureDriverBuffer_GetPosition(This->device->hwbuf, lpdwCapturePosition, lpdwReadPosition );
855         if (hres != DS_OK)
856             WARN("IDsCaptureDriverBuffer_GetPosition failed\n");
857     } else if (This->device->hwi) {
858         EnterCriticalSection(&(This->device->lock));
859         TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
860         if (lpdwCapturePosition) {
861             MMTIME mtime;
862             mtime.wType = TIME_BYTES;
863             waveInGetPosition(This->device->hwi, &mtime, sizeof(mtime));
864             TRACE("mtime.u.cb=%ld,This->device->buflen=%ld\n", mtime.u.cb,
865                 This->device->buflen);
866             mtime.u.cb = mtime.u.cb % This->device->buflen;
867             *lpdwCapturePosition = mtime.u.cb;
868         }
869
870         if (lpdwReadPosition) {
871             if (This->device->state == STATE_STARTING) {
872                 if (lpdwCapturePosition)
873                     This->device->read_position = *lpdwCapturePosition;
874                 This->device->state = STATE_CAPTURING;
875             }
876             *lpdwReadPosition = This->device->read_position;
877         }
878         TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
879         LeaveCriticalSection(&(This->device->lock));
880         if (lpdwCapturePosition) TRACE("*lpdwCapturePosition=%ld\n",*lpdwCapturePosition);
881         if (lpdwReadPosition) TRACE("*lpdwReadPosition=%ld\n",*lpdwReadPosition);
882     } else {
883         WARN("no driver\n");
884         hres = DSERR_NODRIVER;
885     }
886
887     TRACE("returning %08lx\n", hres);
888     return hres;
889 }
890
891 static HRESULT WINAPI
892 IDirectSoundCaptureBufferImpl_GetFormat(
893     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
894     LPWAVEFORMATEX lpwfxFormat,
895     DWORD dwSizeAllocated,
896     LPDWORD lpdwSizeWritten )
897 {
898     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
899     HRESULT hres = DS_OK;
900     TRACE( "(%p,%p,0x%08lx,%p)\n", This, lpwfxFormat, dwSizeAllocated,
901         lpdwSizeWritten );
902
903     if (This->device == NULL) {
904         WARN("invalid parameter: This->device == NULL\n");
905         return DSERR_INVALIDPARAM;
906     }
907
908     if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize))
909         dwSizeAllocated = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
910
911     if (lpwfxFormat) { /* NULL is valid (just want size) */
912         CopyMemory(lpwfxFormat, This->device->pwfx, dwSizeAllocated);
913         if (lpdwSizeWritten)
914             *lpdwSizeWritten = dwSizeAllocated;
915     } else {
916         if (lpdwSizeWritten)
917             *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
918         else {
919             TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
920             hres = DSERR_INVALIDPARAM;
921         }
922     }
923
924     TRACE("returning %08lx\n", hres);
925     return hres;
926 }
927
928 static HRESULT WINAPI
929 IDirectSoundCaptureBufferImpl_GetStatus(
930     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
931     LPDWORD lpdwStatus )
932 {
933     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
934     TRACE( "(%p, %p), thread is %04lx\n", This, lpdwStatus, GetCurrentThreadId() );
935
936     if (This->device == NULL) {
937         WARN("invalid parameter: This->device == NULL\n");
938         return DSERR_INVALIDPARAM;
939     }
940
941     if (lpdwStatus == NULL) {
942         WARN("invalid parameter: lpdwStatus == NULL\n");
943         return DSERR_INVALIDPARAM;
944     }
945
946     *lpdwStatus = 0;
947     EnterCriticalSection(&(This->device->lock));
948
949     TRACE("old This->device->state=%s, old lpdwStatus=%08lx\n",
950         captureStateString[This->device->state],*lpdwStatus);
951     if ((This->device->state == STATE_STARTING) ||
952         (This->device->state == STATE_CAPTURING)) {
953         *lpdwStatus |= DSCBSTATUS_CAPTURING;
954         if (This->flags & DSCBSTART_LOOPING)
955             *lpdwStatus |= DSCBSTATUS_LOOPING;
956     }
957     TRACE("new This->device->state=%s, new lpdwStatus=%08lx\n",
958         captureStateString[This->device->state],*lpdwStatus);
959     LeaveCriticalSection(&(This->device->lock));
960
961     TRACE("status=%lx\n", *lpdwStatus);
962     TRACE("returning DS_OK\n");
963     return DS_OK;
964 }
965
966 static HRESULT WINAPI
967 IDirectSoundCaptureBufferImpl_Initialize(
968     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
969     LPDIRECTSOUNDCAPTURE lpDSC,
970     LPCDSCBUFFERDESC lpcDSCBDesc )
971 {
972     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
973
974     FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
975
976     return DS_OK;
977 }
978
979 static HRESULT WINAPI
980 IDirectSoundCaptureBufferImpl_Lock(
981     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
982     DWORD dwReadCusor,
983     DWORD dwReadBytes,
984     LPVOID* lplpvAudioPtr1,
985     LPDWORD lpdwAudioBytes1,
986     LPVOID* lplpvAudioPtr2,
987     LPDWORD lpdwAudioBytes2,
988     DWORD dwFlags )
989 {
990     HRESULT hres = DS_OK;
991     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
992     TRACE( "(%p,%08lu,%08lu,%p,%p,%p,%p,0x%08lx) at %ld\n", This, dwReadCusor,
993         dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
994         lpdwAudioBytes2, dwFlags, GetTickCount() );
995
996     if (This->device == NULL) {
997         WARN("invalid parameter: This->device == NULL\n");
998         return DSERR_INVALIDPARAM;
999     }
1000
1001     if (lplpvAudioPtr1 == NULL) {
1002         WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
1003         return DSERR_INVALIDPARAM;
1004     }
1005
1006     if (lpdwAudioBytes1 == NULL) {
1007         WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
1008         return DSERR_INVALIDPARAM;
1009     }
1010
1011     EnterCriticalSection(&(This->device->lock));
1012
1013     if (This->device->driver) {
1014         hres = IDsCaptureDriverBuffer_Lock(This->device->hwbuf, lplpvAudioPtr1,
1015                                            lpdwAudioBytes1, lplpvAudioPtr2,
1016                                            lpdwAudioBytes2, dwReadCusor,
1017                                            dwReadBytes, dwFlags);
1018         if (hres != DS_OK)
1019             WARN("IDsCaptureDriverBuffer_Lock failed\n");
1020     } else if (This->device->hwi) {
1021         *lplpvAudioPtr1 = This->device->buffer + dwReadCusor;
1022         if ( (dwReadCusor + dwReadBytes) > This->device->buflen) {
1023             *lpdwAudioBytes1 = This->device->buflen - dwReadCusor;
1024             if (lplpvAudioPtr2)
1025                 *lplpvAudioPtr2 = This->device->buffer;
1026             if (lpdwAudioBytes2)
1027                 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
1028         } else {
1029             *lpdwAudioBytes1 = dwReadBytes;
1030             if (lplpvAudioPtr2)
1031                 *lplpvAudioPtr2 = 0;
1032             if (lpdwAudioBytes2)
1033                 *lpdwAudioBytes2 = 0;
1034         }
1035     } else {
1036         TRACE("invalid call\n");
1037         hres = DSERR_INVALIDCALL;   /* DSERR_NODRIVER ? */
1038     }
1039
1040     LeaveCriticalSection(&(This->device->lock));
1041
1042     TRACE("returning %08lx\n", hres);
1043     return hres;
1044 }
1045
1046 static HRESULT WINAPI
1047 IDirectSoundCaptureBufferImpl_Start(
1048     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1049     DWORD dwFlags )
1050 {
1051     HRESULT hres = DS_OK;
1052     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1053     TRACE( "(%p,0x%08lx)\n", This, dwFlags );
1054
1055     if (This->device == NULL) {
1056         WARN("invalid parameter: This->device == NULL\n");
1057         return DSERR_INVALIDPARAM;
1058     }
1059
1060     if ( (This->device->driver == 0) && (This->device->hwi == 0) ) {
1061         WARN("no driver\n");
1062         return DSERR_NODRIVER;
1063     }
1064
1065     EnterCriticalSection(&(This->device->lock));
1066
1067     This->flags = dwFlags;
1068     TRACE("old This->state=%s\n",captureStateString[This->device->state]);
1069     if (This->device->state == STATE_STOPPED)
1070         This->device->state = STATE_STARTING;
1071     else if (This->device->state == STATE_STOPPING)
1072         This->device->state = STATE_CAPTURING;
1073     TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
1074
1075     LeaveCriticalSection(&(This->device->lock));
1076
1077     if (This->device->driver) {
1078         hres = IDsCaptureDriverBuffer_Start(This->device->hwbuf, dwFlags);
1079         if (hres != DS_OK)
1080             WARN("IDsCaptureDriverBuffer_Start failed\n");
1081     } else if (This->device->hwi) {
1082         DirectSoundCaptureDevice *device = This->device;
1083
1084         if (device->buffer) {
1085             if (This->nrofnotifies) {
1086                 int c;
1087
1088                 device->nrofpwaves = This->nrofnotifies;
1089                 TRACE("nrofnotifies=%d\n", This->nrofnotifies);
1090
1091                 /* prepare headers */
1092                 if (device->pwave)
1093                     device->pwave = HeapReAlloc(GetProcessHeap(),0,device->pwave,
1094                         device->nrofpwaves*sizeof(WAVEHDR));
1095                 else
1096                     device->pwave = HeapAlloc(GetProcessHeap(),0,
1097                         device->nrofpwaves*sizeof(WAVEHDR));
1098
1099                 for (c = 0; c < device->nrofpwaves; c++) {
1100                     if (This->notifies[c].dwOffset == DSBPN_OFFSETSTOP) {
1101                         TRACE("got DSBPN_OFFSETSTOP\n");
1102                         device->nrofpwaves = c;
1103                         break;
1104                     }
1105                     if (c == 0) {
1106                         device->pwave[0].lpData = (LPSTR)device->buffer;
1107                         device->pwave[0].dwBufferLength =
1108                             This->notifies[0].dwOffset + 1;
1109                     } else {
1110                         device->pwave[c].lpData = (LPSTR)device->buffer +
1111                             This->notifies[c-1].dwOffset + 1;
1112                         device->pwave[c].dwBufferLength =
1113                             This->notifies[c].dwOffset -
1114                             This->notifies[c-1].dwOffset;
1115                     }
1116                     device->pwave[c].dwBytesRecorded = 0;
1117                     device->pwave[c].dwUser = (DWORD)device;
1118                     device->pwave[c].dwFlags = 0;
1119                     device->pwave[c].dwLoops = 0;
1120                     hres = mmErr(waveInPrepareHeader(device->hwi,
1121                         &(device->pwave[c]),sizeof(WAVEHDR)));
1122                     if (hres != DS_OK) {
1123                         WARN("waveInPrepareHeader failed\n");
1124                         while (c--)
1125                             waveInUnprepareHeader(device->hwi,
1126                                 &(device->pwave[c]),sizeof(WAVEHDR));
1127                         break;
1128                     }
1129
1130                     hres = mmErr(waveInAddBuffer(device->hwi,
1131                         &(device->pwave[c]), sizeof(WAVEHDR)));
1132                     if (hres != DS_OK) {
1133                         WARN("waveInAddBuffer failed\n");
1134                         while (c--)
1135                             waveInUnprepareHeader(device->hwi,
1136                                 &(device->pwave[c]),sizeof(WAVEHDR));
1137                         break;
1138                     }
1139                 }
1140
1141                 FillMemory(device->buffer, device->buflen,
1142                     (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
1143             } else {
1144                 TRACE("no notifiers specified\n");
1145                 /* no notifiers specified so just create a single default header */
1146                 device->nrofpwaves = 1;
1147                 if (device->pwave)
1148                     device->pwave = HeapReAlloc(GetProcessHeap(),0,device->pwave,sizeof(WAVEHDR));
1149                 else
1150                     device->pwave = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEHDR));
1151
1152                 device->pwave[0].lpData = (LPSTR)device->buffer;
1153                 device->pwave[0].dwBufferLength = device->buflen;
1154                 device->pwave[0].dwBytesRecorded = 0;
1155                 device->pwave[0].dwUser = (DWORD)device;
1156                 device->pwave[0].dwFlags = 0;
1157                 device->pwave[0].dwLoops = 0;
1158
1159                 hres = mmErr(waveInPrepareHeader(device->hwi,
1160                     &(device->pwave[0]),sizeof(WAVEHDR)));
1161                 if (hres != DS_OK) {
1162                     WARN("waveInPrepareHeader failed\n");
1163                     waveInUnprepareHeader(device->hwi,
1164                         &(device->pwave[0]),sizeof(WAVEHDR));
1165                 }
1166                 hres = mmErr(waveInAddBuffer(device->hwi,
1167                     &(device->pwave[0]), sizeof(WAVEHDR)));
1168                 if (hres != DS_OK) {
1169                     WARN("waveInAddBuffer failed\n");
1170                     waveInUnprepareHeader(device->hwi,
1171                         &(device->pwave[0]),sizeof(WAVEHDR));
1172                 }
1173             }
1174         }
1175
1176         device->index = 0;
1177         device->read_position = 0;
1178
1179         if (hres == DS_OK) {
1180             /* start filling the first buffer */
1181             hres = mmErr(waveInStart(device->hwi));
1182             if (hres != DS_OK)
1183                 WARN("waveInStart failed\n");
1184         }
1185
1186         if (hres != DS_OK) {
1187             WARN("calling waveInClose because of error\n");
1188             waveInClose(device->hwi);
1189             device->hwi = 0;
1190         }
1191     } else {
1192         WARN("no driver\n");
1193         hres = DSERR_NODRIVER;
1194     }
1195
1196     TRACE("returning %08lx\n", hres);
1197     return hres;
1198 }
1199
1200 static HRESULT WINAPI
1201 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
1202 {
1203     HRESULT hres = DS_OK;
1204     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1205     TRACE( "(%p)\n", This );
1206
1207     if (This->device == NULL) {
1208         WARN("invalid parameter: This->device == NULL\n");
1209         return DSERR_INVALIDPARAM;
1210     }
1211
1212     EnterCriticalSection(&(This->device->lock));
1213
1214     TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
1215     if (This->device->state == STATE_CAPTURING)
1216         This->device->state = STATE_STOPPING;
1217     else if (This->device->state == STATE_STARTING)
1218         This->device->state = STATE_STOPPED;
1219     TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
1220
1221     LeaveCriticalSection(&(This->device->lock));
1222
1223     if (This->device->driver) {
1224         hres = IDsCaptureDriverBuffer_Stop(This->device->hwbuf);
1225         if (hres != DS_OK)
1226             WARN("IDsCaptureDriverBuffer_Stop() failed\n");
1227     } else if (This->device->hwi) {
1228         hres = mmErr(waveInReset(This->device->hwi));
1229         if (hres != DS_OK)
1230             WARN("waveInReset() failed\n");
1231     } else {
1232         WARN("no driver\n");
1233         hres = DSERR_NODRIVER;
1234     }
1235
1236     TRACE("returning %08lx\n", hres);
1237     return hres;
1238 }
1239
1240 static HRESULT WINAPI
1241 IDirectSoundCaptureBufferImpl_Unlock(
1242     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1243     LPVOID lpvAudioPtr1,
1244     DWORD dwAudioBytes1,
1245     LPVOID lpvAudioPtr2,
1246     DWORD dwAudioBytes2 )
1247 {
1248     HRESULT hres = DS_OK;
1249     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1250     TRACE( "(%p,%p,%08lu,%p,%08lu)\n", This, lpvAudioPtr1, dwAudioBytes1,
1251         lpvAudioPtr2, dwAudioBytes2 );
1252
1253     if (lpvAudioPtr1 == NULL) {
1254         WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
1255         return DSERR_INVALIDPARAM;
1256     }
1257
1258     if (This->device->driver) {
1259         hres = IDsCaptureDriverBuffer_Unlock(This->device->hwbuf, lpvAudioPtr1,
1260                                              dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1261         if (hres != DS_OK)
1262             WARN("IDsCaptureDriverBuffer_Unlock failed\n");
1263     } else if (This->device->hwi) {
1264         This->device->read_position = (This->device->read_position +
1265             (dwAudioBytes1 + dwAudioBytes2)) % This->device->buflen;
1266     } else {
1267         WARN("invalid call\n");
1268         hres = DSERR_INVALIDCALL;
1269     }
1270
1271     TRACE("returning %08lx\n", hres);
1272     return hres;
1273 }
1274
1275 static HRESULT WINAPI
1276 IDirectSoundCaptureBufferImpl_GetObjectInPath(
1277     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1278     REFGUID rguidObject,
1279     DWORD dwIndex,
1280     REFGUID rguidInterface,
1281     LPVOID* ppObject )
1282 {
1283     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1284
1285     FIXME( "(%p,%s,%lu,%s,%p): stub\n", This, debugstr_guid(rguidObject),
1286         dwIndex, debugstr_guid(rguidInterface), ppObject );
1287
1288     return DS_OK;
1289 }
1290
1291 static HRESULT WINAPI
1292 IDirectSoundCaptureBufferImpl_GetFXStatus(
1293     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1294     DWORD dwFXCount,
1295     LPDWORD pdwFXStatus )
1296 {
1297     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1298
1299     FIXME( "(%p,%lu,%p): stub\n", This, dwFXCount, pdwFXStatus );
1300
1301     return DS_OK;
1302 }
1303
1304 static const IDirectSoundCaptureBuffer8Vtbl dscbvt =
1305 {
1306     /* IUnknown methods */
1307     IDirectSoundCaptureBufferImpl_QueryInterface,
1308     IDirectSoundCaptureBufferImpl_AddRef,
1309     IDirectSoundCaptureBufferImpl_Release,
1310
1311     /* IDirectSoundCaptureBuffer methods */
1312     IDirectSoundCaptureBufferImpl_GetCaps,
1313     IDirectSoundCaptureBufferImpl_GetCurrentPosition,
1314     IDirectSoundCaptureBufferImpl_GetFormat,
1315     IDirectSoundCaptureBufferImpl_GetStatus,
1316     IDirectSoundCaptureBufferImpl_Initialize,
1317     IDirectSoundCaptureBufferImpl_Lock,
1318     IDirectSoundCaptureBufferImpl_Start,
1319     IDirectSoundCaptureBufferImpl_Stop,
1320     IDirectSoundCaptureBufferImpl_Unlock,
1321
1322     /* IDirectSoundCaptureBuffer methods */
1323     IDirectSoundCaptureBufferImpl_GetObjectInPath,
1324     IDirectSoundCaptureBufferImpl_GetFXStatus
1325 };
1326
1327 HRESULT IDirectSoundCaptureBufferImpl_Create(
1328     DirectSoundCaptureDevice *device,
1329     IDirectSoundCaptureBufferImpl ** ppobj,
1330     LPCDSCBUFFERDESC lpcDSCBufferDesc)
1331 {
1332     LPWAVEFORMATEX  wfex;
1333     TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
1334
1335     if (ppobj == NULL) {
1336         WARN("invalid parameter: ppobj == NULL\n");
1337         return DSERR_INVALIDPARAM;
1338     }
1339
1340     if (!device) {
1341         WARN("not initialized\n");
1342         *ppobj = NULL;
1343         return DSERR_UNINITIALIZED;
1344     }
1345
1346     if (lpcDSCBufferDesc == NULL) {
1347         WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
1348         *ppobj = NULL;
1349         return DSERR_INVALIDPARAM;
1350     }
1351
1352     if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
1353           (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
1354         (lpcDSCBufferDesc->dwBufferBytes == 0) ||
1355         (lpcDSCBufferDesc->lpwfxFormat == NULL) ) {
1356         WARN("invalid lpcDSCBufferDesc\n");
1357         *ppobj = NULL;
1358         return DSERR_INVALIDPARAM;
1359     }
1360
1361     wfex = lpcDSCBufferDesc->lpwfxFormat;
1362
1363     if (wfex) {
1364         TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1365             "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1366             wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
1367             wfex->nAvgBytesPerSec, wfex->nBlockAlign,
1368             wfex->wBitsPerSample, wfex->cbSize);
1369
1370         if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
1371             device->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX));
1372             CopyMemory(device->pwfx, wfex, sizeof(WAVEFORMATEX));
1373             device->pwfx->cbSize = 0;
1374         } else {
1375             device->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)+wfex->cbSize);
1376             CopyMemory(device->pwfx, wfex, sizeof(WAVEFORMATEX)+wfex->cbSize);
1377         }
1378     } else {
1379         WARN("lpcDSCBufferDesc->lpwfxFormat == 0\n");
1380         *ppobj = NULL;
1381         return DSERR_INVALIDPARAM; /* FIXME: DSERR_BADFORMAT ? */
1382     }
1383
1384     *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1385         sizeof(IDirectSoundCaptureBufferImpl));
1386
1387     if ( *ppobj == NULL ) {
1388         WARN("out of memory\n");
1389         *ppobj = NULL;
1390         return DSERR_OUTOFMEMORY;
1391     } else {
1392         HRESULT err = DS_OK;
1393         LPBYTE newbuf;
1394         DWORD buflen;
1395         IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)*ppobj;
1396
1397         This->ref = 1;
1398         This->device = device;
1399         This->device->capture_buffer = This;
1400         This->notify = NULL;
1401         This->nrofnotifies = 0;
1402         This->hwnotify = NULL;
1403
1404         This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1405             lpcDSCBufferDesc->dwSize);
1406         if (This->pdscbd)
1407             CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
1408         else {
1409             WARN("no memory\n");
1410             This->device->capture_buffer = 0;
1411             HeapFree( GetProcessHeap(), 0, This );
1412             *ppobj = NULL;
1413             return DSERR_OUTOFMEMORY;
1414         }
1415
1416         This->lpVtbl = &dscbvt;
1417
1418         if (device->driver) {
1419             if (This->device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1420                 FIXME("DSDDESC_DOMMSYSTEMOPEN not supported\n");
1421
1422             if (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
1423                 /* allocate buffer from system memory */
1424                 buflen = lpcDSCBufferDesc->dwBufferBytes;
1425                 TRACE("desired buflen=%ld, old buffer=%p\n", buflen, device->buffer);
1426                 if (device->buffer)
1427                     newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
1428                 else
1429                     newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
1430
1431                 if (newbuf == NULL) {
1432                     WARN("failed to allocate capture buffer\n");
1433                     err = DSERR_OUTOFMEMORY;
1434                     /* but the old buffer might still exist and must be re-prepared */
1435                 } else {
1436                     device->buffer = newbuf;
1437                     device->buflen = buflen;
1438                 }
1439             } else {
1440                 /* let driver allocate memory */
1441                 device->buflen = lpcDSCBufferDesc->dwBufferBytes;
1442                 /* FIXME: */
1443                 HeapFree( GetProcessHeap(), 0, device->buffer);
1444                 device->buffer = NULL;
1445             }
1446
1447             err = IDsCaptureDriver_CreateCaptureBuffer(device->driver,
1448                 device->pwfx,0,0,&(device->buflen),&(device->buffer),(LPVOID*)&(device->hwbuf));
1449             if (err != DS_OK) {
1450                 WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n");
1451                 This->device->capture_buffer = 0;
1452                 HeapFree( GetProcessHeap(), 0, This );
1453                 *ppobj = NULL;
1454                 return err;
1455             }
1456         } else {
1457             DWORD flags = CALLBACK_FUNCTION;
1458             if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
1459                 flags |= WAVE_DIRECTSOUND;
1460             err = mmErr(waveInOpen(&(device->hwi),
1461                 device->drvdesc.dnDevNode, device->pwfx,
1462                 (DWORD_PTR)DSOUND_capture_callback, (DWORD)device, flags));
1463             if (err != DS_OK) {
1464                 WARN("waveInOpen failed\n");
1465                 This->device->capture_buffer = 0;
1466                 HeapFree( GetProcessHeap(), 0, This );
1467                 *ppobj = NULL;
1468                 return err;
1469             }
1470
1471             buflen = lpcDSCBufferDesc->dwBufferBytes;
1472             TRACE("desired buflen=%ld, old buffer=%p\n", buflen, device->buffer);
1473             if (device->buffer)
1474                 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
1475             else
1476                 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
1477             if (newbuf == NULL) {
1478                 WARN("failed to allocate capture buffer\n");
1479                 err = DSERR_OUTOFMEMORY;
1480                 /* but the old buffer might still exist and must be re-prepared */
1481             } else {
1482                 device->buffer = newbuf;
1483                 device->buflen = buflen;
1484             }
1485         }
1486     }
1487
1488     TRACE("returning DS_OK\n");
1489     return DS_OK;
1490 }
1491
1492 /*******************************************************************************
1493  * DirectSoundCaptureDevice
1494  */
1495 HRESULT DirectSoundCaptureDevice_Initialize(
1496     DirectSoundCaptureDevice ** ppDevice,
1497     LPCGUID lpcGUID)
1498 {
1499     HRESULT err = DSERR_INVALIDPARAM;
1500     unsigned wid, widn;
1501     BOOLEAN found = FALSE;
1502     GUID devGUID;
1503     DirectSoundCaptureDevice *device = *ppDevice;
1504     TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
1505
1506     /* Default device? */
1507     if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
1508         lpcGUID = &DSDEVID_DefaultCapture;
1509
1510     if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1511         WARN("invalid parameter: lpcGUID\n");
1512         return DSERR_INVALIDPARAM;
1513     }
1514
1515     widn = waveInGetNumDevs();
1516     if (!widn) {
1517         WARN("no audio devices found\n");
1518         return DSERR_NODRIVER;
1519     }
1520
1521     /* enumerate WINMM audio devices and find the one we want */
1522     for (wid=0; wid<widn; wid++) {
1523         if (IsEqualGUID( &devGUID, &DSOUND_capture_guids[wid]) ) {
1524             found = TRUE;
1525             break;
1526         }
1527     }
1528
1529     if (found == FALSE) {
1530         WARN("No device found matching given ID!\n");
1531         return DSERR_NODRIVER;
1532     }
1533
1534     if (DSOUND_capture[wid]) {
1535         WARN("already in use\n");
1536         return DSERR_ALLOCATED;
1537     }
1538
1539     err = DirectSoundCaptureDevice_Create(&(device));
1540     if (err != DS_OK) {
1541         WARN("DirectSoundCaptureDevice_Create failed\n");
1542         return err;
1543     }
1544
1545     *ppDevice = device;
1546     device->guid = devGUID;
1547
1548     err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD_PTR)&(device->driver),0));
1549     if ( (err != DS_OK) && (err != DSERR_UNSUPPORTED) ) {
1550         WARN("waveInMessage failed; err=%lx\n",err);
1551         return err;
1552     }
1553     err = DS_OK;
1554
1555     /* Disable the direct sound driver to force emulation if requested. */
1556     if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
1557         device->driver = NULL;
1558
1559     /* Get driver description */
1560     if (device->driver) {
1561         TRACE("using DirectSound driver\n");
1562         err = IDsCaptureDriver_GetDriverDesc(device->driver, &(device->drvdesc));
1563         if (err != DS_OK) {
1564             WARN("IDsCaptureDriver_GetDriverDesc failed\n");
1565             return err;
1566         }
1567     } else {
1568         TRACE("using WINMM\n");
1569         /* if no DirectSound interface available, use WINMM API instead */
1570         device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN |
1571             DSDDESC_DOMMSYSTEMSETFORMAT;
1572     }
1573
1574     device->drvdesc.dnDevNode = wid;
1575
1576     /* open the DirectSound driver if available */
1577     if (device->driver && (err == DS_OK))
1578         err = IDsCaptureDriver_Open(device->driver);
1579
1580     if (err == DS_OK) {
1581         *ppDevice = device;
1582
1583         /* the driver is now open, so it's now allowed to call GetCaps */
1584         if (device->driver) {
1585             device->drvcaps.dwSize = sizeof(device->drvcaps);
1586             err = IDsCaptureDriver_GetCaps(device->driver,&(device->drvcaps));
1587             if (err != DS_OK) {
1588                 WARN("IDsCaptureDriver_GetCaps failed\n");
1589                 return err;
1590             }
1591         } else /*if (device->hwi)*/ {
1592             WAVEINCAPSA    wic;
1593             err = mmErr(waveInGetDevCapsA((UINT)device->drvdesc.dnDevNode, &wic, sizeof(wic)));
1594
1595             if (err == DS_OK) {
1596                 device->drvcaps.dwFlags = 0;
1597                 lstrcpynA(device->drvdesc.szDrvname, wic.szPname,
1598                           sizeof(device->drvdesc.szDrvname));
1599
1600                 device->drvcaps.dwFlags |= DSCCAPS_EMULDRIVER;
1601                 device->drvcaps.dwFormats = wic.dwFormats;
1602                 device->drvcaps.dwChannels = wic.wChannels;
1603             }
1604         }
1605     }
1606
1607     return err;
1608 }
1609
1610 static HRESULT DirectSoundCaptureDevice_Create(
1611     DirectSoundCaptureDevice ** ppDevice)
1612 {
1613     DirectSoundCaptureDevice * device;
1614     TRACE("(%p)\n", ppDevice);
1615
1616     /* Allocate memory */
1617     device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
1618
1619     if (device == NULL) {
1620         WARN("out of memory\n");
1621         return DSERR_OUTOFMEMORY;
1622     }
1623
1624     device->ref = 1;
1625     device->state = STATE_STOPPED;
1626
1627     InitializeCriticalSection( &(device->lock) );
1628     device->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSCAPTURE_lock";
1629
1630     *ppDevice = device;
1631
1632     return DS_OK;
1633 }
1634
1635 ULONG DirectSoundCaptureDevice_AddRef(
1636     DirectSoundCaptureDevice * device)
1637 {
1638     ULONG ref = InterlockedIncrement(&(device->ref));
1639     TRACE("(%p) ref was %ld\n", device, ref - 1);
1640     return ref;
1641 }
1642
1643 ULONG DirectSoundCaptureDevice_Release(
1644     DirectSoundCaptureDevice * device)
1645 {
1646     ULONG ref = InterlockedDecrement(&(device->ref));
1647     TRACE("(%p) ref was %ld\n", device, ref + 1);
1648
1649     if (!ref) {
1650         TRACE("deleting object\n");
1651         if (device->capture_buffer)
1652             IDirectSoundCaptureBufferImpl_Release(
1653                 (LPDIRECTSOUNDCAPTUREBUFFER8) device->capture_buffer);
1654
1655         if (device->driver) {
1656             IDsCaptureDriver_Close(device->driver);
1657             IDsCaptureDriver_Release(device->driver);
1658         }
1659
1660         HeapFree(GetProcessHeap(), 0, device->pwfx);
1661         device->lock.DebugInfo->Spare[0] = 0;
1662         DeleteCriticalSection( &(device->lock) );
1663         DSOUND_capture[device->drvdesc.dnDevNode] = NULL;
1664         HeapFree(GetProcessHeap(), 0, device);
1665         TRACE("(%p) released\n", device);
1666     }
1667     return ref;
1668 }
1669
1670 /*******************************************************************************
1671  * DirectSoundCapture ClassFactory
1672  */
1673
1674 static HRESULT WINAPI
1675 DSCCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
1676 {
1677     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1678
1679     FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1680     return E_NOINTERFACE;
1681 }
1682
1683 static ULONG WINAPI
1684 DSCCF_AddRef(LPCLASSFACTORY iface)
1685 {
1686     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1687     ULONG ref = InterlockedIncrement(&(This->ref));
1688     TRACE("(%p) ref was %ld\n", This, ref - 1);
1689     return ref;
1690 }
1691
1692 static ULONG WINAPI
1693 DSCCF_Release(LPCLASSFACTORY iface)
1694 {
1695     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1696     ULONG ref = InterlockedDecrement(&(This->ref));
1697     TRACE("(%p) ref was %ld\n", This, ref + 1);
1698     /* static class, won't be  freed */
1699     return ref;
1700 }
1701
1702 static HRESULT WINAPI
1703 DSCCF_CreateInstance(
1704         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj )
1705 {
1706     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1707     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1708
1709     if (pOuter) {
1710         WARN("aggregation not supported\n");
1711         return CLASS_E_NOAGGREGATION;
1712     }
1713
1714     if (ppobj == NULL) {
1715         WARN("invalid parameter\n");
1716         return E_INVALIDARG;
1717     }
1718
1719     *ppobj = NULL;
1720
1721     if ( IsEqualGUID( &IID_IDirectSoundCapture, riid ) )
1722         return DSOUND_CaptureCreate8((LPDIRECTSOUNDCAPTURE*)ppobj,pOuter);
1723
1724     WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); 
1725     return E_NOINTERFACE;
1726 }
1727
1728 static HRESULT WINAPI
1729 DSCCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
1730 {
1731     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1732     FIXME("(%p)->(%d),stub!\n",This,dolock);
1733     return S_OK;
1734 }
1735
1736 static const IClassFactoryVtbl DSCCF_Vtbl =
1737 {
1738     DSCCF_QueryInterface,
1739     DSCCF_AddRef,
1740     DSCCF_Release,
1741     DSCCF_CreateInstance,
1742     DSCCF_LockServer
1743 };
1744
1745 IClassFactoryImpl DSOUND_CAPTURE_CF = { &DSCCF_Vtbl, 1 };