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