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