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