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