dsound: Add COM aggregation to DirectSoundCapture for internal use.
[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 typedef struct IDirectSoundCaptureImpl
999 {
1000     IUnknown                 IUnknown_inner;
1001     IDirectSoundCapture      IDirectSoundCapture_iface;
1002     LONG                     ref, refdsc, numIfaces;
1003     IUnknown                 *outer_unk;        /* internal */
1004     DirectSoundCaptureDevice *device;
1005     BOOL                     has_dsc8;
1006 } IDirectSoundCaptureImpl;
1007
1008 static void capture_destroy(IDirectSoundCaptureImpl *This)
1009 {
1010     if (This->device)
1011         DirectSoundCaptureDevice_Release(This->device);
1012     HeapFree(GetProcessHeap(),0,This);
1013     TRACE("(%p) released\n", This);
1014 }
1015
1016 /*******************************************************************************
1017  *      IUnknown Implementation for DirectSoundCapture
1018  */
1019 static inline IDirectSoundCaptureImpl *impl_from_IUnknown(IUnknown *iface)
1020 {
1021     return CONTAINING_RECORD(iface, IDirectSoundCaptureImpl, IUnknown_inner);
1022 }
1023
1024 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1025 {
1026     IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1027
1028     TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
1029
1030     if (!ppv) {
1031         WARN("invalid parameter\n");
1032         return E_INVALIDARG;
1033     }
1034     *ppv = NULL;
1035
1036     if (IsEqualIID(riid, &IID_IUnknown))
1037         *ppv = &This->IUnknown_inner;
1038     else if (IsEqualIID(riid, &IID_IDirectSoundCapture))
1039         *ppv = &This->IDirectSoundCapture_iface;
1040     else {
1041         WARN("unknown IID %s\n", debugstr_guid(riid));
1042         return E_NOINTERFACE;
1043     }
1044
1045     IUnknown_AddRef((IUnknown*)*ppv);
1046     return S_OK;
1047 }
1048
1049 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
1050 {
1051     IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1052     ULONG ref = InterlockedIncrement(&This->ref);
1053
1054     TRACE("(%p) ref=%d\n", This, ref);
1055
1056     if(ref == 1)
1057         InterlockedIncrement(&This->numIfaces);
1058     return ref;
1059 }
1060
1061 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
1062 {
1063     IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1064     ULONG ref = InterlockedDecrement(&This->ref);
1065
1066     TRACE("(%p) ref=%d\n", This, ref);
1067
1068     if (!ref && !InterlockedDecrement(&This->numIfaces))
1069         capture_destroy(This);
1070     return ref;
1071 }
1072
1073 static const IUnknownVtbl unk_vtbl =
1074 {
1075     IUnknownImpl_QueryInterface,
1076     IUnknownImpl_AddRef,
1077     IUnknownImpl_Release
1078 };
1079
1080 /***************************************************************************
1081  * IDirectSoundCaptureImpl
1082  */
1083 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1084 {
1085     return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1086 }
1087
1088 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1089         REFIID riid, void **ppv)
1090 {
1091     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1092     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
1093     return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1094 }
1095
1096 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1097 {
1098     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1099     ULONG ref = InterlockedIncrement(&This->refdsc);
1100
1101     TRACE("(%p) ref=%d\n", This, ref);
1102
1103     if(ref == 1)
1104         InterlockedIncrement(&This->numIfaces);
1105     return ref;
1106 }
1107
1108 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1109 {
1110     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1111     ULONG ref = InterlockedDecrement(&This->refdsc);
1112
1113     TRACE("(%p) ref=%d\n", This, ref);
1114
1115     if (!ref && !InterlockedDecrement(&This->numIfaces))
1116         capture_destroy(This);
1117     return ref;
1118 }
1119
1120 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1121         LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1122         IUnknown *pUnk)
1123 {
1124     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1125     HRESULT hr;
1126
1127     TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1128
1129     if (pUnk) {
1130         WARN("invalid parameter: pUnk != NULL\n");
1131         return DSERR_NOAGGREGATION;
1132     }
1133
1134     if (lpcDSCBufferDesc == NULL) {
1135         WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1136         return DSERR_INVALIDPARAM;
1137     }
1138
1139     if (lplpDSCaptureBuffer == NULL) {
1140         WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1141         return DSERR_INVALIDPARAM;
1142     }
1143
1144     if (pUnk != NULL) {
1145         WARN("invalid parameter: pUnk != NULL\n");
1146         return DSERR_INVALIDPARAM;
1147     }
1148
1149     /* FIXME: We can only have one buffer so what do we do here? */
1150     if (This->device->capture_buffer) {
1151         WARN("invalid parameter: already has buffer\n");
1152         return DSERR_INVALIDPARAM;    /* DSERR_GENERIC ? */
1153     }
1154
1155     hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1156         (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1157
1158     if (hr != DS_OK)
1159         WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1160
1161     return hr;
1162 }
1163
1164 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1165         LPDSCCAPS lpDSCCaps)
1166 {
1167     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1168
1169     TRACE("(%p,%p)\n",This,lpDSCCaps);
1170
1171     if (This->device == NULL) {
1172         WARN("not initialized\n");
1173         return DSERR_UNINITIALIZED;
1174     }
1175
1176     if (lpDSCCaps== NULL) {
1177         WARN("invalid parameter: lpDSCCaps== NULL\n");
1178         return DSERR_INVALIDPARAM;
1179     }
1180
1181     if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1182         WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1183         return DSERR_INVALIDPARAM;
1184     }
1185
1186     lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1187     lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1188     lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1189
1190     TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1191         lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1192
1193     return DS_OK;
1194 }
1195
1196 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1197         LPCGUID lpcGUID)
1198 {
1199     IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1200
1201     TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1202
1203     if (This->device != NULL) {
1204         WARN("already initialized\n");
1205         return DSERR_ALREADYINITIALIZED;
1206     }
1207     return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1208 }
1209
1210 static const IDirectSoundCaptureVtbl dscvt =
1211 {
1212     /* IUnknown methods */
1213     IDirectSoundCaptureImpl_QueryInterface,
1214     IDirectSoundCaptureImpl_AddRef,
1215     IDirectSoundCaptureImpl_Release,
1216
1217     /* IDirectSoundCapture methods */
1218     IDirectSoundCaptureImpl_CreateCaptureBuffer,
1219     IDirectSoundCaptureImpl_GetCaps,
1220     IDirectSoundCaptureImpl_Initialize
1221 };
1222
1223 HRESULT IDirectSoundCaptureImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_dsc8)
1224 {
1225     IDirectSoundCaptureImpl *obj;
1226     HRESULT hr;
1227
1228     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1229
1230     *ppv = NULL;
1231     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
1232     if (obj == NULL) {
1233         WARN("out of memory\n");
1234         return DSERR_OUTOFMEMORY;
1235     }
1236
1237     setup_dsound_options();
1238
1239     obj->IUnknown_inner.lpVtbl = &unk_vtbl;
1240     obj->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1241     obj->ref = 1;
1242     obj->refdsc = 0;
1243     obj->numIfaces = 1;
1244     obj->device = NULL;
1245     obj->has_dsc8 = has_dsc8;
1246
1247     /* COM aggregation supported only internally */
1248     if (outer_unk)
1249         obj->outer_unk = outer_unk;
1250     else
1251         obj->outer_unk = &obj->IUnknown_inner;
1252
1253     hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
1254     IUnknown_Release(&obj->IUnknown_inner);
1255
1256     return hr;
1257 }
1258
1259 HRESULT DSOUND_CaptureCreate(REFIID riid, void **ppv)
1260 {
1261     return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, FALSE);
1262 }
1263
1264 HRESULT DSOUND_CaptureCreate8(REFIID riid, void **ppv)
1265 {
1266     return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, TRUE);
1267 }
1268
1269 /***************************************************************************
1270  * DirectSoundCaptureCreate [DSOUND.6]
1271  *
1272  * Create and initialize a DirectSoundCapture interface.
1273  *
1274  * PARAMS
1275  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
1276  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
1277  *    pUnkOuter [I] Must be NULL.
1278  *
1279  * RETURNS
1280  *    Success: DS_OK
1281  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1282  *             DSERR_OUTOFMEMORY
1283  *
1284  * NOTES
1285  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1286  *    or NULL for the default device or DSDEVID_DefaultCapture or
1287  *    DSDEVID_DefaultVoiceCapture.
1288  *
1289  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1290  */
1291 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1292         IUnknown *pUnkOuter)
1293 {
1294     HRESULT hr;
1295     IDirectSoundCapture *pDSC;
1296
1297     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1298
1299     if (ppDSC == NULL) {
1300         WARN("invalid parameter: ppDSC == NULL\n");
1301         return DSERR_INVALIDPARAM;
1302     }
1303
1304     if (pUnkOuter) {
1305         WARN("invalid parameter: pUnkOuter != NULL\n");
1306         return DSERR_NOAGGREGATION;
1307     }
1308
1309     hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, (void**)&pDSC);
1310     if (hr == DS_OK) {
1311         hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1312         if (hr != DS_OK) {
1313             IDirectSoundCapture_Release(pDSC);
1314             pDSC = 0;
1315         }
1316     }
1317
1318     *ppDSC = pDSC;
1319
1320     return hr;
1321 }
1322
1323 /***************************************************************************
1324  * DirectSoundCaptureCreate8 [DSOUND.12]
1325  *
1326  * Create and initialize a DirectSoundCapture interface.
1327  *
1328  * PARAMS
1329  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
1330  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
1331  *    pUnkOuter [I] Must be NULL.
1332  *
1333  * RETURNS
1334  *    Success: DS_OK
1335  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1336  *             DSERR_OUTOFMEMORY
1337  *
1338  * NOTES
1339  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1340  *    or NULL for the default device or DSDEVID_DefaultCapture or
1341  *    DSDEVID_DefaultVoiceCapture.
1342  *
1343  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1344  */
1345 HRESULT WINAPI DirectSoundCaptureCreate8(
1346     LPCGUID lpcGUID,
1347     LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1348     LPUNKNOWN pUnkOuter)
1349 {
1350     HRESULT hr;
1351     LPDIRECTSOUNDCAPTURE8 pDSC8;
1352     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1353
1354     if (ppDSC8 == NULL) {
1355         WARN("invalid parameter: ppDSC8 == NULL\n");
1356         return DSERR_INVALIDPARAM;
1357     }
1358
1359     if (pUnkOuter) {
1360         WARN("invalid parameter: pUnkOuter != NULL\n");
1361         *ppDSC8 = NULL;
1362         return DSERR_NOAGGREGATION;
1363     }
1364
1365     hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, (void**)&pDSC8);
1366     if (hr == DS_OK) {
1367         hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1368         if (hr != DS_OK) {
1369             IDirectSoundCapture_Release(pDSC8);
1370             pDSC8 = 0;
1371         }
1372     }
1373
1374     *ppDSC8 = pDSC8;
1375
1376     return hr;
1377 }