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