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