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