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