dsound: Fix type conversion problems.
[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         LeaveCriticalSection(&DSOUND_capturers_lock);
1040         return DSERR_NODRIVER;
1041     }
1042
1043     for(fmt = formats_to_test; fmt->flag; ++fmt){
1044         if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
1045             device->drvcaps.dwFormats |= fmt->flag;
1046             if(fmt->channels > device->drvcaps.dwChannels)
1047                 device->drvcaps.dwChannels = fmt->channels;
1048         }
1049     }
1050     IAudioClient_Release(client);
1051
1052     device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
1053
1054     list_add_tail(&DSOUND_capturers, &device->entry);
1055
1056     *ppDevice = device;
1057
1058     LeaveCriticalSection(&DSOUND_capturers_lock);
1059
1060     return S_OK;
1061 }
1062
1063
1064 /*****************************************************************************
1065  * IDirectSoundCapture implementation structure
1066  */
1067 struct IDirectSoundCaptureImpl
1068 {
1069     IDirectSoundCapture      IDirectSoundCapture_iface;
1070     LONG                     ref;
1071     DirectSoundCaptureDevice *device;
1072 };
1073
1074 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1075 {
1076     return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1077 }
1078
1079 /***************************************************************************
1080  * IDirectSoundCaptureImpl
1081  */
1082 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1083         REFIID riid, void **ppobj)
1084 {
1085     TRACE( "(%p,%s,%p)\n", iface, debugstr_guid(riid), ppobj );
1086
1087     if (ppobj == NULL) {
1088         WARN("invalid parameter\n");
1089         return E_INVALIDARG;
1090     }
1091
1092     *ppobj = NULL;
1093
1094     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1095         IDirectSoundCapture_AddRef(iface);
1096         *ppobj = iface;
1097         return S_OK;
1098     }
1099
1100     WARN("unsupported riid: %s\n", debugstr_guid(riid));
1101     return E_NOINTERFACE;
1102 }
1103
1104 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1105 {
1106     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1107     ULONG ref = InterlockedIncrement(&(This->ref));
1108
1109     TRACE("(%p) ref was %d\n", This, ref - 1);
1110     return ref;
1111 }
1112
1113 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1114 {
1115     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1116     ULONG ref = InterlockedDecrement(&(This->ref));
1117
1118     TRACE("(%p) ref was %d\n", This, ref + 1);
1119
1120     if (!ref) {
1121         if (This->device)
1122             DirectSoundCaptureDevice_Release(This->device);
1123
1124         HeapFree( GetProcessHeap(), 0, This );
1125         TRACE("(%p) released\n", This);
1126     }
1127     return ref;
1128 }
1129
1130 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1131         LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1132         IUnknown *pUnk)
1133 {
1134     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1135     HRESULT hr;
1136
1137     TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1138
1139     if (lpcDSCBufferDesc == NULL) {
1140         WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1141         return DSERR_INVALIDPARAM;
1142     }
1143
1144     if (lplpDSCaptureBuffer == NULL) {
1145         WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1146         return DSERR_INVALIDPARAM;
1147     }
1148
1149     if (pUnk != NULL) {
1150         WARN("invalid parameter: pUnk != NULL\n");
1151         return DSERR_INVALIDPARAM;
1152     }
1153
1154     /* FIXME: We can only have one buffer so what do we do here? */
1155     if (This->device->capture_buffer) {
1156         WARN("invalid parameter: already has buffer\n");
1157         return DSERR_INVALIDPARAM;    /* DSERR_GENERIC ? */
1158     }
1159
1160     hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1161         (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1162
1163     if (hr != DS_OK)
1164         WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1165
1166     return hr;
1167 }
1168
1169 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1170         LPDSCCAPS lpDSCCaps)
1171 {
1172     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1173
1174     TRACE("(%p,%p)\n",This,lpDSCCaps);
1175
1176     if (This->device == NULL) {
1177         WARN("not initialized\n");
1178         return DSERR_UNINITIALIZED;
1179     }
1180
1181     if (lpDSCCaps== NULL) {
1182         WARN("invalid parameter: lpDSCCaps== NULL\n");
1183         return DSERR_INVALIDPARAM;
1184     }
1185
1186     if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1187         WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1188         return DSERR_INVALIDPARAM;
1189     }
1190
1191     lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1192     lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1193     lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1194
1195     TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1196         lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1197
1198     return DS_OK;
1199 }
1200
1201 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1202         LPCGUID lpcGUID)
1203 {
1204     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1205
1206     TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1207
1208     if (This->device != NULL) {
1209         WARN("already initialized\n");
1210         return DSERR_ALREADYINITIALIZED;
1211     }
1212     return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1213 }
1214
1215 static const IDirectSoundCaptureVtbl dscvt =
1216 {
1217     /* IUnknown methods */
1218     IDirectSoundCaptureImpl_QueryInterface,
1219     IDirectSoundCaptureImpl_AddRef,
1220     IDirectSoundCaptureImpl_Release,
1221
1222     /* IDirectSoundCapture methods */
1223     IDirectSoundCaptureImpl_CreateCaptureBuffer,
1224     IDirectSoundCaptureImpl_GetCaps,
1225     IDirectSoundCaptureImpl_Initialize
1226 };
1227
1228 static HRESULT IDirectSoundCaptureImpl_Create(
1229     LPDIRECTSOUNDCAPTURE8 * ppDSC)
1230 {
1231     IDirectSoundCaptureImpl *pDSC;
1232     TRACE("(%p)\n", ppDSC);
1233
1234     /* Allocate memory */
1235     pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
1236     if (pDSC == NULL) {
1237         WARN("out of memory\n");
1238         *ppDSC = NULL;
1239         return DSERR_OUTOFMEMORY;
1240     }
1241
1242     pDSC->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1243     pDSC->ref    = 0;
1244     pDSC->device = NULL;
1245
1246     *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
1247
1248     return DS_OK;
1249 }
1250
1251 HRESULT DSOUND_CaptureCreate(REFIID riid, IDirectSoundCapture **ppDSC)
1252 {
1253     IDirectSoundCapture *pDSC;
1254     HRESULT hr;
1255     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC);
1256
1257     if (!IsEqualIID(riid, &IID_IUnknown) &&
1258         !IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1259         *ppDSC = 0;
1260         return E_NOINTERFACE;
1261     }
1262
1263     /* Get dsound configuration */
1264     setup_dsound_options();
1265
1266     hr = IDirectSoundCaptureImpl_Create(&pDSC);
1267     if (hr == DS_OK) {
1268         IDirectSoundCapture_AddRef(pDSC);
1269         *ppDSC = pDSC;
1270     } else {
1271         WARN("IDirectSoundCaptureImpl_Create failed\n");
1272         *ppDSC = 0;
1273     }
1274
1275     return hr;
1276 }
1277
1278 HRESULT DSOUND_CaptureCreate8(
1279     REFIID riid,
1280     LPDIRECTSOUNDCAPTURE8 *ppDSC8)
1281 {
1282     LPDIRECTSOUNDCAPTURE8 pDSC8;
1283     HRESULT hr;
1284     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC8);
1285
1286     if (!IsEqualIID(riid, &IID_IUnknown) &&
1287         !IsEqualIID(riid, &IID_IDirectSoundCapture8)) {
1288         *ppDSC8 = 0;
1289         return E_NOINTERFACE;
1290     }
1291
1292     /* Get dsound configuration */
1293     setup_dsound_options();
1294
1295     hr = IDirectSoundCaptureImpl_Create(&pDSC8);
1296     if (hr == DS_OK) {
1297         IDirectSoundCapture_AddRef(pDSC8);
1298         *ppDSC8 = pDSC8;
1299     } else {
1300         WARN("IDirectSoundCaptureImpl_Create failed\n");
1301         *ppDSC8 = 0;
1302     }
1303
1304     return hr;
1305 }
1306
1307 /***************************************************************************
1308  * DirectSoundCaptureCreate [DSOUND.6]
1309  *
1310  * Create and initialize a DirectSoundCapture interface.
1311  *
1312  * PARAMS
1313  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
1314  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
1315  *    pUnkOuter [I] Must be NULL.
1316  *
1317  * RETURNS
1318  *    Success: DS_OK
1319  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1320  *             DSERR_OUTOFMEMORY
1321  *
1322  * NOTES
1323  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1324  *    or NULL for the default device or DSDEVID_DefaultCapture or
1325  *    DSDEVID_DefaultVoiceCapture.
1326  *
1327  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1328  */
1329 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1330         IUnknown *pUnkOuter)
1331 {
1332     HRESULT hr;
1333     IDirectSoundCapture *pDSC;
1334
1335     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1336
1337     if (ppDSC == NULL) {
1338         WARN("invalid parameter: ppDSC == NULL\n");
1339         return DSERR_INVALIDPARAM;
1340     }
1341
1342     if (pUnkOuter) {
1343         WARN("invalid parameter: pUnkOuter != NULL\n");
1344         *ppDSC = NULL;
1345         return DSERR_NOAGGREGATION;
1346     }
1347
1348     hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, &pDSC);
1349     if (hr == DS_OK) {
1350         hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1351         if (hr != DS_OK) {
1352             IDirectSoundCapture_Release(pDSC);
1353             pDSC = 0;
1354         }
1355     }
1356
1357     *ppDSC = pDSC;
1358
1359     return hr;
1360 }
1361
1362 /***************************************************************************
1363  * DirectSoundCaptureCreate8 [DSOUND.12]
1364  *
1365  * Create and initialize a DirectSoundCapture interface.
1366  *
1367  * PARAMS
1368  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
1369  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
1370  *    pUnkOuter [I] Must be NULL.
1371  *
1372  * RETURNS
1373  *    Success: DS_OK
1374  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1375  *             DSERR_OUTOFMEMORY
1376  *
1377  * NOTES
1378  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1379  *    or NULL for the default device or DSDEVID_DefaultCapture or
1380  *    DSDEVID_DefaultVoiceCapture.
1381  *
1382  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1383  */
1384 HRESULT WINAPI DirectSoundCaptureCreate8(
1385     LPCGUID lpcGUID,
1386     LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1387     LPUNKNOWN pUnkOuter)
1388 {
1389     HRESULT hr;
1390     LPDIRECTSOUNDCAPTURE8 pDSC8;
1391     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1392
1393     if (ppDSC8 == NULL) {
1394         WARN("invalid parameter: ppDSC8 == NULL\n");
1395         return DSERR_INVALIDPARAM;
1396     }
1397
1398     if (pUnkOuter) {
1399         WARN("invalid parameter: pUnkOuter != NULL\n");
1400         *ppDSC8 = NULL;
1401         return DSERR_NOAGGREGATION;
1402     }
1403
1404     hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, &pDSC8);
1405     if (hr == DS_OK) {
1406         hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1407         if (hr != DS_OK) {
1408             IDirectSoundCapture_Release(pDSC8);
1409             pDSC8 = 0;
1410         }
1411     }
1412
1413     *ppDSC8 = pDSC8;
1414
1415     return hr;
1416 }