Removed W->A from DEFWND_ImmIsUIMessageW.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 /*
22  * TODO:
23  *      Implement DirectSoundFullDuplex support.
24  *      Implement FX support.
25  */
26
27 #include "config.h"
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <sys/types.h>
32 #include <sys/fcntl.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "windef.h"
40 #include "winbase.h"
41 #include "wingdi.h"
42 #include "winuser.h"
43 #include "winerror.h"
44 #include "mmsystem.h"
45 #include "mmddk.h"
46 #include "winreg.h"
47 #include "winternl.h"
48 #include "winnls.h"
49 #include "wine/debug.h"
50 #include "dsound.h"
51 #include "dsdriver.h"
52 #include "dsound_private.h"
53
54 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
55
56 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(
57     LPDIRECTSOUNDCAPTURE iface,
58     LPCGUID lpcGUID );
59 static ULONG WINAPI IDirectSoundCaptureImpl_Release(
60     LPDIRECTSOUNDCAPTURE iface );
61 static ULONG WINAPI IDirectSoundCaptureBufferImpl_Release(
62     LPDIRECTSOUNDCAPTUREBUFFER8 iface );
63 static HRESULT DSOUND_CreateDirectSoundCaptureBuffer(
64     IDirectSoundCaptureImpl *ipDSC,
65     LPCDSCBUFFERDESC lpcDSCBufferDesc,
66     LPVOID* ppobj );
67 static HRESULT WINAPI IDirectSoundFullDuplexImpl_Initialize(
68     LPDIRECTSOUNDFULLDUPLEX iface,
69     LPCGUID pCaptureGuid,
70     LPCGUID pRendererGuid,
71     LPCDSCBUFFERDESC lpDscBufferDesc,
72     LPCDSBUFFERDESC lpDsBufferDesc,
73     HWND hWnd,
74     DWORD dwLevel,
75     LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8,
76     LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 );
77
78 static IDirectSoundCaptureVtbl dscvt;
79 static IDirectSoundCaptureBuffer8Vtbl dscbvt;
80 static IDirectSoundFullDuplexVtbl dsfdvt;
81
82 static IDirectSoundCaptureImpl*       dsound_capture = NULL;
83
84 static const char * captureStateString[] = {
85     "STATE_STOPPED",
86     "STATE_STARTING",
87     "STATE_CAPTURING",
88     "STATE_STOPPING"
89 };
90
91 /***************************************************************************
92  * DirectSoundCaptureCreate [DSOUND.6]
93  *
94  * Create and initialize a DirectSoundCapture interface.
95  *
96  * PARAMS
97  *    lpcGUID   [I] Address of the GUID that identifies the sound capture device.
98  *    lplpDSC   [O] Address of a variable to receive the interface pointer.
99  *    pUnkOuter [I] Must be NULL.
100  *
101  * RETURNS
102  *    Success: DS_OK
103  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
104  *             DSERR_OUTOFMEMORY
105  *
106  * NOTES
107  *    lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
108  *    or NULL for the default device or DSDEVID_DefaultCapture or
109  *    DSDEVID_DefaultVoiceCapture.
110  *
111  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
112  */
113 HRESULT WINAPI
114 DirectSoundCaptureCreate8(
115     LPCGUID lpcGUID,
116     LPDIRECTSOUNDCAPTURE* lplpDSC,
117     LPUNKNOWN pUnkOuter )
118 {
119     IDirectSoundCaptureImpl** ippDSC=(IDirectSoundCaptureImpl**)lplpDSC;
120     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), lplpDSC, pUnkOuter);
121
122     if ( pUnkOuter ) {
123         WARN("invalid parameter: pUnkOuter != NULL\n");
124         return DSERR_NOAGGREGATION;
125     }
126
127     if ( !lplpDSC ) {
128         WARN("invalid parameter: lplpDSC == NULL\n");
129         return DSERR_INVALIDPARAM;
130     }
131
132     /* Default device? */
133     if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
134         lpcGUID = &DSDEVID_DefaultCapture;
135
136     *ippDSC = HeapAlloc(GetProcessHeap(),
137         HEAP_ZERO_MEMORY, sizeof(IDirectSoundCaptureImpl));
138
139     if (*ippDSC == NULL) {
140         WARN("out of memory\n");
141         return DSERR_OUTOFMEMORY;
142     } else {
143         IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)*ippDSC;
144
145         This->ref = 1;
146         This->state = STATE_STOPPED;
147
148         InitializeCriticalSection( &(This->lock) );
149         This->lock.DebugInfo->Spare[1] = (DWORD)"DSCAPTURE_lock";
150
151         This->lpVtbl = &dscvt;
152         dsound_capture = This;
153
154         if (GetDeviceID(lpcGUID, &This->guid) == DS_OK) {
155             HRESULT     hres;
156             hres = IDirectSoundCaptureImpl_Initialize( (LPDIRECTSOUNDCAPTURE)This, &This->guid);
157             if (hres != DS_OK)
158                 WARN("IDirectSoundCaptureImpl_Initialize failed\n");
159             return hres;
160         }
161     }
162     WARN("invalid GUID: %s\n", debugstr_guid(lpcGUID));
163     return DSERR_INVALIDPARAM;
164 }
165
166 /***************************************************************************
167  * DirectSoundCaptureEnumerateA [DSOUND.7]
168  *
169  * Enumerate all DirectSound drivers installed in the system.
170  *
171  * PARAMS
172  *    lpDSEnumCallback  [I] Address of callback function.
173  *    lpContext         [I] Address of user defined context passed to callback function.
174  *
175  * RETURNS
176  *    Success: DS_OK
177  *    Failure: DSERR_INVALIDPARAM
178  */
179 HRESULT WINAPI
180 DirectSoundCaptureEnumerateA(
181     LPDSENUMCALLBACKA lpDSEnumCallback,
182     LPVOID lpContext)
183 {
184     unsigned devs, wid;
185     DSDRIVERDESC desc;
186     GUID guid;
187     int err;
188
189     TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
190
191     if (lpDSEnumCallback == NULL) {
192         WARN("invalid parameter: lpDSEnumCallback == NULL\n");
193         return DSERR_INVALIDPARAM;
194     }
195
196     devs = waveInGetNumDevs();
197     if (devs > 0) {
198         if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) {
199             for (wid = 0; wid < devs; ++wid) {
200                 if (IsEqualGUID( &guid, &capture_guids[wid] ) ) {
201                     err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
202                     if (err == DS_OK) {
203                         TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
204                               "Primary Sound Capture Driver",desc.szDrvName,lpContext);
205                         if (lpDSEnumCallback(NULL, "Primary Sound Capture Driver", desc.szDrvName, lpContext) == FALSE)
206                             return DS_OK;
207                     }
208                 }
209             }
210         }
211     }
212
213     for (wid = 0; wid < devs; ++wid) {
214         err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
215         if (err == DS_OK) {
216             TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
217                   debugstr_guid(&capture_guids[wid]),desc.szDesc,desc.szDrvName,lpContext);
218             if (lpDSEnumCallback(&capture_guids[wid], desc.szDesc, desc.szDrvName, lpContext) == FALSE)
219                 return DS_OK;
220         }
221     }
222
223     return DS_OK;
224 }
225
226 /***************************************************************************
227  * DirectSoundCaptureEnumerateW [DSOUND.8]
228  *
229  * Enumerate all DirectSound drivers installed in the system.
230  *
231  * PARAMS
232  *    lpDSEnumCallback  [I] Address of callback function.
233  *    lpContext         [I] Address of user defined context passed to callback function.
234  *
235  * RETURNS
236  *    Success: DS_OK
237  *    Failure: DSERR_INVALIDPARAM
238  */
239 HRESULT WINAPI
240 DirectSoundCaptureEnumerateW(
241     LPDSENUMCALLBACKW lpDSEnumCallback,
242     LPVOID lpContext)
243 {
244     unsigned devs, wid;
245     DSDRIVERDESC desc;
246     GUID guid;
247     int err;
248     WCHAR wDesc[MAXPNAMELEN];
249     WCHAR wName[MAXPNAMELEN];
250
251     TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
252
253     if (lpDSEnumCallback == NULL) {
254         WARN("invalid parameter: lpDSEnumCallback == NULL\n");
255         return DSERR_INVALIDPARAM;
256     }
257
258     devs = waveInGetNumDevs();
259     if (devs > 0) {
260         if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) {
261             for (wid = 0; wid < devs; ++wid) {
262                 if (IsEqualGUID( &guid, &capture_guids[wid] ) ) {
263                     err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
264                     if (err == DS_OK) {
265                         TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
266                               "Primary Sound Capture Driver",desc.szDrvName,lpContext);
267                         MultiByteToWideChar( CP_ACP, 0, "Primary Sound Capture Driver", -1,
268                                              wDesc, sizeof(wDesc)/sizeof(WCHAR) );
269                         MultiByteToWideChar( CP_ACP, 0, desc.szDrvName, -1,
270                                              wName, sizeof(wName)/sizeof(WCHAR) );
271                         if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE)
272                             return DS_OK;
273                     }
274                 }
275             }
276         }
277     }
278
279     for (wid = 0; wid < devs; ++wid) {
280         err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
281         if (err == DS_OK) {
282             TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
283                   debugstr_guid(&capture_guids[wid]),desc.szDesc,desc.szDrvName,lpContext);
284             MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1,
285                                  wDesc, sizeof(wDesc)/sizeof(WCHAR) );
286             MultiByteToWideChar( CP_ACP, 0, desc.szDrvName, -1,
287                                  wName, sizeof(wName)/sizeof(WCHAR) );
288             if (lpDSEnumCallback((LPGUID)&capture_guids[wid], wDesc, wName, lpContext) == FALSE)
289                 return DS_OK;
290         }
291     }
292
293     return DS_OK;
294 }
295
296 static void CALLBACK
297 DSOUND_capture_callback(
298     HWAVEIN hwi,
299     UINT msg,
300     DWORD dwUser,
301     DWORD dw1,
302     DWORD dw2 )
303 {
304     IDirectSoundCaptureImpl* This = (IDirectSoundCaptureImpl*)dwUser;
305     TRACE("(%p,%08x(%s),%08lx,%08lx,%08lx) entering at %ld\n",hwi,msg,
306         msg == MM_WIM_OPEN ? "MM_WIM_OPEN" : msg == MM_WIM_CLOSE ? "MM_WIM_CLOSE" :
307         msg == MM_WIM_DATA ? "MM_WIM_DATA" : "UNKNOWN",dwUser,dw1,dw2,GetTickCount());
308
309     if (msg == MM_WIM_DATA) {
310         LPWAVEHDR pHdr = (LPWAVEHDR)dw1;
311         EnterCriticalSection( &(This->lock) );
312         TRACE("DirectSoundCapture msg=MM_WIM_DATA, old This->state=%s, old This->index=%d\n",
313             captureStateString[This->state],This->index);
314         if (This->state != STATE_STOPPED) {
315             int index = This->index;
316             if (This->state == STATE_STARTING) {
317                 This->read_position = pHdr->dwBytesRecorded;
318                 This->state = STATE_CAPTURING;
319             }
320             waveInUnprepareHeader(hwi,&(This->pwave[This->index]),sizeof(WAVEHDR));
321             if (This->capture_buffer->nrofnotifies)
322                 SetEvent(This->capture_buffer->notifies[This->index].hEventNotify);
323             This->index = (This->index + 1) % This->nrofpwaves;
324             if ( (This->index == 0) && !(This->capture_buffer->flags & DSCBSTART_LOOPING) ) {
325                 TRACE("end of buffer\n");
326                 This->state = STATE_STOPPED;
327             } else {
328                 if (This->state == STATE_CAPTURING) {
329                     waveInPrepareHeader(hwi,&(This->pwave[index]),sizeof(WAVEHDR));
330                     waveInAddBuffer(hwi, &(This->pwave[index]), sizeof(WAVEHDR));
331                 } else if (This->state == STATE_STOPPING) {
332                     TRACE("stopping\n");
333                     This->state = STATE_STOPPED;
334                 }
335             }
336         }
337         TRACE("DirectSoundCapture new This->state=%s, new This->index=%d\n",
338             captureStateString[This->state],This->index);
339         LeaveCriticalSection( &(This->lock) );
340     }
341
342     TRACE("completed\n");
343 }
344
345 static HRESULT WINAPI
346 IDirectSoundCaptureImpl_QueryInterface(
347     LPDIRECTSOUNDCAPTURE iface,
348     REFIID riid,
349     LPVOID* ppobj )
350 {
351     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
352     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
353
354     if (ppobj == NULL) {
355         WARN("invalid parameter\n");
356         return E_INVALIDARG;
357     }
358
359     *ppobj = NULL;
360
361     if (This->driver) {
362         HRESULT hres;
363         hres = IDsCaptureDriver_QueryInterface(This->driver, riid, ppobj);
364         if (hres != DS_OK)
365             WARN("IDsCaptureDriver_QueryInterface failed\n");
366         return hres;
367     }
368
369     WARN("unsupported riid: %s\n", debugstr_guid(riid));
370     return E_FAIL;
371 }
372
373 static ULONG WINAPI
374 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface )
375 {
376     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
377     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
378     return InterlockedIncrement(&(This->ref));
379 }
380
381 static ULONG WINAPI
382 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface )
383 {
384     ULONG uRef;
385     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
386     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
387
388     uRef = InterlockedDecrement(&(This->ref));
389     if ( uRef == 0 ) {
390         TRACE("deleting object\n");
391         if (This->capture_buffer)
392             IDirectSoundCaptureBufferImpl_Release(
393                 (LPDIRECTSOUNDCAPTUREBUFFER8) This->capture_buffer);
394
395         if (This->driver) {
396             IDsCaptureDriver_Close(This->driver);
397             IDsCaptureDriver_Release(This->driver);
398         }
399
400         if (This->pwfx)
401             HeapFree(GetProcessHeap(), 0, This->pwfx);
402
403         This->lock.DebugInfo->Spare[1] = 0;
404         DeleteCriticalSection( &(This->lock) );
405         HeapFree( GetProcessHeap(), 0, This );
406         dsound_capture = NULL;
407         TRACE("(%p) released\n",This);
408     }
409
410     return uRef;
411 }
412
413 static HRESULT WINAPI
414 IDirectSoundCaptureImpl_CreateCaptureBuffer(
415     LPDIRECTSOUNDCAPTURE iface,
416     LPCDSCBUFFERDESC lpcDSCBufferDesc,
417     LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
418     LPUNKNOWN pUnk )
419 {
420     HRESULT hr;
421     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
422
423     TRACE( "(%p,%p,%p,%p)\n",This,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk );
424
425     if (This == NULL) {
426         WARN("invalid parameter: This == NULL\n");
427         return DSERR_INVALIDPARAM;
428     }
429
430     if (lpcDSCBufferDesc == NULL) {
431         WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
432         return DSERR_INVALIDPARAM;
433     }
434
435     if (lplpDSCaptureBuffer == NULL) {
436         WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
437         return DSERR_INVALIDPARAM;
438     }
439
440     if (pUnk != NULL) {
441         WARN("invalid parameter: pUnk != NULL\n");
442         return DSERR_INVALIDPARAM;
443     }
444
445     /* FIXME: We can only have one buffer so what do we do here? */
446     if (This->capture_buffer) {
447         WARN("lnvalid parameter: already has buffer\n");
448         return DSERR_INVALIDPARAM;    /* DSERR_GENERIC ? */
449     }
450
451     hr = DSOUND_CreateDirectSoundCaptureBuffer( This, lpcDSCBufferDesc,
452         (LPVOID*)lplpDSCaptureBuffer );
453
454     if (hr != DS_OK)
455         WARN("DSOUND_CreateDirectSoundCaptureBuffer failed\n");
456
457     return hr;
458 }
459
460 static HRESULT WINAPI
461 IDirectSoundCaptureImpl_GetCaps(
462     LPDIRECTSOUNDCAPTURE iface,
463     LPDSCCAPS lpDSCCaps )
464 {
465     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
466     TRACE("(%p,%p)\n",This,lpDSCCaps);
467
468     if (lpDSCCaps== NULL) {
469         WARN("invalid parameter: lpDSCCaps== NULL\n");
470         return DSERR_INVALIDPARAM;
471     }
472
473     if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
474         WARN("invalid parameter: lpDSCCaps->dwSize = %ld < %d\n",
475             lpDSCCaps->dwSize, sizeof(*lpDSCCaps));
476         return DSERR_INVALIDPARAM;
477     }
478
479     if ( !(This->initialized) ) {
480         WARN("not initialized\n");
481         return DSERR_UNINITIALIZED;
482     }
483
484     lpDSCCaps->dwFlags = This->drvcaps.dwFlags;
485     lpDSCCaps->dwFormats = This->drvcaps.dwFormats;
486     lpDSCCaps->dwChannels = This->drvcaps.dwChannels;
487
488     TRACE("(flags=0x%08lx,format=0x%08lx,channels=%ld)\n",lpDSCCaps->dwFlags,
489         lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
490
491     return DS_OK;
492 }
493
494 static HRESULT WINAPI
495 IDirectSoundCaptureImpl_Initialize(
496     LPDIRECTSOUNDCAPTURE iface,
497     LPCGUID lpcGUID )
498 {
499     HRESULT err = DSERR_INVALIDPARAM;
500     unsigned wid, widn;
501     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
502     TRACE("(%p)\n", This);
503
504     if (!This) {
505         WARN("invalid parameter: This == NULL\n");
506         return DSERR_INVALIDPARAM;
507     }
508
509     if (This->initialized) {
510         WARN("already initialized\n");
511         return DSERR_ALREADYINITIALIZED;
512     }
513
514     widn = waveInGetNumDevs();
515
516     if (!widn) {
517         WARN("no audio devices found\n");
518         return DSERR_NODRIVER;
519     }
520
521     /* Get dsound configuration */
522     setup_dsound_options();
523
524     /* enumerate WINMM audio devices and find the one we want */
525     for (wid=0; wid<widn; wid++) {
526         if (IsEqualGUID( lpcGUID, &capture_guids[wid]) ) {
527             err = DS_OK;
528             break;
529         }
530     }
531
532     if (err != DS_OK) {
533         WARN("invalid parameter\n");
534         return DSERR_INVALIDPARAM;
535     }
536
537     err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD)&(This->driver),0));
538     if ( (err != DS_OK) && (err != DSERR_UNSUPPORTED) ) {
539         WARN("waveInMessage failed; err=%lx\n",err);
540         return err;
541     }
542     err = DS_OK;
543
544     /* Disable the direct sound driver to force emulation if requested. */
545     if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
546         This->driver = NULL;
547
548     /* Get driver description */
549     if (This->driver) {
550         TRACE("using DirectSound driver\n");
551         err = IDsCaptureDriver_GetDriverDesc(This->driver, &(This->drvdesc));
552         if (err != DS_OK) {
553             WARN("IDsCaptureDriver_GetDriverDesc failed\n");
554             return err;
555         }
556     } else {
557         TRACE("using WINMM\n");
558         /* if no DirectSound interface available, use WINMM API instead */
559         This->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN |
560             DSDDESC_DOMMSYSTEMSETFORMAT;
561     }
562
563     This->drvdesc.dnDevNode = wid;
564
565     /* open the DirectSound driver if available */
566     if (This->driver && (err == DS_OK))
567         err = IDsCaptureDriver_Open(This->driver);
568
569     if (err == DS_OK) {
570         This->initialized = TRUE;
571
572         /* the driver is now open, so it's now allowed to call GetCaps */
573         if (This->driver) {
574             This->drvcaps.dwSize = sizeof(This->drvcaps);
575             err = IDsCaptureDriver_GetCaps(This->driver,&(This->drvcaps));
576             if (err != DS_OK) {
577                 WARN("IDsCaptureDriver_GetCaps failed\n");
578                 return err;
579             }
580         } else /*if (This->hwi)*/ {
581             WAVEINCAPSA    wic;
582             err = mmErr(waveInGetDevCapsA((UINT)This->drvdesc.dnDevNode, &wic, sizeof(wic)));
583
584             if (err == DS_OK) {
585                 This->drvcaps.dwFlags = 0;
586                 strncpy(This->drvdesc.szDrvName, wic.szPname,
587                     sizeof(This->drvdesc.szDrvName));
588
589                 This->drvcaps.dwFlags |= DSCCAPS_EMULDRIVER;
590                 This->drvcaps.dwFormats = wic.dwFormats;
591                 This->drvcaps.dwChannels = wic.wChannels;
592             }
593         }
594     }
595
596     return err;
597 }
598
599 static IDirectSoundCaptureVtbl dscvt =
600 {
601     /* IUnknown methods */
602     IDirectSoundCaptureImpl_QueryInterface,
603     IDirectSoundCaptureImpl_AddRef,
604     IDirectSoundCaptureImpl_Release,
605
606     /* IDirectSoundCapture methods */
607     IDirectSoundCaptureImpl_CreateCaptureBuffer,
608     IDirectSoundCaptureImpl_GetCaps,
609     IDirectSoundCaptureImpl_Initialize
610 };
611
612 static HRESULT
613 DSOUND_CreateDirectSoundCaptureBuffer(
614     IDirectSoundCaptureImpl *ipDSC,
615     LPCDSCBUFFERDESC lpcDSCBufferDesc,
616     LPVOID* ppobj )
617 {
618     LPWAVEFORMATEX  wfex;
619     TRACE( "(%p,%p)\n", lpcDSCBufferDesc, ppobj );
620
621     if (ipDSC == NULL) {
622         WARN("invalid parameter: ipDSC == NULL\n");
623         return DSERR_INVALIDPARAM;
624     }
625
626     if (lpcDSCBufferDesc == NULL) {
627         WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
628         return DSERR_INVALIDPARAM;
629     }
630
631     if (ppobj == NULL) {
632         WARN("invalid parameter: ppobj == NULL\n");
633         return DSERR_INVALIDPARAM;
634     }
635
636     if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
637           (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
638         (lpcDSCBufferDesc->dwBufferBytes == 0) ||
639         (lpcDSCBufferDesc->lpwfxFormat == NULL) ) {
640         WARN("invalid lpcDSCBufferDesc\n");
641         *ppobj = NULL;
642         return DSERR_INVALIDPARAM;
643     }
644
645     if ( !ipDSC->initialized ) {
646         WARN("not initialized\n");
647         *ppobj = NULL;
648         return DSERR_UNINITIALIZED;
649     }
650
651     wfex = lpcDSCBufferDesc->lpwfxFormat;
652
653     if (wfex) {
654         TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
655             "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
656             wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
657             wfex->nAvgBytesPerSec, wfex->nBlockAlign,
658             wfex->wBitsPerSample, wfex->cbSize);
659
660         if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
661             ipDSC->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX));
662             memcpy(ipDSC->pwfx, wfex, sizeof(WAVEFORMATEX));
663             ipDSC->pwfx->cbSize = 0;
664         } else {
665             ipDSC->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)+wfex->cbSize);
666             memcpy(ipDSC->pwfx, wfex, sizeof(WAVEFORMATEX)+wfex->cbSize);
667         }
668     } else {
669         WARN("lpcDSCBufferDesc->lpwfxFormat == 0\n");
670         *ppobj = NULL;
671         return DSERR_INVALIDPARAM; /* FIXME: DSERR_BADFORMAT ? */
672     }
673
674     *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
675         sizeof(IDirectSoundCaptureBufferImpl));
676
677     if ( *ppobj == NULL ) {
678         WARN("out of memory\n");
679         *ppobj = NULL;
680         return DSERR_OUTOFMEMORY;
681     } else {
682         HRESULT err = DS_OK;
683         LPBYTE newbuf;
684         DWORD buflen;
685         IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)*ppobj;
686
687         This->ref = 1;
688         This->dsound = ipDSC;
689         This->dsound->capture_buffer = This;
690         This->notify = NULL;
691         This->nrofnotifies = 0;
692         This->hwnotify = NULL;
693
694         This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
695             lpcDSCBufferDesc->dwSize);
696         if (This->pdscbd)
697             memcpy(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
698         else {
699             WARN("no memory\n");
700             This->dsound->capture_buffer = 0;
701             HeapFree( GetProcessHeap(), 0, This );
702             *ppobj = NULL;
703             return DSERR_OUTOFMEMORY;
704         }
705
706         This->lpVtbl = &dscbvt;
707
708         if (ipDSC->driver) {
709             if (This->dsound->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
710                 FIXME("DSDDESC_DOMMSYSTEMOPEN not supported\n");
711
712             if (This->dsound->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
713                 /* allocate buffer from system memory */
714                 buflen = lpcDSCBufferDesc->dwBufferBytes;
715                 TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->buffer);
716                 if (ipDSC->buffer)
717                     newbuf = HeapReAlloc(GetProcessHeap(),0,ipDSC->buffer,buflen);
718                 else
719                     newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
720
721                 if (newbuf == NULL) {
722                     WARN("failed to allocate capture buffer\n");
723                     err = DSERR_OUTOFMEMORY;
724                     /* but the old buffer might still exist and must be re-prepared */
725                 } else {
726                     ipDSC->buffer = newbuf;
727                     ipDSC->buflen = buflen;
728                 }
729             } else {
730                 /* let driver allocate memory */
731                 ipDSC->buflen = lpcDSCBufferDesc->dwBufferBytes;
732                 /* FIXME: */
733                 if (ipDSC->buffer)
734                     HeapFree( GetProcessHeap(), 0, ipDSC->buffer);
735                 ipDSC->buffer = NULL;
736             }
737
738             err = IDsCaptureDriver_CreateCaptureBuffer(ipDSC->driver,
739                 ipDSC->pwfx,0,0,&(ipDSC->buflen),&(ipDSC->buffer),(LPVOID*)&(ipDSC->hwbuf));
740             if (err != DS_OK) {
741                 WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n");
742                 This->dsound->capture_buffer = 0;
743                 HeapFree( GetProcessHeap(), 0, This );
744                 *ppobj = NULL;
745                 return err;
746             }
747         } else {
748             DWORD flags = CALLBACK_FUNCTION;
749             if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
750                 flags |= WAVE_DIRECTSOUND;
751             err = mmErr(waveInOpen(&(ipDSC->hwi),
752                 ipDSC->drvdesc.dnDevNode, ipDSC->pwfx,
753                 (DWORD)DSOUND_capture_callback, (DWORD)ipDSC, flags));
754             if (err != DS_OK) {
755                 WARN("waveInOpen failed\n");
756                 This->dsound->capture_buffer = 0;
757                 HeapFree( GetProcessHeap(), 0, This );
758                 *ppobj = NULL;
759                 return err;
760             }
761
762             buflen = lpcDSCBufferDesc->dwBufferBytes;
763             TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->buffer);
764             if (ipDSC->buffer)
765                 newbuf = HeapReAlloc(GetProcessHeap(),0,ipDSC->buffer,buflen);
766             else
767                 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
768             if (newbuf == NULL) {
769                 WARN("failed to allocate capture buffer\n");
770                 err = DSERR_OUTOFMEMORY;
771                 /* but the old buffer might still exist and must be re-prepared */
772             } else {
773                 ipDSC->buffer = newbuf;
774                 ipDSC->buflen = buflen;
775             }
776         }
777     }
778
779     TRACE("returning DS_OK\n");
780     return DS_OK;
781 }
782
783 /*******************************************************************************
784  *              IDirectSoundCaptureNotify
785  */
786 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface(
787     LPDIRECTSOUNDNOTIFY iface,
788     REFIID riid,
789     LPVOID *ppobj)
790 {
791     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
792     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
793
794     if (This->dscb == NULL) {
795         WARN("invalid parameter\n");
796         return E_INVALIDARG;
797     }
798
799     return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
800 }
801
802 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
803 {
804     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
805     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
806     return InterlockedIncrement(&(This->ref));
807 }
808
809 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
810 {
811     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
812     ULONG ref;
813
814     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
815
816     ref = InterlockedDecrement(&(This->ref));
817     if (ref == 0) {
818         if (This->dscb->hwnotify)
819             IDsDriverNotify_Release(This->dscb->hwnotify);
820         This->dscb->notify=NULL;
821         IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb);
822         HeapFree(GetProcessHeap(),0,This);
823         TRACE("(%p) released\n",This);
824     }
825     return ref;
826 }
827
828 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions(
829     LPDIRECTSOUNDNOTIFY iface,
830     DWORD howmuch,
831     LPCDSBPOSITIONNOTIFY notify)
832 {
833     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
834     TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
835
836     if (howmuch > 0 && notify == NULL) {
837         WARN("invalid parameter: notify == NULL\n");
838         return DSERR_INVALIDPARAM;
839     }
840
841     if (TRACE_ON(dsound)) {
842         unsigned int i;
843         for (i=0;i<howmuch;i++)
844             TRACE("notify at %ld to 0x%08lx\n",
845             notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
846     }
847
848     if (This->dscb->hwnotify) {
849         HRESULT hres;
850         hres = IDsDriverNotify_SetNotificationPositions(This->dscb->hwnotify, howmuch, notify);
851         if (hres != DS_OK)
852             WARN("IDsDriverNotify_SetNotificationPositions failed\n");
853         return hres;
854     } else if (howmuch > 0) {
855         /* Make an internal copy of the caller-supplied array.
856          * Replace the existing copy if one is already present. */
857         if (This->dscb->notifies)
858             This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
859                 This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
860         else
861             This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
862                 howmuch * sizeof(DSBPOSITIONNOTIFY));
863
864         if (This->dscb->notifies == NULL) {
865             WARN("out of memory\n");
866             return DSERR_OUTOFMEMORY;
867         }
868         memcpy(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
869         This->dscb->nrofnotifies = howmuch;
870     } else {
871         if (This->dscb->notifies) {
872             HeapFree(GetProcessHeap(), 0, This->dscb->notifies);
873             This->dscb->notifies = NULL;
874         }
875         This->dscb->nrofnotifies = 0;
876     }
877
878     return S_OK;
879 }
880
881 IDirectSoundNotifyVtbl dscnvt =
882 {
883     IDirectSoundCaptureNotifyImpl_QueryInterface,
884     IDirectSoundCaptureNotifyImpl_AddRef,
885     IDirectSoundCaptureNotifyImpl_Release,
886     IDirectSoundCaptureNotifyImpl_SetNotificationPositions,
887 };
888
889 HRESULT WINAPI IDirectSoundCaptureNotifyImpl_Create(
890     IDirectSoundCaptureBufferImpl *dscb,
891     IDirectSoundCaptureNotifyImpl **pdscn)
892 {
893     IDirectSoundCaptureNotifyImpl * dscn;
894     TRACE("(%p,%p)\n",dscb,pdscn);
895
896     dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscn));
897
898     if (dscn == NULL) {
899         WARN("out of memory\n");
900         return DSERR_OUTOFMEMORY;
901     }
902
903     dscn->ref = 0;
904     dscn->lpVtbl = &dscnvt;
905     dscn->dscb = dscb;
906     dscb->notify = dscn;
907     IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb);
908
909     *pdscn = dscn;
910     return DS_OK;
911 }
912
913 /*******************************************************************************
914  *              IDirectSoundCaptureBuffer
915  */
916 static HRESULT WINAPI
917 IDirectSoundCaptureBufferImpl_QueryInterface(
918     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
919     REFIID riid,
920     LPVOID* ppobj )
921 {
922     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
923     HRESULT hres;
924     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
925
926     if (ppobj == NULL) {
927         WARN("invalid parameter\n");
928         return E_INVALIDARG;
929     }
930
931     *ppobj = NULL;
932
933     if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
934         if (!This->notify)
935             hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify);
936         if (This->notify) {
937             if (This->dsound->hwbuf) {
938                 hres = IDsCaptureDriverBuffer_QueryInterface(This->dsound->hwbuf,
939                     &IID_IDsDriverNotify, (LPVOID*)&(This->hwnotify));
940                 if (hres != DS_OK) {
941                     WARN("IDsCaptureDriverBuffer_QueryInterface failed\n");
942                     *ppobj = 0;
943                     return hres;
944                 }
945             }
946
947             IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
948             *ppobj = (LPVOID)This->notify;
949             return DS_OK;
950         }
951
952         WARN("IID_IDirectSoundNotify\n");
953         return E_FAIL;
954     }
955
956     if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
957          IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
958         IDirectSoundCaptureBuffer8_AddRef(iface);
959         *ppobj = This;
960         return NO_ERROR;
961     }
962
963     FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
964     return E_NOINTERFACE;
965 }
966
967 static ULONG WINAPI
968 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
969 {
970     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
971     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
972     return InterlockedIncrement(&(This->ref));
973 }
974
975 static ULONG WINAPI
976 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
977 {
978     ULONG uRef;
979     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
980     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
981
982     uRef = InterlockedDecrement(&(This->ref));
983     if ( uRef == 0 ) {
984         TRACE("deleting object\n");
985         if (This->dsound->state == STATE_CAPTURING)
986             This->dsound->state = STATE_STOPPING;
987
988         if (This->pdscbd)
989             HeapFree(GetProcessHeap(),0, This->pdscbd);
990
991         if (This->dsound->hwi) {
992             waveInReset(This->dsound->hwi);
993             waveInClose(This->dsound->hwi);
994             if (This->dsound->pwave) {
995                 HeapFree(GetProcessHeap(),0, This->dsound->pwave);
996                 This->dsound->pwave = 0;
997             }
998             This->dsound->hwi = 0;
999         }
1000
1001         if (This->dsound->hwbuf)
1002             IDsCaptureDriverBuffer_Release(This->dsound->hwbuf);
1003
1004         /* remove from IDirectSoundCaptureImpl */
1005         if (This->dsound)
1006             This->dsound->capture_buffer = NULL;
1007         else
1008             ERR("does not reference dsound\n");
1009
1010         if (This->notify)
1011             IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
1012
1013         if (This->notifies != NULL)
1014                 HeapFree(GetProcessHeap(), 0, This->notifies);
1015
1016         HeapFree( GetProcessHeap(), 0, This );
1017         TRACE("(%p) released\n",This);
1018     }
1019
1020     return uRef;
1021 }
1022
1023 static HRESULT WINAPI
1024 IDirectSoundCaptureBufferImpl_GetCaps(
1025     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1026     LPDSCBCAPS lpDSCBCaps )
1027 {
1028     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1029     TRACE( "(%p,%p)\n", This, lpDSCBCaps );
1030
1031     if (This == NULL) {
1032         WARN("invalid parameter: This == NULL\n");
1033         return DSERR_INVALIDPARAM;
1034     }
1035
1036     if (lpDSCBCaps == NULL) {
1037         WARN("invalid parameter: lpDSCBCaps == NULL\n");
1038         return DSERR_INVALIDPARAM;
1039     }
1040
1041     if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
1042         WARN("invalid parameter: lpDSCBCaps->dwSize = %ld < %d\n",
1043             lpDSCBCaps->dwSize, sizeof(DSCBCAPS));
1044         return DSERR_INVALIDPARAM;
1045     }
1046
1047     if (This->dsound == NULL) {
1048         WARN("invalid parameter: This->dsound == NULL\n");
1049         return DSERR_INVALIDPARAM;
1050     }
1051
1052     lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
1053     lpDSCBCaps->dwFlags = This->flags;
1054     lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
1055     lpDSCBCaps->dwReserved = 0;
1056
1057     TRACE("returning DS_OK\n");
1058     return DS_OK;
1059 }
1060
1061 static HRESULT WINAPI
1062 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
1063     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1064     LPDWORD lpdwCapturePosition,
1065     LPDWORD lpdwReadPosition )
1066 {
1067     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1068     HRESULT hres = DS_OK;
1069     TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
1070
1071     if (This == NULL) {
1072         WARN("invalid parameter: This == NULL\n");
1073         return DSERR_INVALIDPARAM;
1074     }
1075
1076     if (This->dsound == NULL) {
1077         WARN("invalid parameter: This->dsound == NULL\n");
1078         return DSERR_INVALIDPARAM;
1079     }
1080
1081     if (This->dsound->driver) {
1082         hres = IDsCaptureDriverBuffer_GetPosition(This->dsound->hwbuf, lpdwCapturePosition, lpdwReadPosition );
1083         if (hres != DS_OK)
1084             WARN("IDsCaptureDriverBuffer_GetPosition failed\n");
1085     } else if (This->dsound->hwi) {
1086         EnterCriticalSection(&(This->dsound->lock));
1087         TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1088         if (lpdwCapturePosition) {
1089             MMTIME mtime;
1090             mtime.wType = TIME_BYTES;
1091             waveInGetPosition(This->dsound->hwi, &mtime, sizeof(mtime));
1092             TRACE("mtime.u.cb=%ld,This->dsound->buflen=%ld\n", mtime.u.cb,
1093                 This->dsound->buflen);
1094             mtime.u.cb = mtime.u.cb % This->dsound->buflen;
1095             *lpdwCapturePosition = mtime.u.cb;
1096         }
1097
1098         if (lpdwReadPosition) {
1099             if (This->dsound->state == STATE_STARTING) {
1100                 if (lpdwCapturePosition)
1101                     This->dsound->read_position = *lpdwCapturePosition;
1102                 This->dsound->state = STATE_CAPTURING;
1103             }
1104             *lpdwReadPosition = This->dsound->read_position;
1105         }
1106         TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1107         LeaveCriticalSection(&(This->dsound->lock));
1108         if (lpdwCapturePosition) TRACE("*lpdwCapturePosition=%ld\n",*lpdwCapturePosition);
1109         if (lpdwReadPosition) TRACE("*lpdwReadPosition=%ld\n",*lpdwReadPosition);
1110     } else {
1111         WARN("no driver\n");
1112         hres = DSERR_NODRIVER;
1113     }
1114
1115     TRACE("returning %08lx\n", hres);
1116     return hres;
1117 }
1118
1119 static HRESULT WINAPI
1120 IDirectSoundCaptureBufferImpl_GetFormat(
1121     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1122     LPWAVEFORMATEX lpwfxFormat,
1123     DWORD dwSizeAllocated,
1124     LPDWORD lpdwSizeWritten )
1125 {
1126     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1127     HRESULT hres = DS_OK;
1128     TRACE( "(%p,%p,0x%08lx,%p)\n", This, lpwfxFormat, dwSizeAllocated,
1129         lpdwSizeWritten );
1130
1131     if (This == NULL) {
1132         WARN("invalid parameter: This == NULL\n");
1133         return DSERR_INVALIDPARAM;
1134     }
1135
1136     if (This->dsound == NULL) {
1137         WARN("invalid parameter: This->dsound == NULL\n");
1138         return DSERR_INVALIDPARAM;
1139     }
1140
1141     if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize))
1142         dwSizeAllocated = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize;
1143
1144     if (lpwfxFormat) { /* NULL is valid (just want size) */
1145         memcpy(lpwfxFormat, This->dsound->pwfx, dwSizeAllocated);
1146         if (lpdwSizeWritten)
1147             *lpdwSizeWritten = dwSizeAllocated;
1148     } else {
1149         if (lpdwSizeWritten)
1150             *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize;
1151         else {
1152             TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
1153             hres = DSERR_INVALIDPARAM;
1154         }
1155     }
1156
1157     TRACE("returning %08lx\n", hres);
1158     return hres;
1159 }
1160
1161 static HRESULT WINAPI
1162 IDirectSoundCaptureBufferImpl_GetStatus(
1163     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1164     LPDWORD lpdwStatus )
1165 {
1166     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1167     TRACE( "(%p, %p), thread is %04lx\n", This, lpdwStatus, GetCurrentThreadId() );
1168
1169     if (This == NULL) {
1170         WARN("invalid parameter: This == NULL\n");
1171         return DSERR_INVALIDPARAM;
1172     }
1173
1174     if (This->dsound == NULL) {
1175         WARN("invalid parameter: This->dsound == NULL\n");
1176         return DSERR_INVALIDPARAM;
1177     }
1178
1179     if (lpdwStatus == NULL) {
1180         WARN("invalid parameter: lpdwStatus == NULL\n");
1181         return DSERR_INVALIDPARAM;
1182     }
1183
1184     *lpdwStatus = 0;
1185     EnterCriticalSection(&(This->dsound->lock));
1186
1187     TRACE("old This->dsound->state=%s, old lpdwStatus=%08lx\n",
1188         captureStateString[This->dsound->state],*lpdwStatus);
1189     if ((This->dsound->state == STATE_STARTING) ||
1190         (This->dsound->state == STATE_CAPTURING)) {
1191         *lpdwStatus |= DSCBSTATUS_CAPTURING;
1192         if (This->flags & DSCBSTART_LOOPING)
1193             *lpdwStatus |= DSCBSTATUS_LOOPING;
1194     }
1195     TRACE("new This->dsound->state=%s, new lpdwStatus=%08lx\n",
1196         captureStateString[This->dsound->state],*lpdwStatus);
1197     LeaveCriticalSection(&(This->dsound->lock));
1198
1199     TRACE("status=%lx\n", *lpdwStatus);
1200     TRACE("returning DS_OK\n");
1201     return DS_OK;
1202 }
1203
1204 static HRESULT WINAPI
1205 IDirectSoundCaptureBufferImpl_Initialize(
1206     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1207     LPDIRECTSOUNDCAPTURE lpDSC,
1208     LPCDSCBUFFERDESC lpcDSCBDesc )
1209 {
1210     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1211
1212     FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
1213
1214     return DS_OK;
1215 }
1216
1217 static HRESULT WINAPI
1218 IDirectSoundCaptureBufferImpl_Lock(
1219     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1220     DWORD dwReadCusor,
1221     DWORD dwReadBytes,
1222     LPVOID* lplpvAudioPtr1,
1223     LPDWORD lpdwAudioBytes1,
1224     LPVOID* lplpvAudioPtr2,
1225     LPDWORD lpdwAudioBytes2,
1226     DWORD dwFlags )
1227 {
1228     HRESULT hres = DS_OK;
1229     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1230     TRACE( "(%p,%08lu,%08lu,%p,%p,%p,%p,0x%08lx) at %ld\n", This, dwReadCusor,
1231         dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
1232         lpdwAudioBytes2, dwFlags, GetTickCount() );
1233
1234     if (This == NULL) {
1235         WARN("invalid parameter: This == NULL\n");
1236         return DSERR_INVALIDPARAM;
1237     }
1238
1239     if (This->dsound == NULL) {
1240         WARN("invalid parameter: This->dsound == NULL\n");
1241         return DSERR_INVALIDPARAM;
1242     }
1243
1244     if (lplpvAudioPtr1 == NULL) {
1245         WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
1246         return DSERR_INVALIDPARAM;
1247     }
1248
1249     if (lpdwAudioBytes1 == NULL) {
1250         WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
1251         return DSERR_INVALIDPARAM;
1252     }
1253
1254     EnterCriticalSection(&(This->dsound->lock));
1255
1256     if (This->dsound->driver) {
1257         hres = IDsCaptureDriverBuffer_Lock(This->dsound->hwbuf, lplpvAudioPtr1,
1258                                            lpdwAudioBytes1, lplpvAudioPtr2,
1259                                            lpdwAudioBytes2, dwReadCusor,
1260                                            dwReadBytes, dwFlags);
1261         if (hres != DS_OK)
1262             WARN("IDsCaptureDriverBuffer_Lock failed\n");
1263     } else if (This->dsound->hwi) {
1264         *lplpvAudioPtr1 = This->dsound->buffer + dwReadCusor;
1265         if ( (dwReadCusor + dwReadBytes) > This->dsound->buflen) {
1266             *lpdwAudioBytes1 = This->dsound->buflen - dwReadCusor;
1267             if (lplpvAudioPtr2)
1268                 *lplpvAudioPtr2 = This->dsound->buffer;
1269             if (lpdwAudioBytes2)
1270                 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
1271         } else {
1272             *lpdwAudioBytes1 = dwReadBytes;
1273             if (lplpvAudioPtr2)
1274                 *lplpvAudioPtr2 = 0;
1275             if (lpdwAudioBytes2)
1276                 *lpdwAudioBytes2 = 0;
1277         }
1278     } else {
1279         TRACE("invalid call\n");
1280         hres = DSERR_INVALIDCALL;   /* DSERR_NODRIVER ? */
1281     }
1282
1283     LeaveCriticalSection(&(This->dsound->lock));
1284
1285     TRACE("returning %08lx\n", hres);
1286     return hres;
1287 }
1288
1289 static HRESULT WINAPI
1290 IDirectSoundCaptureBufferImpl_Start(
1291     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1292     DWORD dwFlags )
1293 {
1294     HRESULT hres = DS_OK;
1295     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1296     TRACE( "(%p,0x%08lx)\n", This, dwFlags );
1297
1298     if (This == NULL) {
1299         WARN("invalid parameter: This == NULL\n");
1300         return DSERR_INVALIDPARAM;
1301     }
1302
1303     if (This->dsound == NULL) {
1304         WARN("invalid parameter: This->dsound == NULL\n");
1305         return DSERR_INVALIDPARAM;
1306     }
1307
1308     if ( (This->dsound->driver == 0) && (This->dsound->hwi == 0) ) {
1309         WARN("no driver\n");
1310         return DSERR_NODRIVER;
1311     }
1312
1313     EnterCriticalSection(&(This->dsound->lock));
1314
1315     This->flags = dwFlags;
1316     TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1317     if (This->dsound->state == STATE_STOPPED)
1318         This->dsound->state = STATE_STARTING;
1319     else if (This->dsound->state == STATE_STOPPING)
1320         This->dsound->state = STATE_CAPTURING;
1321     TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1322
1323     LeaveCriticalSection(&(This->dsound->lock));
1324
1325     if (This->dsound->driver) {
1326         hres = IDsCaptureDriverBuffer_Start(This->dsound->hwbuf, dwFlags);
1327         if (hres != DS_OK)
1328             WARN("IDsCaptureDriverBuffer_Start failed\n");
1329     } else if (This->dsound->hwi) {
1330         IDirectSoundCaptureImpl* ipDSC = This->dsound;
1331
1332         if (ipDSC->buffer) {
1333             if (This->nrofnotifies) {
1334                 int c;
1335
1336                 ipDSC->nrofpwaves = This->nrofnotifies;
1337                 TRACE("nrofnotifies=%d\n", This->nrofnotifies);
1338
1339                 /* prepare headers */
1340                 if (ipDSC->pwave)
1341                     ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave,
1342                         ipDSC->nrofpwaves*sizeof(WAVEHDR));
1343                 else
1344                     ipDSC->pwave = HeapAlloc(GetProcessHeap(),0,
1345                         ipDSC->nrofpwaves*sizeof(WAVEHDR));
1346
1347                 for (c = 0; c < ipDSC->nrofpwaves; c++) {
1348                     if (This->notifies[c].dwOffset == DSBPN_OFFSETSTOP) {
1349                         TRACE("got DSBPN_OFFSETSTOP\n");
1350                         ipDSC->nrofpwaves = c;
1351                         break;
1352                     }
1353                     if (c == 0) {
1354                         ipDSC->pwave[0].lpData = ipDSC->buffer;
1355                         ipDSC->pwave[0].dwBufferLength =
1356                             This->notifies[0].dwOffset + 1;
1357                     } else {
1358                         ipDSC->pwave[c].lpData = ipDSC->buffer +
1359                             This->notifies[c-1].dwOffset + 1;
1360                         ipDSC->pwave[c].dwBufferLength =
1361                             This->notifies[c].dwOffset -
1362                             This->notifies[c-1].dwOffset;
1363                     }
1364                     ipDSC->pwave[c].dwBytesRecorded = 0;
1365                     ipDSC->pwave[c].dwUser = (DWORD)ipDSC;
1366                     ipDSC->pwave[c].dwFlags = 0;
1367                     ipDSC->pwave[c].dwLoops = 0;
1368                     hres = mmErr(waveInPrepareHeader(ipDSC->hwi,
1369                         &(ipDSC->pwave[c]),sizeof(WAVEHDR)));
1370                     if (hres != DS_OK) {
1371                         WARN("waveInPrepareHeader failed\n");
1372                         while (c--)
1373                             waveInUnprepareHeader(ipDSC->hwi,
1374                                 &(ipDSC->pwave[c]),sizeof(WAVEHDR));
1375                         break;
1376                     }
1377
1378                     hres = mmErr(waveInAddBuffer(ipDSC->hwi,
1379                         &(ipDSC->pwave[c]), sizeof(WAVEHDR)));
1380                     if (hres != DS_OK) {
1381                         WARN("waveInAddBuffer failed\n");
1382                         while (c--)
1383                             waveInUnprepareHeader(ipDSC->hwi,
1384                                 &(ipDSC->pwave[c]),sizeof(WAVEHDR));
1385                         break;
1386                     }
1387                 }
1388
1389                 memset(ipDSC->buffer,
1390                     (ipDSC->pwfx->wBitsPerSample == 8) ? 128 : 0, ipDSC->buflen);
1391             } else {
1392                 TRACE("no notifiers specified\n");
1393                 /* no notifiers specified so just create a single default header */
1394                 ipDSC->nrofpwaves = 1;
1395                 if (ipDSC->pwave)
1396                     ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave,sizeof(WAVEHDR));
1397                 else
1398                     ipDSC->pwave = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEHDR));
1399
1400                 ipDSC->pwave[0].lpData = ipDSC->buffer;
1401                 ipDSC->pwave[0].dwBufferLength = ipDSC->buflen;
1402                 ipDSC->pwave[0].dwBytesRecorded = 0;
1403                 ipDSC->pwave[0].dwUser = (DWORD)ipDSC;
1404                 ipDSC->pwave[0].dwFlags = 0;
1405                 ipDSC->pwave[0].dwLoops = 0;
1406
1407                 hres = mmErr(waveInPrepareHeader(ipDSC->hwi,
1408                     &(ipDSC->pwave[0]),sizeof(WAVEHDR)));
1409                 if (hres != DS_OK) {
1410                     WARN("waveInPrepareHeader failed\n");
1411                     waveInUnprepareHeader(ipDSC->hwi,
1412                         &(ipDSC->pwave[0]),sizeof(WAVEHDR));
1413                 }
1414                 hres = mmErr(waveInAddBuffer(ipDSC->hwi,
1415                     &(ipDSC->pwave[0]), sizeof(WAVEHDR)));
1416                 if (hres != DS_OK) {
1417                     WARN("waveInAddBuffer failed\n");
1418                     waveInUnprepareHeader(ipDSC->hwi,
1419                         &(ipDSC->pwave[0]),sizeof(WAVEHDR));
1420                 }
1421             }
1422         }
1423
1424         ipDSC->index = 0;
1425         ipDSC->read_position = 0;
1426
1427         if (hres == DS_OK) {
1428             /* start filling the first buffer */
1429             hres = mmErr(waveInStart(ipDSC->hwi));
1430             if (hres != DS_OK)
1431                 WARN("waveInStart failed\n");
1432         }
1433
1434         if (hres != DS_OK) {
1435             WARN("calling waveInClose because of error\n");
1436             waveInClose(This->dsound->hwi);
1437             This->dsound->hwi = 0;
1438         }
1439     } else {
1440         WARN("no driver\n");
1441         hres = DSERR_NODRIVER;
1442     }
1443
1444     TRACE("returning %08lx\n", hres);
1445     return hres;
1446 }
1447
1448 static HRESULT WINAPI
1449 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
1450 {
1451     HRESULT hres = DS_OK;
1452     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1453     TRACE( "(%p)\n", This );
1454
1455     if (This == NULL) {
1456         WARN("invalid parameter: This == NULL\n");
1457         return DSERR_INVALIDPARAM;
1458     }
1459
1460     if (This->dsound == NULL) {
1461         WARN("invalid parameter: This->dsound == NULL\n");
1462         return DSERR_INVALIDPARAM;
1463     }
1464
1465     EnterCriticalSection(&(This->dsound->lock));
1466
1467     TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1468     if (This->dsound->state == STATE_CAPTURING)
1469         This->dsound->state = STATE_STOPPING;
1470     else if (This->dsound->state == STATE_STARTING)
1471         This->dsound->state = STATE_STOPPED;
1472     TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1473
1474     LeaveCriticalSection(&(This->dsound->lock));
1475
1476     if (This->dsound->driver) {
1477         hres = IDsCaptureDriverBuffer_Stop(This->dsound->hwbuf);
1478         if (hres != DS_OK)
1479             WARN("IDsCaptureDriverBuffer_Stop() failed\n");
1480     } else if (This->dsound->hwi) {
1481         hres = mmErr(waveInReset(This->dsound->hwi));
1482         if (hres != DS_OK)
1483             WARN("waveInReset() failed\n");
1484     } else {
1485         WARN("no driver\n");
1486         hres = DSERR_NODRIVER;
1487     }
1488
1489     TRACE("returning %08lx\n", hres);
1490     return hres;
1491 }
1492
1493 static HRESULT WINAPI
1494 IDirectSoundCaptureBufferImpl_Unlock(
1495     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1496     LPVOID lpvAudioPtr1,
1497     DWORD dwAudioBytes1,
1498     LPVOID lpvAudioPtr2,
1499     DWORD dwAudioBytes2 )
1500 {
1501     HRESULT hres = DS_OK;
1502     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1503     TRACE( "(%p,%p,%08lu,%p,%08lu)\n", This, lpvAudioPtr1, dwAudioBytes1,
1504         lpvAudioPtr2, dwAudioBytes2 );
1505
1506     if (This == NULL) {
1507         WARN("invalid parameter: This == NULL\n");
1508         return DSERR_INVALIDPARAM;
1509     }
1510
1511     if (lpvAudioPtr1 == NULL) {
1512         WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
1513         return DSERR_INVALIDPARAM;
1514     }
1515
1516     if (This->dsound->driver) {
1517         hres = IDsCaptureDriverBuffer_Unlock(This->dsound->hwbuf, lpvAudioPtr1,
1518                                              dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1519         if (hres != DS_OK)
1520             WARN("IDsCaptureDriverBuffer_Unlock failed\n");
1521     } else if (This->dsound->hwi) {
1522         This->dsound->read_position = (This->dsound->read_position +
1523             (dwAudioBytes1 + dwAudioBytes2)) % This->dsound->buflen;
1524     } else {
1525         WARN("invalid call\n");
1526         hres = DSERR_INVALIDCALL;
1527     }
1528
1529     TRACE("returning %08lx\n", hres);
1530     return hres;
1531 }
1532
1533 static HRESULT WINAPI
1534 IDirectSoundCaptureBufferImpl_GetObjectInPath(
1535     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1536     REFGUID rguidObject,
1537     DWORD dwIndex,
1538     REFGUID rguidInterface,
1539     LPVOID* ppObject )
1540 {
1541     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1542
1543     FIXME( "(%p,%s,%lu,%s,%p): stub\n", This, debugstr_guid(rguidObject),
1544         dwIndex, debugstr_guid(rguidInterface), ppObject );
1545
1546     return DS_OK;
1547 }
1548
1549 static HRESULT WINAPI
1550 IDirectSoundCaptureBufferImpl_GetFXStatus(
1551     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1552     DWORD dwFXCount,
1553     LPDWORD pdwFXStatus )
1554 {
1555     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1556
1557     FIXME( "(%p,%lu,%p): stub\n", This, dwFXCount, pdwFXStatus );
1558
1559     return DS_OK;
1560 }
1561
1562 static IDirectSoundCaptureBuffer8Vtbl dscbvt =
1563 {
1564     /* IUnknown methods */
1565     IDirectSoundCaptureBufferImpl_QueryInterface,
1566     IDirectSoundCaptureBufferImpl_AddRef,
1567     IDirectSoundCaptureBufferImpl_Release,
1568
1569     /* IDirectSoundCaptureBuffer methods */
1570     IDirectSoundCaptureBufferImpl_GetCaps,
1571     IDirectSoundCaptureBufferImpl_GetCurrentPosition,
1572     IDirectSoundCaptureBufferImpl_GetFormat,
1573     IDirectSoundCaptureBufferImpl_GetStatus,
1574     IDirectSoundCaptureBufferImpl_Initialize,
1575     IDirectSoundCaptureBufferImpl_Lock,
1576     IDirectSoundCaptureBufferImpl_Start,
1577     IDirectSoundCaptureBufferImpl_Stop,
1578     IDirectSoundCaptureBufferImpl_Unlock,
1579
1580     /* IDirectSoundCaptureBuffer methods */
1581     IDirectSoundCaptureBufferImpl_GetObjectInPath,
1582     IDirectSoundCaptureBufferImpl_GetFXStatus
1583 };
1584
1585 /*******************************************************************************
1586  * DirectSoundCapture ClassFactory
1587  */
1588
1589 static HRESULT WINAPI
1590 DSCCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
1591 {
1592     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1593
1594     FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1595     return E_NOINTERFACE;
1596 }
1597
1598 static ULONG WINAPI
1599 DSCCF_AddRef(LPCLASSFACTORY iface)
1600 {
1601     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1602     TRACE("(%p) ref was %ld\n", This, This->ref);
1603     return InterlockedIncrement(&(This->ref));
1604 }
1605
1606 static ULONG WINAPI
1607 DSCCF_Release(LPCLASSFACTORY iface)
1608 {
1609     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1610     /* static class, won't be  freed */
1611     TRACE("(%p) ref was %ld\n", This, This->ref);
1612     return InterlockedDecrement(&(This->ref));
1613 }
1614
1615 static HRESULT WINAPI
1616 DSCCF_CreateInstance(
1617         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj )
1618 {
1619     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1620     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1621
1622     if (pOuter) {
1623         WARN("aggregation not supported\n");
1624         return CLASS_E_NOAGGREGATION;
1625     }
1626
1627     if (ppobj == NULL) {
1628         WARN("invalid parameter\n");
1629         return E_INVALIDARG;
1630     }
1631
1632     *ppobj = NULL;
1633
1634     if ( IsEqualGUID( &IID_IDirectSoundCapture8, riid ) )
1635         return DirectSoundCaptureCreate8(0,(LPDIRECTSOUNDCAPTURE8*)ppobj,pOuter);
1636
1637     WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); 
1638     return E_NOINTERFACE;
1639 }
1640
1641 static HRESULT WINAPI
1642 DSCCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
1643 {
1644     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1645     FIXME("(%p)->(%d),stub!\n",This,dolock);
1646     return S_OK;
1647 }
1648
1649 static IClassFactoryVtbl DSCCF_Vtbl =
1650 {
1651     DSCCF_QueryInterface,
1652     DSCCF_AddRef,
1653     DSCCF_Release,
1654     DSCCF_CreateInstance,
1655     DSCCF_LockServer
1656 };
1657
1658 IClassFactoryImpl DSOUND_CAPTURE_CF = { &DSCCF_Vtbl, 1 };
1659
1660 /***************************************************************************
1661  * DirectSoundFullDuplexCreate [DSOUND.10]
1662  *
1663  * Create and initialize a DirectSoundFullDuplex interface.
1664  *
1665  * PARAMS
1666  *    pcGuidCaptureDevice [I] Address of sound capture device GUID.
1667  *    pcGuidRenderDevice  [I] Address of sound render device GUID.
1668  *    pcDSCBufferDesc     [I] Address of capture buffer description.
1669  *    pcDSBufferDesc      [I] Address of  render buffer description.
1670  *    hWnd                [I] Handle to application window.
1671  *    dwLevel             [I] Cooperative level.
1672  *    ppDSFD              [O] Address where full duplex interface returned.
1673  *    ppDSCBuffer8        [0] Address where capture buffer interface returned.
1674  *    ppDSBuffer8         [0] Address where render buffer interface returned.
1675  *    pUnkOuter           [I] Must be NULL.
1676  *
1677  * RETURNS
1678  *    Success: DS_OK
1679  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1680  *             DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
1681  */
1682 HRESULT WINAPI
1683 DirectSoundFullDuplexCreate(
1684     LPCGUID pcGuidCaptureDevice,
1685     LPCGUID pcGuidRenderDevice,
1686     LPCDSCBUFFERDESC pcDSCBufferDesc,
1687     LPCDSBUFFERDESC pcDSBufferDesc,
1688     HWND hWnd,
1689     DWORD dwLevel,
1690     LPDIRECTSOUNDFULLDUPLEX *ppDSFD,
1691     LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8,
1692     LPDIRECTSOUNDBUFFER8 *ppDSBuffer8,
1693     LPUNKNOWN pUnkOuter)
1694 {
1695     IDirectSoundFullDuplexImpl** ippDSFD=(IDirectSoundFullDuplexImpl**)ppDSFD;
1696     TRACE("(%s,%s,%p,%p,%lx,%lx,%p,%p,%p,%p)\n", debugstr_guid(pcGuidCaptureDevice),
1697         debugstr_guid(pcGuidRenderDevice), pcDSCBufferDesc, pcDSBufferDesc,
1698         (DWORD)hWnd, dwLevel, ppDSFD, ppDSCBuffer8, ppDSBuffer8, pUnkOuter);
1699
1700     if ( pUnkOuter ) {
1701         WARN("pUnkOuter != 0\n");
1702         return DSERR_NOAGGREGATION;
1703     }
1704
1705     *ippDSFD = HeapAlloc(GetProcessHeap(),
1706         HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl));
1707
1708     if (*ippDSFD == NULL) {
1709         WARN("out of memory\n");
1710         return DSERR_OUTOFMEMORY;
1711     } else {
1712         HRESULT hres;
1713         IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)*ippDSFD;
1714
1715         This->ref = 1;
1716         This->lpVtbl = &dsfdvt;
1717
1718         InitializeCriticalSection( &(This->lock) );
1719         This->lock.DebugInfo->Spare[1] = (DWORD)"DSDUPLEX_lock";
1720
1721         hres = IDirectSoundFullDuplexImpl_Initialize( (LPDIRECTSOUNDFULLDUPLEX)This,
1722                                                       pcGuidCaptureDevice, pcGuidRenderDevice,
1723                                                       pcDSCBufferDesc, pcDSBufferDesc,
1724                                                       hWnd, dwLevel, ppDSCBuffer8, ppDSBuffer8);
1725         if (hres != DS_OK)
1726             WARN("IDirectSoundFullDuplexImpl_Initialize failed\n");
1727         return hres;
1728     }
1729
1730     return DSERR_GENERIC;
1731 }
1732
1733 static HRESULT WINAPI
1734 IDirectSoundFullDuplexImpl_QueryInterface(
1735     LPDIRECTSOUNDFULLDUPLEX iface,
1736     REFIID riid,
1737     LPVOID* ppobj )
1738 {
1739     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
1740     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
1741
1742     if (ppobj == NULL) {
1743         WARN("invalid parameter\n");
1744         return E_INVALIDARG;
1745     }
1746
1747     *ppobj = NULL;
1748     return E_NOINTERFACE;
1749 }
1750
1751 static ULONG WINAPI
1752 IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface )
1753 {
1754     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
1755     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1756     return InterlockedIncrement(&(This->ref));
1757 }
1758
1759 static ULONG WINAPI
1760 IDirectSoundFullDuplexImpl_Release( LPDIRECTSOUNDFULLDUPLEX iface )
1761 {
1762     ULONG uRef;
1763     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
1764     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1765
1766     uRef = InterlockedDecrement(&(This->ref));
1767     if ( uRef == 0 ) {
1768         This->lock.DebugInfo->Spare[1] = 0;
1769         DeleteCriticalSection( &(This->lock) );
1770         HeapFree( GetProcessHeap(), 0, This );
1771         TRACE("(%p) released\n",This);
1772     }
1773
1774     return uRef;
1775 }
1776
1777 static HRESULT WINAPI
1778 IDirectSoundFullDuplexImpl_Initialize(
1779     LPDIRECTSOUNDFULLDUPLEX iface,
1780     LPCGUID pCaptureGuid,
1781     LPCGUID pRendererGuid,
1782     LPCDSCBUFFERDESC lpDscBufferDesc,
1783     LPCDSBUFFERDESC lpDsBufferDesc,
1784     HWND hWnd,
1785     DWORD dwLevel,
1786     LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8,
1787     LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 )
1788 {
1789     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
1790     IDirectSoundCaptureBufferImpl** ippdscb=(IDirectSoundCaptureBufferImpl**)lplpDirectSoundCaptureBuffer8;
1791     IDirectSoundBufferImpl** ippdsc=(IDirectSoundBufferImpl**)lplpDirectSoundBuffer8;
1792
1793     FIXME( "(%p,%s,%s,%p,%p,%lx,%lx,%p,%p) stub!\n", This, debugstr_guid(pCaptureGuid),
1794         debugstr_guid(pRendererGuid), lpDscBufferDesc, lpDsBufferDesc, (DWORD)hWnd, dwLevel,
1795         ippdscb, ippdsc);
1796
1797     return E_FAIL;
1798 }
1799
1800 static IDirectSoundFullDuplexVtbl dsfdvt =
1801 {
1802     /* IUnknown methods */
1803     IDirectSoundFullDuplexImpl_QueryInterface,
1804     IDirectSoundFullDuplexImpl_AddRef,
1805     IDirectSoundFullDuplexImpl_Release,
1806
1807     /* IDirectSoundFullDuplex methods */
1808     IDirectSoundFullDuplexImpl_Initialize
1809 };
1810
1811 /*******************************************************************************
1812  * DirectSoundFullDuplex ClassFactory
1813  */
1814
1815 static HRESULT WINAPI
1816 DSFDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
1817 {
1818     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1819
1820     FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1821     return E_NOINTERFACE;
1822 }
1823
1824 static ULONG WINAPI
1825 DSFDCF_AddRef(LPCLASSFACTORY iface)
1826 {
1827     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1828     TRACE("(%p) ref was %ld\n", This, This->ref);
1829     return InterlockedIncrement(&(This->ref));
1830 }
1831
1832 static ULONG WINAPI
1833 DSFDCF_Release(LPCLASSFACTORY iface)
1834 {
1835     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1836     /* static class, won't be  freed */
1837     TRACE("(%p) ref was %ld\n", This, This->ref);
1838     return InterlockedDecrement(&(This->ref));
1839 }
1840
1841 static HRESULT WINAPI
1842 DSFDCF_CreateInstance(
1843     LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj )
1844 {
1845     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1846
1847     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1848
1849     if (pOuter) {
1850         WARN("aggregation not supported\n");
1851         return CLASS_E_NOAGGREGATION;
1852     }
1853
1854     if (ppobj == NULL) {
1855         WARN("invalid parameter\n");
1856         return E_INVALIDARG;
1857     }
1858
1859     *ppobj = NULL;
1860
1861     if ( IsEqualGUID( &IID_IDirectSoundFullDuplex, riid ) ) {
1862         /* FIXME: how do we do this one ? */
1863         FIXME("not implemented\n");
1864         return E_NOINTERFACE;
1865     }
1866
1867     WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); 
1868     return E_NOINTERFACE;
1869 }
1870
1871 static HRESULT WINAPI
1872 DSFDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
1873 {
1874     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1875     FIXME("(%p)->(%d),stub!\n",This,dolock);
1876     return S_OK;
1877 }
1878
1879 static IClassFactoryVtbl DSFDCF_Vtbl =
1880 {
1881     DSFDCF_QueryInterface,
1882     DSFDCF_AddRef,
1883     DSFDCF_Release,
1884     DSFDCF_CreateInstance,
1885     DSFDCF_LockServer
1886 };
1887
1888 IClassFactoryImpl DSOUND_FULLDUPLEX_CF = { &DSFDCF_Vtbl, 1 };