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