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