mshtml: Added IHTMLElement2::get_readyState implementation.
[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 NONAMELESSSTRUCT
31 #define NONAMELESSUNION
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winuser.h"
35 #include "mmsystem.h"
36 #include "mmddk.h"
37 #include "winternl.h"
38 #include "winnls.h"
39 #include "wine/debug.h"
40 #include "dsound.h"
41 #include "dsdriver.h"
42 #include "dsound_private.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
45
46 /*****************************************************************************
47  * IDirectSoundCapture implementation structure
48  */
49 struct IDirectSoundCaptureImpl
50 {
51     /* IUnknown fields */
52     const IDirectSoundCaptureVtbl     *lpVtbl;
53     LONG                               ref;
54
55     DirectSoundCaptureDevice          *device;
56 };
57
58 static HRESULT IDirectSoundCaptureImpl_Create(LPDIRECTSOUNDCAPTURE8 * ppds);
59
60
61 /*****************************************************************************
62  * IDirectSoundCaptureNotify implementation structure
63  */
64 struct IDirectSoundCaptureNotifyImpl
65 {
66     /* IUnknown fields */
67     const IDirectSoundNotifyVtbl       *lpVtbl;
68     LONG                                ref;
69     IDirectSoundCaptureBufferImpl*      dscb;
70 };
71
72 static HRESULT IDirectSoundCaptureNotifyImpl_Create(IDirectSoundCaptureBufferImpl *dscb,
73                                                     IDirectSoundCaptureNotifyImpl ** pdscn);
74
75
76 DirectSoundCaptureDevice * DSOUND_capture[MAXWAVEDRIVERS];
77
78 static HRESULT DirectSoundCaptureDevice_Create(DirectSoundCaptureDevice ** ppDevice);
79
80 static const char * const captureStateString[] = {
81     "STATE_STOPPED",
82     "STATE_STARTING",
83     "STATE_CAPTURING",
84     "STATE_STOPPING"
85 };
86
87 HRESULT DSOUND_CaptureCreate(
88     REFIID riid,
89     LPDIRECTSOUNDCAPTURE *ppDSC)
90 {
91     LPDIRECTSOUNDCAPTURE pDSC;
92     HRESULT hr;
93     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC);
94
95     if (!IsEqualIID(riid, &IID_IUnknown) &&
96         !IsEqualIID(riid, &IID_IDirectSoundCapture)) {
97         *ppDSC = 0;
98         return E_NOINTERFACE;
99     }
100
101     /* Get dsound configuration */
102     setup_dsound_options();
103
104     hr = IDirectSoundCaptureImpl_Create(&pDSC);
105     if (hr == DS_OK) {
106         IDirectSoundCapture_AddRef(pDSC);
107         *ppDSC = pDSC;
108     } else {
109         WARN("IDirectSoundCaptureImpl_Create failed\n");
110         *ppDSC = 0;
111     }
112
113     return hr;
114 }
115
116 HRESULT DSOUND_CaptureCreate8(
117     REFIID riid,
118     LPDIRECTSOUNDCAPTURE8 *ppDSC8)
119 {
120     LPDIRECTSOUNDCAPTURE8 pDSC8;
121     HRESULT hr;
122     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC8);
123
124     if (!IsEqualIID(riid, &IID_IUnknown) &&
125         !IsEqualIID(riid, &IID_IDirectSoundCapture8)) {
126         *ppDSC8 = 0;
127         return E_NOINTERFACE;
128     }
129
130     /* Get dsound configuration */
131     setup_dsound_options();
132
133     hr = IDirectSoundCaptureImpl_Create(&pDSC8);
134     if (hr == DS_OK) {
135         IDirectSoundCapture_AddRef(pDSC8);
136         *ppDSC8 = pDSC8;
137     } else {
138         WARN("IDirectSoundCaptureImpl_Create failed\n");
139         *ppDSC8 = 0;
140     }
141
142     return hr;
143 }
144
145 /***************************************************************************
146  * DirectSoundCaptureCreate [DSOUND.6]
147  *
148  * Create and initialize a DirectSoundCapture interface.
149  *
150  * PARAMS
151  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
152  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
153  *    pUnkOuter [I] Must be NULL.
154  *
155  * RETURNS
156  *    Success: DS_OK
157  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
158  *             DSERR_OUTOFMEMORY
159  *
160  * NOTES
161  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
162  *    or NULL for the default device or DSDEVID_DefaultCapture or
163  *    DSDEVID_DefaultVoiceCapture.
164  *
165  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
166  */
167 HRESULT WINAPI DirectSoundCaptureCreate(
168     LPCGUID lpcGUID,
169     LPDIRECTSOUNDCAPTURE *ppDSC,
170     LPUNKNOWN pUnkOuter)
171 {
172     HRESULT hr;
173     LPDIRECTSOUNDCAPTURE pDSC;
174     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
175
176     if (ppDSC == NULL) {
177         WARN("invalid parameter: ppDSC == NULL\n");
178         return DSERR_INVALIDPARAM;
179     }
180
181     if (pUnkOuter) {
182         WARN("invalid parameter: pUnkOuter != NULL\n");
183         *ppDSC = NULL;
184         return DSERR_NOAGGREGATION;
185     }
186
187     hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, &pDSC);
188     if (hr == DS_OK) {
189         hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
190         if (hr != DS_OK) {
191             IDirectSoundCapture_Release(pDSC);
192             pDSC = 0;
193         }
194     }
195
196     *ppDSC = pDSC;
197
198     return hr;
199 }
200
201 /***************************************************************************
202  * DirectSoundCaptureCreate8 [DSOUND.12]
203  *
204  * Create and initialize a DirectSoundCapture interface.
205  *
206  * PARAMS
207  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
208  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
209  *    pUnkOuter [I] Must be NULL.
210  *
211  * RETURNS
212  *    Success: DS_OK
213  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
214  *             DSERR_OUTOFMEMORY
215  *
216  * NOTES
217  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
218  *    or NULL for the default device or DSDEVID_DefaultCapture or
219  *    DSDEVID_DefaultVoiceCapture.
220  *
221  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
222  */
223 HRESULT WINAPI DirectSoundCaptureCreate8(
224     LPCGUID lpcGUID,
225     LPDIRECTSOUNDCAPTURE8 *ppDSC8,
226     LPUNKNOWN pUnkOuter)
227 {
228     HRESULT hr;
229     LPDIRECTSOUNDCAPTURE8 pDSC8;
230     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
231
232     if (ppDSC8 == NULL) {
233         WARN("invalid parameter: ppDSC8 == NULL\n");
234         return DSERR_INVALIDPARAM;
235     }
236
237     if (pUnkOuter) {
238         WARN("invalid parameter: pUnkOuter != NULL\n");
239         *ppDSC8 = NULL;
240         return DSERR_NOAGGREGATION;
241     }
242
243     hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, &pDSC8);
244     if (hr == DS_OK) {
245         hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
246         if (hr != DS_OK) {
247             IDirectSoundCapture_Release(pDSC8);
248             pDSC8 = 0;
249         }
250     }
251
252     *ppDSC8 = pDSC8;
253
254     return hr;
255 }
256
257 static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len)
258 {
259     int i;
260     for (i = 0; i < This->nrofnotifies; ++i) {
261         LPDSBPOSITIONNOTIFY event = This->notifies + i;
262         DWORD offset = event->dwOffset;
263         TRACE("checking %d, position %d, event = %p\n", i, offset, event->hEventNotify);
264
265         if (offset == DSBPN_OFFSETSTOP) {
266             if (!from && !len) {
267                 SetEvent(event->hEventNotify);
268                 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
269                 return;
270             }
271             else return;
272         }
273
274         if (offset >= from && offset < (from + len))
275         {
276             TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
277             SetEvent(event->hEventNotify);
278         }
279     }
280 }
281
282 static void CALLBACK
283 DSOUND_capture_callback(HWAVEIN hwi, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1,
284                         DWORD_PTR dw2)
285 {
286     DirectSoundCaptureDevice * This = (DirectSoundCaptureDevice*)dwUser;
287     IDirectSoundCaptureBufferImpl * Moi = This->capture_buffer;
288     TRACE("(%p,%08x(%s),%08lx,%08lx,%08lx) entering at %d\n",hwi,msg,
289         msg == MM_WIM_OPEN ? "MM_WIM_OPEN" : msg == MM_WIM_CLOSE ? "MM_WIM_CLOSE" :
290         msg == MM_WIM_DATA ? "MM_WIM_DATA" : "UNKNOWN",dwUser,dw1,dw2,GetTickCount());
291
292     if (msg == MM_WIM_DATA) {
293         EnterCriticalSection( &(This->lock) );
294         TRACE("DirectSoundCapture msg=MM_WIM_DATA, old This->state=%s, old This->index=%d\n",
295             captureStateString[This->state],This->index);
296         if (This->state != STATE_STOPPED) {
297             int index = This->index;
298             if (This->state == STATE_STARTING)
299                 This->state = STATE_CAPTURING;
300             capture_CheckNotify(Moi, (DWORD_PTR)This->pwave[index].lpData - (DWORD_PTR)This->buffer, This->pwave[index].dwBufferLength);
301             This->index = (This->index + 1) % This->nrofpwaves;
302             if ( (This->index == 0) && !(This->capture_buffer->flags & DSCBSTART_LOOPING) ) {
303                 TRACE("end of buffer\n");
304                 This->state = STATE_STOPPED;
305                 capture_CheckNotify(Moi, 0, 0);
306             } else {
307                 if (This->state == STATE_CAPTURING) {
308                     waveInUnprepareHeader(hwi, &(This->pwave[index]), sizeof(WAVEHDR));
309                     waveInPrepareHeader(hwi, &(This->pwave[index]), sizeof(WAVEHDR));
310                     waveInAddBuffer(hwi, &(This->pwave[index]), sizeof(WAVEHDR));
311                 } else if (This->state == STATE_STOPPING) {
312                     TRACE("stopping\n");
313                     This->state = STATE_STOPPED;
314                 }
315             }
316         }
317         TRACE("DirectSoundCapture new This->state=%s, new This->index=%d\n",
318             captureStateString[This->state],This->index);
319         LeaveCriticalSection( &(This->lock) );
320     }
321
322     TRACE("completed\n");
323 }
324
325 /***************************************************************************
326  * IDirectSoundCaptureImpl
327  */
328 static HRESULT WINAPI
329 IDirectSoundCaptureImpl_QueryInterface(
330     LPDIRECTSOUNDCAPTURE iface,
331     REFIID riid,
332     LPVOID* ppobj )
333 {
334     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
335     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
336
337     if (ppobj == NULL) {
338         WARN("invalid parameter\n");
339         return E_INVALIDARG;
340     }
341
342     *ppobj = NULL;
343
344     if (IsEqualIID(riid, &IID_IUnknown)) {
345         IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This);
346         *ppobj = This;
347         return DS_OK;
348     } else if (IsEqualIID(riid, &IID_IDirectSoundCapture)) {
349         IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This);
350         *ppobj = This;
351         return DS_OK;
352     }
353
354     WARN("unsupported riid: %s\n", debugstr_guid(riid));
355     return E_NOINTERFACE;
356 }
357
358 static ULONG WINAPI
359 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface )
360 {
361     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
362     ULONG ref = InterlockedIncrement(&(This->ref));
363     TRACE("(%p) ref was %d\n", This, ref - 1);
364     return ref;
365 }
366
367 static ULONG WINAPI
368 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface )
369 {
370     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
371     ULONG ref = InterlockedDecrement(&(This->ref));
372     TRACE("(%p) ref was %d\n", This, ref + 1);
373
374     if (!ref) {
375         if (This->device)
376             DirectSoundCaptureDevice_Release(This->device);
377
378         HeapFree( GetProcessHeap(), 0, This );
379         TRACE("(%p) released\n", This);
380     }
381     return ref;
382 }
383
384 HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(
385     LPDIRECTSOUNDCAPTURE iface,
386     LPCDSCBUFFERDESC lpcDSCBufferDesc,
387     LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
388     LPUNKNOWN pUnk )
389 {
390     HRESULT hr;
391     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
392
393     TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
394
395     if (lpcDSCBufferDesc == NULL) {
396         WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
397         return DSERR_INVALIDPARAM;
398     }
399
400     if (lplpDSCaptureBuffer == NULL) {
401         WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
402         return DSERR_INVALIDPARAM;
403     }
404
405     if (pUnk != NULL) {
406         WARN("invalid parameter: pUnk != NULL\n");
407         return DSERR_INVALIDPARAM;
408     }
409
410     /* FIXME: We can only have one buffer so what do we do here? */
411     if (This->device->capture_buffer) {
412         WARN("lnvalid parameter: already has buffer\n");
413         return DSERR_INVALIDPARAM;    /* DSERR_GENERIC ? */
414     }
415
416     hr = IDirectSoundCaptureBufferImpl_Create(This->device,
417         (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
418
419     if (hr != DS_OK)
420         WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
421
422     return hr;
423 }
424
425 HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(
426     LPDIRECTSOUNDCAPTURE iface,
427     LPDSCCAPS lpDSCCaps )
428 {
429     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
430     TRACE("(%p,%p)\n",This,lpDSCCaps);
431
432     if (This->device == NULL) {
433         WARN("not initialized\n");
434         return DSERR_UNINITIALIZED;
435     }
436
437     if (lpDSCCaps== NULL) {
438         WARN("invalid parameter: lpDSCCaps== NULL\n");
439         return DSERR_INVALIDPARAM;
440     }
441
442     if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
443         WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
444         return DSERR_INVALIDPARAM;
445     }
446
447     lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
448     lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
449     lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
450
451     TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
452         lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
453
454     return DS_OK;
455 }
456
457 HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(
458     LPDIRECTSOUNDCAPTURE iface,
459     LPCGUID lpcGUID )
460 {
461     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
462     TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
463
464     if (This->device != NULL) {
465         WARN("already initialized\n");
466         return DSERR_ALREADYINITIALIZED;
467     }
468     return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
469 }
470
471 static const IDirectSoundCaptureVtbl dscvt =
472 {
473     /* IUnknown methods */
474     IDirectSoundCaptureImpl_QueryInterface,
475     IDirectSoundCaptureImpl_AddRef,
476     IDirectSoundCaptureImpl_Release,
477
478     /* IDirectSoundCapture methods */
479     IDirectSoundCaptureImpl_CreateCaptureBuffer,
480     IDirectSoundCaptureImpl_GetCaps,
481     IDirectSoundCaptureImpl_Initialize
482 };
483
484 static HRESULT IDirectSoundCaptureImpl_Create(
485     LPDIRECTSOUNDCAPTURE8 * ppDSC)
486 {
487     IDirectSoundCaptureImpl *pDSC;
488     TRACE("(%p)\n", ppDSC);
489
490     /* Allocate memory */
491     pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
492     if (pDSC == NULL) {
493         WARN("out of memory\n");
494         *ppDSC = NULL;
495         return DSERR_OUTOFMEMORY;
496     }
497
498     pDSC->lpVtbl = &dscvt;
499     pDSC->ref    = 0;
500     pDSC->device = NULL;
501
502     *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
503
504     return DS_OK;
505 }
506
507 /*******************************************************************************
508  *              IDirectSoundCaptureNotify
509  */
510 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface(
511     LPDIRECTSOUNDNOTIFY iface,
512     REFIID riid,
513     LPVOID *ppobj)
514 {
515     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
516     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
517
518     if (This->dscb == NULL) {
519         WARN("invalid parameter\n");
520         return E_INVALIDARG;
521     }
522
523     return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
524 }
525
526 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
527 {
528     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
529     ULONG ref = InterlockedIncrement(&(This->ref));
530     TRACE("(%p) ref was %d\n", This, ref - 1);
531     return ref;
532 }
533
534 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
535 {
536     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
537     ULONG ref = InterlockedDecrement(&(This->ref));
538     TRACE("(%p) ref was %d\n", This, ref + 1);
539
540     if (!ref) {
541         if (This->dscb->hwnotify)
542             IDsDriverNotify_Release(This->dscb->hwnotify);
543         This->dscb->notify=NULL;
544         IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb);
545         HeapFree(GetProcessHeap(),0,This);
546         TRACE("(%p) released\n", This);
547     }
548     return ref;
549 }
550
551 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions(
552     LPDIRECTSOUNDNOTIFY iface,
553     DWORD howmuch,
554     LPCDSBPOSITIONNOTIFY notify)
555 {
556     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
557     TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
558
559     if (howmuch > 0 && notify == NULL) {
560         WARN("invalid parameter: notify == NULL\n");
561         return DSERR_INVALIDPARAM;
562     }
563
564     if (TRACE_ON(dsound)) {
565         unsigned int i;
566         for (i=0;i<howmuch;i++)
567             TRACE("notify at %d to %p\n",
568             notify[i].dwOffset,notify[i].hEventNotify);
569     }
570
571     if (This->dscb->hwnotify) {
572         HRESULT hres;
573         hres = IDsDriverNotify_SetNotificationPositions(This->dscb->hwnotify, howmuch, notify);
574         if (hres != DS_OK)
575             WARN("IDsDriverNotify_SetNotificationPositions failed\n");
576         return hres;
577     } else if (howmuch > 0) {
578         /* Make an internal copy of the caller-supplied array.
579          * Replace the existing copy if one is already present. */
580         if (This->dscb->notifies)
581             This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
582                 This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
583         else
584             This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
585                 howmuch * sizeof(DSBPOSITIONNOTIFY));
586
587         if (This->dscb->notifies == NULL) {
588             WARN("out of memory\n");
589             return DSERR_OUTOFMEMORY;
590         }
591         CopyMemory(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
592         This->dscb->nrofnotifies = howmuch;
593     } else {
594         HeapFree(GetProcessHeap(), 0, This->dscb->notifies);
595         This->dscb->notifies = NULL;
596         This->dscb->nrofnotifies = 0;
597     }
598
599     return S_OK;
600 }
601
602 static const IDirectSoundNotifyVtbl dscnvt =
603 {
604     IDirectSoundCaptureNotifyImpl_QueryInterface,
605     IDirectSoundCaptureNotifyImpl_AddRef,
606     IDirectSoundCaptureNotifyImpl_Release,
607     IDirectSoundCaptureNotifyImpl_SetNotificationPositions,
608 };
609
610 static HRESULT IDirectSoundCaptureNotifyImpl_Create(
611     IDirectSoundCaptureBufferImpl *dscb,
612     IDirectSoundCaptureNotifyImpl **pdscn)
613 {
614     IDirectSoundCaptureNotifyImpl * dscn;
615     TRACE("(%p,%p)\n",dscb,pdscn);
616
617     dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscn));
618
619     if (dscn == NULL) {
620         WARN("out of memory\n");
621         return DSERR_OUTOFMEMORY;
622     }
623
624     dscn->ref = 0;
625     dscn->lpVtbl = &dscnvt;
626     dscn->dscb = dscb;
627     dscb->notify = dscn;
628     IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb);
629
630     *pdscn = dscn;
631     return DS_OK;
632 }
633
634 /*******************************************************************************
635  *              IDirectSoundCaptureBuffer
636  */
637 static HRESULT WINAPI
638 IDirectSoundCaptureBufferImpl_QueryInterface(
639     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
640     REFIID riid,
641     LPVOID* ppobj )
642 {
643     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
644     HRESULT hres;
645     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
646
647     if (ppobj == NULL) {
648         WARN("invalid parameter\n");
649         return E_INVALIDARG;
650     }
651
652     *ppobj = NULL;
653
654     if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
655         if (!This->notify)
656             hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify);
657         if (This->notify) {
658             IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
659             if (This->device->hwbuf && !This->hwnotify) {
660                 hres = IDsCaptureDriverBuffer_QueryInterface(This->device->hwbuf,
661                     &IID_IDsDriverNotify, (LPVOID*)&(This->hwnotify));
662                 if (hres != DS_OK) {
663                     WARN("IDsCaptureDriverBuffer_QueryInterface failed\n");
664                     IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
665                     *ppobj = 0;
666                     return hres;
667                 }
668             }
669
670             *ppobj = This->notify;
671             return DS_OK;
672         }
673
674         WARN("IID_IDirectSoundNotify\n");
675         return E_FAIL;
676     }
677
678     if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
679          IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
680         IDirectSoundCaptureBuffer8_AddRef(iface);
681         *ppobj = This;
682         return NO_ERROR;
683     }
684
685     FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
686     return E_NOINTERFACE;
687 }
688
689 static ULONG WINAPI
690 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
691 {
692     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
693     ULONG ref = InterlockedIncrement(&(This->ref));
694     TRACE("(%p) ref was %d\n", This, ref - 1);
695     return ref;
696 }
697
698 static ULONG WINAPI
699 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
700 {
701     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
702     ULONG ref = InterlockedDecrement(&(This->ref));
703     TRACE("(%p) ref was %d\n", This, ref + 1);
704
705     if (!ref) {
706         TRACE("deleting object\n");
707         if (This->device->state == STATE_CAPTURING)
708             This->device->state = STATE_STOPPING;
709
710         HeapFree(GetProcessHeap(),0, This->pdscbd);
711
712         if (This->device->hwi) {
713             waveInReset(This->device->hwi);
714             waveInClose(This->device->hwi);
715             HeapFree(GetProcessHeap(),0, This->device->pwave);
716             This->device->pwave = 0;
717             This->device->hwi = 0;
718         }
719
720         if (This->device->hwbuf)
721             IDsCaptureDriverBuffer_Release(This->device->hwbuf);
722
723         /* remove from DirectSoundCaptureDevice */
724         This->device->capture_buffer = NULL;
725
726         if (This->notify)
727             IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
728
729         /* If driver manages its own buffer, IDsCaptureDriverBuffer_Release
730            should have freed the buffer. Prevent freeing it again in
731            IDirectSoundCaptureBufferImpl_Create */
732         if (!(This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY))
733             This->device->buffer = NULL;
734
735         HeapFree(GetProcessHeap(), 0, This->notifies);
736         HeapFree( GetProcessHeap(), 0, This );
737         TRACE("(%p) released\n", This);
738     }
739     return ref;
740 }
741
742 static HRESULT WINAPI
743 IDirectSoundCaptureBufferImpl_GetCaps(
744     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
745     LPDSCBCAPS lpDSCBCaps )
746 {
747     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
748     TRACE( "(%p,%p)\n", This, lpDSCBCaps );
749
750     if (lpDSCBCaps == NULL) {
751         WARN("invalid parameter: lpDSCBCaps == NULL\n");
752         return DSERR_INVALIDPARAM;
753     }
754
755     if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
756         WARN("invalid parameter: lpDSCBCaps->dwSize = %d\n", lpDSCBCaps->dwSize);
757         return DSERR_INVALIDPARAM;
758     }
759
760     if (This->device == NULL) {
761         WARN("invalid parameter: This->device == NULL\n");
762         return DSERR_INVALIDPARAM;
763     }
764
765     lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
766     lpDSCBCaps->dwFlags = This->flags;
767     lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
768     lpDSCBCaps->dwReserved = 0;
769
770     TRACE("returning DS_OK\n");
771     return DS_OK;
772 }
773
774 static HRESULT WINAPI
775 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
776     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
777     LPDWORD lpdwCapturePosition,
778     LPDWORD lpdwReadPosition )
779 {
780     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
781     HRESULT hres = DS_OK;
782     TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
783
784     if (This->device == NULL) {
785         WARN("invalid parameter: This->device == NULL\n");
786         return DSERR_INVALIDPARAM;
787     }
788
789     if (This->device->driver) {
790         hres = IDsCaptureDriverBuffer_GetPosition(This->device->hwbuf, lpdwCapturePosition, lpdwReadPosition );
791         if (hres != DS_OK)
792             WARN("IDsCaptureDriverBuffer_GetPosition failed\n");
793     } else if (This->device->hwi) {
794         DWORD pos;
795
796         EnterCriticalSection(&This->device->lock);
797         pos = (DWORD_PTR)This->device->pwave[This->device->index].lpData - (DWORD_PTR)This->device->buffer;
798         if (lpdwCapturePosition)
799             *lpdwCapturePosition = (This->device->pwave[This->device->index].dwBufferLength + pos) % This->device->buflen;
800         if (lpdwReadPosition)
801             *lpdwReadPosition = pos;
802         LeaveCriticalSection(&This->device->lock);
803
804     } else {
805         WARN("no driver\n");
806         hres = DSERR_NODRIVER;
807     }
808
809     TRACE("cappos=%d readpos=%d\n", (lpdwCapturePosition?*lpdwCapturePosition:-1), (lpdwReadPosition?*lpdwReadPosition:-1));
810     TRACE("returning %08x\n", hres);
811     return hres;
812 }
813
814 static HRESULT WINAPI
815 IDirectSoundCaptureBufferImpl_GetFormat(
816     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
817     LPWAVEFORMATEX lpwfxFormat,
818     DWORD dwSizeAllocated,
819     LPDWORD lpdwSizeWritten )
820 {
821     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
822     HRESULT hres = DS_OK;
823     TRACE( "(%p,%p,0x%08x,%p)\n", This, lpwfxFormat, dwSizeAllocated,
824         lpdwSizeWritten );
825
826     if (This->device == NULL) {
827         WARN("invalid parameter: This->device == NULL\n");
828         return DSERR_INVALIDPARAM;
829     }
830
831     if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize))
832         dwSizeAllocated = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
833
834     if (lpwfxFormat) { /* NULL is valid (just want size) */
835         CopyMemory(lpwfxFormat, This->device->pwfx, dwSizeAllocated);
836         if (lpdwSizeWritten)
837             *lpdwSizeWritten = dwSizeAllocated;
838     } else {
839         if (lpdwSizeWritten)
840             *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
841         else {
842             TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
843             hres = DSERR_INVALIDPARAM;
844         }
845     }
846
847     TRACE("returning %08x\n", hres);
848     return hres;
849 }
850
851 static HRESULT WINAPI
852 IDirectSoundCaptureBufferImpl_GetStatus(
853     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
854     LPDWORD lpdwStatus )
855 {
856     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
857     TRACE( "(%p, %p), thread is %04x\n", This, lpdwStatus, GetCurrentThreadId() );
858
859     if (This->device == NULL) {
860         WARN("invalid parameter: This->device == NULL\n");
861         return DSERR_INVALIDPARAM;
862     }
863
864     if (lpdwStatus == NULL) {
865         WARN("invalid parameter: lpdwStatus == NULL\n");
866         return DSERR_INVALIDPARAM;
867     }
868
869     *lpdwStatus = 0;
870     EnterCriticalSection(&(This->device->lock));
871
872     TRACE("old This->device->state=%s, old lpdwStatus=%08x\n",
873         captureStateString[This->device->state],*lpdwStatus);
874     if ((This->device->state == STATE_STARTING) ||
875         (This->device->state == STATE_CAPTURING)) {
876         *lpdwStatus |= DSCBSTATUS_CAPTURING;
877         if (This->flags & DSCBSTART_LOOPING)
878             *lpdwStatus |= DSCBSTATUS_LOOPING;
879     }
880     TRACE("new This->device->state=%s, new lpdwStatus=%08x\n",
881         captureStateString[This->device->state],*lpdwStatus);
882     LeaveCriticalSection(&(This->device->lock));
883
884     TRACE("status=%x\n", *lpdwStatus);
885     TRACE("returning DS_OK\n");
886     return DS_OK;
887 }
888
889 static HRESULT WINAPI
890 IDirectSoundCaptureBufferImpl_Initialize(
891     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
892     LPDIRECTSOUNDCAPTURE lpDSC,
893     LPCDSCBUFFERDESC lpcDSCBDesc )
894 {
895     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
896
897     FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
898
899     return DS_OK;
900 }
901
902 static HRESULT WINAPI
903 IDirectSoundCaptureBufferImpl_Lock(
904     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
905     DWORD dwReadCusor,
906     DWORD dwReadBytes,
907     LPVOID* lplpvAudioPtr1,
908     LPDWORD lpdwAudioBytes1,
909     LPVOID* lplpvAudioPtr2,
910     LPDWORD lpdwAudioBytes2,
911     DWORD dwFlags )
912 {
913     HRESULT hres = DS_OK;
914     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
915     TRACE( "(%p,%08u,%08u,%p,%p,%p,%p,0x%08x) at %d\n", This, dwReadCusor,
916         dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
917         lpdwAudioBytes2, dwFlags, GetTickCount() );
918
919     if (This->device == NULL) {
920         WARN("invalid parameter: This->device == NULL\n");
921         return DSERR_INVALIDPARAM;
922     }
923
924     if (lplpvAudioPtr1 == NULL) {
925         WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
926         return DSERR_INVALIDPARAM;
927     }
928
929     if (lpdwAudioBytes1 == NULL) {
930         WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
931         return DSERR_INVALIDPARAM;
932     }
933
934     EnterCriticalSection(&(This->device->lock));
935
936     if (This->device->driver) {
937         hres = IDsCaptureDriverBuffer_Lock(This->device->hwbuf, lplpvAudioPtr1,
938                                            lpdwAudioBytes1, lplpvAudioPtr2,
939                                            lpdwAudioBytes2, dwReadCusor,
940                                            dwReadBytes, dwFlags);
941         if (hres != DS_OK)
942             WARN("IDsCaptureDriverBuffer_Lock failed\n");
943     } else if (This->device->hwi) {
944         *lplpvAudioPtr1 = This->device->buffer + dwReadCusor;
945         if ( (dwReadCusor + dwReadBytes) > This->device->buflen) {
946             *lpdwAudioBytes1 = This->device->buflen - dwReadCusor;
947             if (lplpvAudioPtr2)
948                 *lplpvAudioPtr2 = This->device->buffer;
949             if (lpdwAudioBytes2)
950                 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
951         } else {
952             *lpdwAudioBytes1 = dwReadBytes;
953             if (lplpvAudioPtr2)
954                 *lplpvAudioPtr2 = 0;
955             if (lpdwAudioBytes2)
956                 *lpdwAudioBytes2 = 0;
957         }
958     } else {
959         TRACE("invalid call\n");
960         hres = DSERR_INVALIDCALL;   /* DSERR_NODRIVER ? */
961     }
962
963     LeaveCriticalSection(&(This->device->lock));
964
965     TRACE("returning %08x\n", hres);
966     return hres;
967 }
968
969 static HRESULT WINAPI
970 IDirectSoundCaptureBufferImpl_Start(
971     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
972     DWORD dwFlags )
973 {
974     HRESULT hres = DS_OK;
975     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
976     TRACE( "(%p,0x%08x)\n", This, dwFlags );
977
978     if (This->device == NULL) {
979         WARN("invalid parameter: This->device == NULL\n");
980         return DSERR_INVALIDPARAM;
981     }
982
983     if ( (This->device->driver == 0) && (This->device->hwi == 0) ) {
984         WARN("no driver\n");
985         return DSERR_NODRIVER;
986     }
987
988     EnterCriticalSection(&(This->device->lock));
989
990     This->flags = dwFlags;
991     TRACE("old This->state=%s\n",captureStateString[This->device->state]);
992     if (This->device->state == STATE_STOPPED)
993         This->device->state = STATE_STARTING;
994     else if (This->device->state == STATE_STOPPING)
995         This->device->state = STATE_CAPTURING;
996     TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
997
998     LeaveCriticalSection(&(This->device->lock));
999
1000     if (This->device->driver) {
1001         hres = IDsCaptureDriverBuffer_Start(This->device->hwbuf, dwFlags);
1002         if (hres != DS_OK)
1003             WARN("IDsCaptureDriverBuffer_Start failed\n");
1004     } else if (This->device->hwi) {
1005         DirectSoundCaptureDevice *device = This->device;
1006
1007         if (device->buffer) {
1008             int c;
1009             DWORD blocksize = DSOUND_fraglen(device->pwfx->nSamplesPerSec, device->pwfx->nBlockAlign);
1010             device->nrofpwaves = device->buflen / blocksize + !!(device->buflen % blocksize);
1011             TRACE("nrofpwaves=%d\n", device->nrofpwaves);
1012
1013             /* prepare headers */
1014             if (device->pwave)
1015                 device->pwave = HeapReAlloc(GetProcessHeap(), 0,device->pwave, device->nrofpwaves*sizeof(WAVEHDR));
1016             else
1017                 device->pwave = HeapAlloc(GetProcessHeap(), 0, device->nrofpwaves*sizeof(WAVEHDR));
1018
1019             for (c = 0; c < device->nrofpwaves; ++c) {
1020                 device->pwave[c].lpData = (char *)device->buffer + c * blocksize;
1021                 if (c + 1 == device->nrofpwaves)
1022                     device->pwave[c].dwBufferLength = device->buflen - c * blocksize;
1023                 else
1024                     device->pwave[c].dwBufferLength = blocksize;
1025                 device->pwave[c].dwBytesRecorded = 0;
1026                 device->pwave[c].dwUser = (DWORD_PTR)device;
1027                 device->pwave[c].dwFlags = 0;
1028                 device->pwave[c].dwLoops = 0;
1029                 hres = mmErr(waveInPrepareHeader(device->hwi, &(device->pwave[c]),sizeof(WAVEHDR)));
1030                 if (hres != DS_OK) {
1031                     WARN("waveInPrepareHeader failed\n");
1032                     while (c--)
1033                         waveInUnprepareHeader(device->hwi, &(device->pwave[c]),sizeof(WAVEHDR));
1034                     break;
1035                 }
1036
1037                 hres = mmErr(waveInAddBuffer(device->hwi, &(device->pwave[c]), sizeof(WAVEHDR)));
1038                 if (hres != DS_OK) {
1039                     WARN("waveInAddBuffer failed\n");
1040                     while (c--)
1041                         waveInUnprepareHeader(device->hwi, &(device->pwave[c]),sizeof(WAVEHDR));
1042                     break;
1043                 }
1044             }
1045
1046             FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
1047         }
1048
1049         device->index = 0;
1050
1051         if (hres == DS_OK) {
1052             /* start filling the first buffer */
1053             hres = mmErr(waveInStart(device->hwi));
1054             if (hres != DS_OK)
1055                 WARN("waveInStart failed\n");
1056         }
1057
1058         if (hres != DS_OK) {
1059             WARN("calling waveInClose because of error\n");
1060             waveInClose(device->hwi);
1061             device->hwi = 0;
1062         }
1063     } else {
1064         WARN("no driver\n");
1065         hres = DSERR_NODRIVER;
1066     }
1067
1068     TRACE("returning %08x\n", hres);
1069     return hres;
1070 }
1071
1072 static HRESULT WINAPI
1073 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
1074 {
1075     HRESULT hres = DS_OK;
1076     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1077     TRACE( "(%p)\n", This );
1078
1079     if (This->device == NULL) {
1080         WARN("invalid parameter: This->device == NULL\n");
1081         return DSERR_INVALIDPARAM;
1082     }
1083
1084     EnterCriticalSection(&(This->device->lock));
1085
1086     TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
1087     if (This->device->state == STATE_CAPTURING)
1088         This->device->state = STATE_STOPPING;
1089     else if (This->device->state == STATE_STARTING)
1090         This->device->state = STATE_STOPPED;
1091     TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
1092
1093     LeaveCriticalSection(&(This->device->lock));
1094
1095     if (This->device->driver) {
1096         hres = IDsCaptureDriverBuffer_Stop(This->device->hwbuf);
1097         if (hres != DS_OK)
1098             WARN("IDsCaptureDriverBuffer_Stop() failed\n");
1099     } else if (This->device->hwi) {
1100         hres = mmErr(waveInReset(This->device->hwi));
1101         if (hres != DS_OK)
1102             WARN("waveInReset() failed\n");
1103     } else {
1104         WARN("no driver\n");
1105         hres = DSERR_NODRIVER;
1106     }
1107
1108     TRACE("returning %08x\n", hres);
1109     return hres;
1110 }
1111
1112 static HRESULT WINAPI
1113 IDirectSoundCaptureBufferImpl_Unlock(
1114     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1115     LPVOID lpvAudioPtr1,
1116     DWORD dwAudioBytes1,
1117     LPVOID lpvAudioPtr2,
1118     DWORD dwAudioBytes2 )
1119 {
1120     HRESULT hres = DS_OK;
1121     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1122     TRACE( "(%p,%p,%08u,%p,%08u)\n", This, lpvAudioPtr1, dwAudioBytes1,
1123         lpvAudioPtr2, dwAudioBytes2 );
1124
1125     if (lpvAudioPtr1 == NULL) {
1126         WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
1127         return DSERR_INVALIDPARAM;
1128     }
1129
1130     if (This->device->driver) {
1131         hres = IDsCaptureDriverBuffer_Unlock(This->device->hwbuf, lpvAudioPtr1,
1132                                              dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1133         if (hres != DS_OK)
1134             WARN("IDsCaptureDriverBuffer_Unlock failed\n");
1135     } else if (!This->device->hwi) {
1136         WARN("invalid call\n");
1137         hres = DSERR_INVALIDCALL;
1138     }
1139
1140     TRACE("returning %08x\n", hres);
1141     return hres;
1142 }
1143
1144 static HRESULT WINAPI
1145 IDirectSoundCaptureBufferImpl_GetObjectInPath(
1146     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1147     REFGUID rguidObject,
1148     DWORD dwIndex,
1149     REFGUID rguidInterface,
1150     LPVOID* ppObject )
1151 {
1152     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1153
1154     FIXME( "(%p,%s,%u,%s,%p): stub\n", This, debugstr_guid(rguidObject),
1155         dwIndex, debugstr_guid(rguidInterface), ppObject );
1156
1157     return DS_OK;
1158 }
1159
1160 static HRESULT WINAPI
1161 IDirectSoundCaptureBufferImpl_GetFXStatus(
1162     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1163     DWORD dwFXCount,
1164     LPDWORD pdwFXStatus )
1165 {
1166     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1167
1168     FIXME( "(%p,%u,%p): stub\n", This, dwFXCount, pdwFXStatus );
1169
1170     return DS_OK;
1171 }
1172
1173 static const IDirectSoundCaptureBuffer8Vtbl dscbvt =
1174 {
1175     /* IUnknown methods */
1176     IDirectSoundCaptureBufferImpl_QueryInterface,
1177     IDirectSoundCaptureBufferImpl_AddRef,
1178     IDirectSoundCaptureBufferImpl_Release,
1179
1180     /* IDirectSoundCaptureBuffer methods */
1181     IDirectSoundCaptureBufferImpl_GetCaps,
1182     IDirectSoundCaptureBufferImpl_GetCurrentPosition,
1183     IDirectSoundCaptureBufferImpl_GetFormat,
1184     IDirectSoundCaptureBufferImpl_GetStatus,
1185     IDirectSoundCaptureBufferImpl_Initialize,
1186     IDirectSoundCaptureBufferImpl_Lock,
1187     IDirectSoundCaptureBufferImpl_Start,
1188     IDirectSoundCaptureBufferImpl_Stop,
1189     IDirectSoundCaptureBufferImpl_Unlock,
1190
1191     /* IDirectSoundCaptureBuffer methods */
1192     IDirectSoundCaptureBufferImpl_GetObjectInPath,
1193     IDirectSoundCaptureBufferImpl_GetFXStatus
1194 };
1195
1196 HRESULT IDirectSoundCaptureBufferImpl_Create(
1197     DirectSoundCaptureDevice *device,
1198     IDirectSoundCaptureBufferImpl ** ppobj,
1199     LPCDSCBUFFERDESC lpcDSCBufferDesc)
1200 {
1201     LPWAVEFORMATEX  wfex;
1202     TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
1203
1204     if (ppobj == NULL) {
1205         WARN("invalid parameter: ppobj == NULL\n");
1206         return DSERR_INVALIDPARAM;
1207     }
1208
1209     if (!device) {
1210         WARN("not initialized\n");
1211         *ppobj = NULL;
1212         return DSERR_UNINITIALIZED;
1213     }
1214
1215     if (lpcDSCBufferDesc == NULL) {
1216         WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
1217         *ppobj = NULL;
1218         return DSERR_INVALIDPARAM;
1219     }
1220
1221     if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
1222           (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
1223         (lpcDSCBufferDesc->dwBufferBytes == 0) ||
1224         (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { /* FIXME: DSERR_BADFORMAT ? */
1225         WARN("invalid lpcDSCBufferDesc\n");
1226         *ppobj = NULL;
1227         return DSERR_INVALIDPARAM;
1228     }
1229
1230     wfex = lpcDSCBufferDesc->lpwfxFormat;
1231
1232     TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1233         "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1234         wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
1235         wfex->nAvgBytesPerSec, wfex->nBlockAlign,
1236         wfex->wBitsPerSample, wfex->cbSize);
1237
1238     device->pwfx = DSOUND_CopyFormat(wfex);
1239     if ( device->pwfx == NULL ) {
1240         *ppobj = NULL;
1241         return DSERR_OUTOFMEMORY;
1242     }
1243
1244     *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1245         sizeof(IDirectSoundCaptureBufferImpl));
1246
1247     if ( *ppobj == NULL ) {
1248         WARN("out of memory\n");
1249         *ppobj = NULL;
1250         return DSERR_OUTOFMEMORY;
1251     } else {
1252         HRESULT err = DS_OK;
1253         LPBYTE newbuf;
1254         DWORD buflen;
1255         IDirectSoundCaptureBufferImpl *This = *ppobj;
1256
1257         This->ref = 1;
1258         This->device = device;
1259         This->device->capture_buffer = This;
1260         This->notify = NULL;
1261         This->nrofnotifies = 0;
1262         This->hwnotify = NULL;
1263
1264         This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1265             lpcDSCBufferDesc->dwSize);
1266         if (This->pdscbd)
1267             CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
1268         else {
1269             WARN("no memory\n");
1270             This->device->capture_buffer = 0;
1271             HeapFree( GetProcessHeap(), 0, This );
1272             *ppobj = NULL;
1273             return DSERR_OUTOFMEMORY;
1274         }
1275
1276         This->lpVtbl = &dscbvt;
1277
1278         if (device->driver) {
1279             if (This->device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1280                 FIXME("DSDDESC_DOMMSYSTEMOPEN not supported\n");
1281
1282             if (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
1283                 /* allocate buffer from system memory */
1284                 buflen = lpcDSCBufferDesc->dwBufferBytes;
1285                 TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
1286                 if (device->buffer)
1287                     newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
1288                 else
1289                     newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
1290
1291                 if (newbuf == NULL) {
1292                     WARN("failed to allocate capture buffer\n");
1293                     err = DSERR_OUTOFMEMORY;
1294                     /* but the old buffer might still exist and must be re-prepared */
1295                 } else {
1296                     device->buffer = newbuf;
1297                     device->buflen = buflen;
1298                 }
1299             } else {
1300                 /* let driver allocate memory */
1301                 device->buflen = lpcDSCBufferDesc->dwBufferBytes;
1302                 /* FIXME: */
1303                 HeapFree( GetProcessHeap(), 0, device->buffer);
1304                 device->buffer = NULL;
1305             }
1306
1307             err = IDsCaptureDriver_CreateCaptureBuffer(device->driver,
1308                 device->pwfx,0,0,&(device->buflen),&(device->buffer),(LPVOID*)&(device->hwbuf));
1309             if (err != DS_OK) {
1310                 WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n");
1311                 This->device->capture_buffer = 0;
1312                 HeapFree( GetProcessHeap(), 0, This );
1313                 *ppobj = NULL;
1314                 return err;
1315             }
1316         } else {
1317             DWORD flags = CALLBACK_FUNCTION;
1318             err = mmErr(waveInOpen(&(device->hwi),
1319                 device->drvdesc.dnDevNode, device->pwfx,
1320                 (DWORD_PTR)DSOUND_capture_callback, (DWORD_PTR)device, flags));
1321             if (err != DS_OK) {
1322                 WARN("waveInOpen failed\n");
1323                 This->device->capture_buffer = 0;
1324                 HeapFree( GetProcessHeap(), 0, This );
1325                 *ppobj = NULL;
1326                 return err;
1327             }
1328
1329             buflen = lpcDSCBufferDesc->dwBufferBytes;
1330             TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
1331             if (device->buffer)
1332                 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
1333             else
1334                 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
1335             if (newbuf == NULL) {
1336                 WARN("failed to allocate capture buffer\n");
1337                 err = DSERR_OUTOFMEMORY;
1338                 /* but the old buffer might still exist and must be re-prepared */
1339             } else {
1340                 device->buffer = newbuf;
1341                 device->buflen = buflen;
1342             }
1343         }
1344     }
1345
1346     TRACE("returning DS_OK\n");
1347     return DS_OK;
1348 }
1349
1350 /*******************************************************************************
1351  * DirectSoundCaptureDevice
1352  */
1353 HRESULT DirectSoundCaptureDevice_Initialize(
1354     DirectSoundCaptureDevice ** ppDevice,
1355     LPCGUID lpcGUID)
1356 {
1357     HRESULT err = DSERR_INVALIDPARAM;
1358     unsigned wid, widn;
1359     BOOLEAN found = FALSE;
1360     GUID devGUID;
1361     DirectSoundCaptureDevice *device = *ppDevice;
1362     TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
1363
1364     /* Default device? */
1365     if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
1366         lpcGUID = &DSDEVID_DefaultCapture;
1367
1368     if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1369         WARN("invalid parameter: lpcGUID\n");
1370         return DSERR_INVALIDPARAM;
1371     }
1372
1373     widn = waveInGetNumDevs();
1374     if (!widn) {
1375         WARN("no audio devices found\n");
1376         return DSERR_NODRIVER;
1377     }
1378
1379     /* enumerate WINMM audio devices and find the one we want */
1380     for (wid=0; wid<widn; wid++) {
1381         if (IsEqualGUID( &devGUID, &DSOUND_capture_guids[wid]) ) {
1382             found = TRUE;
1383             break;
1384         }
1385     }
1386
1387     if (found == FALSE) {
1388         WARN("No device found matching given ID!\n");
1389         return DSERR_NODRIVER;
1390     }
1391
1392     if (DSOUND_capture[wid]) {
1393         WARN("already in use\n");
1394         return DSERR_ALLOCATED;
1395     }
1396
1397     err = DirectSoundCaptureDevice_Create(&(device));
1398     if (err != DS_OK) {
1399         WARN("DirectSoundCaptureDevice_Create failed\n");
1400         return err;
1401     }
1402
1403     *ppDevice = device;
1404     device->guid = devGUID;
1405
1406     /* Disable the direct sound driver to force emulation if requested. */
1407     device->driver = NULL;
1408     if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
1409     {
1410         err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDIFACE,(DWORD_PTR)&device->driver,0));
1411         if ( (err != DS_OK) && (err != DSERR_UNSUPPORTED) ) {
1412             WARN("waveInMessage failed; err=%x\n",err);
1413             return err;
1414         }
1415     }
1416     err = DS_OK;
1417
1418     /* Get driver description */
1419     if (device->driver) {
1420         TRACE("using DirectSound driver\n");
1421         err = IDsCaptureDriver_GetDriverDesc(device->driver, &(device->drvdesc));
1422         if (err != DS_OK) {
1423             WARN("IDsCaptureDriver_GetDriverDesc failed\n");
1424             return err;
1425         }
1426     } else {
1427         TRACE("using WINMM\n");
1428         /* if no DirectSound interface available, use WINMM API instead */
1429         device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN |
1430             DSDDESC_DOMMSYSTEMSETFORMAT;
1431     }
1432
1433     device->drvdesc.dnDevNode = wid;
1434
1435     /* open the DirectSound driver if available */
1436     if (device->driver && (err == DS_OK))
1437         err = IDsCaptureDriver_Open(device->driver);
1438
1439     if (err == DS_OK) {
1440         *ppDevice = device;
1441
1442         /* the driver is now open, so it's now allowed to call GetCaps */
1443         if (device->driver) {
1444             device->drvcaps.dwSize = sizeof(device->drvcaps);
1445             err = IDsCaptureDriver_GetCaps(device->driver,&(device->drvcaps));
1446             if (err != DS_OK) {
1447                 WARN("IDsCaptureDriver_GetCaps failed\n");
1448                 return err;
1449             }
1450         } else /*if (device->hwi)*/ {
1451             WAVEINCAPSA    wic;
1452             err = mmErr(waveInGetDevCapsA((UINT)device->drvdesc.dnDevNode, &wic, sizeof(wic)));
1453
1454             if (err == DS_OK) {
1455                 device->drvcaps.dwFlags = 0;
1456                 lstrcpynA(device->drvdesc.szDrvname, wic.szPname,
1457                           sizeof(device->drvdesc.szDrvname));
1458
1459                 device->drvcaps.dwFlags |= DSCCAPS_EMULDRIVER;
1460                 device->drvcaps.dwFormats = wic.dwFormats;
1461                 device->drvcaps.dwChannels = wic.wChannels;
1462             }
1463         }
1464     }
1465
1466     return err;
1467 }
1468
1469 static HRESULT DirectSoundCaptureDevice_Create(
1470     DirectSoundCaptureDevice ** ppDevice)
1471 {
1472     DirectSoundCaptureDevice * device;
1473     TRACE("(%p)\n", ppDevice);
1474
1475     /* Allocate memory */
1476     device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
1477
1478     if (device == NULL) {
1479         WARN("out of memory\n");
1480         return DSERR_OUTOFMEMORY;
1481     }
1482
1483     device->ref = 1;
1484     device->state = STATE_STOPPED;
1485
1486     InitializeCriticalSection( &(device->lock) );
1487     device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
1488
1489     *ppDevice = device;
1490
1491     return DS_OK;
1492 }
1493
1494 ULONG DirectSoundCaptureDevice_Release(
1495     DirectSoundCaptureDevice * device)
1496 {
1497     ULONG ref = InterlockedDecrement(&(device->ref));
1498     TRACE("(%p) ref was %d\n", device, ref + 1);
1499
1500     if (!ref) {
1501         TRACE("deleting object\n");
1502         if (device->capture_buffer)
1503             IDirectSoundCaptureBufferImpl_Release(
1504                 (LPDIRECTSOUNDCAPTUREBUFFER8) device->capture_buffer);
1505
1506         if (device->driver) {
1507             IDsCaptureDriver_Close(device->driver);
1508             IDsCaptureDriver_Release(device->driver);
1509         }
1510
1511         HeapFree(GetProcessHeap(), 0, device->pwfx);
1512         device->lock.DebugInfo->Spare[0] = 0;
1513         DeleteCriticalSection( &(device->lock) );
1514         DSOUND_capture[device->drvdesc.dnDevNode] = NULL;
1515         HeapFree(GetProcessHeap(), 0, device);
1516         TRACE("(%p) released\n", device);
1517     }
1518     return ref;
1519 }