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