dmloader: complete rewrite and full implementation.
[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->dwSize != sizeof(DSCBUFFERDESC1))) || 
672         (lpcDSCBufferDesc->dwBufferBytes == 0) ||
673         (lpcDSCBufferDesc->lpwfxFormat == NULL) ) {
674         WARN("invalid lpcDSCBufferDesc\n");
675         *ppobj = NULL;
676         return DSERR_INVALIDPARAM;
677     }
678
679     if ( !ipDSC->initialized ) {
680         WARN("not initialized\n");
681         *ppobj = NULL;
682         return DSERR_UNINITIALIZED;
683     }
684
685     wfex = lpcDSCBufferDesc->lpwfxFormat;
686
687     if (wfex) {
688         TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
689             "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
690             wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
691             wfex->nAvgBytesPerSec, wfex->nBlockAlign,
692             wfex->wBitsPerSample, wfex->cbSize);
693
694         if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
695             ipDSC->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX));
696             memcpy(ipDSC->pwfx, wfex, sizeof(WAVEFORMATEX));
697             ipDSC->pwfx->cbSize = 0;
698         } else {
699             ipDSC->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)+wfex->cbSize);
700             memcpy(ipDSC->pwfx, wfex, sizeof(WAVEFORMATEX)+wfex->cbSize);
701         }
702     } else {
703         WARN("lpcDSCBufferDesc->lpwfxFormat == 0\n");
704         *ppobj = NULL;
705         return DSERR_INVALIDPARAM; /* FIXME: DSERR_BADFORMAT ? */
706     }
707
708     *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
709         sizeof(IDirectSoundCaptureBufferImpl));
710
711     if ( *ppobj == NULL ) {
712         WARN("out of memory\n");
713         *ppobj = NULL;
714         return DSERR_OUTOFMEMORY;
715     } else {
716         HRESULT err = DS_OK;
717         ICOM_THIS(IDirectSoundCaptureBufferImpl,*ppobj);
718
719         This->ref = 1;
720         This->dsound = ipDSC;
721         This->dsound->capture_buffer = This;
722         This->notify = NULL;
723         This->nrofnotifies = 0;
724         This->hwnotify = NULL;
725
726         This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
727             lpcDSCBufferDesc->dwSize);
728         if (This->pdscbd)     
729             memcpy(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
730         else {
731             WARN("no memory\n");
732             This->dsound->capture_buffer = 0;
733             HeapFree( GetProcessHeap(), 0, This );
734             *ppobj = NULL;
735             return DSERR_OUTOFMEMORY; 
736         }
737
738         This->lpVtbl = &dscbvt;
739
740         if (ipDSC->driver) {
741             err = IDsCaptureDriver_CreateCaptureBuffer(ipDSC->driver, 
742                 ipDSC->pwfx,0,0,&(ipDSC->buflen),&(ipDSC->buffer),(LPVOID*)&(ipDSC->hwbuf));
743             if (err != DS_OK) {
744                 WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n");
745                 This->dsound->capture_buffer = 0;
746                 HeapFree( GetProcessHeap(), 0, This );
747                 *ppobj = NULL;
748                 return err;
749             }
750         } else {
751             LPBYTE newbuf;
752             DWORD buflen;
753             DWORD flags = CALLBACK_FUNCTION;
754             if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
755                 flags |= WAVE_DIRECTSOUND;
756             err = mmErr(waveInOpen(&(ipDSC->hwi),
757                 ipDSC->drvdesc.dnDevNode, ipDSC->pwfx,
758                 (DWORD)DSOUND_capture_callback, (DWORD)ipDSC, flags));
759             if (err != DS_OK) {
760                 WARN("waveInOpen failed\n");
761                 This->dsound->capture_buffer = 0;
762                 HeapFree( GetProcessHeap(), 0, This );
763                 *ppobj = NULL;
764                 return err;
765             }
766
767             buflen = lpcDSCBufferDesc->dwBufferBytes;
768             TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->buffer);
769             if (ipDSC->buffer)
770                 newbuf = (LPBYTE)HeapReAlloc(GetProcessHeap(),0,ipDSC->buffer,buflen);
771             else
772                 newbuf = (LPBYTE)HeapAlloc(GetProcessHeap(),0,buflen);      
773             if (newbuf == NULL) {
774                 WARN("failed to allocate capture buffer\n");
775                 err = DSERR_OUTOFMEMORY;
776                 /* but the old buffer might still exist and must be re-prepared */
777             } else {
778                 ipDSC->buffer = newbuf;
779                 ipDSC->buflen = buflen;
780             }
781         }
782     }
783
784     TRACE("returning DS_OK\n");
785     return DS_OK;
786 }
787
788 /*******************************************************************************
789  *              IDirectSoundCaptureNotify
790  */
791 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface(
792     LPDIRECTSOUNDNOTIFY iface,
793     REFIID riid,
794     LPVOID *ppobj)
795 {
796     ICOM_THIS(IDirectSoundCaptureNotifyImpl,iface);
797     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
798
799     if (This->dscb == NULL) {
800         WARN("invalid parameter\n");
801         return E_INVALIDARG;
802     }
803
804     return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
805 }
806
807 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
808 {
809     ICOM_THIS(IDirectSoundCaptureNotifyImpl,iface);
810     DWORD ref;
811
812     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
813
814     ref = InterlockedIncrement(&(This->ref));
815     return ref;
816 }
817
818 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
819 {
820     ICOM_THIS(IDirectSoundCaptureNotifyImpl,iface);
821     DWORD ref;
822
823     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
824
825     ref = InterlockedDecrement(&(This->ref));
826     if (ref == 0) {
827         if (This->dscb->hwnotify)
828             IDsDriverNotify_Release(This->dscb->hwnotify);
829         This->dscb->notify=NULL;
830         IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb);
831         HeapFree(GetProcessHeap(),0,This);
832         TRACE("(%p) released\n",This);
833     }
834     return ref;
835 }
836
837 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions(
838     LPDIRECTSOUNDNOTIFY iface,
839     DWORD howmuch,
840     LPCDSBPOSITIONNOTIFY notify)
841 {
842     ICOM_THIS(IDirectSoundCaptureNotifyImpl,iface);
843     TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
844
845     if (howmuch > 0 && notify == NULL) {
846         WARN("invalid parameter: notify == NULL\n");
847         return DSERR_INVALIDPARAM;
848     }
849
850     if (TRACE_ON(dsound)) {
851         int     i;
852         for (i=0;i<howmuch;i++)
853             TRACE("notify at %ld to 0x%08lx\n",
854             notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
855     }
856
857     if (This->dscb->hwnotify) {
858         HRESULT hres;
859         hres = IDsDriverNotify_SetNotificationPositions(This->dscb->hwnotify, howmuch, notify);
860         if (hres != DS_OK)
861             WARN("IDsDriverNotify_SetNotificationPositions failed\n");
862         return hres;
863     } else if (howmuch > 0) {
864         /* Make an internal copy of the caller-supplied array.
865          * Replace the existing copy if one is already present. */
866         if (This->dscb->notifies)
867             This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 
868                 This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
869         else
870             This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 
871                 howmuch * sizeof(DSBPOSITIONNOTIFY));
872
873         if (This->dscb->notifies == NULL) {
874             WARN("out of memory\n");
875             return DSERR_OUTOFMEMORY;
876         }
877         memcpy(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
878         This->dscb->nrofnotifies = howmuch;
879     } else {
880         if (This->dscb->notifies) {
881             HeapFree(GetProcessHeap(), 0, This->dscb->notifies);
882             This->dscb->notifies = NULL;
883         }
884         This->dscb->nrofnotifies = 0;
885     }
886
887     return S_OK;
888 }
889
890 ICOM_VTABLE(IDirectSoundNotify) dscnvt =
891 {
892     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
893     IDirectSoundCaptureNotifyImpl_QueryInterface,
894     IDirectSoundCaptureNotifyImpl_AddRef,
895     IDirectSoundCaptureNotifyImpl_Release,
896     IDirectSoundCaptureNotifyImpl_SetNotificationPositions,
897 };
898
899 HRESULT WINAPI IDirectSoundCaptureNotifyImpl_Create(
900     IDirectSoundCaptureBufferImpl *dscb,
901     IDirectSoundCaptureNotifyImpl **pdscn)
902 {
903     IDirectSoundCaptureNotifyImpl * dscn;
904     TRACE("(%p,%p)\n",dscb,pdscn);
905
906     dscn = (IDirectSoundCaptureNotifyImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscn));
907
908     if (dscn == NULL) {
909         WARN("out of memory\n");
910         return DSERR_OUTOFMEMORY;
911     }
912
913     dscn->ref = 0;
914     dscn->lpVtbl = &dscnvt;
915     dscn->dscb = dscb;
916     dscb->notify = dscn;
917     IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb);
918
919     *pdscn = dscn;
920     return DS_OK;
921 }
922
923 /*******************************************************************************
924  *              IDirectSoundCaptureBuffer
925  */
926 static HRESULT WINAPI
927 IDirectSoundCaptureBufferImpl_QueryInterface(
928     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
929     REFIID riid,
930     LPVOID* ppobj )
931 {
932     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
933     HRESULT hres;
934     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
935
936     if (ppobj == NULL) {
937         WARN("invalid parameter\n");
938         return E_INVALIDARG;
939     }
940
941     *ppobj = NULL;
942
943     if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ||
944          IsEqualGUID( &IID_IDirectSoundNotify8, riid ) ) {
945         if (!This->notify)
946             hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify);
947         if (This->notify) {
948             if (This->dsound->hwbuf) {
949                 hres = IDsCaptureDriverBuffer_QueryInterface(This->dsound->hwbuf, 
950                     &IID_IDsDriverNotify, (LPVOID*)&(This->hwnotify));
951                 if (hres != DS_OK) {
952                     WARN("IDsCaptureDriverBuffer_QueryInterface failed\n");
953                     *ppobj = 0;
954                     return hres;
955                 }
956             }
957
958             IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
959             *ppobj = (LPVOID)This->notify;
960             return DS_OK;
961         }
962
963         WARN("IID_IDirectSoundNotify\n");
964         return E_FAIL;
965     }
966
967     if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
968          IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
969         IDirectSoundCaptureBuffer8_AddRef(iface);
970         *ppobj = This;
971         return NO_ERROR;
972     }
973
974     FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
975     return E_NOINTERFACE;
976 }
977
978 static ULONG WINAPI
979 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
980 {
981     ULONG uRef;
982     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
983     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
984
985     assert(This->dsound);
986
987     EnterCriticalSection( &(This->dsound->lock) );
988
989     uRef = ++(This->ref);
990
991     LeaveCriticalSection( &(This->dsound->lock) );
992
993     return uRef;
994 }
995
996 static ULONG WINAPI
997 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
998 {
999     ULONG uRef;
1000     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1001     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1002
1003     assert(This->dsound);
1004
1005     EnterCriticalSection( &(This->dsound->lock) );
1006
1007     uRef = --(This->ref);
1008
1009     LeaveCriticalSection( &(This->dsound->lock) );
1010
1011     if ( uRef == 0 ) {
1012         TRACE("deleting object\n");
1013         if (This->pdscbd)
1014             HeapFree(GetProcessHeap(),0, This->pdscbd);
1015
1016         if (This->dsound->hwi) {
1017             waveInReset(This->dsound->hwi);
1018             waveInClose(This->dsound->hwi);
1019             if (This->dsound->pwave) {
1020                 HeapFree(GetProcessHeap(),0, This->dsound->pwave);
1021                 This->dsound->pwave = 0;
1022             }
1023             This->dsound->hwi = 0;
1024         }
1025
1026         if (This->dsound->hwbuf) 
1027             IDsCaptureDriverBuffer_Release(This->dsound->hwbuf);
1028
1029         /* remove from IDirectSoundCaptureImpl */
1030         if (This->dsound)
1031             This->dsound->capture_buffer = NULL;
1032         else
1033             ERR("does not reference dsound\n");
1034
1035         if (This->notify)
1036             IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
1037         
1038         if (This->notifies != NULL)
1039                 HeapFree(GetProcessHeap(), 0, This->notifies);
1040
1041         HeapFree( GetProcessHeap(), 0, This );
1042         TRACE("(%p) released\n",This);
1043     }
1044
1045     return uRef;
1046 }
1047
1048 static HRESULT WINAPI
1049 IDirectSoundCaptureBufferImpl_GetCaps(
1050     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1051     LPDSCBCAPS lpDSCBCaps )
1052 {
1053     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1054     TRACE( "(%p,%p)\n", This, lpDSCBCaps );
1055
1056     if (This == NULL) {
1057         WARN("invalid parameter: This == NULL\n");
1058         return DSERR_INVALIDPARAM;
1059     }
1060
1061     if (lpDSCBCaps == NULL) {
1062         WARN("invalid parameter: lpDSCBCaps == NULL\n");
1063         return DSERR_INVALIDPARAM;
1064     }
1065
1066     if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
1067         WARN("invalid parameter: lpDSCBCaps->dwSize = %ld < %d\n", 
1068             lpDSCBCaps->dwSize, sizeof(DSCBCAPS));
1069         return DSERR_INVALIDPARAM;
1070     }
1071
1072     if (This->dsound == NULL) {
1073         WARN("invalid parameter: This->dsound == NULL\n");
1074         return DSERR_INVALIDPARAM;
1075     }
1076
1077     lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
1078     lpDSCBCaps->dwFlags = This->flags;
1079     lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
1080     lpDSCBCaps->dwReserved = 0;
1081
1082     TRACE("returning DS_OK\n");
1083     return DS_OK;
1084 }
1085
1086 static HRESULT WINAPI
1087 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
1088     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1089     LPDWORD lpdwCapturePosition,
1090     LPDWORD lpdwReadPosition )
1091 {
1092     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1093     TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
1094
1095     if (This == NULL) {
1096         WARN("invalid parameter: This == NULL\n");
1097         return DSERR_INVALIDPARAM;
1098     }
1099
1100     if (This->dsound == NULL) {
1101         WARN("invalid parameter: This->dsound == NULL\n");
1102         return DSERR_INVALIDPARAM;
1103     }
1104
1105     if (This->dsound->driver) {
1106         HRESULT hres;
1107         hres = IDsCaptureDriverBuffer_GetPosition(This->dsound->hwbuf, lpdwCapturePosition, lpdwReadPosition );
1108         if (hres != DS_OK) {
1109             WARN("IDsCaptureDriverBuffer_GetPosition failed\n");
1110             return hres;
1111         }
1112     } else if (This->dsound->hwi) {
1113         EnterCriticalSection(&(This->dsound->lock));
1114         TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1115         if (lpdwCapturePosition) {
1116             MMTIME mtime;
1117             mtime.wType = TIME_BYTES;
1118             waveInGetPosition(This->dsound->hwi, &mtime, sizeof(mtime));
1119             TRACE("mtime.u.cb=%ld,This->dsound->buflen=%ld\n", mtime.u.cb, 
1120                 This->dsound->buflen);
1121             mtime.u.cb = mtime.u.cb % This->dsound->buflen;
1122             *lpdwCapturePosition = mtime.u.cb;
1123         }
1124     
1125         if (lpdwReadPosition) {
1126             if (This->dsound->state == STATE_STARTING) { 
1127                 if (lpdwCapturePosition)
1128                     This->dsound->read_position = *lpdwCapturePosition;
1129                 This->dsound->state = STATE_CAPTURING;
1130             } 
1131             *lpdwReadPosition = This->dsound->read_position;
1132         }
1133         TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1134         LeaveCriticalSection(&(This->dsound->lock));
1135         if (lpdwCapturePosition) TRACE("*lpdwCapturePosition=%ld\n",*lpdwCapturePosition);
1136         if (lpdwReadPosition) TRACE("*lpdwReadPosition=%ld\n",*lpdwReadPosition);
1137     } else {
1138         WARN("no driver\n");
1139         return DSERR_NODRIVER;
1140     }
1141     
1142     TRACE("returning DS_OK\n");
1143     return DS_OK;
1144 }
1145
1146 static HRESULT WINAPI
1147 IDirectSoundCaptureBufferImpl_GetFormat(
1148     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1149     LPWAVEFORMATEX lpwfxFormat,
1150     DWORD dwSizeAllocated,
1151     LPDWORD lpdwSizeWritten )
1152 {
1153     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1154     TRACE( "(%p,%p,0x%08lx,%p)\n", This, lpwfxFormat, dwSizeAllocated, 
1155         lpdwSizeWritten );
1156
1157     if (This == NULL) {
1158         WARN("invalid parameter: This == NULL\n");
1159         return DSERR_INVALIDPARAM;
1160     }
1161
1162     if (This->dsound == NULL) {
1163         WARN("invalid parameter: This->dsound == NULL\n");
1164         return DSERR_INVALIDPARAM;
1165     }
1166
1167     if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize))
1168         dwSizeAllocated = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize;
1169
1170     if (lpwfxFormat) { /* NULL is valid (just want size) */
1171         memcpy(lpwfxFormat, This->dsound->pwfx, dwSizeAllocated);
1172         if (lpdwSizeWritten)
1173             *lpdwSizeWritten = dwSizeAllocated;
1174     } else {
1175         if (lpdwSizeWritten)
1176             *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize;
1177         else {
1178             TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
1179             return DSERR_INVALIDPARAM;
1180         }
1181     }
1182
1183     TRACE("returning DS_OK\n");
1184     return DS_OK;
1185 }
1186
1187 static HRESULT WINAPI
1188 IDirectSoundCaptureBufferImpl_GetStatus(
1189     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1190     LPDWORD lpdwStatus )
1191 {
1192     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1193     TRACE( "(%p, %p), thread is %04lx\n", This, lpdwStatus, GetCurrentThreadId() );
1194
1195     if (This == NULL) {
1196         WARN("invalid parameter: This == NULL\n");
1197         return DSERR_INVALIDPARAM;
1198     }
1199
1200     if (This->dsound == NULL) {
1201         WARN("invalid parameter: This->dsound == NULL\n");
1202         return DSERR_INVALIDPARAM;
1203     }
1204
1205     if (lpdwStatus == NULL) {
1206         WARN("invalid parameter: lpdwStatus == NULL\n");
1207         return DSERR_INVALIDPARAM;
1208     }
1209
1210     *lpdwStatus = 0;
1211     EnterCriticalSection(&(This->dsound->lock));
1212
1213     TRACE("old This->dsound->state=%s, old lpdwStatus=%08lx\n",
1214         captureStateString[This->dsound->state],*lpdwStatus);
1215     if ((This->dsound->state == STATE_STARTING) || 
1216         (This->dsound->state == STATE_CAPTURING)) {
1217         *lpdwStatus |= DSCBSTATUS_CAPTURING;
1218         if (This->flags & DSCBSTART_LOOPING)
1219             *lpdwStatus |= DSCBSTATUS_LOOPING;
1220     }
1221     TRACE("new This->dsound->state=%s, new lpdwStatus=%08lx\n",
1222         captureStateString[This->dsound->state],*lpdwStatus);
1223     LeaveCriticalSection(&(This->dsound->lock));
1224
1225     TRACE("status=%lx\n", *lpdwStatus);
1226     TRACE("returning DS_OK\n");
1227     return DS_OK;
1228 }
1229
1230 static HRESULT WINAPI
1231 IDirectSoundCaptureBufferImpl_Initialize(
1232     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1233     LPDIRECTSOUNDCAPTURE lpDSC,
1234     LPCDSCBUFFERDESC lpcDSCBDesc )
1235 {
1236     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1237
1238     FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
1239
1240     return DS_OK;
1241 }
1242
1243 static HRESULT WINAPI
1244 IDirectSoundCaptureBufferImpl_Lock(
1245     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1246     DWORD dwReadCusor,
1247     DWORD dwReadBytes,
1248     LPVOID* lplpvAudioPtr1,
1249     LPDWORD lpdwAudioBytes1,
1250     LPVOID* lplpvAudioPtr2,
1251     LPDWORD lpdwAudioBytes2,
1252     DWORD dwFlags )
1253 {
1254     HRESULT err = DS_OK;
1255     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1256     TRACE( "(%p,%08lu,%08lu,%p,%p,%p,%p,0x%08lx) at %ld\n", This, dwReadCusor,
1257         dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
1258         lpdwAudioBytes2, dwFlags, GetTickCount() );
1259
1260     if (This == NULL) {
1261         WARN("invalid parameter: This == NULL\n");
1262         return DSERR_INVALIDPARAM;
1263     }
1264
1265     if (This->dsound == NULL) {
1266         WARN("invalid parameter: This->dsound == NULL\n");
1267         return DSERR_INVALIDPARAM;
1268     }
1269
1270     if (lplpvAudioPtr1 == NULL) {
1271         WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
1272         return DSERR_INVALIDPARAM;
1273     }
1274
1275     if (lpdwAudioBytes1 == NULL) {
1276         WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
1277         return DSERR_INVALIDPARAM;
1278     }
1279
1280     EnterCriticalSection(&(This->dsound->lock));
1281
1282     if (This->dsound->driver) {
1283         err = IDsCaptureDriverBuffer_Lock(This->dsound->hwbuf, lplpvAudioPtr1, 
1284                                            lpdwAudioBytes1, lplpvAudioPtr2, lpdwAudioBytes2,
1285                                            dwReadCusor, dwReadBytes, dwFlags);
1286         if (err != DS_OK)
1287             WARN("IDsCaptureDriverBuffer_Lock failed\n");
1288     } else if (This->dsound->hwi) {
1289         *lplpvAudioPtr1 = This->dsound->buffer + dwReadCusor;
1290         if ( (dwReadCusor + dwReadBytes) > This->dsound->buflen) {
1291             *lpdwAudioBytes1 = This->dsound->buflen - dwReadCusor;
1292             if (lplpvAudioPtr2)
1293                 *lplpvAudioPtr2 = This->dsound->buffer;
1294             if (lpdwAudioBytes2)
1295                 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
1296         } else {
1297             *lpdwAudioBytes1 = dwReadBytes;
1298             if (lplpvAudioPtr2)
1299                 *lplpvAudioPtr2 = 0;
1300             if (lpdwAudioBytes2)
1301                 *lpdwAudioBytes2 = 0;
1302         }
1303     } else {
1304         TRACE("invalid call\n");
1305         err = DSERR_INVALIDCALL;   /* DSERR_NODRIVER ? */
1306     }
1307
1308     LeaveCriticalSection(&(This->dsound->lock));
1309
1310     return err;
1311 }
1312
1313 static HRESULT WINAPI
1314 IDirectSoundCaptureBufferImpl_Start(
1315     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1316     DWORD dwFlags )
1317 {
1318     HRESULT err = DS_OK;
1319     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1320     TRACE( "(%p,0x%08lx)\n", This, dwFlags );
1321
1322     if (This == NULL) {
1323         WARN("invalid parameter: This == NULL\n");
1324         return DSERR_INVALIDPARAM;
1325     }
1326
1327     if (This->dsound == NULL) {
1328         WARN("invalid parameter: This->dsound == NULL\n");
1329         return DSERR_INVALIDPARAM;
1330     }
1331
1332     if ( (This->dsound->driver == 0) && (This->dsound->hwi == 0) ) {
1333         WARN("no driver\n");
1334         return DSERR_NODRIVER;
1335     }
1336
1337     EnterCriticalSection(&(This->dsound->lock));
1338
1339     This->flags = dwFlags;
1340     TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1341     if (This->dsound->state == STATE_STOPPED)
1342         This->dsound->state = STATE_STARTING;
1343     else if (This->dsound->state == STATE_STOPPING)
1344         This->dsound->state = STATE_CAPTURING;
1345     TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1346
1347     LeaveCriticalSection(&(This->dsound->lock));
1348
1349     if (This->dsound->driver) {
1350         err = IDsCaptureDriverBuffer_Start(This->dsound->hwbuf, dwFlags);
1351         if (err != DS_OK)
1352             WARN("IDsCaptureDriverBuffer_Start failed\n");
1353         return err;
1354     } else {
1355         IDirectSoundCaptureImpl* ipDSC = This->dsound;
1356
1357         if (ipDSC->buffer) {
1358             if (This->nrofnotifies) {
1359                 unsigned c;
1360
1361                 ipDSC->nrofpwaves = This->nrofnotifies;
1362                 TRACE("nrofnotifies=%d\n", This->nrofnotifies);
1363
1364                 /* prepare headers */
1365                 if (ipDSC->pwave)
1366                     ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave,
1367                         ipDSC->nrofpwaves*sizeof(WAVEHDR));
1368                 else 
1369                     ipDSC->pwave = HeapAlloc(GetProcessHeap(),0,
1370                         ipDSC->nrofpwaves*sizeof(WAVEHDR));
1371
1372                 for (c = 0; c < ipDSC->nrofpwaves; c++) {
1373                     if (This->notifies[c].dwOffset == DSBPN_OFFSETSTOP) {
1374                         TRACE("got DSBPN_OFFSETSTOP\n");
1375                         ipDSC->nrofpwaves = c;
1376                         break;
1377                     }
1378                     if (c == 0) {
1379                         ipDSC->pwave[0].lpData = ipDSC->buffer;
1380                         ipDSC->pwave[0].dwBufferLength = 
1381                             This->notifies[0].dwOffset + 1;
1382                     } else {
1383                         ipDSC->pwave[c].lpData = ipDSC->buffer + 
1384                             This->notifies[c-1].dwOffset + 1;
1385                         ipDSC->pwave[c].dwBufferLength = 
1386                             This->notifies[c].dwOffset - 
1387                             This->notifies[c-1].dwOffset;
1388                     }
1389                     ipDSC->pwave[c].dwBytesRecorded = 0;
1390                     ipDSC->pwave[c].dwUser = (DWORD)ipDSC;
1391                     ipDSC->pwave[c].dwFlags = 0;
1392                     ipDSC->pwave[c].dwLoops = 0;
1393                     err = mmErr(waveInPrepareHeader(ipDSC->hwi,
1394                         &(ipDSC->pwave[c]),sizeof(WAVEHDR)));
1395                     if (err != DS_OK) {
1396                         WARN("waveInPrepareHeader failed\n");
1397                         while (c--)
1398                             waveInUnprepareHeader(ipDSC->hwi,
1399                                 &(ipDSC->pwave[c]),sizeof(WAVEHDR));
1400                         break;
1401                     }
1402
1403                     err = mmErr(waveInAddBuffer(ipDSC->hwi, 
1404                         &(ipDSC->pwave[c]), sizeof(WAVEHDR)));
1405                     if (err != DS_OK) {
1406                         WARN("waveInAddBuffer failed\n");
1407                         while (c--)
1408                             waveInUnprepareHeader(ipDSC->hwi,
1409                                 &(ipDSC->pwave[c]),sizeof(WAVEHDR));
1410                         break;
1411                     }
1412                 }
1413
1414                 memset(ipDSC->buffer, 
1415                     (ipDSC->pwfx->wBitsPerSample == 8) ? 128 : 0, ipDSC->buflen);
1416             } else {
1417                 TRACE("no notifiers specified\n");
1418                 /* no notifiers specified so just create a single default header */
1419                 ipDSC->nrofpwaves = 1;
1420                 if (ipDSC->pwave)
1421                     ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave,sizeof(WAVEHDR));
1422                 else
1423                     ipDSC->pwave = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEHDR));
1424
1425                 ipDSC->pwave[0].lpData = ipDSC->buffer;
1426                 ipDSC->pwave[0].dwBufferLength = ipDSC->buflen; 
1427                 ipDSC->pwave[0].dwBytesRecorded = 0;
1428                 ipDSC->pwave[0].dwUser = (DWORD)ipDSC;
1429                 ipDSC->pwave[0].dwFlags = 0;
1430                 ipDSC->pwave[0].dwLoops = 0;
1431
1432                 err = mmErr(waveInPrepareHeader(ipDSC->hwi,
1433                     &(ipDSC->pwave[0]),sizeof(WAVEHDR)));
1434                 if (err != DS_OK) {
1435                     WARN("waveInPrepareHeader failed\n");
1436                     waveInUnprepareHeader(ipDSC->hwi,
1437                         &(ipDSC->pwave[0]),sizeof(WAVEHDR));
1438                 }
1439                 err = mmErr(waveInAddBuffer(ipDSC->hwi, 
1440                     &(ipDSC->pwave[0]), sizeof(WAVEHDR)));
1441                 if (err != DS_OK) {
1442                     WARN("waveInAddBuffer failed\n");
1443                     waveInUnprepareHeader(ipDSC->hwi,
1444                         &(ipDSC->pwave[0]),sizeof(WAVEHDR));
1445                 }
1446             }
1447         }
1448
1449         ipDSC->index = 0;
1450         ipDSC->read_position = 0;
1451
1452         if (err == DS_OK) {
1453             /* start filling the first buffer */
1454             err = mmErr(waveInStart(ipDSC->hwi));
1455             if (err != DS_OK)
1456                 WARN("waveInStart failed\n");
1457         }
1458     }
1459
1460     if (err != DS_OK) {
1461         WARN("calling waveInClose because of error\n");
1462         waveInClose(This->dsound->hwi);
1463         This->dsound->hwi = 0;
1464     }
1465
1466     TRACE("returning %ld\n", err);
1467     return err;
1468 }
1469
1470 static HRESULT WINAPI
1471 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
1472 {
1473     HRESULT err = DS_OK;
1474     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1475     TRACE( "(%p)\n", This );
1476
1477     if (This == NULL) {
1478         WARN("invalid parameter: This == NULL\n");
1479         return DSERR_INVALIDPARAM;
1480     }
1481
1482     if (This->dsound == NULL) {
1483         WARN("invalid parameter: This->dsound == NULL\n");
1484         return DSERR_INVALIDPARAM;
1485     }
1486
1487     EnterCriticalSection(&(This->dsound->lock));
1488
1489     TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1490     if (This->dsound->state == STATE_CAPTURING)
1491         This->dsound->state = STATE_STOPPING;
1492     else if (This->dsound->state == STATE_STARTING)
1493         This->dsound->state = STATE_STOPPED;
1494     TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1495
1496     LeaveCriticalSection(&(This->dsound->lock));
1497
1498     if (This->dsound->driver) {
1499         err = IDsCaptureDriverBuffer_Stop(This->dsound->hwbuf);
1500         if (err == DSERR_BUFFERLOST) {
1501             /* Wine-only: the driver wants us to reopen the device */
1502             IDsCaptureDriverBuffer_Release(This->dsound->hwbuf);
1503             err = IDsCaptureDriver_CreateCaptureBuffer(This->dsound->driver,
1504                 This->dsound->pwfx,0,0,&(This->dsound->buflen),&(This->dsound->buffer),
1505                 (LPVOID*)&(This->dsound->hwbuf));
1506             if (err != DS_OK) {
1507                 WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n");
1508                 This->dsound->hwbuf = 0;
1509             }
1510         } else if (err != DS_OK) 
1511             WARN("IDsCaptureDriverBuffer_Stop failed\n");
1512     } else if (This->dsound->hwi) {
1513         err = waveInStop(This->dsound->hwi);
1514     } else {
1515         WARN("no driver\n");
1516         err = DSERR_NODRIVER;
1517     }
1518
1519     TRACE( "(%p) returning 0x%08lx\n", This,err);
1520     return err;
1521 }
1522
1523 static HRESULT WINAPI
1524 IDirectSoundCaptureBufferImpl_Unlock(
1525     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1526     LPVOID lpvAudioPtr1,
1527     DWORD dwAudioBytes1,
1528     LPVOID lpvAudioPtr2,
1529     DWORD dwAudioBytes2 )
1530 {
1531     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1532     TRACE( "(%p,%p,%08lu,%p,%08lu)\n", This, lpvAudioPtr1, dwAudioBytes1, 
1533         lpvAudioPtr2, dwAudioBytes2 );
1534
1535     if (This == NULL) {
1536         WARN("invalid parameter: This == NULL\n");
1537         return DSERR_INVALIDPARAM;
1538     }
1539
1540     if (lpvAudioPtr1 == NULL) {
1541         WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
1542         return DSERR_INVALIDPARAM;
1543     }
1544
1545     if (This->dsound->driver) {
1546         HRESULT hres;
1547         hres = IDsCaptureDriverBuffer_Unlock(This->dsound->hwbuf, lpvAudioPtr1, 
1548                                            dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1549         if (hres != DS_OK)
1550             WARN("IDsCaptureDriverBuffer_Unlock failed\n");
1551         return hres;
1552     } else if (This->dsound->hwi) {
1553         This->dsound->read_position = (This->dsound->read_position + 
1554             (dwAudioBytes1 + dwAudioBytes2)) % This->dsound->buflen;
1555     } else {
1556         WARN("invalid call\n");
1557         return DSERR_INVALIDCALL;
1558     }
1559
1560     return DS_OK;
1561 }
1562
1563 static HRESULT WINAPI
1564 IDirectSoundCaptureBufferImpl_GetObjectInPath(
1565     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1566     REFGUID rguidObject,
1567     DWORD dwIndex,
1568     REFGUID rguidInterface,
1569     LPVOID* ppObject )
1570 {
1571     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1572
1573     FIXME( "(%p,%s,%lu,%s,%p): stub\n", This, debugstr_guid(rguidObject), 
1574         dwIndex, debugstr_guid(rguidInterface), ppObject );
1575
1576     return DS_OK;
1577 }
1578
1579 static HRESULT WINAPI
1580 IDirectSoundCaptureBufferImpl_GetFXStatus(
1581     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1582     DWORD dwFXCount,
1583     LPDWORD pdwFXStatus )
1584 {
1585     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1586
1587     FIXME( "(%p,%lu,%p): stub\n", This, dwFXCount, pdwFXStatus );
1588
1589     return DS_OK;
1590 }
1591
1592 static ICOM_VTABLE(IDirectSoundCaptureBuffer8) dscbvt =
1593 {
1594     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1595     /* IUnknown methods */
1596     IDirectSoundCaptureBufferImpl_QueryInterface,
1597     IDirectSoundCaptureBufferImpl_AddRef,
1598     IDirectSoundCaptureBufferImpl_Release,
1599
1600     /* IDirectSoundCaptureBuffer methods */
1601     IDirectSoundCaptureBufferImpl_GetCaps,
1602     IDirectSoundCaptureBufferImpl_GetCurrentPosition,
1603     IDirectSoundCaptureBufferImpl_GetFormat,
1604     IDirectSoundCaptureBufferImpl_GetStatus,
1605     IDirectSoundCaptureBufferImpl_Initialize,
1606     IDirectSoundCaptureBufferImpl_Lock,
1607     IDirectSoundCaptureBufferImpl_Start,
1608     IDirectSoundCaptureBufferImpl_Stop,
1609     IDirectSoundCaptureBufferImpl_Unlock,
1610
1611     /* IDirectSoundCaptureBuffer methods */
1612     IDirectSoundCaptureBufferImpl_GetObjectInPath,
1613     IDirectSoundCaptureBufferImpl_GetFXStatus
1614 };
1615
1616 /*******************************************************************************
1617  * DirectSoundCapture ClassFactory
1618  */
1619
1620 static HRESULT WINAPI
1621 DSCCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) 
1622 {
1623     ICOM_THIS(IClassFactoryImpl,iface);
1624
1625     FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1626     return E_NOINTERFACE;
1627 }
1628
1629 static ULONG WINAPI
1630 DSCCF_AddRef(LPCLASSFACTORY iface)
1631 {
1632     ICOM_THIS(IClassFactoryImpl,iface);
1633     TRACE("(%p) ref was %ld\n", This, This->ref);
1634     return ++(This->ref);
1635 }
1636
1637 static ULONG WINAPI 
1638 DSCCF_Release(LPCLASSFACTORY iface)
1639 {
1640     ICOM_THIS(IClassFactoryImpl,iface);
1641     /* static class, won't be  freed */
1642     TRACE("(%p) ref was %ld\n", This, This->ref);
1643     return --(This->ref);
1644 }
1645
1646 static HRESULT WINAPI 
1647 DSCCF_CreateInstance(
1648         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj )
1649 {
1650     ICOM_THIS(IClassFactoryImpl,iface);
1651     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1652
1653     if (ppobj == NULL) {
1654         WARN("invalid parameter\n");
1655         return E_INVALIDARG;
1656     }
1657
1658     *ppobj = NULL;
1659
1660     if ( IsEqualGUID( &IID_IDirectSoundCapture, riid ) ||
1661          IsEqualGUID( &IID_IDirectSoundCapture8, riid ) ) {
1662         return DirectSoundCaptureCreate8(0,(LPDIRECTSOUNDCAPTURE8*)ppobj,pOuter);
1663     }
1664
1665     WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); 
1666     return E_NOINTERFACE;
1667 }
1668
1669 static HRESULT WINAPI 
1670 DSCCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
1671 {
1672     ICOM_THIS(IClassFactoryImpl,iface);
1673     FIXME("(%p)->(%d),stub!\n",This,dolock);
1674     return S_OK;
1675 }
1676
1677 static ICOM_VTABLE(IClassFactory) DSCCF_Vtbl =
1678 {
1679     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1680     DSCCF_QueryInterface,
1681     DSCCF_AddRef,
1682     DSCCF_Release,
1683     DSCCF_CreateInstance,
1684     DSCCF_LockServer
1685 };
1686
1687 IClassFactoryImpl DSOUND_CAPTURE_CF = { &DSCCF_Vtbl, 1 };
1688
1689 /***************************************************************************
1690  * DirectSoundFullDuplexCreate8 [DSOUND.10]
1691  *
1692  * Create and initialize a DirectSoundFullDuplex interface.
1693  *
1694  * PARAMS
1695  *    pcGuidCaptureDevice [I] Address of sound capture device GUID. 
1696  *    pcGuidRenderDevice  [I] Address of sound render device GUID.
1697  *    pcDSCBufferDesc     [I] Address of capture buffer description.
1698  *    pcDSBufferDesc      [I] Address of  render buffer description.
1699  *    hWnd                [I] Handle to application window.
1700  *    dwLevel             [I] Cooperative level.
1701  *    ppDSFD              [O] Address where full duplex interface returned.
1702  *    ppDSCBuffer8        [0] Address where capture buffer interface returned.
1703  *    ppDSBuffer8         [0] Address where render buffer interface returned.
1704  *    pUnkOuter           [I] Must be NULL.
1705  *
1706  * RETURNS
1707  *    Success: DS_OK
1708  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1709  *             DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
1710  */
1711 HRESULT WINAPI 
1712 DirectSoundFullDuplexCreate8(
1713     LPCGUID pcGuidCaptureDevice,
1714     LPCGUID pcGuidRenderDevice,
1715     LPCDSCBUFFERDESC pcDSCBufferDesc,
1716     LPCDSBUFFERDESC pcDSBufferDesc,
1717     HWND hWnd,
1718     DWORD dwLevel,
1719     LPDIRECTSOUNDFULLDUPLEX *ppDSFD,
1720     LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8,
1721     LPDIRECTSOUNDBUFFER8 *ppDSBuffer8,
1722     LPUNKNOWN pUnkOuter)
1723 {
1724     IDirectSoundFullDuplexImpl** ippDSFD=(IDirectSoundFullDuplexImpl**)ppDSFD;
1725     TRACE("(%s,%s,%p,%p,%lx,%lx,%p,%p,%p,%p)\n", debugstr_guid(pcGuidCaptureDevice), 
1726         debugstr_guid(pcGuidRenderDevice), pcDSCBufferDesc, pcDSBufferDesc,
1727         (DWORD)hWnd, dwLevel, ppDSFD, ppDSCBuffer8, ppDSBuffer8, pUnkOuter);
1728
1729     if ( pUnkOuter ) {
1730         WARN("pUnkOuter != 0\n");
1731         return DSERR_NOAGGREGATION;
1732     }
1733
1734     *ippDSFD = (IDirectSoundFullDuplexImpl*)HeapAlloc(GetProcessHeap(),
1735         HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl));
1736
1737     if (*ippDSFD == NULL) {
1738         WARN("out of memory\n");
1739         return DSERR_OUTOFMEMORY;
1740     } else {
1741         HRESULT hres;
1742         ICOM_THIS(IDirectSoundFullDuplexImpl, *ippDSFD);
1743
1744         This->ref = 1;
1745         This->lpVtbl = &dsfdvt;
1746
1747         InitializeCriticalSection( &(This->lock) );
1748
1749         hres = IDirectSoundFullDuplexImpl_Initialize( (LPDIRECTSOUNDFULLDUPLEX)This,
1750                                                       pcGuidCaptureDevice, pcGuidRenderDevice,
1751                                                       pcDSCBufferDesc, pcDSBufferDesc,
1752                                                       hWnd, dwLevel, ppDSCBuffer8, ppDSBuffer8);
1753         if (hres != DS_OK)
1754             WARN("IDirectSoundFullDuplexImpl_Initialize failed\n");
1755         return hres;
1756     }
1757
1758     return DSERR_GENERIC;
1759 }
1760
1761 static HRESULT WINAPI
1762 IDirectSoundFullDuplexImpl_QueryInterface(
1763     LPDIRECTSOUNDFULLDUPLEX iface,
1764     REFIID riid,
1765     LPVOID* ppobj )
1766 {
1767     ICOM_THIS(IDirectSoundFullDuplexImpl,iface);
1768     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
1769
1770     if (ppobj == NULL) {
1771         WARN("invalid parameter\n");
1772         return E_INVALIDARG;
1773     }
1774
1775     *ppobj = NULL;
1776     return E_NOINTERFACE;
1777 }
1778
1779 static ULONG WINAPI
1780 IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface )
1781 {
1782     ULONG uRef;
1783     ICOM_THIS(IDirectSoundFullDuplexImpl,iface);
1784     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1785
1786     EnterCriticalSection( &(This->lock) );
1787
1788     uRef = ++(This->ref);
1789
1790     LeaveCriticalSection( &(This->lock) );
1791
1792     return uRef;
1793 }
1794
1795 static ULONG WINAPI
1796 IDirectSoundFullDuplexImpl_Release( LPDIRECTSOUNDFULLDUPLEX iface )
1797 {
1798     ULONG uRef;
1799     ICOM_THIS(IDirectSoundFullDuplexImpl,iface);
1800     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1801
1802     EnterCriticalSection( &(This->lock) );
1803
1804     uRef = --(This->ref);
1805
1806     LeaveCriticalSection( &(This->lock) );
1807
1808     if ( uRef == 0 ) {
1809         DeleteCriticalSection( &(This->lock) );
1810         HeapFree( GetProcessHeap(), 0, This );
1811         TRACE("(%p) released\n",This);
1812     }
1813
1814     return uRef;
1815 }
1816
1817 static HRESULT WINAPI
1818 IDirectSoundFullDuplexImpl_Initialize(
1819     LPDIRECTSOUNDFULLDUPLEX iface,
1820     LPCGUID pCaptureGuid,
1821     LPCGUID pRendererGuid,
1822     LPCDSCBUFFERDESC lpDscBufferDesc,
1823     LPCDSBUFFERDESC lpDsBufferDesc,
1824     HWND hWnd,
1825     DWORD dwLevel,
1826     LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8,
1827     LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 )
1828 {
1829     ICOM_THIS(IDirectSoundFullDuplexImpl,iface);
1830     IDirectSoundCaptureBufferImpl** ippdscb=(IDirectSoundCaptureBufferImpl**)lplpDirectSoundCaptureBuffer8;
1831     IDirectSoundBufferImpl** ippdsc=(IDirectSoundBufferImpl**)lplpDirectSoundBuffer8;
1832
1833     FIXME( "(%p,%s,%s,%p,%p,%lx,%lx,%p,%p) stub!\n", This, debugstr_guid(pCaptureGuid), 
1834         debugstr_guid(pRendererGuid), lpDscBufferDesc, lpDsBufferDesc, (DWORD)hWnd, dwLevel,
1835         ippdscb, ippdsc);
1836
1837     return E_FAIL;
1838 }
1839
1840 static ICOM_VTABLE(IDirectSoundFullDuplex) dsfdvt =
1841 {
1842     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1843     /* IUnknown methods */
1844     IDirectSoundFullDuplexImpl_QueryInterface,
1845     IDirectSoundFullDuplexImpl_AddRef,
1846     IDirectSoundFullDuplexImpl_Release,
1847
1848     /* IDirectSoundFullDuplex methods */
1849     IDirectSoundFullDuplexImpl_Initialize
1850 };
1851
1852 /*******************************************************************************
1853  * DirectSoundFullDuplex ClassFactory
1854  */
1855
1856 static HRESULT WINAPI
1857 DSFDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
1858 {
1859     ICOM_THIS(IClassFactoryImpl,iface);
1860
1861     FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1862     return E_NOINTERFACE;
1863 }
1864
1865 static ULONG WINAPI
1866 DSFDCF_AddRef(LPCLASSFACTORY iface)
1867 {
1868     ICOM_THIS(IClassFactoryImpl,iface);
1869     TRACE("(%p) ref was %ld\n", This, This->ref);
1870     return ++(This->ref);
1871 }
1872
1873 static ULONG WINAPI 
1874 DSFDCF_Release(LPCLASSFACTORY iface) 
1875 {
1876     ICOM_THIS(IClassFactoryImpl,iface);
1877     /* static class, won't be  freed */
1878     TRACE("(%p) ref was %ld\n", This, This->ref);
1879     return --(This->ref);
1880 }
1881
1882 static HRESULT WINAPI 
1883 DSFDCF_CreateInstance(
1884     LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj )
1885 {
1886     ICOM_THIS(IClassFactoryImpl,iface);
1887
1888     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1889
1890     if (ppobj == NULL) {
1891         WARN("invalid parameter\n");
1892         return E_INVALIDARG;
1893     }
1894
1895     *ppobj = NULL;
1896
1897     if ( IsEqualGUID( &IID_IDirectSoundFullDuplex, riid ) ) {
1898         /* FIXME: how do we do this one ? */
1899         FIXME("not implemented\n");
1900         return E_NOINTERFACE;
1901     }
1902
1903     WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); 
1904     return E_NOINTERFACE;
1905 }
1906
1907 static HRESULT WINAPI 
1908 DSFDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
1909 {
1910     ICOM_THIS(IClassFactoryImpl,iface);
1911     FIXME("(%p)->(%d),stub!\n",This,dolock);
1912     return S_OK;
1913 }
1914
1915 static ICOM_VTABLE(IClassFactory) DSFDCF_Vtbl =
1916 {
1917     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1918     DSFDCF_QueryInterface,
1919     DSFDCF_AddRef,
1920     DSFDCF_Release,
1921     DSFDCF_CreateInstance,
1922     DSFDCF_LockServer
1923 };
1924
1925 IClassFactoryImpl DSOUND_FULLDUPLEX_CF = { &DSFDCF_Vtbl, 1 };