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