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