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