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