Added fields from NetBSD struct sigcontext on i386.
[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         ICOM_VTBL(This) = &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         This->drvdesc.dnDevNode = wid; /* FIXME? */
521     }
522     
523     /* open the DirectSound driver if available */
524     if (This->driver && (err == DS_OK))
525         err = IDsCaptureDriver_Open(This->driver);
526
527     if (err == DS_OK) {
528         This->initialized = TRUE;
529
530         /* the driver is now open, so it's now allowed to call GetCaps */
531         if (This->driver) {
532             This->drvcaps.dwSize = sizeof(This->drvcaps);
533             err = IDsCaptureDriver_GetCaps(This->driver,&(This->drvcaps));
534             if (err != DS_OK) {
535                 WARN("IDsCaptureDriver_GetCaps failed\n");
536                 return err;
537             }
538         } else /*if (This->hwi)*/ {
539             WAVEINCAPSA    wic;
540             err = mmErr(waveInGetDevCapsA((UINT)This->drvdesc.dnDevNode, &wic, sizeof(wic)));
541
542             if (err == DS_OK) {
543                 This->drvcaps.dwFlags = 0;
544                 strncpy(This->drvdesc.szDrvName, wic.szPname, 
545                     sizeof(This->drvdesc.szDrvName)); 
546
547                 This->drvcaps.dwFlags |= DSCCAPS_EMULDRIVER;
548                 This->drvcaps.dwFormats = wic.dwFormats;
549                 This->drvcaps.dwChannels = wic.wChannels;
550             }
551         }
552     }
553
554     return err;
555 }
556
557 static ICOM_VTABLE(IDirectSoundCapture) dscvt =
558 {
559     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
560     /* IUnknown methods */
561     IDirectSoundCaptureImpl_QueryInterface,
562     IDirectSoundCaptureImpl_AddRef,
563     IDirectSoundCaptureImpl_Release,
564
565     /* IDirectSoundCapture methods */
566     IDirectSoundCaptureImpl_CreateCaptureBuffer,
567     IDirectSoundCaptureImpl_GetCaps,
568     IDirectSoundCaptureImpl_Initialize
569 };
570
571 static HRESULT
572 DSOUND_CreateDirectSoundCaptureBuffer(
573     IDirectSoundCaptureImpl *ipDSC, 
574     LPCDSCBUFFERDESC lpcDSCBufferDesc, 
575     LPVOID* ppobj )
576 {
577     LPWAVEFORMATEX  wfex;
578     TRACE( "(%p,%p)\n", lpcDSCBufferDesc, ppobj );
579
580     if ( (ipDSC == NULL) || (lpcDSCBufferDesc == NULL) || (ppobj == NULL) ) {
581         WARN("invalid parameters\n");
582         return DSERR_INVALIDPARAM;
583     }
584
585     if ( (lpcDSCBufferDesc->dwSize < sizeof(DSCBUFFERDESC)) || 
586         (lpcDSCBufferDesc->dwBufferBytes == 0) ||
587         (lpcDSCBufferDesc->lpwfxFormat == NULL) ) {
588         WARN("invalid lpcDSCBufferDesc\n");
589         return DSERR_INVALIDPARAM;
590     }
591
592     if ( !ipDSC->initialized ) {
593         WARN("not initialized\n");
594         return DSERR_UNINITIALIZED;
595     }
596
597     wfex = lpcDSCBufferDesc->lpwfxFormat;
598
599     if (wfex) {
600         TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
601             "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
602             wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
603             wfex->nAvgBytesPerSec, wfex->nBlockAlign,
604             wfex->wBitsPerSample, wfex->cbSize);
605
606         if (wfex->cbSize == 0)
607             memcpy(&(ipDSC->wfx), wfex, sizeof(*wfex) + wfex->cbSize);
608         else {
609             WARN("non PCM formats not supported\n");
610             return DSERR_BADFORMAT; /* FIXME: DSERR_INVALIDPARAM ? */
611         }
612     } else {
613         WARN("lpcDSCBufferDesc->lpwfxFormat == 0\n");
614         return DSERR_INVALIDPARAM; /* FIXME: DSERR_BADFORMAT ? */
615     }
616
617     *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
618         sizeof(IDirectSoundCaptureBufferImpl));
619
620     if ( *ppobj == NULL ) {
621         WARN("out of memory\n");
622         return DSERR_OUTOFMEMORY;
623     } else {
624         HRESULT err = DS_OK;
625         ICOM_THIS(IDirectSoundCaptureBufferImpl,*ppobj);
626
627         This->ref = 1;
628         This->dsound = ipDSC;
629         This->dsound->capture_buffer = This;
630
631         This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
632             lpcDSCBufferDesc->dwSize);
633         if (This->pdscbd)     
634             memcpy(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
635         else {
636             WARN("no memory\n");
637             This->dsound->capture_buffer = 0;
638             HeapFree( GetProcessHeap(), 0, This );
639             *ppobj = NULL;
640             return DSERR_OUTOFMEMORY; 
641         }
642
643         ICOM_VTBL(This) = &dscbvt;
644
645         if (ipDSC->driver) {
646             err = IDsCaptureDriver_CreateCaptureBuffer(ipDSC->driver, 
647                 &(ipDSC->wfx),0,0,&(ipDSC->buflen),&(ipDSC->buffer),(LPVOID*)&(ipDSC->hwbuf));
648             if (err != DS_OK) {
649                 WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n");
650                 ipDSC->hwbuf = 0;
651                 return DSERR_GENERIC;
652             }
653         } else {
654             LPBYTE newbuf;
655             DWORD buflen;
656             DWORD flags = CALLBACK_FUNCTION;
657             if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
658                 flags |= WAVE_DIRECTSOUND;
659             err = mmErr(waveInOpen(&(ipDSC->hwi),
660                 ipDSC->drvdesc.dnDevNode, &(ipDSC->wfx),
661                 (DWORD)DSOUND_capture_callback, (DWORD)ipDSC, flags));
662             if (err != DS_OK) {
663                 WARN("waveInOpen failed\n");
664                 ipDSC->hwi = 0;
665                 return DSERR_BADFORMAT; /* FIXME: DSERR_INVALIDPARAM ? */
666             }
667
668             buflen = lpcDSCBufferDesc->dwBufferBytes;
669             TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->buffer);
670             newbuf = (LPBYTE)HeapReAlloc(GetProcessHeap(),0,ipDSC->buffer,buflen);
671
672             if (newbuf == NULL) {
673                 WARN("failed to allocate capture buffer\n");
674                 err = DSERR_OUTOFMEMORY;
675                 /* but the old buffer might still exist and must be re-prepared */
676             } else {
677                 ipDSC->buffer = newbuf;
678                 ipDSC->buflen = buflen;
679             }
680         }
681     }
682
683     TRACE("returning DS_OK\n");
684     return DS_OK;
685 }
686
687 static HRESULT WINAPI
688 IDirectSoundCaptureBufferImpl_QueryInterface(
689     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
690     REFIID riid,
691     LPVOID* ppobj )
692 {
693     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
694     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
695
696     if (IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
697         IDirectSoundNotifyImpl  *dsn;
698
699         dsn = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(),0,
700             sizeof(*dsn));
701         dsn->ref = 1;
702         dsn->dsb = 0;
703         dsn->dscb = This;
704         /* FIXME: get this right someday */
705         IDirectSoundCaptureBuffer8_AddRef(iface);
706         ICOM_VTBL(dsn) = &dsnvt;
707         *ppobj = (LPVOID)dsn;
708         return DS_OK;
709     }
710
711     if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
712         IDirectSoundCaptureBuffer8_AddRef(iface);
713         *ppobj = This;
714         return NO_ERROR;
715     }
716
717     FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
718
719     return E_FAIL;
720 }
721
722 static ULONG WINAPI
723 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
724 {
725     ULONG uRef;
726     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
727     TRACE( "(%p)\n", This );
728
729     assert(This->dsound);
730
731     EnterCriticalSection( &(This->dsound->lock) );
732
733     TRACE( "(%p) was 0x%08lx\n", This, This->ref );
734     uRef = ++(This->ref);
735
736     LeaveCriticalSection( &(This->dsound->lock) );
737
738     return uRef;
739 }
740
741 static ULONG WINAPI
742 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
743 {
744     ULONG uRef;
745     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
746     TRACE( "(%p)\n", This );
747
748     assert(This->dsound);
749
750     EnterCriticalSection( &(This->dsound->lock) );
751
752     TRACE( "(%p) was 0x%08lx\n", This, This->ref );
753     uRef = --(This->ref);
754
755     LeaveCriticalSection( &(This->dsound->lock) );
756
757     if ( uRef == 0 ) {
758         TRACE("deleting object\n");
759         if (This->pdscbd)
760             HeapFree(GetProcessHeap(),0, This->pdscbd);
761
762         if (This->dsound->hwi) {
763             waveInReset(This->dsound->hwi);
764             waveInClose(This->dsound->hwi);
765             if (This->dsound->pwave) {
766                 HeapFree(GetProcessHeap(),0, This->dsound->pwave);
767                 This->dsound->pwave = 0;
768             }
769             This->dsound->hwi = 0;
770         }
771
772         if (This->dsound->hwbuf) 
773             IDsCaptureDriverBuffer_Release(This->dsound->hwbuf);
774
775         /* remove from IDirectSoundCaptureImpl */
776         if (This->dsound)
777             This->dsound->capture_buffer = NULL;
778         else
779             ERR("does not reference dsound\n");
780
781         if (This->notifies)
782             HeapFree(GetProcessHeap(),0, This->notifies);
783         
784         HeapFree( GetProcessHeap(), 0, This );
785     }
786
787     TRACE( "returning 0x%08lx\n", uRef );
788     return uRef;
789 }
790
791 static HRESULT WINAPI
792 IDirectSoundCaptureBufferImpl_GetCaps(
793     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
794     LPDSCBCAPS lpDSCBCaps )
795 {
796     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
797     TRACE( "(%p,%p)\n", This, lpDSCBCaps );
798
799     if ( (This == NULL) || (lpDSCBCaps == NULL) ) {
800         WARN("invalid parameters\n");
801         return DSERR_INVALIDPARAM;
802     }
803
804     if ( (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) || (This->dsound == NULL) ) {
805         WARN("invalid parameters\n");
806         return DSERR_INVALIDPARAM;
807     }
808
809     lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
810     lpDSCBCaps->dwFlags = This->flags;
811     lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
812     lpDSCBCaps->dwReserved = 0;
813
814     TRACE("returning DS_OK\n");
815     return DS_OK;
816 }
817
818 static HRESULT WINAPI
819 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
820     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
821     LPDWORD lpdwCapturePosition,
822     LPDWORD lpdwReadPosition )
823 {
824     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
825     TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
826
827     if ( (This == NULL) || (This->dsound == NULL) ) {
828         WARN("invalid parameter\n");
829         return DSERR_INVALIDPARAM;
830     }
831
832     if (This->dsound->driver) {
833         return IDsCaptureDriverBuffer_GetPosition(This->dsound->hwbuf, lpdwCapturePosition, lpdwReadPosition );
834     } else if (This->dsound->hwi) {
835         EnterCriticalSection(&(This->dsound->lock));
836         TRACE("old This->dsound->state=%ld\n",This->dsound->state);
837         if (lpdwCapturePosition) {
838             MMTIME mtime;
839             mtime.wType = TIME_BYTES;
840             waveInGetPosition(This->dsound->hwi, &mtime, sizeof(mtime));
841             TRACE("mtime.u.cb=%ld,This->dsound->buflen=%ld\n", mtime.u.cb, 
842                 This->dsound->buflen);
843             mtime.u.cb = mtime.u.cb % This->dsound->buflen;
844             *lpdwCapturePosition = mtime.u.cb;
845         }
846     
847         if (lpdwReadPosition) {
848             if (This->dsound->state == STATE_STARTING) { 
849                 if (lpdwCapturePosition)
850                     This->dsound->read_position = *lpdwCapturePosition;
851                 This->dsound->state = STATE_CAPTURING;
852             } 
853             *lpdwReadPosition = This->dsound->read_position;
854         }
855         TRACE("new This->dsound->state=%ld\n",This->dsound->state);
856         LeaveCriticalSection(&(This->dsound->lock));
857         if (lpdwCapturePosition) TRACE("*lpdwCapturePosition=%ld\n",*lpdwCapturePosition);
858         if (lpdwReadPosition) TRACE("*lpdwReadPosition=%ld\n",*lpdwReadPosition);
859     } else {
860         WARN("no driver\n");
861         return DSERR_NODRIVER;
862     }
863     
864     TRACE("returning DS_OK\n");
865     return DS_OK;
866 }
867
868 static HRESULT WINAPI
869 IDirectSoundCaptureBufferImpl_GetFormat(
870     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
871     LPWAVEFORMATEX lpwfxFormat,
872     DWORD dwSizeAllocated,
873     LPDWORD lpdwSizeWritten )
874 {
875     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
876     TRACE( "(%p,%p,0x%08lx,%p)\n", This, lpwfxFormat, dwSizeAllocated, 
877         lpdwSizeWritten );
878
879     if ( (This == NULL) || (This->dsound == NULL) ) {
880         WARN("invalid parameter\n");
881         return DSERR_INVALIDPARAM;
882     }
883
884     /* FIXME: use real size for extended formats someday */
885     if (dwSizeAllocated > sizeof(This->dsound->wfx))
886         dwSizeAllocated = sizeof(This->dsound->wfx);
887     if (lpwfxFormat) { /* NULL is valid (just want size) */
888         memcpy(lpwfxFormat,&(This->dsound->wfx),dwSizeAllocated);
889         if (lpdwSizeWritten)
890             *lpdwSizeWritten = dwSizeAllocated;
891     } else {
892         if (lpdwSizeWritten)
893             *lpdwSizeWritten = sizeof(This->dsound->wfx);
894         else {
895             TRACE("invalid parameter\n");
896             return DSERR_INVALIDPARAM;
897         }
898     }
899
900     TRACE("returning DS_OK\n");
901     return DS_OK;
902 }
903
904 static HRESULT WINAPI
905 IDirectSoundCaptureBufferImpl_GetStatus(
906     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
907     LPDWORD lpdwStatus )
908 {
909     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
910     TRACE( "(%p, %p), thread is %04lx\n", This, lpdwStatus, GetCurrentThreadId() );
911
912     if ( (This == NULL ) || (This->dsound == NULL) || (lpdwStatus == NULL) ) {
913         WARN("invalid parameter\n");
914         return DSERR_INVALIDPARAM;
915     }
916
917     *lpdwStatus = 0;
918     EnterCriticalSection(&(This->dsound->lock));
919
920     TRACE("old This->dsound->state=%ld, old lpdwStatus=%08lx\n",This->dsound->state,*lpdwStatus);
921     if ((This->dsound->state == STATE_STARTING) || 
922         (This->dsound->state == STATE_CAPTURING)) {
923         *lpdwStatus |= DSCBSTATUS_CAPTURING;
924         if (This->flags & DSCBSTART_LOOPING)
925             *lpdwStatus |= DSCBSTATUS_LOOPING;
926     }
927     TRACE("new This->dsound->state=%ld, new lpdwStatus=%08lx\n",This->dsound->state,*lpdwStatus);
928     LeaveCriticalSection(&(This->dsound->lock));
929
930     TRACE("status=%lx\n", *lpdwStatus);
931     TRACE("returning DS_OK\n");
932     return DS_OK;
933 }
934
935 static HRESULT WINAPI
936 IDirectSoundCaptureBufferImpl_Initialize(
937     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
938     LPDIRECTSOUNDCAPTURE lpDSC,
939     LPCDSCBUFFERDESC lpcDSCBDesc )
940 {
941     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
942
943     FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
944
945     return DS_OK;
946 }
947
948 static HRESULT WINAPI
949 IDirectSoundCaptureBufferImpl_Lock(
950     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
951     DWORD dwReadCusor,
952     DWORD dwReadBytes,
953     LPVOID* lplpvAudioPtr1,
954     LPDWORD lpdwAudioBytes1,
955     LPVOID* lplpvAudioPtr2,
956     LPDWORD lpdwAudioBytes2,
957     DWORD dwFlags )
958 {
959     HRESULT err = DS_OK;
960     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
961     TRACE( "(%p,%08lu,%08lu,%p,%p,%p,%p,0x%08lx) at %ld\n", This, dwReadCusor,
962         dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
963         lpdwAudioBytes2, dwFlags, GetTickCount() );
964
965     if ( (This == NULL) || (This->dsound == NULL) || (lplpvAudioPtr1 == NULL) ||
966         (lpdwAudioBytes1 == NULL) ) {
967         WARN("invalid parameter\n");
968         return DSERR_INVALIDPARAM;
969     }
970
971     EnterCriticalSection(&(This->dsound->lock));
972
973     if (This->dsound->driver) {
974         err = IDsCaptureDriverBuffer_Lock(This->dsound->hwbuf, lplpvAudioPtr1, 
975                                            lpdwAudioBytes1, lplpvAudioPtr2, lpdwAudioBytes2,
976                                            dwReadCusor, dwReadBytes, dwFlags);
977     } else if (This->dsound->hwi) {
978         *lplpvAudioPtr1 = This->dsound->buffer + dwReadCusor;
979         if ( (dwReadCusor + dwReadBytes) > This->dsound->buflen) {
980             *lpdwAudioBytes1 = This->dsound->buflen - dwReadCusor;
981             if (lplpvAudioPtr2)
982                 *lplpvAudioPtr2 = This->dsound->buffer;
983             if (lpdwAudioBytes2)
984                 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
985         } else {
986             *lpdwAudioBytes1 = dwReadBytes;
987             if (lplpvAudioPtr2)
988                 *lplpvAudioPtr2 = 0;
989             if (lpdwAudioBytes2)
990                 *lpdwAudioBytes2 = 0;
991         }
992     } else {
993         TRACE("invalid call\n");
994         err = DSERR_INVALIDCALL;   /* DSERR_NODRIVER ? */
995     }
996
997     LeaveCriticalSection(&(This->dsound->lock));
998
999     return err;
1000 }
1001
1002 static HRESULT WINAPI
1003 IDirectSoundCaptureBufferImpl_Start(
1004     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1005     DWORD dwFlags )
1006 {
1007     HRESULT err = DS_OK;
1008     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1009     TRACE( "(%p,0x%08lx)\n", This, dwFlags );
1010
1011     if ( (This == NULL) || (This->dsound == NULL) ) {
1012         WARN("invalid parameter\n");
1013         return DSERR_INVALIDPARAM;
1014     }
1015
1016     if ( (This->dsound->driver == 0) && (This->dsound->hwi == 0) ) {
1017         WARN("no driver\n");
1018         return DSERR_NODRIVER;
1019     }
1020
1021     EnterCriticalSection(&(This->dsound->lock));
1022
1023     This->flags = dwFlags;
1024     TRACE("old This->dsound->state=%ld\n",This->dsound->state);
1025     if (This->dsound->state == STATE_STOPPED)
1026         This->dsound->state = STATE_STARTING;
1027     else if (This->dsound->state == STATE_STOPPING)
1028         This->dsound->state = STATE_CAPTURING;
1029     TRACE("new This->dsound->state=%ld\n",This->dsound->state);
1030
1031     LeaveCriticalSection(&(This->dsound->lock));
1032
1033     if (This->dsound->driver) {
1034         err = IDsCaptureDriverBuffer_Start(This->dsound->hwbuf, dwFlags);
1035         return err;
1036     } else {
1037         IDirectSoundCaptureImpl* ipDSC = This->dsound;
1038
1039         if (ipDSC->buffer) {
1040             if (This->nrofnotifies) {
1041                 unsigned c;
1042
1043                 ipDSC->nrofpwaves = This->nrofnotifies;
1044
1045                 /* prepare headers */
1046                 ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave,
1047                     ipDSC->nrofpwaves*sizeof(WAVEHDR));
1048
1049                 for (c = 0; c < ipDSC->nrofpwaves; c++) {
1050                     if (c == 0) {
1051                         ipDSC->pwave[0].lpData = ipDSC->buffer;
1052                         ipDSC->pwave[0].dwBufferLength = 
1053                             This->notifies[0].dwOffset + 1;
1054                     } else {
1055                         ipDSC->pwave[c].lpData = ipDSC->buffer + 
1056                             This->notifies[c-1].dwOffset + 1;
1057                         ipDSC->pwave[c].dwBufferLength = 
1058                             This->notifies[c].dwOffset - 
1059                             This->notifies[c-1].dwOffset;
1060                     }
1061                     ipDSC->pwave[c].dwUser = (DWORD)ipDSC;
1062                     ipDSC->pwave[c].dwFlags = 0;
1063                     ipDSC->pwave[c].dwLoops = 0;
1064                     err = mmErr(waveInPrepareHeader(ipDSC->hwi,
1065                         &(ipDSC->pwave[c]),sizeof(WAVEHDR)));
1066                     if (err != DS_OK) {
1067                         while (c--)
1068                             waveInUnprepareHeader(ipDSC->hwi,
1069                                 &(ipDSC->pwave[c]),sizeof(WAVEHDR));
1070                         break;
1071                     }
1072                 }
1073
1074                 memset(ipDSC->buffer, 
1075                     (ipDSC->wfx.wBitsPerSample == 16) ? 0 : 128, ipDSC->buflen);
1076             } else {
1077                 TRACE("no notifiers specified\n");
1078                 /* no notifiers specified so just create a single default header */
1079                 ipDSC->nrofpwaves = 1;
1080                 ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave,sizeof(WAVEHDR));
1081                 ipDSC->pwave[0].lpData = ipDSC->buffer;
1082                 ipDSC->pwave[0].dwBufferLength = ipDSC->buflen; 
1083                 ipDSC->pwave[0].dwUser = (DWORD)ipDSC;
1084                 ipDSC->pwave[0].dwFlags = 0;
1085                 ipDSC->pwave[0].dwLoops = 0;
1086
1087                 err = mmErr(waveInPrepareHeader(ipDSC->hwi,
1088                     &(ipDSC->pwave[0]),sizeof(WAVEHDR)));
1089                 if (err != DS_OK) {
1090                     waveInUnprepareHeader(ipDSC->hwi,
1091                         &(ipDSC->pwave[0]),sizeof(WAVEHDR));
1092                 }
1093             }
1094         }
1095
1096         ipDSC->index = 0;
1097         ipDSC->read_position = 0;
1098
1099         if (err == DS_OK) {
1100             err = mmErr(waveInReset(ipDSC->hwi));
1101             if (err == DS_OK) {
1102                 /* add the first buffer to the queue */
1103                 err = mmErr(waveInAddBuffer(ipDSC->hwi, &(ipDSC->pwave[0]), sizeof(WAVEHDR)));
1104                 if (err == DS_OK) {
1105                     /* start filling the first buffer */
1106                     err = mmErr(waveInStart(ipDSC->hwi));
1107                 }
1108             }
1109         }
1110     }
1111
1112     if (err != DS_OK) {
1113         WARN("calling waveInClose because of error\n");
1114         waveInClose(This->dsound->hwi);
1115         This->dsound->hwi = 0;
1116     }
1117
1118     TRACE("returning %ld\n", err);
1119     return err;
1120 }
1121
1122 static HRESULT WINAPI
1123 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
1124 {
1125     HRESULT err = DS_OK;
1126     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1127     TRACE( "(%p)\n", This );
1128
1129     if ( (This == NULL) || (This->dsound == NULL) ) {
1130         WARN("invalid parameter\n");
1131         return DSERR_INVALIDPARAM;
1132     }
1133
1134     EnterCriticalSection(&(This->dsound->lock));
1135
1136     TRACE("old This->dsound->state=%ld\n",This->dsound->state);
1137     if (This->dsound->state == STATE_CAPTURING)
1138         This->dsound->state = STATE_STOPPING;
1139     else if (This->dsound->state == STATE_STARTING)
1140         This->dsound->state = STATE_STOPPED;
1141     TRACE("new This->dsound->state=%ld\n",This->dsound->state);
1142
1143     LeaveCriticalSection(&(This->dsound->lock));
1144
1145     if (This->dsound->driver) {
1146         err = IDsCaptureDriverBuffer_Stop(This->dsound->hwbuf);
1147         if (err == DSERR_BUFFERLOST) {
1148             /* Wine-only: the driver wants us to reopen the device */
1149             IDsCaptureDriverBuffer_Release(This->dsound->hwbuf);
1150             err = IDsCaptureDriver_CreateCaptureBuffer(This->dsound->driver,
1151                 &(This->dsound->wfx),0,0,&(This->dsound->buflen),&(This->dsound->buffer),
1152                 (LPVOID*)&(This->dsound->hwbuf));
1153             if (err != DS_OK) {
1154                 WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n");
1155                 This->dsound->hwbuf = 0;
1156             }
1157         }
1158     } else if (This->dsound->hwi) {
1159         err = waveInStop(This->dsound->hwi);
1160     } else {
1161         WARN("no driver\n");
1162         err = DSERR_NODRIVER;
1163     }
1164
1165     TRACE( "(%p) returning 0x%08lx\n", This,err);
1166     return err;
1167 }
1168
1169 static HRESULT WINAPI
1170 IDirectSoundCaptureBufferImpl_Unlock(
1171     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1172     LPVOID lpvAudioPtr1,
1173     DWORD dwAudioBytes1,
1174     LPVOID lpvAudioPtr2,
1175     DWORD dwAudioBytes2 )
1176 {
1177     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1178     TRACE( "(%p,%p,%08lu,%p,%08lu)\n", This, lpvAudioPtr1, dwAudioBytes1, 
1179         lpvAudioPtr2, dwAudioBytes2 );
1180
1181     if ( (This == NULL) || (lpvAudioPtr1 == NULL) ) {
1182         WARN("invalid parameters\n");
1183         return DSERR_INVALIDPARAM;
1184     }
1185
1186     if (This->dsound->driver) {
1187         return IDsCaptureDriverBuffer_Unlock(This->dsound->hwbuf, lpvAudioPtr1, 
1188                                            dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1189     } else if (This->dsound->hwi) {
1190         This->dsound->read_position = (This->dsound->read_position + 
1191             (dwAudioBytes1 + dwAudioBytes2)) % This->dsound->buflen;
1192     } else {
1193         WARN("invalid call\n");
1194         return DSERR_INVALIDCALL;
1195     }
1196
1197     return DS_OK;
1198 }
1199
1200 static HRESULT WINAPI
1201 IDirectSoundCaptureBufferImpl_GetObjectInPath(
1202     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1203     REFGUID rguidObject,
1204     DWORD dwIndex,
1205     REFGUID rguidInterface,
1206     LPVOID* ppObject )
1207 {
1208     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1209
1210     FIXME( "(%p,%s,%lu,%s,%p): stub\n", This, debugstr_guid(rguidObject), 
1211         dwIndex, debugstr_guid(rguidInterface), ppObject );
1212
1213     return DS_OK;
1214 }
1215
1216 static HRESULT WINAPI
1217 IDirectSoundCaptureBufferImpl_GetFXStatus(
1218     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1219     DWORD dwFXCount,
1220     LPDWORD pdwFXStatus )
1221 {
1222     ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
1223
1224     FIXME( "(%p,%lu,%p): stub\n", This, dwFXCount, pdwFXStatus );
1225
1226     return DS_OK;
1227 }
1228
1229 static ICOM_VTABLE(IDirectSoundCaptureBuffer8) dscbvt =
1230 {
1231     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1232     /* IUnknown methods */
1233     IDirectSoundCaptureBufferImpl_QueryInterface,
1234     IDirectSoundCaptureBufferImpl_AddRef,
1235     IDirectSoundCaptureBufferImpl_Release,
1236
1237     /* IDirectSoundCaptureBuffer methods */
1238     IDirectSoundCaptureBufferImpl_GetCaps,
1239     IDirectSoundCaptureBufferImpl_GetCurrentPosition,
1240     IDirectSoundCaptureBufferImpl_GetFormat,
1241     IDirectSoundCaptureBufferImpl_GetStatus,
1242     IDirectSoundCaptureBufferImpl_Initialize,
1243     IDirectSoundCaptureBufferImpl_Lock,
1244     IDirectSoundCaptureBufferImpl_Start,
1245     IDirectSoundCaptureBufferImpl_Stop,
1246     IDirectSoundCaptureBufferImpl_Unlock,
1247
1248     /* IDirectSoundCaptureBuffer methods */
1249     IDirectSoundCaptureBufferImpl_GetObjectInPath,
1250     IDirectSoundCaptureBufferImpl_GetFXStatus
1251 };
1252
1253 /***************************************************************************
1254  * DirectSoundFullDuplexCreate8 [DSOUND.8]
1255  *
1256  * Create and initialize a DirectSoundFullDuplex interface
1257  *
1258  * RETURNS
1259  *    Success: DS_OK
1260  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1261  *             DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
1262  */
1263 HRESULT WINAPI 
1264 DirectSoundFullDuplexCreate8(
1265     LPCGUID pcGuidCaptureDevice,
1266     LPCGUID pcGuidRenderDevice,
1267     LPCDSCBUFFERDESC pcDSCBufferDesc,
1268     LPCDSBUFFERDESC pcDSBufferDesc,
1269     HWND hWnd,
1270     DWORD dwLevel,
1271     LPDIRECTSOUNDFULLDUPLEX *ppDSFD,
1272     LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8,
1273     LPDIRECTSOUNDBUFFER8 *ppDSBuffer8,
1274     LPUNKNOWN pUnkOuter)
1275 {
1276     IDirectSoundFullDuplexImpl** ippDSFD=(IDirectSoundFullDuplexImpl**)ppDSFD;
1277     TRACE("(%s,%s,%p,%p,%lx,%lx,%p,%p,%p,%p)\n", debugstr_guid(pcGuidCaptureDevice), 
1278         debugstr_guid(pcGuidRenderDevice), pcDSCBufferDesc, pcDSBufferDesc,
1279         (DWORD)hWnd, dwLevel, ppDSFD, ppDSCBuffer8, ppDSBuffer8, pUnkOuter);
1280
1281     if ( pUnkOuter ) {
1282         WARN("pUnkOuter != 0\n");
1283         return DSERR_NOAGGREGATION;
1284     }
1285
1286     *ippDSFD = (IDirectSoundFullDuplexImpl*)HeapAlloc(GetProcessHeap(),
1287         HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl));
1288
1289     if (*ippDSFD == NULL) {
1290         TRACE("couldn't allocate memory\n");
1291         return DSERR_OUTOFMEMORY;
1292     }
1293     else
1294     {
1295         ICOM_THIS(IDirectSoundFullDuplexImpl, *ippDSFD);
1296
1297         This->ref = 1;
1298
1299         InitializeCriticalSection( &(This->lock) );
1300
1301         ICOM_VTBL(This) = &dsfdvt;
1302
1303         return IDirectSoundFullDuplexImpl_Initialize( (LPDIRECTSOUNDFULLDUPLEX)This,
1304                                                       pcGuidCaptureDevice, pcGuidRenderDevice,
1305                                                       pcDSCBufferDesc, pcDSBufferDesc,
1306                                                       hWnd, dwLevel, ppDSCBuffer8, ppDSBuffer8);
1307     }
1308 }
1309
1310 static HRESULT WINAPI
1311 IDirectSoundFullDuplexImpl_QueryInterface(
1312     LPDIRECTSOUNDFULLDUPLEX iface,
1313     REFIID riid,
1314     LPVOID* ppobj )
1315 {
1316     ICOM_THIS(IDirectSoundFullDuplexImpl,iface);
1317     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
1318
1319     return E_FAIL;
1320 }
1321
1322 static ULONG WINAPI
1323 IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface )
1324 {
1325     ULONG uRef;
1326     ICOM_THIS(IDirectSoundFullDuplexImpl,iface);
1327
1328     EnterCriticalSection( &(This->lock) );
1329
1330     TRACE( "(%p) was 0x%08lx\n", This, This->ref );
1331     uRef = ++(This->ref);
1332
1333     LeaveCriticalSection( &(This->lock) );
1334
1335     return uRef;
1336 }
1337
1338 static ULONG WINAPI
1339 IDirectSoundFullDuplexImpl_Release( LPDIRECTSOUNDFULLDUPLEX iface )
1340 {
1341     ULONG uRef;
1342     ICOM_THIS(IDirectSoundFullDuplexImpl,iface);
1343
1344     EnterCriticalSection( &(This->lock) );
1345
1346     TRACE( "(%p) was 0x%08lx\n", This, This->ref );
1347     uRef = --(This->ref);
1348
1349     LeaveCriticalSection( &(This->lock) );
1350
1351     if ( uRef == 0 ) {
1352         TRACE("deleting object\n");
1353         DeleteCriticalSection( &(This->lock) );
1354         HeapFree( GetProcessHeap(), 0, This );
1355     }
1356
1357     return uRef;
1358 }
1359
1360 static HRESULT WINAPI
1361 IDirectSoundFullDuplexImpl_Initialize(
1362     LPDIRECTSOUNDFULLDUPLEX iface,
1363     LPCGUID pCaptureGuid,
1364     LPCGUID pRendererGuid,
1365     LPCDSCBUFFERDESC lpDscBufferDesc,
1366     LPCDSBUFFERDESC lpDsBufferDesc,
1367     HWND hWnd,
1368     DWORD dwLevel,
1369     LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8,
1370     LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 )
1371 {
1372     ICOM_THIS(IDirectSoundFullDuplexImpl,iface);
1373     IDirectSoundCaptureBufferImpl** ippdscb=(IDirectSoundCaptureBufferImpl**)lplpDirectSoundCaptureBuffer8;
1374     IDirectSoundBufferImpl** ippdsc=(IDirectSoundBufferImpl**)lplpDirectSoundBuffer8;
1375
1376     TRACE( "(%p,%s,%s,%p,%p,%lx,%lx,%p,%p)\n", This, debugstr_guid(pCaptureGuid), 
1377         debugstr_guid(pRendererGuid), lpDscBufferDesc, lpDsBufferDesc, (DWORD)hWnd, dwLevel,
1378         ippdscb, ippdsc);
1379
1380     return E_FAIL;
1381 }
1382
1383 static ICOM_VTABLE(IDirectSoundFullDuplex) dsfdvt =
1384 {
1385     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1386     /* IUnknown methods */
1387     IDirectSoundFullDuplexImpl_QueryInterface,
1388     IDirectSoundFullDuplexImpl_AddRef,
1389     IDirectSoundFullDuplexImpl_Release,
1390
1391     /* IDirectSoundFullDuplex methods */
1392     IDirectSoundFullDuplexImpl_Initialize
1393 };