dsound: Move the capture structs declarations to the .c file.
[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     This->flags = dwFlags;
497     TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
498     if (This->device->state == STATE_STOPPED)
499         This->device->state = STATE_STARTING;
500     else if (This->device->state == STATE_STOPPING)
501         This->device->state = STATE_CAPTURING;
502     TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
503
504     if (This->device->buffer)
505         FillMemory(This->device->buffer, This->device->buflen, (This->device->pwfx->wBitsPerSample == 8) ? 128 : 0);
506
507     hres = IAudioClient_Start(This->device->client);
508     if(FAILED(hres)){
509         WARN("Start failed: %08x\n", hres);
510         LeaveCriticalSection(&This->device->lock);
511         return hres;
512     }
513
514     LeaveCriticalSection(&This->device->lock);
515
516     TRACE("returning DS_OK\n");
517     return DS_OK;
518 }
519
520 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Stop(IDirectSoundCaptureBuffer8 *iface)
521 {
522     IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
523     HRESULT hres;
524
525     TRACE("(%p)\n", This);
526
527     if (This->device == NULL) {
528         WARN("invalid parameter: This->device == NULL\n");
529         return DSERR_INVALIDPARAM;
530     }
531
532     EnterCriticalSection(&(This->device->lock));
533
534     TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
535     if (This->device->state == STATE_CAPTURING)
536         This->device->state = STATE_STOPPING;
537     else if (This->device->state == STATE_STARTING)
538         This->device->state = STATE_STOPPED;
539     TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
540
541     if(This->device->client){
542         hres = IAudioClient_Stop(This->device->client);
543         if(FAILED(hres)){
544             LeaveCriticalSection(&This->device->lock);
545             return hres;
546         }
547     }
548
549     LeaveCriticalSection(&(This->device->lock));
550
551     TRACE("returning DS_OK\n");
552     return DS_OK;
553 }
554
555 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Unlock(IDirectSoundCaptureBuffer8 *iface,
556         void *lpvAudioPtr1, DWORD dwAudioBytes1, void *lpvAudioPtr2, DWORD dwAudioBytes2)
557 {
558     IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
559     HRESULT hres = DS_OK;
560
561     TRACE( "(%p,%p,%08u,%p,%08u)\n", This, lpvAudioPtr1, dwAudioBytes1,
562         lpvAudioPtr2, dwAudioBytes2 );
563
564     if (lpvAudioPtr1 == NULL) {
565         WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
566         return DSERR_INVALIDPARAM;
567     }
568
569     if (!This->device->client) {
570         WARN("invalid call\n");
571         hres = DSERR_INVALIDCALL;
572     }
573
574     TRACE("returning %08x\n", hres);
575     return hres;
576 }
577
578 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface,
579         REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
580 {
581     IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
582
583     FIXME( "(%p,%s,%u,%s,%p): stub\n", This, debugstr_guid(rguidObject),
584         dwIndex, debugstr_guid(rguidInterface), ppObject );
585
586     return DS_OK;
587 }
588
589 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFXStatus(IDirectSoundCaptureBuffer8 *iface,
590         DWORD dwFXCount, DWORD *pdwFXStatus)
591 {
592     IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
593
594     FIXME( "(%p,%u,%p): stub\n", This, dwFXCount, pdwFXStatus );
595
596     return DS_OK;
597 }
598
599 static const IDirectSoundCaptureBuffer8Vtbl dscbvt =
600 {
601     /* IUnknown methods */
602     IDirectSoundCaptureBufferImpl_QueryInterface,
603     IDirectSoundCaptureBufferImpl_AddRef,
604     IDirectSoundCaptureBufferImpl_Release,
605
606     /* IDirectSoundCaptureBuffer methods */
607     IDirectSoundCaptureBufferImpl_GetCaps,
608     IDirectSoundCaptureBufferImpl_GetCurrentPosition,
609     IDirectSoundCaptureBufferImpl_GetFormat,
610     IDirectSoundCaptureBufferImpl_GetStatus,
611     IDirectSoundCaptureBufferImpl_Initialize,
612     IDirectSoundCaptureBufferImpl_Lock,
613     IDirectSoundCaptureBufferImpl_Start,
614     IDirectSoundCaptureBufferImpl_Stop,
615     IDirectSoundCaptureBufferImpl_Unlock,
616
617     /* IDirectSoundCaptureBuffer methods */
618     IDirectSoundCaptureBufferImpl_GetObjectInPath,
619     IDirectSoundCaptureBufferImpl_GetFXStatus
620 };
621
622 static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len)
623 {
624     int i;
625     for (i = 0; i < This->nrofnotifies; ++i) {
626         LPDSBPOSITIONNOTIFY event = This->notifies + i;
627         DWORD offset = event->dwOffset;
628         TRACE("checking %d, position %d, event = %p\n", i, offset, event->hEventNotify);
629
630         if (offset == DSBPN_OFFSETSTOP) {
631             if (!from && !len) {
632                 SetEvent(event->hEventNotify);
633                 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
634                 return;
635             }
636             else return;
637         }
638
639         if (offset >= from && offset < (from + len))
640         {
641             TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
642             SetEvent(event->hEventNotify);
643         }
644     }
645 }
646
647 static HRESULT IDirectSoundCaptureBufferImpl_Create(
648     DirectSoundCaptureDevice *device,
649     IDirectSoundCaptureBufferImpl ** ppobj,
650     LPCDSCBUFFERDESC lpcDSCBufferDesc)
651 {
652     LPWAVEFORMATEX  wfex;
653     IDirectSoundCaptureBufferImpl *This;
654     TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
655
656     if (ppobj == NULL) {
657         WARN("invalid parameter: ppobj == NULL\n");
658         return DSERR_INVALIDPARAM;
659     }
660
661     *ppobj = NULL;
662
663     if (!device) {
664         WARN("not initialized\n");
665         return DSERR_UNINITIALIZED;
666     }
667
668     if (lpcDSCBufferDesc == NULL) {
669         WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
670         return DSERR_INVALIDPARAM;
671     }
672
673     if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
674           (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
675         (lpcDSCBufferDesc->dwBufferBytes == 0) ||
676         (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { /* FIXME: DSERR_BADFORMAT ? */
677         WARN("invalid lpcDSCBufferDesc\n");
678         return DSERR_INVALIDPARAM;
679     }
680
681     wfex = lpcDSCBufferDesc->lpwfxFormat;
682
683     TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
684         "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
685         wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
686         wfex->nAvgBytesPerSec, wfex->nBlockAlign,
687         wfex->wBitsPerSample, wfex->cbSize);
688
689     device->pwfx = DSOUND_CopyFormat(wfex);
690     if ( device->pwfx == NULL )
691         return DSERR_OUTOFMEMORY;
692
693     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
694         sizeof(IDirectSoundCaptureBufferImpl));
695
696     if ( This == NULL ) {
697         WARN("out of memory\n");
698         return DSERR_OUTOFMEMORY;
699     } else {
700         HRESULT err = DS_OK;
701         LPBYTE newbuf;
702         DWORD buflen;
703
704         This->numIfaces = 0;
705         This->ref = 0;
706         This->refn = 0;
707         This->device = device;
708         This->device->capture_buffer = This;
709         This->nrofnotifies = 0;
710
711         This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
712             lpcDSCBufferDesc->dwSize);
713         if (This->pdscbd)
714             CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
715         else {
716             WARN("no memory\n");
717             This->device->capture_buffer = 0;
718             HeapFree( GetProcessHeap(), 0, This );
719             return DSERR_OUTOFMEMORY;
720         }
721
722         This->IDirectSoundCaptureBuffer8_iface.lpVtbl = &dscbvt;
723         This->IDirectSoundNotify_iface.lpVtbl = &dscnvt;
724
725         err = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
726                 CLSCTX_INPROC_SERVER, NULL, (void**)&device->client);
727         if(FAILED(err)){
728             WARN("Activate failed: %08x\n", err);
729             HeapFree(GetProcessHeap(), 0, This->pdscbd);
730             This->device->capture_buffer = 0;
731             HeapFree( GetProcessHeap(), 0, This );
732             return err;
733         }
734
735         err = IAudioClient_Initialize(device->client,
736                 AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
737                 200 * 100000, 50000, device->pwfx, NULL);
738         if(FAILED(err)){
739             WARN("Initialize failed: %08x\n", err);
740             IAudioClient_Release(device->client);
741             device->client = NULL;
742             HeapFree(GetProcessHeap(), 0, This->pdscbd);
743             This->device->capture_buffer = 0;
744             HeapFree( GetProcessHeap(), 0, This );
745             if(err == AUDCLNT_E_UNSUPPORTED_FORMAT)
746                 return DSERR_BADFORMAT;
747             return err;
748         }
749
750         err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
751                 (void**)&device->capture);
752         if(FAILED(err)){
753             WARN("GetService failed: %08x\n", err);
754             IAudioClient_Release(device->client);
755             device->client = NULL;
756             HeapFree(GetProcessHeap(), 0, This->pdscbd);
757             This->device->capture_buffer = 0;
758             HeapFree( GetProcessHeap(), 0, This );
759             return err;
760         }
761
762         buflen = lpcDSCBufferDesc->dwBufferBytes;
763         TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
764         if (device->buffer)
765             newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
766         else
767             newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
768         if (newbuf == NULL) {
769             IAudioClient_Release(device->client);
770             device->client = NULL;
771             IAudioCaptureClient_Release(device->capture);
772             device->capture = NULL;
773             HeapFree(GetProcessHeap(), 0, This->pdscbd);
774             This->device->capture_buffer = 0;
775             HeapFree( GetProcessHeap(), 0, This );
776             return DSERR_OUTOFMEMORY;
777         }
778         device->buffer = newbuf;
779         device->buflen = buflen;
780     }
781
782     IDirectSoundCaptureBuffer_AddRef(&This->IDirectSoundCaptureBuffer8_iface);
783     *ppobj = This;
784
785     TRACE("returning DS_OK\n");
786     return DS_OK;
787 }
788
789
790 /*******************************************************************************
791  * DirectSoundCaptureDevice
792  */
793 static HRESULT DirectSoundCaptureDevice_Create(
794     DirectSoundCaptureDevice ** ppDevice)
795 {
796     DirectSoundCaptureDevice * device;
797     TRACE("(%p)\n", ppDevice);
798
799     /* Allocate memory */
800     device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
801
802     if (device == NULL) {
803         WARN("out of memory\n");
804         return DSERR_OUTOFMEMORY;
805     }
806
807     device->ref = 1;
808     device->state = STATE_STOPPED;
809
810     InitializeCriticalSection( &(device->lock) );
811     device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
812
813     *ppDevice = device;
814
815     return DS_OK;
816 }
817
818 static ULONG DirectSoundCaptureDevice_Release(
819     DirectSoundCaptureDevice * device)
820 {
821     ULONG ref = InterlockedDecrement(&(device->ref));
822     TRACE("(%p) ref was %d\n", device, ref + 1);
823
824     if (!ref) {
825         TRACE("deleting object\n");
826
827         timeKillEvent(device->timerID);
828         timeEndPeriod(DS_TIME_RES);
829
830         EnterCriticalSection(&DSOUND_capturers_lock);
831         list_remove(&device->entry);
832         LeaveCriticalSection(&DSOUND_capturers_lock);
833
834         if (device->capture_buffer)
835             IDirectSoundCaptureBufferImpl_Release(&device->capture_buffer->IDirectSoundCaptureBuffer8_iface);
836
837         if(device->mmdevice)
838             IMMDevice_Release(device->mmdevice);
839         HeapFree(GetProcessHeap(), 0, device->pwfx);
840         device->lock.DebugInfo->Spare[0] = 0;
841         DeleteCriticalSection( &(device->lock) );
842         HeapFree(GetProcessHeap(), 0, device);
843         TRACE("(%p) released\n", device);
844     }
845     return ref;
846 }
847
848 static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user,
849                                           DWORD_PTR dw1, DWORD_PTR dw2)
850 {
851     DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user;
852     UINT32 packet_frames, packet_bytes, avail_bytes;
853     DWORD flags;
854     BYTE *buf;
855     HRESULT hr;
856
857     if(!device->ref)
858         return;
859
860     EnterCriticalSection(&device->lock);
861
862     if(!device->capture_buffer || device->state == STATE_STOPPED){
863         LeaveCriticalSection(&device->lock);
864         return;
865     }
866
867     if(device->state == STATE_STOPPING){
868         device->state = STATE_STOPPED;
869         LeaveCriticalSection(&device->lock);
870         return;
871     }
872
873     if(device->state == STATE_STARTING)
874         device->state = STATE_CAPTURING;
875
876     hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
877             &flags, NULL, NULL);
878     if(FAILED(hr)){
879         LeaveCriticalSection(&device->lock);
880         WARN("GetBuffer failed: %08x\n", hr);
881         return;
882     }
883
884     packet_bytes = packet_frames * device->pwfx->nBlockAlign;
885
886     avail_bytes = device->buflen - device->write_pos_bytes;
887     if(avail_bytes > packet_bytes)
888         avail_bytes = packet_bytes;
889
890     memcpy(device->buffer + device->write_pos_bytes, buf, avail_bytes);
891     capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
892
893     packet_bytes -= avail_bytes;
894     if(packet_bytes > 0){
895         if(device->capture_buffer->flags & DSCBSTART_LOOPING){
896             memcpy(device->buffer, buf + avail_bytes, packet_bytes);
897             capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
898         }else{
899             device->state = STATE_STOPPED;
900             capture_CheckNotify(device->capture_buffer, 0, 0);
901         }
902     }
903
904     device->write_pos_bytes += avail_bytes + packet_bytes;
905     device->write_pos_bytes %= device->buflen;
906
907     hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
908     if(FAILED(hr)){
909         LeaveCriticalSection(&device->lock);
910         WARN("ReleaseBuffer failed: %08x\n", hr);
911         return;
912     }
913
914     LeaveCriticalSection(&device->lock);
915 }
916
917 static struct _TestFormat {
918     DWORD flag;
919     DWORD rate;
920     DWORD depth;
921     WORD channels;
922 } formats_to_test[] = {
923     { WAVE_FORMAT_1M08, 11025, 8, 1 },
924     { WAVE_FORMAT_1M16, 11025, 16, 1 },
925     { WAVE_FORMAT_1S08, 11025, 8, 2 },
926     { WAVE_FORMAT_1S16, 11025, 16, 2 },
927     { WAVE_FORMAT_2M08, 22050, 8, 1 },
928     { WAVE_FORMAT_2M16, 22050, 16, 1 },
929     { WAVE_FORMAT_2S08, 22050, 8, 2 },
930     { WAVE_FORMAT_2S16, 22050, 16, 2 },
931     { WAVE_FORMAT_4M08, 44100, 8, 1 },
932     { WAVE_FORMAT_4M16, 44100, 16, 1 },
933     { WAVE_FORMAT_4S08, 44100, 8, 2 },
934     { WAVE_FORMAT_4S16, 44100, 16, 2 },
935     { WAVE_FORMAT_48M08, 48000, 8, 1 },
936     { WAVE_FORMAT_48M16, 48000, 16, 1 },
937     { WAVE_FORMAT_48S08, 48000, 8, 2 },
938     { WAVE_FORMAT_48S16, 48000, 16, 2 },
939     { WAVE_FORMAT_96M08, 96000, 8, 1 },
940     { WAVE_FORMAT_96M16, 96000, 16, 1 },
941     { WAVE_FORMAT_96S08, 96000, 8, 2 },
942     { WAVE_FORMAT_96S16, 96000, 16, 2 },
943     {0}
944 };
945
946 static HRESULT DirectSoundCaptureDevice_Initialize(
947     DirectSoundCaptureDevice ** ppDevice,
948     LPCGUID lpcGUID)
949 {
950     HRESULT hr;
951     GUID devGUID;
952     IMMDevice *mmdevice;
953     struct _TestFormat *fmt;
954     DirectSoundCaptureDevice *device;
955     IAudioClient *client;
956
957     TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
958
959     /* Default device? */
960     if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
961         lpcGUID = &DSDEVID_DefaultCapture;
962
963     if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
964             IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
965         return DSERR_NODRIVER;
966
967     if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
968         WARN("invalid parameter: lpcGUID\n");
969         return DSERR_INVALIDPARAM;
970     }
971
972     hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
973     if(FAILED(hr))
974         return hr;
975
976     EnterCriticalSection(&DSOUND_capturers_lock);
977
978     LIST_FOR_EACH_ENTRY(device, &DSOUND_capturers, DirectSoundCaptureDevice, entry){
979         if(IsEqualGUID(&device->guid, &devGUID)){
980             IMMDevice_Release(mmdevice);
981             LeaveCriticalSection(&DSOUND_capturers_lock);
982             return DSERR_ALLOCATED;
983         }
984     }
985
986     hr = DirectSoundCaptureDevice_Create(&device);
987     if (hr != DS_OK) {
988         WARN("DirectSoundCaptureDevice_Create failed\n");
989         LeaveCriticalSection(&DSOUND_capturers_lock);
990         return hr;
991     }
992
993     device->guid = devGUID;
994
995     device->mmdevice = mmdevice;
996
997     device->drvcaps.dwFlags = 0;
998
999     device->drvcaps.dwFormats = 0;
1000     device->drvcaps.dwChannels = 0;
1001     hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
1002             CLSCTX_INPROC_SERVER, NULL, (void**)&client);
1003     if(FAILED(hr)){
1004         device->lock.DebugInfo->Spare[0] = 0;
1005         DeleteCriticalSection(&device->lock);
1006         HeapFree(GetProcessHeap(), 0, device);
1007         LeaveCriticalSection(&DSOUND_capturers_lock);
1008         return DSERR_NODRIVER;
1009     }
1010
1011     for(fmt = formats_to_test; fmt->flag; ++fmt){
1012         if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
1013             device->drvcaps.dwFormats |= fmt->flag;
1014             if(fmt->channels > device->drvcaps.dwChannels)
1015                 device->drvcaps.dwChannels = fmt->channels;
1016         }
1017     }
1018     IAudioClient_Release(client);
1019
1020     device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
1021
1022     list_add_tail(&DSOUND_capturers, &device->entry);
1023
1024     *ppDevice = device;
1025
1026     LeaveCriticalSection(&DSOUND_capturers_lock);
1027
1028     return S_OK;
1029 }
1030
1031
1032 /*****************************************************************************
1033  * IDirectSoundCapture implementation structure
1034  */
1035 typedef struct IDirectSoundCaptureImpl
1036 {
1037     IUnknown                 IUnknown_inner;
1038     IDirectSoundCapture      IDirectSoundCapture_iface;
1039     LONG                     ref, refdsc, numIfaces;
1040     IUnknown                 *outer_unk;        /* internal */
1041     DirectSoundCaptureDevice *device;
1042     BOOL                     has_dsc8;
1043 } IDirectSoundCaptureImpl;
1044
1045 static void capture_destroy(IDirectSoundCaptureImpl *This)
1046 {
1047     if (This->device)
1048         DirectSoundCaptureDevice_Release(This->device);
1049     HeapFree(GetProcessHeap(),0,This);
1050     TRACE("(%p) released\n", This);
1051 }
1052
1053 /*******************************************************************************
1054  *      IUnknown Implementation for DirectSoundCapture
1055  */
1056 static inline IDirectSoundCaptureImpl *impl_from_IUnknown(IUnknown *iface)
1057 {
1058     return CONTAINING_RECORD(iface, IDirectSoundCaptureImpl, IUnknown_inner);
1059 }
1060
1061 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1062 {
1063     IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1064
1065     TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
1066
1067     if (!ppv) {
1068         WARN("invalid parameter\n");
1069         return E_INVALIDARG;
1070     }
1071     *ppv = NULL;
1072
1073     if (IsEqualIID(riid, &IID_IUnknown))
1074         *ppv = &This->IUnknown_inner;
1075     else if (IsEqualIID(riid, &IID_IDirectSoundCapture))
1076         *ppv = &This->IDirectSoundCapture_iface;
1077     else {
1078         WARN("unknown IID %s\n", debugstr_guid(riid));
1079         return E_NOINTERFACE;
1080     }
1081
1082     IUnknown_AddRef((IUnknown*)*ppv);
1083     return S_OK;
1084 }
1085
1086 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
1087 {
1088     IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1089     ULONG ref = InterlockedIncrement(&This->ref);
1090
1091     TRACE("(%p) ref=%d\n", This, ref);
1092
1093     if(ref == 1)
1094         InterlockedIncrement(&This->numIfaces);
1095     return ref;
1096 }
1097
1098 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
1099 {
1100     IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1101     ULONG ref = InterlockedDecrement(&This->ref);
1102
1103     TRACE("(%p) ref=%d\n", This, ref);
1104
1105     if (!ref && !InterlockedDecrement(&This->numIfaces))
1106         capture_destroy(This);
1107     return ref;
1108 }
1109
1110 static const IUnknownVtbl unk_vtbl =
1111 {
1112     IUnknownImpl_QueryInterface,
1113     IUnknownImpl_AddRef,
1114     IUnknownImpl_Release
1115 };
1116
1117 /***************************************************************************
1118  * IDirectSoundCaptureImpl
1119  */
1120 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1121 {
1122     return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1123 }
1124
1125 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1126         REFIID riid, void **ppv)
1127 {
1128     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1129     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
1130     return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1131 }
1132
1133 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1134 {
1135     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1136     ULONG ref = InterlockedIncrement(&This->refdsc);
1137
1138     TRACE("(%p) ref=%d\n", This, ref);
1139
1140     if(ref == 1)
1141         InterlockedIncrement(&This->numIfaces);
1142     return ref;
1143 }
1144
1145 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1146 {
1147     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1148     ULONG ref = InterlockedDecrement(&This->refdsc);
1149
1150     TRACE("(%p) ref=%d\n", This, ref);
1151
1152     if (!ref && !InterlockedDecrement(&This->numIfaces))
1153         capture_destroy(This);
1154     return ref;
1155 }
1156
1157 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1158         LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1159         IUnknown *pUnk)
1160 {
1161     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1162     HRESULT hr;
1163
1164     TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1165
1166     if (pUnk) {
1167         WARN("invalid parameter: pUnk != NULL\n");
1168         return DSERR_NOAGGREGATION;
1169     }
1170
1171     if (lpcDSCBufferDesc == NULL) {
1172         WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1173         return DSERR_INVALIDPARAM;
1174     }
1175
1176     if (lplpDSCaptureBuffer == NULL) {
1177         WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1178         return DSERR_INVALIDPARAM;
1179     }
1180
1181     if (pUnk != NULL) {
1182         WARN("invalid parameter: pUnk != NULL\n");
1183         return DSERR_INVALIDPARAM;
1184     }
1185
1186     /* FIXME: We can only have one buffer so what do we do here? */
1187     if (This->device->capture_buffer) {
1188         WARN("invalid parameter: already has buffer\n");
1189         return DSERR_INVALIDPARAM;    /* DSERR_GENERIC ? */
1190     }
1191
1192     hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1193         (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1194
1195     if (hr != DS_OK)
1196         WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1197
1198     return hr;
1199 }
1200
1201 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1202         LPDSCCAPS lpDSCCaps)
1203 {
1204     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1205
1206     TRACE("(%p,%p)\n",This,lpDSCCaps);
1207
1208     if (This->device == NULL) {
1209         WARN("not initialized\n");
1210         return DSERR_UNINITIALIZED;
1211     }
1212
1213     if (lpDSCCaps== NULL) {
1214         WARN("invalid parameter: lpDSCCaps== NULL\n");
1215         return DSERR_INVALIDPARAM;
1216     }
1217
1218     if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1219         WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1220         return DSERR_INVALIDPARAM;
1221     }
1222
1223     lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1224     lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1225     lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1226
1227     TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1228         lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1229
1230     return DS_OK;
1231 }
1232
1233 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1234         LPCGUID lpcGUID)
1235 {
1236     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1237
1238     TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1239
1240     if (This->device != NULL) {
1241         WARN("already initialized\n");
1242         return DSERR_ALREADYINITIALIZED;
1243     }
1244     return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1245 }
1246
1247 static const IDirectSoundCaptureVtbl dscvt =
1248 {
1249     /* IUnknown methods */
1250     IDirectSoundCaptureImpl_QueryInterface,
1251     IDirectSoundCaptureImpl_AddRef,
1252     IDirectSoundCaptureImpl_Release,
1253
1254     /* IDirectSoundCapture methods */
1255     IDirectSoundCaptureImpl_CreateCaptureBuffer,
1256     IDirectSoundCaptureImpl_GetCaps,
1257     IDirectSoundCaptureImpl_Initialize
1258 };
1259
1260 HRESULT IDirectSoundCaptureImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_dsc8)
1261 {
1262     IDirectSoundCaptureImpl *obj;
1263     HRESULT hr;
1264
1265     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1266
1267     *ppv = NULL;
1268     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
1269     if (obj == NULL) {
1270         WARN("out of memory\n");
1271         return DSERR_OUTOFMEMORY;
1272     }
1273
1274     setup_dsound_options();
1275
1276     obj->IUnknown_inner.lpVtbl = &unk_vtbl;
1277     obj->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1278     obj->ref = 1;
1279     obj->refdsc = 0;
1280     obj->numIfaces = 1;
1281     obj->device = NULL;
1282     obj->has_dsc8 = has_dsc8;
1283
1284     /* COM aggregation supported only internally */
1285     if (outer_unk)
1286         obj->outer_unk = outer_unk;
1287     else
1288         obj->outer_unk = &obj->IUnknown_inner;
1289
1290     hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
1291     IUnknown_Release(&obj->IUnknown_inner);
1292
1293     return hr;
1294 }
1295
1296 HRESULT DSOUND_CaptureCreate(REFIID riid, void **ppv)
1297 {
1298     return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, FALSE);
1299 }
1300
1301 HRESULT DSOUND_CaptureCreate8(REFIID riid, void **ppv)
1302 {
1303     return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, TRUE);
1304 }
1305
1306 /***************************************************************************
1307  * DirectSoundCaptureCreate [DSOUND.6]
1308  *
1309  * Create and initialize a DirectSoundCapture interface.
1310  *
1311  * PARAMS
1312  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
1313  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
1314  *    pUnkOuter [I] Must be NULL.
1315  *
1316  * RETURNS
1317  *    Success: DS_OK
1318  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1319  *             DSERR_OUTOFMEMORY
1320  *
1321  * NOTES
1322  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1323  *    or NULL for the default device or DSDEVID_DefaultCapture or
1324  *    DSDEVID_DefaultVoiceCapture.
1325  *
1326  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1327  */
1328 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1329         IUnknown *pUnkOuter)
1330 {
1331     HRESULT hr;
1332     IDirectSoundCapture *pDSC;
1333
1334     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1335
1336     if (ppDSC == NULL) {
1337         WARN("invalid parameter: ppDSC == NULL\n");
1338         return DSERR_INVALIDPARAM;
1339     }
1340
1341     if (pUnkOuter) {
1342         WARN("invalid parameter: pUnkOuter != NULL\n");
1343         return DSERR_NOAGGREGATION;
1344     }
1345
1346     hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, (void**)&pDSC);
1347     if (hr == DS_OK) {
1348         hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1349         if (hr != DS_OK) {
1350             IDirectSoundCapture_Release(pDSC);
1351             pDSC = 0;
1352         }
1353     }
1354
1355     *ppDSC = pDSC;
1356
1357     return hr;
1358 }
1359
1360 /***************************************************************************
1361  * DirectSoundCaptureCreate8 [DSOUND.12]
1362  *
1363  * Create and initialize a DirectSoundCapture interface.
1364  *
1365  * PARAMS
1366  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
1367  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
1368  *    pUnkOuter [I] Must be NULL.
1369  *
1370  * RETURNS
1371  *    Success: DS_OK
1372  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1373  *             DSERR_OUTOFMEMORY
1374  *
1375  * NOTES
1376  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1377  *    or NULL for the default device or DSDEVID_DefaultCapture or
1378  *    DSDEVID_DefaultVoiceCapture.
1379  *
1380  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1381  */
1382 HRESULT WINAPI DirectSoundCaptureCreate8(
1383     LPCGUID lpcGUID,
1384     LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1385     LPUNKNOWN pUnkOuter)
1386 {
1387     HRESULT hr;
1388     LPDIRECTSOUNDCAPTURE8 pDSC8;
1389     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1390
1391     if (ppDSC8 == NULL) {
1392         WARN("invalid parameter: ppDSC8 == NULL\n");
1393         return DSERR_INVALIDPARAM;
1394     }
1395
1396     if (pUnkOuter) {
1397         WARN("invalid parameter: pUnkOuter != NULL\n");
1398         *ppDSC8 = NULL;
1399         return DSERR_NOAGGREGATION;
1400     }
1401
1402     hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, (void**)&pDSC8);
1403     if (hr == DS_OK) {
1404         hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1405         if (hr != DS_OK) {
1406             IDirectSoundCapture_Release(pDSC8);
1407             pDSC8 = 0;
1408         }
1409     }
1410
1411     *ppDSC8 = pDSC8;
1412
1413     return hr;
1414 }