Update the address of the Free Software Foundation.
[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 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 (lpcDSCBufferDesc == NULL) {
462         WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
463         return DSERR_INVALIDPARAM;
464     }
465
466     if (lplpDSCaptureBuffer == NULL) {
467         WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
468         return DSERR_INVALIDPARAM;
469     }
470
471     if (pUnk != NULL) {
472         WARN("invalid parameter: pUnk != NULL\n");
473         return DSERR_INVALIDPARAM;
474     }
475
476     /* FIXME: We can only have one buffer so what do we do here? */
477     if (This->device->capture_buffer) {
478         WARN("lnvalid parameter: already has buffer\n");
479         return DSERR_INVALIDPARAM;    /* DSERR_GENERIC ? */
480     }
481
482     hr = IDirectSoundCaptureBufferImpl_Create(This->device,
483         (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
484
485     if (hr != DS_OK)
486         WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
487
488     return hr;
489 }
490
491 HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(
492     LPDIRECTSOUNDCAPTURE iface,
493     LPDSCCAPS lpDSCCaps )
494 {
495     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
496     TRACE("(%p,%p)\n",This,lpDSCCaps);
497
498     if (This->device == NULL) {
499         WARN("not initialized\n");
500         return DSERR_UNINITIALIZED;
501     }
502
503     if (lpDSCCaps== NULL) {
504         WARN("invalid parameter: lpDSCCaps== NULL\n");
505         return DSERR_INVALIDPARAM;
506     }
507
508     if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
509         WARN("invalid parameter: lpDSCCaps->dwSize = %ld < %d\n",
510             lpDSCCaps->dwSize, sizeof(*lpDSCCaps));
511         return DSERR_INVALIDPARAM;
512     }
513
514     lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
515     lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
516     lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
517
518     TRACE("(flags=0x%08lx,format=0x%08lx,channels=%ld)\n",lpDSCCaps->dwFlags,
519         lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
520
521     return DS_OK;
522 }
523
524 HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(
525     LPDIRECTSOUNDCAPTURE iface,
526     LPCGUID lpcGUID )
527 {
528     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
529     TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
530
531     if (This->device != NULL) {
532         WARN("already initialized\n");
533         return DSERR_ALREADYINITIALIZED;
534     }
535
536     return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
537 }
538
539 static const IDirectSoundCaptureVtbl dscvt =
540 {
541     /* IUnknown methods */
542     IDirectSoundCaptureImpl_QueryInterface,
543     IDirectSoundCaptureImpl_AddRef,
544     IDirectSoundCaptureImpl_Release,
545
546     /* IDirectSoundCapture methods */
547     IDirectSoundCaptureImpl_CreateCaptureBuffer,
548     IDirectSoundCaptureImpl_GetCaps,
549     IDirectSoundCaptureImpl_Initialize
550 };
551
552 HRESULT IDirectSoundCaptureImpl_Create(
553     LPDIRECTSOUNDCAPTURE8 * ppDSC)
554 {
555     IDirectSoundCaptureImpl *pDSC;
556     TRACE("(%p)\n", ppDSC);
557
558     /* Allocate memory */
559     pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
560     if (pDSC == NULL) {
561         WARN("out of memory\n");
562         *ppDSC = NULL;
563         return DSERR_OUTOFMEMORY;
564     }
565
566     pDSC->lpVtbl = &dscvt;
567     pDSC->ref    = 0;
568     pDSC->device = NULL;
569
570     *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
571
572     return DS_OK;
573 }
574
575 /*******************************************************************************
576  *              IDirectSoundCaptureNotify
577  */
578 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface(
579     LPDIRECTSOUNDNOTIFY iface,
580     REFIID riid,
581     LPVOID *ppobj)
582 {
583     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
584     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
585
586     if (This->dscb == NULL) {
587         WARN("invalid parameter\n");
588         return E_INVALIDARG;
589     }
590
591     return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
592 }
593
594 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
595 {
596     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
597     ULONG ref = InterlockedIncrement(&(This->ref));
598     TRACE("(%p) ref was %ld\n", This, ref - 1);
599     return ref;
600 }
601
602 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
603 {
604     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
605     ULONG ref = InterlockedDecrement(&(This->ref));
606     TRACE("(%p) ref was %ld\n", This, ref + 1);
607
608     if (!ref) {
609         if (This->dscb->hwnotify)
610             IDsDriverNotify_Release(This->dscb->hwnotify);
611         This->dscb->notify=NULL;
612         IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb);
613         HeapFree(GetProcessHeap(),0,This);
614         TRACE("(%p) released\n", This);
615     }
616     return ref;
617 }
618
619 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions(
620     LPDIRECTSOUNDNOTIFY iface,
621     DWORD howmuch,
622     LPCDSBPOSITIONNOTIFY notify)
623 {
624     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
625     TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
626
627     if (howmuch > 0 && notify == NULL) {
628         WARN("invalid parameter: notify == NULL\n");
629         return DSERR_INVALIDPARAM;
630     }
631
632     if (TRACE_ON(dsound)) {
633         unsigned int i;
634         for (i=0;i<howmuch;i++)
635             TRACE("notify at %ld to %p\n",
636             notify[i].dwOffset,notify[i].hEventNotify);
637     }
638
639     if (This->dscb->hwnotify) {
640         HRESULT hres;
641         hres = IDsDriverNotify_SetNotificationPositions(This->dscb->hwnotify, howmuch, notify);
642         if (hres != DS_OK)
643             WARN("IDsDriverNotify_SetNotificationPositions failed\n");
644         return hres;
645     } else if (howmuch > 0) {
646         /* Make an internal copy of the caller-supplied array.
647          * Replace the existing copy if one is already present. */
648         if (This->dscb->notifies)
649             This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
650                 This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
651         else
652             This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
653                 howmuch * sizeof(DSBPOSITIONNOTIFY));
654
655         if (This->dscb->notifies == NULL) {
656             WARN("out of memory\n");
657             return DSERR_OUTOFMEMORY;
658         }
659         CopyMemory(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
660         This->dscb->nrofnotifies = howmuch;
661     } else {
662         HeapFree(GetProcessHeap(), 0, This->dscb->notifies);
663         This->dscb->notifies = NULL;
664         This->dscb->nrofnotifies = 0;
665     }
666
667     return S_OK;
668 }
669
670 static const IDirectSoundNotifyVtbl dscnvt =
671 {
672     IDirectSoundCaptureNotifyImpl_QueryInterface,
673     IDirectSoundCaptureNotifyImpl_AddRef,
674     IDirectSoundCaptureNotifyImpl_Release,
675     IDirectSoundCaptureNotifyImpl_SetNotificationPositions,
676 };
677
678 HRESULT IDirectSoundCaptureNotifyImpl_Create(
679     IDirectSoundCaptureBufferImpl *dscb,
680     IDirectSoundCaptureNotifyImpl **pdscn)
681 {
682     IDirectSoundCaptureNotifyImpl * dscn;
683     TRACE("(%p,%p)\n",dscb,pdscn);
684
685     dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscn));
686
687     if (dscn == NULL) {
688         WARN("out of memory\n");
689         return DSERR_OUTOFMEMORY;
690     }
691
692     dscn->ref = 0;
693     dscn->lpVtbl = &dscnvt;
694     dscn->dscb = dscb;
695     dscb->notify = dscn;
696     IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb);
697
698     *pdscn = dscn;
699     return DS_OK;
700 }
701
702 /*******************************************************************************
703  *              IDirectSoundCaptureBuffer
704  */
705 static HRESULT WINAPI
706 IDirectSoundCaptureBufferImpl_QueryInterface(
707     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
708     REFIID riid,
709     LPVOID* ppobj )
710 {
711     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
712     HRESULT hres;
713     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
714
715     if (ppobj == NULL) {
716         WARN("invalid parameter\n");
717         return E_INVALIDARG;
718     }
719
720     *ppobj = NULL;
721
722     if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
723         if (!This->notify)
724             hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify);
725         if (This->notify) {
726             if (This->device->hwbuf) {
727                 hres = IDsCaptureDriverBuffer_QueryInterface(This->device->hwbuf,
728                     &IID_IDsDriverNotify, (LPVOID*)&(This->hwnotify));
729                 if (hres != DS_OK) {
730                     WARN("IDsCaptureDriverBuffer_QueryInterface failed\n");
731                     *ppobj = 0;
732                     return hres;
733                 }
734             }
735
736             IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
737             *ppobj = (LPVOID)This->notify;
738             return DS_OK;
739         }
740
741         WARN("IID_IDirectSoundNotify\n");
742         return E_FAIL;
743     }
744
745     if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
746          IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
747         IDirectSoundCaptureBuffer8_AddRef(iface);
748         *ppobj = This;
749         return NO_ERROR;
750     }
751
752     FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
753     return E_NOINTERFACE;
754 }
755
756 static ULONG WINAPI
757 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
758 {
759     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
760     ULONG ref = InterlockedIncrement(&(This->ref));
761     TRACE("(%p) ref was %ld\n", This, ref - 1);
762     return ref;
763 }
764
765 static ULONG WINAPI
766 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
767 {
768     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
769     ULONG ref = InterlockedDecrement(&(This->ref));
770     TRACE("(%p) ref was %ld\n", This, ref + 1);
771
772     if (!ref) {
773         TRACE("deleting object\n");
774         if (This->device->state == STATE_CAPTURING)
775             This->device->state = STATE_STOPPING;
776
777         HeapFree(GetProcessHeap(),0, This->pdscbd);
778
779         if (This->device->hwi) {
780             waveInReset(This->device->hwi);
781             waveInClose(This->device->hwi);
782             HeapFree(GetProcessHeap(),0, This->device->pwave);
783             This->device->pwave = 0;
784             This->device->hwi = 0;
785         }
786
787         if (This->device->hwbuf)
788             IDsCaptureDriverBuffer_Release(This->device->hwbuf);
789
790         /* remove from DirectSoundCaptureDevice */
791         This->device->capture_buffer = NULL;
792
793         if (This->notify)
794             IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
795
796         HeapFree(GetProcessHeap(), 0, This->notifies);
797         HeapFree( GetProcessHeap(), 0, This );
798         TRACE("(%p) released\n", This);
799     }
800     return ref;
801 }
802
803 static HRESULT WINAPI
804 IDirectSoundCaptureBufferImpl_GetCaps(
805     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
806     LPDSCBCAPS lpDSCBCaps )
807 {
808     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
809     TRACE( "(%p,%p)\n", This, lpDSCBCaps );
810
811     if (lpDSCBCaps == NULL) {
812         WARN("invalid parameter: lpDSCBCaps == NULL\n");
813         return DSERR_INVALIDPARAM;
814     }
815
816     if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
817         WARN("invalid parameter: lpDSCBCaps->dwSize = %ld < %d\n",
818             lpDSCBCaps->dwSize, sizeof(DSCBCAPS));
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 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 };