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