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