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