dsound: Don't make the capture buffer object address public until it is prepared.
[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     IDirectSoundCaptureBufferImpl *This;
684     TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
685
686     if (ppobj == NULL) {
687         WARN("invalid parameter: ppobj == NULL\n");
688         return DSERR_INVALIDPARAM;
689     }
690
691     *ppobj = NULL;
692
693     if (!device) {
694         WARN("not initialized\n");
695         return DSERR_UNINITIALIZED;
696     }
697
698     if (lpcDSCBufferDesc == NULL) {
699         WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
700         return DSERR_INVALIDPARAM;
701     }
702
703     if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
704           (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
705         (lpcDSCBufferDesc->dwBufferBytes == 0) ||
706         (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { /* FIXME: DSERR_BADFORMAT ? */
707         WARN("invalid lpcDSCBufferDesc\n");
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         return DSERR_OUTOFMEMORY;
722
723     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
724         sizeof(IDirectSoundCaptureBufferImpl));
725
726     if ( This == NULL ) {
727         WARN("out of memory\n");
728         return DSERR_OUTOFMEMORY;
729     } else {
730         HRESULT err = DS_OK;
731         LPBYTE newbuf;
732         DWORD buflen;
733
734         This->ref = 1;
735         This->device = device;
736         This->device->capture_buffer = This;
737         This->notify = NULL;
738         This->nrofnotifies = 0;
739
740         This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
741             lpcDSCBufferDesc->dwSize);
742         if (This->pdscbd)
743             CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
744         else {
745             WARN("no memory\n");
746             This->device->capture_buffer = 0;
747             HeapFree( GetProcessHeap(), 0, This );
748             return DSERR_OUTOFMEMORY;
749         }
750
751         This->lpVtbl = &dscbvt;
752
753         err = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
754                 CLSCTX_INPROC_SERVER, NULL, (void**)&device->client);
755         if(FAILED(err)){
756             WARN("Activate failed: %08x\n", err);
757             HeapFree(GetProcessHeap(), 0, This->pdscbd);
758             This->device->capture_buffer = 0;
759             HeapFree( GetProcessHeap(), 0, This );
760             return err;
761         }
762
763         err = IAudioClient_Initialize(device->client,
764                 AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
765                 200 * 100000, 50000, device->pwfx, NULL);
766         if(FAILED(err)){
767             WARN("Initialize failed: %08x\n", err);
768             IAudioClient_Release(device->client);
769             device->client = NULL;
770             HeapFree(GetProcessHeap(), 0, This->pdscbd);
771             This->device->capture_buffer = 0;
772             HeapFree( GetProcessHeap(), 0, This );
773             return err;
774         }
775
776         err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
777                 (void**)&device->capture);
778         if(FAILED(err)){
779             WARN("GetService failed: %08x\n", err);
780             IAudioClient_Release(device->client);
781             device->client = NULL;
782             HeapFree(GetProcessHeap(), 0, This->pdscbd);
783             This->device->capture_buffer = 0;
784             HeapFree( GetProcessHeap(), 0, This );
785             return err;
786         }
787
788         buflen = lpcDSCBufferDesc->dwBufferBytes;
789         TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
790         if (device->buffer)
791             newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
792         else
793             newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
794         if (newbuf == NULL) {
795             IAudioClient_Release(device->client);
796             device->client = NULL;
797             IAudioCaptureClient_Release(device->capture);
798             device->capture = NULL;
799             HeapFree(GetProcessHeap(), 0, This->pdscbd);
800             This->device->capture_buffer = 0;
801             HeapFree( GetProcessHeap(), 0, This );
802             return DSERR_OUTOFMEMORY;
803         }
804         device->buffer = newbuf;
805         device->buflen = buflen;
806     }
807
808     *ppobj = This;
809
810     TRACE("returning DS_OK\n");
811     return DS_OK;
812 }
813
814
815 /*******************************************************************************
816  * DirectSoundCaptureDevice
817  */
818 static HRESULT DirectSoundCaptureDevice_Create(
819     DirectSoundCaptureDevice ** ppDevice)
820 {
821     DirectSoundCaptureDevice * device;
822     TRACE("(%p)\n", ppDevice);
823
824     /* Allocate memory */
825     device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
826
827     if (device == NULL) {
828         WARN("out of memory\n");
829         return DSERR_OUTOFMEMORY;
830     }
831
832     device->ref = 1;
833     device->state = STATE_STOPPED;
834
835     InitializeCriticalSection( &(device->lock) );
836     device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
837
838     *ppDevice = device;
839
840     return DS_OK;
841 }
842
843 static ULONG DirectSoundCaptureDevice_Release(
844     DirectSoundCaptureDevice * device)
845 {
846     ULONG ref = InterlockedDecrement(&(device->ref));
847     TRACE("(%p) ref was %d\n", device, ref + 1);
848
849     if (!ref) {
850         TRACE("deleting object\n");
851
852         timeKillEvent(device->timerID);
853         timeEndPeriod(DS_TIME_RES);
854
855         EnterCriticalSection(&DSOUND_capturers_lock);
856         list_remove(&device->entry);
857         LeaveCriticalSection(&DSOUND_capturers_lock);
858
859         if (device->capture_buffer)
860             IDirectSoundCaptureBufferImpl_Release(
861                 (LPDIRECTSOUNDCAPTUREBUFFER8) device->capture_buffer);
862
863         if(device->mmdevice)
864             IMMDevice_Release(device->mmdevice);
865         HeapFree(GetProcessHeap(), 0, device->pwfx);
866         device->lock.DebugInfo->Spare[0] = 0;
867         DeleteCriticalSection( &(device->lock) );
868         HeapFree(GetProcessHeap(), 0, device);
869         TRACE("(%p) released\n", device);
870     }
871     return ref;
872 }
873
874 static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user,
875                                           DWORD_PTR dw1, DWORD_PTR dw2)
876 {
877     DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user;
878     UINT32 packet_frames, packet_bytes, avail_bytes;
879     DWORD flags;
880     BYTE *buf;
881     HRESULT hr;
882
883     if(!device->ref)
884         return;
885
886     EnterCriticalSection(&device->lock);
887
888     if(!device->capture_buffer || device->state == STATE_STOPPED){
889         LeaveCriticalSection(&device->lock);
890         return;
891     }
892
893     if(device->state == STATE_STOPPING){
894         device->state = STATE_STOPPED;
895         LeaveCriticalSection(&device->lock);
896         return;
897     }
898
899     if(device->state == STATE_STARTING)
900         device->state = STATE_CAPTURING;
901
902     hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
903             &flags, NULL, NULL);
904     if(FAILED(hr)){
905         LeaveCriticalSection(&device->lock);
906         WARN("GetBuffer failed: %08x\n", hr);
907         return;
908     }
909
910     packet_bytes = packet_frames * device->pwfx->nBlockAlign;
911
912     avail_bytes = device->buflen - device->write_pos_bytes;
913     if(avail_bytes > packet_bytes)
914         avail_bytes = packet_bytes;
915
916     memcpy(device->buffer + device->write_pos_bytes, buf, avail_bytes);
917     capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
918
919     packet_bytes -= avail_bytes;
920     if(packet_bytes > 0){
921         if(device->capture_buffer->flags & DSCBSTART_LOOPING){
922             memcpy(device->buffer, buf + avail_bytes, packet_bytes);
923             capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
924         }else{
925             device->state = STATE_STOPPED;
926             capture_CheckNotify(device->capture_buffer, 0, 0);
927         }
928     }
929
930     device->write_pos_bytes += avail_bytes + packet_bytes;
931     device->write_pos_bytes %= device->buflen;
932
933     hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
934     if(FAILED(hr)){
935         LeaveCriticalSection(&device->lock);
936         WARN("ReleaseBuffer failed: %08x\n", hr);
937         return;
938     }
939
940     LeaveCriticalSection(&device->lock);
941 }
942
943 static struct _TestFormat {
944     DWORD flag;
945     DWORD rate;
946     DWORD depth;
947     WORD channels;
948 } formats_to_test[] = {
949     { WAVE_FORMAT_1M08, 11025, 8, 1 },
950     { WAVE_FORMAT_1M16, 11025, 16, 1 },
951     { WAVE_FORMAT_1S08, 11025, 8, 2 },
952     { WAVE_FORMAT_1S16, 11025, 16, 2 },
953     { WAVE_FORMAT_2M08, 22050, 8, 1 },
954     { WAVE_FORMAT_2M16, 22050, 16, 1 },
955     { WAVE_FORMAT_2S08, 22050, 8, 2 },
956     { WAVE_FORMAT_2S16, 22050, 16, 2 },
957     { WAVE_FORMAT_4M08, 44100, 8, 1 },
958     { WAVE_FORMAT_4M16, 44100, 16, 1 },
959     { WAVE_FORMAT_4S08, 44100, 8, 2 },
960     { WAVE_FORMAT_4S16, 44100, 16, 2 },
961     { WAVE_FORMAT_48M08, 48000, 8, 1 },
962     { WAVE_FORMAT_48M16, 48000, 16, 1 },
963     { WAVE_FORMAT_48S08, 48000, 8, 2 },
964     { WAVE_FORMAT_48S16, 48000, 16, 2 },
965     { WAVE_FORMAT_96M08, 96000, 8, 1 },
966     { WAVE_FORMAT_96M16, 96000, 16, 1 },
967     { WAVE_FORMAT_96S08, 96000, 8, 2 },
968     { WAVE_FORMAT_96S16, 96000, 16, 2 },
969     {0}
970 };
971
972 static HRESULT DirectSoundCaptureDevice_Initialize(
973     DirectSoundCaptureDevice ** ppDevice,
974     LPCGUID lpcGUID)
975 {
976     HRESULT hr;
977     GUID devGUID;
978     IMMDevice *mmdevice;
979     struct _TestFormat *fmt;
980     DirectSoundCaptureDevice *device;
981     IAudioClient *client;
982
983     TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
984
985     /* Default device? */
986     if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
987         lpcGUID = &DSDEVID_DefaultCapture;
988
989     if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
990             IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
991         return DSERR_NODRIVER;
992
993     if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
994         WARN("invalid parameter: lpcGUID\n");
995         return DSERR_INVALIDPARAM;
996     }
997
998     hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
999     if(FAILED(hr))
1000         return hr;
1001
1002     EnterCriticalSection(&DSOUND_capturers_lock);
1003
1004     LIST_FOR_EACH_ENTRY(device, &DSOUND_capturers, DirectSoundCaptureDevice, entry){
1005         if(IsEqualGUID(&device->guid, &devGUID)){
1006             IMMDevice_Release(mmdevice);
1007             LeaveCriticalSection(&DSOUND_capturers_lock);
1008             return DSERR_ALLOCATED;
1009         }
1010     }
1011
1012     hr = DirectSoundCaptureDevice_Create(&device);
1013     if (hr != DS_OK) {
1014         WARN("DirectSoundCaptureDevice_Create failed\n");
1015         LeaveCriticalSection(&DSOUND_capturers_lock);
1016         return hr;
1017     }
1018
1019     device->guid = devGUID;
1020
1021     device->mmdevice = mmdevice;
1022
1023     device->drvcaps.dwFlags = 0;
1024
1025     device->drvcaps.dwFormats = 0;
1026     device->drvcaps.dwChannels = 0;
1027     hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
1028             CLSCTX_INPROC_SERVER, NULL, (void**)&client);
1029     if(FAILED(hr)){
1030         DeleteCriticalSection(&device->lock);
1031         HeapFree(GetProcessHeap(), 0, device);
1032         LeaveCriticalSection(&DSOUND_capturers_lock);
1033         return DSERR_NODRIVER;
1034     }
1035
1036     for(fmt = formats_to_test; fmt->flag; ++fmt){
1037         if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
1038             device->drvcaps.dwFormats |= fmt->flag;
1039             if(fmt->channels > device->drvcaps.dwChannels)
1040                 device->drvcaps.dwChannels = fmt->channels;
1041         }
1042     }
1043     IAudioClient_Release(client);
1044
1045     device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
1046
1047     list_add_tail(&DSOUND_capturers, &device->entry);
1048
1049     *ppDevice = device;
1050
1051     LeaveCriticalSection(&DSOUND_capturers_lock);
1052
1053     return S_OK;
1054 }
1055
1056
1057 /*****************************************************************************
1058  * IDirectSoundCapture implementation structure
1059  */
1060 struct IDirectSoundCaptureImpl
1061 {
1062     IDirectSoundCapture      IDirectSoundCapture_iface;
1063     LONG                     ref;
1064     DirectSoundCaptureDevice *device;
1065 };
1066
1067 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1068 {
1069     return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1070 }
1071
1072 /***************************************************************************
1073  * IDirectSoundCaptureImpl
1074  */
1075 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1076         REFIID riid, void **ppobj)
1077 {
1078     TRACE( "(%p,%s,%p)\n", iface, debugstr_guid(riid), ppobj );
1079
1080     if (ppobj == NULL) {
1081         WARN("invalid parameter\n");
1082         return E_INVALIDARG;
1083     }
1084
1085     *ppobj = NULL;
1086
1087     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1088         IDirectSoundCapture_AddRef(iface);
1089         *ppobj = iface;
1090         return S_OK;
1091     }
1092
1093     WARN("unsupported riid: %s\n", debugstr_guid(riid));
1094     return E_NOINTERFACE;
1095 }
1096
1097 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1098 {
1099     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1100     ULONG ref = InterlockedIncrement(&(This->ref));
1101
1102     TRACE("(%p) ref was %d\n", This, ref - 1);
1103     return ref;
1104 }
1105
1106 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1107 {
1108     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1109     ULONG ref = InterlockedDecrement(&(This->ref));
1110
1111     TRACE("(%p) ref was %d\n", This, ref + 1);
1112
1113     if (!ref) {
1114         if (This->device)
1115             DirectSoundCaptureDevice_Release(This->device);
1116
1117         HeapFree( GetProcessHeap(), 0, This );
1118         TRACE("(%p) released\n", This);
1119     }
1120     return ref;
1121 }
1122
1123 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1124         LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1125         IUnknown *pUnk)
1126 {
1127     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1128     HRESULT hr;
1129
1130     TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1131
1132     if (lpcDSCBufferDesc == NULL) {
1133         WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1134         return DSERR_INVALIDPARAM;
1135     }
1136
1137     if (lplpDSCaptureBuffer == NULL) {
1138         WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1139         return DSERR_INVALIDPARAM;
1140     }
1141
1142     if (pUnk != NULL) {
1143         WARN("invalid parameter: pUnk != NULL\n");
1144         return DSERR_INVALIDPARAM;
1145     }
1146
1147     /* FIXME: We can only have one buffer so what do we do here? */
1148     if (This->device->capture_buffer) {
1149         WARN("invalid parameter: already has buffer\n");
1150         return DSERR_INVALIDPARAM;    /* DSERR_GENERIC ? */
1151     }
1152
1153     hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1154         (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1155
1156     if (hr != DS_OK)
1157         WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1158
1159     return hr;
1160 }
1161
1162 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1163         LPDSCCAPS lpDSCCaps)
1164 {
1165     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1166
1167     TRACE("(%p,%p)\n",This,lpDSCCaps);
1168
1169     if (This->device == NULL) {
1170         WARN("not initialized\n");
1171         return DSERR_UNINITIALIZED;
1172     }
1173
1174     if (lpDSCCaps== NULL) {
1175         WARN("invalid parameter: lpDSCCaps== NULL\n");
1176         return DSERR_INVALIDPARAM;
1177     }
1178
1179     if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1180         WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1181         return DSERR_INVALIDPARAM;
1182     }
1183
1184     lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1185     lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1186     lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1187
1188     TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1189         lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1190
1191     return DS_OK;
1192 }
1193
1194 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1195         LPCGUID lpcGUID)
1196 {
1197     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1198
1199     TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1200
1201     if (This->device != NULL) {
1202         WARN("already initialized\n");
1203         return DSERR_ALREADYINITIALIZED;
1204     }
1205     return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1206 }
1207
1208 static const IDirectSoundCaptureVtbl dscvt =
1209 {
1210     /* IUnknown methods */
1211     IDirectSoundCaptureImpl_QueryInterface,
1212     IDirectSoundCaptureImpl_AddRef,
1213     IDirectSoundCaptureImpl_Release,
1214
1215     /* IDirectSoundCapture methods */
1216     IDirectSoundCaptureImpl_CreateCaptureBuffer,
1217     IDirectSoundCaptureImpl_GetCaps,
1218     IDirectSoundCaptureImpl_Initialize
1219 };
1220
1221 static HRESULT IDirectSoundCaptureImpl_Create(
1222     LPDIRECTSOUNDCAPTURE8 * ppDSC)
1223 {
1224     IDirectSoundCaptureImpl *pDSC;
1225     TRACE("(%p)\n", ppDSC);
1226
1227     /* Allocate memory */
1228     pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
1229     if (pDSC == NULL) {
1230         WARN("out of memory\n");
1231         *ppDSC = NULL;
1232         return DSERR_OUTOFMEMORY;
1233     }
1234
1235     pDSC->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1236     pDSC->ref    = 0;
1237     pDSC->device = NULL;
1238
1239     *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
1240
1241     return DS_OK;
1242 }
1243
1244 HRESULT DSOUND_CaptureCreate(REFIID riid, IDirectSoundCapture **ppDSC)
1245 {
1246     IDirectSoundCapture *pDSC;
1247     HRESULT hr;
1248     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC);
1249
1250     if (!IsEqualIID(riid, &IID_IUnknown) &&
1251         !IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1252         *ppDSC = 0;
1253         return E_NOINTERFACE;
1254     }
1255
1256     /* Get dsound configuration */
1257     setup_dsound_options();
1258
1259     hr = IDirectSoundCaptureImpl_Create(&pDSC);
1260     if (hr == DS_OK) {
1261         IDirectSoundCapture_AddRef(pDSC);
1262         *ppDSC = pDSC;
1263     } else {
1264         WARN("IDirectSoundCaptureImpl_Create failed\n");
1265         *ppDSC = 0;
1266     }
1267
1268     return hr;
1269 }
1270
1271 HRESULT DSOUND_CaptureCreate8(
1272     REFIID riid,
1273     LPDIRECTSOUNDCAPTURE8 *ppDSC8)
1274 {
1275     LPDIRECTSOUNDCAPTURE8 pDSC8;
1276     HRESULT hr;
1277     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC8);
1278
1279     if (!IsEqualIID(riid, &IID_IUnknown) &&
1280         !IsEqualIID(riid, &IID_IDirectSoundCapture8)) {
1281         *ppDSC8 = 0;
1282         return E_NOINTERFACE;
1283     }
1284
1285     /* Get dsound configuration */
1286     setup_dsound_options();
1287
1288     hr = IDirectSoundCaptureImpl_Create(&pDSC8);
1289     if (hr == DS_OK) {
1290         IDirectSoundCapture_AddRef(pDSC8);
1291         *ppDSC8 = pDSC8;
1292     } else {
1293         WARN("IDirectSoundCaptureImpl_Create failed\n");
1294         *ppDSC8 = 0;
1295     }
1296
1297     return hr;
1298 }
1299
1300 /***************************************************************************
1301  * DirectSoundCaptureCreate [DSOUND.6]
1302  *
1303  * Create and initialize a DirectSoundCapture interface.
1304  *
1305  * PARAMS
1306  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
1307  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
1308  *    pUnkOuter [I] Must be NULL.
1309  *
1310  * RETURNS
1311  *    Success: DS_OK
1312  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1313  *             DSERR_OUTOFMEMORY
1314  *
1315  * NOTES
1316  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1317  *    or NULL for the default device or DSDEVID_DefaultCapture or
1318  *    DSDEVID_DefaultVoiceCapture.
1319  *
1320  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1321  */
1322 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1323         IUnknown *pUnkOuter)
1324 {
1325     HRESULT hr;
1326     IDirectSoundCapture *pDSC;
1327
1328     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1329
1330     if (ppDSC == NULL) {
1331         WARN("invalid parameter: ppDSC == NULL\n");
1332         return DSERR_INVALIDPARAM;
1333     }
1334
1335     if (pUnkOuter) {
1336         WARN("invalid parameter: pUnkOuter != NULL\n");
1337         *ppDSC = NULL;
1338         return DSERR_NOAGGREGATION;
1339     }
1340
1341     hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, &pDSC);
1342     if (hr == DS_OK) {
1343         hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1344         if (hr != DS_OK) {
1345             IDirectSoundCapture_Release(pDSC);
1346             pDSC = 0;
1347         }
1348     }
1349
1350     *ppDSC = pDSC;
1351
1352     return hr;
1353 }
1354
1355 /***************************************************************************
1356  * DirectSoundCaptureCreate8 [DSOUND.12]
1357  *
1358  * Create and initialize a DirectSoundCapture interface.
1359  *
1360  * PARAMS
1361  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
1362  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
1363  *    pUnkOuter [I] Must be NULL.
1364  *
1365  * RETURNS
1366  *    Success: DS_OK
1367  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1368  *             DSERR_OUTOFMEMORY
1369  *
1370  * NOTES
1371  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1372  *    or NULL for the default device or DSDEVID_DefaultCapture or
1373  *    DSDEVID_DefaultVoiceCapture.
1374  *
1375  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1376  */
1377 HRESULT WINAPI DirectSoundCaptureCreate8(
1378     LPCGUID lpcGUID,
1379     LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1380     LPUNKNOWN pUnkOuter)
1381 {
1382     HRESULT hr;
1383     LPDIRECTSOUNDCAPTURE8 pDSC8;
1384     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1385
1386     if (ppDSC8 == NULL) {
1387         WARN("invalid parameter: ppDSC8 == NULL\n");
1388         return DSERR_INVALIDPARAM;
1389     }
1390
1391     if (pUnkOuter) {
1392         WARN("invalid parameter: pUnkOuter != NULL\n");
1393         *ppDSC8 = NULL;
1394         return DSERR_NOAGGREGATION;
1395     }
1396
1397     hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, &pDSC8);
1398     if (hr == DS_OK) {
1399         hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1400         if (hr != DS_OK) {
1401             IDirectSoundCapture_Release(pDSC8);
1402             pDSC8 = 0;
1403         }
1404     }
1405
1406     *ppDSC8 = pDSC8;
1407
1408     return hr;
1409 }