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