~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/dsound/capture.c

Version: ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  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 /***************************************************************************
258  * DirectSoundCaptureEnumerateA [DSOUND.7]
259  *
260  * Enumerate all DirectSound drivers installed in the system.
261  *
262  * PARAMS
263  *    lpDSEnumCallback  [I] Address of callback function.
264  *    lpContext         [I] Address of user defined context passed to callback function.
265  *
266  * RETURNS
267  *    Success: DS_OK
268  *    Failure: DSERR_INVALIDPARAM
269  */
270 HRESULT WINAPI
271 DirectSoundCaptureEnumerateA(
272     LPDSENUMCALLBACKA lpDSEnumCallback,
273     LPVOID lpContext)
274 {
275     unsigned devs, wid;
276     DSDRIVERDESC desc;
277     GUID guid;
278     int err;
279 
280     TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
281 
282     if (lpDSEnumCallback == NULL) {
283         WARN("invalid parameter: lpDSEnumCallback == NULL\n");
284         return DSERR_INVALIDPARAM;
285     }
286 
287     devs = waveInGetNumDevs();
288     if (devs > 0) {
289         if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) {
290             for (wid = 0; wid < devs; ++wid) {
291                 if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) {
292                     err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
293                     if (err == DS_OK) {
294                         TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
295                               "Primary Sound Capture Driver",desc.szDrvname,lpContext);
296                         if (lpDSEnumCallback(NULL, "Primary Sound Capture Driver", desc.szDrvname, lpContext) == FALSE)
297                             return DS_OK;
298                     }
299                 }
300             }
301         }
302     }
303 
304     for (wid = 0; wid < devs; ++wid) {
305         err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
306         if (err == DS_OK) {
307             TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
308                   debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext);
309             if (lpDSEnumCallback(&DSOUND_capture_guids[wid], desc.szDesc, desc.szDrvname, lpContext) == FALSE)
310                 return DS_OK;
311         }
312     }
313 
314     return DS_OK;
315 }
316 
317 /***************************************************************************
318  * DirectSoundCaptureEnumerateW [DSOUND.8]
319  *
320  * Enumerate all DirectSound drivers installed in the system.
321  *
322  * PARAMS
323  *    lpDSEnumCallback  [I] Address of callback function.
324  *    lpContext         [I] Address of user defined context passed to callback function.
325  *
326  * RETURNS
327  *    Success: DS_OK
328  *    Failure: DSERR_INVALIDPARAM
329  */
330 HRESULT WINAPI
331 DirectSoundCaptureEnumerateW(
332     LPDSENUMCALLBACKW lpDSEnumCallback,
333     LPVOID lpContext)
334 {
335     unsigned devs, wid;
336     DSDRIVERDESC desc;
337     GUID guid;
338     int err;
339     WCHAR wDesc[MAXPNAMELEN];
340     WCHAR wName[MAXPNAMELEN];
341 
342     TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
343 
344     if (lpDSEnumCallback == NULL) {
345         WARN("invalid parameter: lpDSEnumCallback == NULL\n");
346         return DSERR_INVALIDPARAM;
347     }
348 
349     devs = waveInGetNumDevs();
350     if (devs > 0) {
351         if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) {
352             for (wid = 0; wid < devs; ++wid) {
353                 if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) {
354                     err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
355                     if (err == DS_OK) {
356                         TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
357                               "Primary Sound Capture Driver",desc.szDrvname,lpContext);
358                         MultiByteToWideChar( CP_ACP, 0, "Primary Sound Capture Driver", -1,
359                                              wDesc, sizeof(wDesc)/sizeof(WCHAR) );
360                         MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1,
361                                              wName, sizeof(wName)/sizeof(WCHAR) );
362                         if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE)
363                             return DS_OK;
364                     }
365                 }
366             }
367         }
368     }
369 
370     for (wid = 0; wid < devs; ++wid) {
371         err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
372         if (err == DS_OK) {
373             TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
374                   debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext);
375             MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1,
376                                  wDesc, sizeof(wDesc)/sizeof(WCHAR) );
377             MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1,
378                                  wName, sizeof(wName)/sizeof(WCHAR) );
379             if (lpDSEnumCallback(&DSOUND_capture_guids[wid], wDesc, wName, lpContext) == FALSE)
380                 return DS_OK;
381         }
382     }
383 
384     return DS_OK;
385 }
386 
387 static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len)
388 {
389     int i;
390     for (i = 0; i < This->nrofnotifies; ++i) {
391         LPDSBPOSITIONNOTIFY event = This->notifies + i;
392         DWORD offset = event->dwOffset;
393         TRACE("checking %d, position %d, event = %p\n", i, offset, event->hEventNotify);
394 
395         if (offset == DSBPN_OFFSETSTOP) {
396             if (!from && !len) {
397                 SetEvent(event->hEventNotify);
398                 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
399                 return;
400             }
401             else return;
402         }
403 
404         if (offset >= from && offset < (from + len))
405         {
406             TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
407             SetEvent(event->hEventNotify);
408         }
409     }
410 }
411 
412 static void CALLBACK
413 DSOUND_capture_callback(
414     HWAVEIN hwi,
415     UINT msg,
416     DWORD dwUser,
417     DWORD dw1,
418     DWORD dw2 )
419 {
420     DirectSoundCaptureDevice * This = (DirectSoundCaptureDevice*)dwUser;
421     IDirectSoundCaptureBufferImpl * Moi = This->capture_buffer;
422     TRACE("(%p,%08x(%s),%08x,%08x,%08x) entering at %d\n",hwi,msg,
423         msg == MM_WIM_OPEN ? "MM_WIM_OPEN" : msg == MM_WIM_CLOSE ? "MM_WIM_CLOSE" :
424         msg == MM_WIM_DATA ? "MM_WIM_DATA" : "UNKNOWN",dwUser,dw1,dw2,GetTickCount());
425 
426     if (msg == MM_WIM_DATA) {
427         EnterCriticalSection( &(This->lock) );
428         TRACE("DirectSoundCapture msg=MM_WIM_DATA, old This->state=%s, old This->index=%d\n",
429             captureStateString[This->state],This->index);
430         if (This->state != STATE_STOPPED) {
431             int index = This->index;
432             if (This->state == STATE_STARTING)
433                 This->state = STATE_CAPTURING;
434             capture_CheckNotify(Moi, (DWORD_PTR)This->pwave[index].lpData - (DWORD_PTR)This->buffer, This->pwave[index].dwBufferLength);
435             This->index = (++This->index) % This->nrofpwaves;
436             if ( (This->index == 0) && !(This->capture_buffer->flags & DSCBSTART_LOOPING) ) {
437                 TRACE("end of buffer\n");
438                 This->state = STATE_STOPPED;
439                 capture_CheckNotify(Moi, 0, 0);
440             } else {
441                 if (This->state == STATE_CAPTURING) {
442                     waveInUnprepareHeader(hwi, &(This->pwave[index]), sizeof(WAVEHDR));
443                     waveInPrepareHeader(hwi, &(This->pwave[index]), sizeof(WAVEHDR));
444                     waveInAddBuffer(hwi, &(This->pwave[index]), sizeof(WAVEHDR));
445                 } else if (This->state == STATE_STOPPING) {
446                     TRACE("stopping\n");
447                     This->state = STATE_STOPPED;
448                 }
449             }
450         }
451         TRACE("DirectSoundCapture new This->state=%s, new This->index=%d\n",
452             captureStateString[This->state],This->index);
453         LeaveCriticalSection( &(This->lock) );
454     }
455 
456     TRACE("completed\n");
457 }
458 
459 /***************************************************************************
460  * IDirectSoundCaptureImpl
461  */
462 static HRESULT WINAPI
463 IDirectSoundCaptureImpl_QueryInterface(
464     LPDIRECTSOUNDCAPTURE iface,
465     REFIID riid,
466     LPVOID* ppobj )
467 {
468     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
469     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
470 
471     if (ppobj == NULL) {
472         WARN("invalid parameter\n");
473         return E_INVALIDARG;
474     }
475 
476     *ppobj = NULL;
477 
478     if (IsEqualIID(riid, &IID_IUnknown)) {
479         IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This);
480         *ppobj = This;
481         return DS_OK;
482     } else if (IsEqualIID(riid, &IID_IDirectSoundCapture)) {
483         IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This);
484         *ppobj = This;
485         return DS_OK;
486     }
487 
488     WARN("unsupported riid: %s\n", debugstr_guid(riid));
489     return E_NOINTERFACE;
490 }
491 
492 static ULONG WINAPI
493 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface )
494 {
495     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
496     ULONG ref = InterlockedIncrement(&(This->ref));
497     TRACE("(%p) ref was %d\n", This, ref - 1);
498     return ref;
499 }
500 
501 static ULONG WINAPI
502 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface )
503 {
504     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
505     ULONG ref = InterlockedDecrement(&(This->ref));
506     TRACE("(%p) ref was %d\n", This, ref + 1);
507 
508     if (!ref) {
509         if (This->device)
510             DirectSoundCaptureDevice_Release(This->device);
511 
512         HeapFree( GetProcessHeap(), 0, This );
513         TRACE("(%p) released\n", This);
514     }
515     return ref;
516 }
517 
518 HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(
519     LPDIRECTSOUNDCAPTURE iface,
520     LPCDSCBUFFERDESC lpcDSCBufferDesc,
521     LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
522     LPUNKNOWN pUnk )
523 {
524     HRESULT hr;
525     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
526 
527     TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
528 
529     if (lpcDSCBufferDesc == NULL) {
530         WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
531         return DSERR_INVALIDPARAM;
532     }
533 
534     if (lplpDSCaptureBuffer == NULL) {
535         WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
536         return DSERR_INVALIDPARAM;
537     }
538 
539     if (pUnk != NULL) {
540         WARN("invalid parameter: pUnk != NULL\n");
541         return DSERR_INVALIDPARAM;
542     }
543 
544     /* FIXME: We can only have one buffer so what do we do here? */
545     if (This->device->capture_buffer) {
546         WARN("lnvalid parameter: already has buffer\n");
547         return DSERR_INVALIDPARAM;    /* DSERR_GENERIC ? */
548     }
549 
550     hr = IDirectSoundCaptureBufferImpl_Create(This->device,
551         (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
552 
553     if (hr != DS_OK)
554         WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
555 
556     return hr;
557 }
558 
559 HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(
560     LPDIRECTSOUNDCAPTURE iface,
561     LPDSCCAPS lpDSCCaps )
562 {
563     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
564     TRACE("(%p,%p)\n",This,lpDSCCaps);
565 
566     if (This->device == NULL) {
567         WARN("not initialized\n");
568         return DSERR_UNINITIALIZED;
569     }
570 
571     if (lpDSCCaps== NULL) {
572         WARN("invalid parameter: lpDSCCaps== NULL\n");
573         return DSERR_INVALIDPARAM;
574     }
575 
576     if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
577         WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
578         return DSERR_INVALIDPARAM;
579     }
580 
581     lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
582     lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
583     lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
584 
585     TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
586         lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
587 
588     return DS_OK;
589 }
590 
591 HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(
592     LPDIRECTSOUNDCAPTURE iface,
593     LPCGUID lpcGUID )
594 {
595     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
596     TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
597 
598     if (This->device != NULL) {
599         WARN("already initialized\n");
600         return DSERR_ALREADYINITIALIZED;
601     }
602     return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
603 }
604 
605 static const IDirectSoundCaptureVtbl dscvt =
606 {
607     /* IUnknown methods */
608     IDirectSoundCaptureImpl_QueryInterface,
609     IDirectSoundCaptureImpl_AddRef,
610     IDirectSoundCaptureImpl_Release,
611 
612     /* IDirectSoundCapture methods */
613     IDirectSoundCaptureImpl_CreateCaptureBuffer,
614     IDirectSoundCaptureImpl_GetCaps,
615     IDirectSoundCaptureImpl_Initialize
616 };
617 
618 static HRESULT IDirectSoundCaptureImpl_Create(
619     LPDIRECTSOUNDCAPTURE8 * ppDSC)
620 {
621     IDirectSoundCaptureImpl *pDSC;
622     TRACE("(%p)\n", ppDSC);
623 
624     /* Allocate memory */
625     pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
626     if (pDSC == NULL) {
627         WARN("out of memory\n");
628         *ppDSC = NULL;
629         return DSERR_OUTOFMEMORY;
630     }
631 
632     pDSC->lpVtbl = &dscvt;
633     pDSC->ref    = 0;
634     pDSC->device = NULL;
635 
636     *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
637 
638     return DS_OK;
639 }
640 
641 /*******************************************************************************
642  *              IDirectSoundCaptureNotify
643  */
644 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface(
645     LPDIRECTSOUNDNOTIFY iface,
646     REFIID riid,
647     LPVOID *ppobj)
648 {
649     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
650     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
651 
652     if (This->dscb == NULL) {
653         WARN("invalid parameter\n");
654         return E_INVALIDARG;
655     }
656 
657     return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
658 }
659 
660 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
661 {
662     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
663     ULONG ref = InterlockedIncrement(&(This->ref));
664     TRACE("(%p) ref was %d\n", This, ref - 1);
665     return ref;
666 }
667 
668 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
669 {
670     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
671     ULONG ref = InterlockedDecrement(&(This->ref));
672     TRACE("(%p) ref was %d\n", This, ref + 1);
673 
674     if (!ref) {
675         if (This->dscb->hwnotify)
676             IDsDriverNotify_Release(This->dscb->hwnotify);
677         This->dscb->notify=NULL;
678         IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb);
679         HeapFree(GetProcessHeap(),0,This);
680         TRACE("(%p) released\n", This);
681     }
682     return ref;
683 }
684 
685 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions(
686     LPDIRECTSOUNDNOTIFY iface,
687     DWORD howmuch,
688     LPCDSBPOSITIONNOTIFY notify)
689 {
690     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
691     TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
692 
693     if (howmuch > 0 && notify == NULL) {
694         WARN("invalid parameter: notify == NULL\n");
695         return DSERR_INVALIDPARAM;
696     }
697 
698     if (TRACE_ON(dsound)) {
699         unsigned int i;
700         for (i=0;i<howmuch;i++)
701             TRACE("notify at %d to %p\n",
702             notify[i].dwOffset,notify[i].hEventNotify);
703     }
704 
705     if (This->dscb->hwnotify) {
706         HRESULT hres;
707         hres = IDsDriverNotify_SetNotificationPositions(This->dscb->hwnotify, howmuch, notify);
708         if (hres != DS_OK)
709             WARN("IDsDriverNotify_SetNotificationPositions failed\n");
710         return hres;
711     } else if (howmuch > 0) {
712         /* Make an internal copy of the caller-supplied array.
713          * Replace the existing copy if one is already present. */
714         if (This->dscb->notifies)
715             This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
716                 This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
717         else
718             This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
719                 howmuch * sizeof(DSBPOSITIONNOTIFY));
720 
721         if (This->dscb->notifies == NULL) {
722             WARN("out of memory\n");
723             return DSERR_OUTOFMEMORY;
724         }
725         CopyMemory(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
726         This->dscb->nrofnotifies = howmuch;
727     } else {
728         HeapFree(GetProcessHeap(), 0, This->dscb->notifies);
729         This->dscb->notifies = NULL;
730         This->dscb->nrofnotifies = 0;
731     }
732 
733     return S_OK;
734 }
735 
736 static const IDirectSoundNotifyVtbl dscnvt =
737 {
738     IDirectSoundCaptureNotifyImpl_QueryInterface,
739     IDirectSoundCaptureNotifyImpl_AddRef,
740     IDirectSoundCaptureNotifyImpl_Release,
741     IDirectSoundCaptureNotifyImpl_SetNotificationPositions,
742 };
743 
744 static HRESULT IDirectSoundCaptureNotifyImpl_Create(
745     IDirectSoundCaptureBufferImpl *dscb,
746     IDirectSoundCaptureNotifyImpl **pdscn)
747 {
748     IDirectSoundCaptureNotifyImpl * dscn;
749     TRACE("(%p,%p)\n",dscb,pdscn);
750 
751     dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscn));
752 
753     if (dscn == NULL) {
754         WARN("out of memory\n");
755         return DSERR_OUTOFMEMORY;
756     }
757 
758     dscn->ref = 0;
759     dscn->lpVtbl = &dscnvt;
760     dscn->dscb = dscb;
761     dscb->notify = dscn;
762     IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb);
763 
764     *pdscn = dscn;
765     return DS_OK;
766 }
767 
768 /*******************************************************************************
769  *              IDirectSoundCaptureBuffer
770  */
771 static HRESULT WINAPI
772 IDirectSoundCaptureBufferImpl_QueryInterface(
773     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
774     REFIID riid,
775     LPVOID* ppobj )
776 {
777     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
778     HRESULT hres;
779     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
780 
781     if (ppobj == NULL) {
782         WARN("invalid parameter\n");
783         return E_INVALIDARG;
784     }
785 
786     *ppobj = NULL;
787 
788     if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
789         if (!This->notify)
790             hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify);
791         if (This->notify) {
792             IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
793             if (This->device->hwbuf && !This->hwnotify) {
794                 hres = IDsCaptureDriverBuffer_QueryInterface(This->device->hwbuf,
795                     &IID_IDsDriverNotify, (LPVOID*)&(This->hwnotify));
796                 if (hres != DS_OK) {
797                     WARN("IDsCaptureDriverBuffer_QueryInterface failed\n");
798                     IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
799                     *ppobj = 0;
800                     return hres;
801                 }
802             }
803 
804             *ppobj = (LPVOID)This->notify;
805             return DS_OK;
806         }
807 
808         WARN("IID_IDirectSoundNotify\n");
809         return E_FAIL;
810     }
811 
812     if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
813          IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
814         IDirectSoundCaptureBuffer8_AddRef(iface);
815         *ppobj = This;
816         return NO_ERROR;
817     }
818 
819     FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
820     return E_NOINTERFACE;
821 }
822 
823 static ULONG WINAPI
824 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
825 {
826     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
827     ULONG ref = InterlockedIncrement(&(This->ref));
828     TRACE("(%p) ref was %d\n", This, ref - 1);
829     return ref;
830 }
831 
832 static ULONG WINAPI
833 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
834 {
835     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
836     ULONG ref = InterlockedDecrement(&(This->ref));
837     TRACE("(%p) ref was %d\n", This, ref + 1);
838 
839     if (!ref) {
840         TRACE("deleting object\n");
841         if (This->device->state == STATE_CAPTURING)
842             This->device->state = STATE_STOPPING;
843 
844         HeapFree(GetProcessHeap(),0, This->pdscbd);
845 
846         if (This->device->hwi) {
847             waveInReset(This->device->hwi);
848             waveInClose(This->device->hwi);
849             HeapFree(GetProcessHeap(),0, This->device->pwave);
850             This->device->pwave = 0;
851             This->device->hwi = 0;
852         }
853 
854         if (This->device->hwbuf)
855             IDsCaptureDriverBuffer_Release(This->device->hwbuf);
856 
857         /* remove from DirectSoundCaptureDevice */
858         This->device->capture_buffer = NULL;
859 
860         if (This->notify)
861             IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
862 
863         /* If driver manages its own buffer, IDsCaptureDriverBuffer_Release
864            should have freed the buffer. Prevent freeing it again in
865            IDirectSoundCaptureBufferImpl_Create */
866         if (!(This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY))
867             This->device->buffer = NULL;
868 
869         HeapFree(GetProcessHeap(), 0, This->notifies);
870         HeapFree( GetProcessHeap(), 0, This );
871         TRACE("(%p) released\n", This);
872     }
873     return ref;
874 }
875 
876 static HRESULT WINAPI
877 IDirectSoundCaptureBufferImpl_GetCaps(
878     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
879     LPDSCBCAPS lpDSCBCaps )
880 {
881     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
882     TRACE( "(%p,%p)\n", This, lpDSCBCaps );
883 
884     if (lpDSCBCaps == NULL) {
885         WARN("invalid parameter: lpDSCBCap