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