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