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