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