Removed excessive statement (break after return or goto, not useful
[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         HeapFree(GetProcessHeap(), 0, This->pwfx);
401         This->lock.DebugInfo->Spare[1] = 0;
402         DeleteCriticalSection( &(This->lock) );
403         HeapFree( GetProcessHeap(), 0, This );
404         dsound_capture = NULL;
405         TRACE("(%p) released\n",This);
406     }
407
408     return uRef;
409 }
410
411 static HRESULT WINAPI
412 IDirectSoundCaptureImpl_CreateCaptureBuffer(
413     LPDIRECTSOUNDCAPTURE iface,
414     LPCDSCBUFFERDESC lpcDSCBufferDesc,
415     LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
416     LPUNKNOWN pUnk )
417 {
418     HRESULT hr;
419     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
420
421     TRACE( "(%p,%p,%p,%p)\n",This,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk );
422
423     if (This == NULL) {
424         WARN("invalid parameter: This == NULL\n");
425         return DSERR_INVALIDPARAM;
426     }
427
428     if (lpcDSCBufferDesc == NULL) {
429         WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
430         return DSERR_INVALIDPARAM;
431     }
432
433     if (lplpDSCaptureBuffer == NULL) {
434         WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
435         return DSERR_INVALIDPARAM;
436     }
437
438     if (pUnk != NULL) {
439         WARN("invalid parameter: pUnk != NULL\n");
440         return DSERR_INVALIDPARAM;
441     }
442
443     /* FIXME: We can only have one buffer so what do we do here? */
444     if (This->capture_buffer) {
445         WARN("lnvalid parameter: already has buffer\n");
446         return DSERR_INVALIDPARAM;    /* DSERR_GENERIC ? */
447     }
448
449     hr = DSOUND_CreateDirectSoundCaptureBuffer( This, lpcDSCBufferDesc,
450         (LPVOID*)lplpDSCaptureBuffer );
451
452     if (hr != DS_OK)
453         WARN("DSOUND_CreateDirectSoundCaptureBuffer failed\n");
454
455     return hr;
456 }
457
458 static HRESULT WINAPI
459 IDirectSoundCaptureImpl_GetCaps(
460     LPDIRECTSOUNDCAPTURE iface,
461     LPDSCCAPS lpDSCCaps )
462 {
463     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
464     TRACE("(%p,%p)\n",This,lpDSCCaps);
465
466     if (lpDSCCaps== NULL) {
467         WARN("invalid parameter: lpDSCCaps== NULL\n");
468         return DSERR_INVALIDPARAM;
469     }
470
471     if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
472         WARN("invalid parameter: lpDSCCaps->dwSize = %ld < %d\n",
473             lpDSCCaps->dwSize, sizeof(*lpDSCCaps));
474         return DSERR_INVALIDPARAM;
475     }
476
477     if ( !(This->initialized) ) {
478         WARN("not initialized\n");
479         return DSERR_UNINITIALIZED;
480     }
481
482     lpDSCCaps->dwFlags = This->drvcaps.dwFlags;
483     lpDSCCaps->dwFormats = This->drvcaps.dwFormats;
484     lpDSCCaps->dwChannels = This->drvcaps.dwChannels;
485
486     TRACE("(flags=0x%08lx,format=0x%08lx,channels=%ld)\n",lpDSCCaps->dwFlags,
487         lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
488
489     return DS_OK;
490 }
491
492 static HRESULT WINAPI
493 IDirectSoundCaptureImpl_Initialize(
494     LPDIRECTSOUNDCAPTURE iface,
495     LPCGUID lpcGUID )
496 {
497     HRESULT err = DSERR_INVALIDPARAM;
498     unsigned wid, widn;
499     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
500     TRACE("(%p)\n", This);
501
502     if (!This) {
503         WARN("invalid parameter: This == NULL\n");
504         return DSERR_INVALIDPARAM;
505     }
506
507     if (This->initialized) {
508         WARN("already initialized\n");
509         return DSERR_ALREADYINITIALIZED;
510     }
511
512     widn = waveInGetNumDevs();
513
514     if (!widn) {
515         WARN("no audio devices found\n");
516         return DSERR_NODRIVER;
517     }
518
519     /* Get dsound configuration */
520     setup_dsound_options();
521
522     /* enumerate WINMM audio devices and find the one we want */
523     for (wid=0; wid<widn; wid++) {
524         if (IsEqualGUID( lpcGUID, &capture_guids[wid]) ) {
525             err = DS_OK;
526             break;
527         }
528     }
529
530     if (err != DS_OK) {
531         WARN("invalid parameter\n");
532         return DSERR_INVALIDPARAM;
533     }
534
535     err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD)&(This->driver),0));
536     if ( (err != DS_OK) && (err != DSERR_UNSUPPORTED) ) {
537         WARN("waveInMessage failed; err=%lx\n",err);
538         return err;
539     }
540     err = DS_OK;
541
542     /* Disable the direct sound driver to force emulation if requested. */
543     if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
544         This->driver = NULL;
545
546     /* Get driver description */
547     if (This->driver) {
548         TRACE("using DirectSound driver\n");
549         err = IDsCaptureDriver_GetDriverDesc(This->driver, &(This->drvdesc));
550         if (err != DS_OK) {
551             WARN("IDsCaptureDriver_GetDriverDesc failed\n");
552             return err;
553         }
554     } else {
555         TRACE("using WINMM\n");
556         /* if no DirectSound interface available, use WINMM API instead */
557         This->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN |
558             DSDDESC_DOMMSYSTEMSETFORMAT;
559     }
560
561     This->drvdesc.dnDevNode = wid;
562
563     /* open the DirectSound driver if available */
564     if (This->driver && (err == DS_OK))
565         err = IDsCaptureDriver_Open(This->driver);
566
567     if (err == DS_OK) {
568         This->initialized = TRUE;
569
570         /* the driver is now open, so it's now allowed to call GetCaps */
571         if (This->driver) {
572             This->drvcaps.dwSize = sizeof(This->drvcaps);
573             err = IDsCaptureDriver_GetCaps(This->driver,&(This->drvcaps));
574             if (err != DS_OK) {
575                 WARN("IDsCaptureDriver_GetCaps failed\n");
576                 return err;
577             }
578         } else /*if (This->hwi)*/ {
579             WAVEINCAPSA    wic;
580             err = mmErr(waveInGetDevCapsA((UINT)This->drvdesc.dnDevNode, &wic, sizeof(wic)));
581
582             if (err == DS_OK) {
583                 This->drvcaps.dwFlags = 0;
584                 strncpy(This->drvdesc.szDrvName, wic.szPname,
585                     sizeof(This->drvdesc.szDrvName));
586
587                 This->drvcaps.dwFlags |= DSCCAPS_EMULDRIVER;
588                 This->drvcaps.dwFormats = wic.dwFormats;
589                 This->drvcaps.dwChannels = wic.wChannels;
590             }
591         }
592     }
593
594     return err;
595 }
596
597 static IDirectSoundCaptureVtbl dscvt =
598 {
599     /* IUnknown methods */
600     IDirectSoundCaptureImpl_QueryInterface,
601     IDirectSoundCaptureImpl_AddRef,
602     IDirectSoundCaptureImpl_Release,
603
604     /* IDirectSoundCapture methods */
605     IDirectSoundCaptureImpl_CreateCaptureBuffer,
606     IDirectSoundCaptureImpl_GetCaps,
607     IDirectSoundCaptureImpl_Initialize
608 };
609
610 static HRESULT
611 DSOUND_CreateDirectSoundCaptureBuffer(
612     IDirectSoundCaptureImpl *ipDSC,
613     LPCDSCBUFFERDESC lpcDSCBufferDesc,
614     LPVOID* ppobj )
615 {
616     LPWAVEFORMATEX  wfex;
617     TRACE( "(%p,%p)\n", lpcDSCBufferDesc, ppobj );
618
619     if (ipDSC == NULL) {
620         WARN("invalid parameter: ipDSC == NULL\n");
621         return DSERR_INVALIDPARAM;
622     }
623
624     if (lpcDSCBufferDesc == NULL) {
625         WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
626         return DSERR_INVALIDPARAM;
627     }
628
629     if (ppobj == NULL) {
630         WARN("invalid parameter: ppobj == NULL\n");
631         return DSERR_INVALIDPARAM;
632     }
633
634     if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
635           (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
636         (lpcDSCBufferDesc->dwBufferBytes == 0) ||
637         (lpcDSCBufferDesc->lpwfxFormat == NULL) ) {
638         WARN("invalid lpcDSCBufferDesc\n");
639         *ppobj = NULL;
640         return DSERR_INVALIDPARAM;
641     }
642
643     if ( !ipDSC->initialized ) {
644         WARN("not initialized\n");
645         *ppobj = NULL;
646         return DSERR_UNINITIALIZED;
647     }
648
649     wfex = lpcDSCBufferDesc->lpwfxFormat;
650
651     if (wfex) {
652         TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
653             "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
654             wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
655             wfex->nAvgBytesPerSec, wfex->nBlockAlign,
656             wfex->wBitsPerSample, wfex->cbSize);
657
658         if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
659             ipDSC->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX));
660             memcpy(ipDSC->pwfx, wfex, sizeof(WAVEFORMATEX));
661             ipDSC->pwfx->cbSize = 0;
662         } else {
663             ipDSC->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)+wfex->cbSize);
664             memcpy(ipDSC->pwfx, wfex, sizeof(WAVEFORMATEX)+wfex->cbSize);
665         }
666     } else {
667         WARN("lpcDSCBufferDesc->lpwfxFormat == 0\n");
668         *ppobj = NULL;
669         return DSERR_INVALIDPARAM; /* FIXME: DSERR_BADFORMAT ? */
670     }
671
672     *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
673         sizeof(IDirectSoundCaptureBufferImpl));
674
675     if ( *ppobj == NULL ) {
676         WARN("out of memory\n");
677         *ppobj = NULL;
678         return DSERR_OUTOFMEMORY;
679     } else {
680         HRESULT err = DS_OK;
681         LPBYTE newbuf;
682         DWORD buflen;
683         IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)*ppobj;
684
685         This->ref = 1;
686         This->dsound = ipDSC;
687         This->dsound->capture_buffer = This;
688         This->notify = NULL;
689         This->nrofnotifies = 0;
690         This->hwnotify = NULL;
691
692         This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
693             lpcDSCBufferDesc->dwSize);
694         if (This->pdscbd)
695             memcpy(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
696         else {
697             WARN("no memory\n");
698             This->dsound->capture_buffer = 0;
699             HeapFree( GetProcessHeap(), 0, This );
700             *ppobj = NULL;
701             return DSERR_OUTOFMEMORY;
702         }
703
704         This->lpVtbl = &dscbvt;
705
706         if (ipDSC->driver) {
707             if (This->dsound->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
708                 FIXME("DSDDESC_DOMMSYSTEMOPEN not supported\n");
709
710             if (This->dsound->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
711                 /* allocate buffer from system memory */
712                 buflen = lpcDSCBufferDesc->dwBufferBytes;
713                 TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->buffer);
714                 if (ipDSC->buffer)
715                     newbuf = HeapReAlloc(GetProcessHeap(),0,ipDSC->buffer,buflen);
716                 else
717                     newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
718
719                 if (newbuf == NULL) {
720                     WARN("failed to allocate capture buffer\n");
721                     err = DSERR_OUTOFMEMORY;
722                     /* but the old buffer might still exist and must be re-prepared */
723                 } else {
724                     ipDSC->buffer = newbuf;
725                     ipDSC->buflen = buflen;
726                 }
727             } else {
728                 /* let driver allocate memory */
729                 ipDSC->buflen = lpcDSCBufferDesc->dwBufferBytes;
730                 /* FIXME: */
731                 HeapFree( GetProcessHeap(), 0, ipDSC->buffer);
732                 ipDSC->buffer = NULL;
733             }
734
735             err = IDsCaptureDriver_CreateCaptureBuffer(ipDSC->driver,
736                 ipDSC->pwfx,0,0,&(ipDSC->buflen),&(ipDSC->buffer),(LPVOID*)&(ipDSC->hwbuf));
737             if (err != DS_OK) {
738                 WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n");
739                 This->dsound->capture_buffer = 0;
740                 HeapFree( GetProcessHeap(), 0, This );
741                 *ppobj = NULL;
742                 return err;
743             }
744         } else {
745             DWORD flags = CALLBACK_FUNCTION;
746             if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
747                 flags |= WAVE_DIRECTSOUND;
748             err = mmErr(waveInOpen(&(ipDSC->hwi),
749                 ipDSC->drvdesc.dnDevNode, ipDSC->pwfx,
750                 (DWORD)DSOUND_capture_callback, (DWORD)ipDSC, flags));
751             if (err != DS_OK) {
752                 WARN("waveInOpen failed\n");
753                 This->dsound->capture_buffer = 0;
754                 HeapFree( GetProcessHeap(), 0, This );
755                 *ppobj = NULL;
756                 return err;
757             }
758
759             buflen = lpcDSCBufferDesc->dwBufferBytes;
760             TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->buffer);
761             if (ipDSC->buffer)
762                 newbuf = HeapReAlloc(GetProcessHeap(),0,ipDSC->buffer,buflen);
763             else
764                 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
765             if (newbuf == NULL) {
766                 WARN("failed to allocate capture buffer\n");
767                 err = DSERR_OUTOFMEMORY;
768                 /* but the old buffer might still exist and must be re-prepared */
769             } else {
770                 ipDSC->buffer = newbuf;
771                 ipDSC->buflen = buflen;
772             }
773         }
774     }
775
776     TRACE("returning DS_OK\n");
777     return DS_OK;
778 }
779
780 /*******************************************************************************
781  *              IDirectSoundCaptureNotify
782  */
783 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface(
784     LPDIRECTSOUNDNOTIFY iface,
785     REFIID riid,
786     LPVOID *ppobj)
787 {
788     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
789     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
790
791     if (This->dscb == NULL) {
792         WARN("invalid parameter\n");
793         return E_INVALIDARG;
794     }
795
796     return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
797 }
798
799 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
800 {
801     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
802     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
803     return InterlockedIncrement(&(This->ref));
804 }
805
806 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
807 {
808     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
809     ULONG ref;
810
811     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
812
813     ref = InterlockedDecrement(&(This->ref));
814     if (ref == 0) {
815         if (This->dscb->hwnotify)
816             IDsDriverNotify_Release(This->dscb->hwnotify);
817         This->dscb->notify=NULL;
818         IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb);
819         HeapFree(GetProcessHeap(),0,This);
820         TRACE("(%p) released\n",This);
821     }
822     return ref;
823 }
824
825 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions(
826     LPDIRECTSOUNDNOTIFY iface,
827     DWORD howmuch,
828     LPCDSBPOSITIONNOTIFY notify)
829 {
830     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
831     TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
832
833     if (howmuch > 0 && notify == NULL) {
834         WARN("invalid parameter: notify == NULL\n");
835         return DSERR_INVALIDPARAM;
836     }
837
838     if (TRACE_ON(dsound)) {
839         unsigned int i;
840         for (i=0;i<howmuch;i++)
841             TRACE("notify at %ld to 0x%08lx\n",
842             notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
843     }
844
845     if (This->dscb->hwnotify) {
846         HRESULT hres;
847         hres = IDsDriverNotify_SetNotificationPositions(This->dscb->hwnotify, howmuch, notify);
848         if (hres != DS_OK)
849             WARN("IDsDriverNotify_SetNotificationPositions failed\n");
850         return hres;
851     } else if (howmuch > 0) {
852         /* Make an internal copy of the caller-supplied array.
853          * Replace the existing copy if one is already present. */
854         if (This->dscb->notifies)
855             This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
856                 This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
857         else
858             This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
859                 howmuch * sizeof(DSBPOSITIONNOTIFY));
860
861         if (This->dscb->notifies == NULL) {
862             WARN("out of memory\n");
863             return DSERR_OUTOFMEMORY;
864         }
865         memcpy(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
866         This->dscb->nrofnotifies = howmuch;
867     } else {
868         HeapFree(GetProcessHeap(), 0, This->dscb->notifies);
869         This->dscb->notifies = NULL;
870         This->dscb->nrofnotifies = 0;
871     }
872
873     return S_OK;
874 }
875
876 IDirectSoundNotifyVtbl dscnvt =
877 {
878     IDirectSoundCaptureNotifyImpl_QueryInterface,
879     IDirectSoundCaptureNotifyImpl_AddRef,
880     IDirectSoundCaptureNotifyImpl_Release,
881     IDirectSoundCaptureNotifyImpl_SetNotificationPositions,
882 };
883
884 HRESULT WINAPI IDirectSoundCaptureNotifyImpl_Create(
885     IDirectSoundCaptureBufferImpl *dscb,
886     IDirectSoundCaptureNotifyImpl **pdscn)
887 {
888     IDirectSoundCaptureNotifyImpl * dscn;
889     TRACE("(%p,%p)\n",dscb,pdscn);
890
891     dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscn));
892
893     if (dscn == NULL) {
894         WARN("out of memory\n");
895         return DSERR_OUTOFMEMORY;
896     }
897
898     dscn->ref = 0;
899     dscn->lpVtbl = &dscnvt;
900     dscn->dscb = dscb;
901     dscb->notify = dscn;
902     IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb);
903
904     *pdscn = dscn;
905     return DS_OK;
906 }
907
908 /*******************************************************************************
909  *              IDirectSoundCaptureBuffer
910  */
911 static HRESULT WINAPI
912 IDirectSoundCaptureBufferImpl_QueryInterface(
913     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
914     REFIID riid,
915     LPVOID* ppobj )
916 {
917     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
918     HRESULT hres;
919     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
920
921     if (ppobj == NULL) {
922         WARN("invalid parameter\n");
923         return E_INVALIDARG;
924     }
925
926     *ppobj = NULL;
927
928     if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
929         if (!This->notify)
930             hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify);
931         if (This->notify) {
932             if (This->dsound->hwbuf) {
933                 hres = IDsCaptureDriverBuffer_QueryInterface(This->dsound->hwbuf,
934                     &IID_IDsDriverNotify, (LPVOID*)&(This->hwnotify));
935                 if (hres != DS_OK) {
936                     WARN("IDsCaptureDriverBuffer_QueryInterface failed\n");
937                     *ppobj = 0;
938                     return hres;
939                 }
940             }
941
942             IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
943             *ppobj = (LPVOID)This->notify;
944             return DS_OK;
945         }
946
947         WARN("IID_IDirectSoundNotify\n");
948         return E_FAIL;
949     }
950
951     if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
952          IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
953         IDirectSoundCaptureBuffer8_AddRef(iface);
954         *ppobj = This;
955         return NO_ERROR;
956     }
957
958     FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
959     return E_NOINTERFACE;
960 }
961
962 static ULONG WINAPI
963 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
964 {
965     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
966     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
967     return InterlockedIncrement(&(This->ref));
968 }
969
970 static ULONG WINAPI
971 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
972 {
973     ULONG uRef;
974     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
975     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
976
977     uRef = InterlockedDecrement(&(This->ref));
978     if ( uRef == 0 ) {
979         TRACE("deleting object\n");
980         if (This->dsound->state == STATE_CAPTURING)
981             This->dsound->state = STATE_STOPPING;
982
983         HeapFree(GetProcessHeap(),0, This->pdscbd);
984
985         if (This->dsound->hwi) {
986             waveInReset(This->dsound->hwi);
987             waveInClose(This->dsound->hwi);
988             HeapFree(GetProcessHeap(),0, This->dsound->pwave);
989             This->dsound->pwave = 0;
990             This->dsound->hwi = 0;
991         }
992
993         if (This->dsound->hwbuf)
994             IDsCaptureDriverBuffer_Release(This->dsound->hwbuf);
995
996         /* remove from IDirectSoundCaptureImpl */
997         if (This->dsound)
998             This->dsound->capture_buffer = NULL;
999         else
1000             ERR("does not reference dsound\n");
1001
1002         if (This->notify)
1003             IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
1004
1005         HeapFree(GetProcessHeap(), 0, This->notifies);
1006         HeapFree( GetProcessHeap(), 0, This );
1007         TRACE("(%p) released\n",This);
1008     }
1009
1010     return uRef;
1011 }
1012
1013 static HRESULT WINAPI
1014 IDirectSoundCaptureBufferImpl_GetCaps(
1015     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1016     LPDSCBCAPS lpDSCBCaps )
1017 {
1018     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1019     TRACE( "(%p,%p)\n", This, lpDSCBCaps );
1020
1021     if (This == NULL) {
1022         WARN("invalid parameter: This == NULL\n");
1023         return DSERR_INVALIDPARAM;
1024     }
1025
1026     if (lpDSCBCaps == NULL) {
1027         WARN("invalid parameter: lpDSCBCaps == NULL\n");
1028         return DSERR_INVALIDPARAM;
1029     }
1030
1031     if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
1032         WARN("invalid parameter: lpDSCBCaps->dwSize = %ld < %d\n",
1033             lpDSCBCaps->dwSize, sizeof(DSCBCAPS));
1034         return DSERR_INVALIDPARAM;
1035     }
1036
1037     if (This->dsound == NULL) {
1038         WARN("invalid parameter: This->dsound == NULL\n");
1039         return DSERR_INVALIDPARAM;
1040     }
1041
1042     lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
1043     lpDSCBCaps->dwFlags = This->flags;
1044     lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
1045     lpDSCBCaps->dwReserved = 0;
1046
1047     TRACE("returning DS_OK\n");
1048     return DS_OK;
1049 }
1050
1051 static HRESULT WINAPI
1052 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
1053     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1054     LPDWORD lpdwCapturePosition,
1055     LPDWORD lpdwReadPosition )
1056 {
1057     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1058     HRESULT hres = DS_OK;
1059     TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
1060
1061     if (This == NULL) {
1062         WARN("invalid parameter: This == NULL\n");
1063         return DSERR_INVALIDPARAM;
1064     }
1065
1066     if (This->dsound == NULL) {
1067         WARN("invalid parameter: This->dsound == NULL\n");
1068         return DSERR_INVALIDPARAM;
1069     }
1070
1071     if (This->dsound->driver) {
1072         hres = IDsCaptureDriverBuffer_GetPosition(This->dsound->hwbuf, lpdwCapturePosition, lpdwReadPosition );
1073         if (hres != DS_OK)
1074             WARN("IDsCaptureDriverBuffer_GetPosition failed\n");
1075     } else if (This->dsound->hwi) {
1076         EnterCriticalSection(&(This->dsound->lock));
1077         TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1078         if (lpdwCapturePosition) {
1079             MMTIME mtime;
1080             mtime.wType = TIME_BYTES;
1081             waveInGetPosition(This->dsound->hwi, &mtime, sizeof(mtime));
1082             TRACE("mtime.u.cb=%ld,This->dsound->buflen=%ld\n", mtime.u.cb,
1083                 This->dsound->buflen);
1084             mtime.u.cb = mtime.u.cb % This->dsound->buflen;
1085             *lpdwCapturePosition = mtime.u.cb;
1086         }
1087
1088         if (lpdwReadPosition) {
1089             if (This->dsound->state == STATE_STARTING) {
1090                 if (lpdwCapturePosition)
1091                     This->dsound->read_position = *lpdwCapturePosition;
1092                 This->dsound->state = STATE_CAPTURING;
1093             }
1094             *lpdwReadPosition = This->dsound->read_position;
1095         }
1096         TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1097         LeaveCriticalSection(&(This->dsound->lock));
1098         if (lpdwCapturePosition) TRACE("*lpdwCapturePosition=%ld\n",*lpdwCapturePosition);
1099         if (lpdwReadPosition) TRACE("*lpdwReadPosition=%ld\n",*lpdwReadPosition);
1100     } else {
1101         WARN("no driver\n");
1102         hres = DSERR_NODRIVER;
1103     }
1104
1105     TRACE("returning %08lx\n", hres);
1106     return hres;
1107 }
1108
1109 static HRESULT WINAPI
1110 IDirectSoundCaptureBufferImpl_GetFormat(
1111     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1112     LPWAVEFORMATEX lpwfxFormat,
1113     DWORD dwSizeAllocated,
1114     LPDWORD lpdwSizeWritten )
1115 {
1116     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1117     HRESULT hres = DS_OK;
1118     TRACE( "(%p,%p,0x%08lx,%p)\n", This, lpwfxFormat, dwSizeAllocated,
1119         lpdwSizeWritten );
1120
1121     if (This == NULL) {
1122         WARN("invalid parameter: This == NULL\n");
1123         return DSERR_INVALIDPARAM;
1124     }
1125
1126     if (This->dsound == NULL) {
1127         WARN("invalid parameter: This->dsound == NULL\n");
1128         return DSERR_INVALIDPARAM;
1129     }
1130
1131     if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize))
1132         dwSizeAllocated = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize;
1133
1134     if (lpwfxFormat) { /* NULL is valid (just want size) */
1135         memcpy(lpwfxFormat, This->dsound->pwfx, dwSizeAllocated);
1136         if (lpdwSizeWritten)
1137             *lpdwSizeWritten = dwSizeAllocated;
1138     } else {
1139         if (lpdwSizeWritten)
1140             *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize;
1141         else {
1142             TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
1143             hres = DSERR_INVALIDPARAM;
1144         }
1145     }
1146
1147     TRACE("returning %08lx\n", hres);
1148     return hres;
1149 }
1150
1151 static HRESULT WINAPI
1152 IDirectSoundCaptureBufferImpl_GetStatus(
1153     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1154     LPDWORD lpdwStatus )
1155 {
1156     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1157     TRACE( "(%p, %p), thread is %04lx\n", This, lpdwStatus, GetCurrentThreadId() );
1158
1159     if (This == NULL) {
1160         WARN("invalid parameter: This == NULL\n");
1161         return DSERR_INVALIDPARAM;
1162     }
1163
1164     if (This->dsound == NULL) {
1165         WARN("invalid parameter: This->dsound == NULL\n");
1166         return DSERR_INVALIDPARAM;
1167     }
1168
1169     if (lpdwStatus == NULL) {
1170         WARN("invalid parameter: lpdwStatus == NULL\n");
1171         return DSERR_INVALIDPARAM;
1172     }
1173
1174     *lpdwStatus = 0;
1175     EnterCriticalSection(&(This->dsound->lock));
1176
1177     TRACE("old This->dsound->state=%s, old lpdwStatus=%08lx\n",
1178         captureStateString[This->dsound->state],*lpdwStatus);
1179     if ((This->dsound->state == STATE_STARTING) ||
1180         (This->dsound->state == STATE_CAPTURING)) {
1181         *lpdwStatus |= DSCBSTATUS_CAPTURING;
1182         if (This->flags & DSCBSTART_LOOPING)
1183             *lpdwStatus |= DSCBSTATUS_LOOPING;
1184     }
1185     TRACE("new This->dsound->state=%s, new lpdwStatus=%08lx\n",
1186         captureStateString[This->dsound->state],*lpdwStatus);
1187     LeaveCriticalSection(&(This->dsound->lock));
1188
1189     TRACE("status=%lx\n", *lpdwStatus);
1190     TRACE("returning DS_OK\n");
1191     return DS_OK;
1192 }
1193
1194 static HRESULT WINAPI
1195 IDirectSoundCaptureBufferImpl_Initialize(
1196     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1197     LPDIRECTSOUNDCAPTURE lpDSC,
1198     LPCDSCBUFFERDESC lpcDSCBDesc )
1199 {
1200     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1201
1202     FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
1203
1204     return DS_OK;
1205 }
1206
1207 static HRESULT WINAPI
1208 IDirectSoundCaptureBufferImpl_Lock(
1209     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1210     DWORD dwReadCusor,
1211     DWORD dwReadBytes,
1212     LPVOID* lplpvAudioPtr1,
1213     LPDWORD lpdwAudioBytes1,
1214     LPVOID* lplpvAudioPtr2,
1215     LPDWORD lpdwAudioBytes2,
1216     DWORD dwFlags )
1217 {
1218     HRESULT hres = DS_OK;
1219     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1220     TRACE( "(%p,%08lu,%08lu,%p,%p,%p,%p,0x%08lx) at %ld\n", This, dwReadCusor,
1221         dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
1222         lpdwAudioBytes2, dwFlags, GetTickCount() );
1223
1224     if (This == NULL) {
1225         WARN("invalid parameter: This == NULL\n");
1226         return DSERR_INVALIDPARAM;
1227     }
1228
1229     if (This->dsound == NULL) {
1230         WARN("invalid parameter: This->dsound == NULL\n");
1231         return DSERR_INVALIDPARAM;
1232     }
1233
1234     if (lplpvAudioPtr1 == NULL) {
1235         WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
1236         return DSERR_INVALIDPARAM;
1237     }
1238
1239     if (lpdwAudioBytes1 == NULL) {
1240         WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
1241         return DSERR_INVALIDPARAM;
1242     }
1243
1244     EnterCriticalSection(&(This->dsound->lock));
1245
1246     if (This->dsound->driver) {
1247         hres = IDsCaptureDriverBuffer_Lock(This->dsound->hwbuf, lplpvAudioPtr1,
1248                                            lpdwAudioBytes1, lplpvAudioPtr2,
1249                                            lpdwAudioBytes2, dwReadCusor,
1250                                            dwReadBytes, dwFlags);
1251         if (hres != DS_OK)
1252             WARN("IDsCaptureDriverBuffer_Lock failed\n");
1253     } else if (This->dsound->hwi) {
1254         *lplpvAudioPtr1 = This->dsound->buffer + dwReadCusor;
1255         if ( (dwReadCusor + dwReadBytes) > This->dsound->buflen) {
1256             *lpdwAudioBytes1 = This->dsound->buflen - dwReadCusor;
1257             if (lplpvAudioPtr2)
1258                 *lplpvAudioPtr2 = This->dsound->buffer;
1259             if (lpdwAudioBytes2)
1260                 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
1261         } else {
1262             *lpdwAudioBytes1 = dwReadBytes;
1263             if (lplpvAudioPtr2)
1264                 *lplpvAudioPtr2 = 0;
1265             if (lpdwAudioBytes2)
1266                 *lpdwAudioBytes2 = 0;
1267         }
1268     } else {
1269         TRACE("invalid call\n");
1270         hres = DSERR_INVALIDCALL;   /* DSERR_NODRIVER ? */
1271     }
1272
1273     LeaveCriticalSection(&(This->dsound->lock));
1274
1275     TRACE("returning %08lx\n", hres);
1276     return hres;
1277 }
1278
1279 static HRESULT WINAPI
1280 IDirectSoundCaptureBufferImpl_Start(
1281     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1282     DWORD dwFlags )
1283 {
1284     HRESULT hres = DS_OK;
1285     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1286     TRACE( "(%p,0x%08lx)\n", This, dwFlags );
1287
1288     if (This == NULL) {
1289         WARN("invalid parameter: This == NULL\n");
1290         return DSERR_INVALIDPARAM;
1291     }
1292
1293     if (This->dsound == NULL) {
1294         WARN("invalid parameter: This->dsound == NULL\n");
1295         return DSERR_INVALIDPARAM;
1296     }
1297
1298     if ( (This->dsound->driver == 0) && (This->dsound->hwi == 0) ) {
1299         WARN("no driver\n");
1300         return DSERR_NODRIVER;
1301     }
1302
1303     EnterCriticalSection(&(This->dsound->lock));
1304
1305     This->flags = dwFlags;
1306     TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1307     if (This->dsound->state == STATE_STOPPED)
1308         This->dsound->state = STATE_STARTING;
1309     else if (This->dsound->state == STATE_STOPPING)
1310         This->dsound->state = STATE_CAPTURING;
1311     TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1312
1313     LeaveCriticalSection(&(This->dsound->lock));
1314
1315     if (This->dsound->driver) {
1316         hres = IDsCaptureDriverBuffer_Start(This->dsound->hwbuf, dwFlags);
1317         if (hres != DS_OK)
1318             WARN("IDsCaptureDriverBuffer_Start failed\n");
1319     } else if (This->dsound->hwi) {
1320         IDirectSoundCaptureImpl* ipDSC = This->dsound;
1321
1322         if (ipDSC->buffer) {
1323             if (This->nrofnotifies) {
1324                 int c;
1325
1326                 ipDSC->nrofpwaves = This->nrofnotifies;
1327                 TRACE("nrofnotifies=%d\n", This->nrofnotifies);
1328
1329                 /* prepare headers */
1330                 if (ipDSC->pwave)
1331                     ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave,
1332                         ipDSC->nrofpwaves*sizeof(WAVEHDR));
1333                 else
1334                     ipDSC->pwave = HeapAlloc(GetProcessHeap(),0,
1335                         ipDSC->nrofpwaves*sizeof(WAVEHDR));
1336
1337                 for (c = 0; c < ipDSC->nrofpwaves; c++) {
1338                     if (This->notifies[c].dwOffset == DSBPN_OFFSETSTOP) {
1339                         TRACE("got DSBPN_OFFSETSTOP\n");
1340                         ipDSC->nrofpwaves = c;
1341                         break;
1342                     }
1343                     if (c == 0) {
1344                         ipDSC->pwave[0].lpData = ipDSC->buffer;
1345                         ipDSC->pwave[0].dwBufferLength =
1346                             This->notifies[0].dwOffset + 1;
1347                     } else {
1348                         ipDSC->pwave[c].lpData = ipDSC->buffer +
1349                             This->notifies[c-1].dwOffset + 1;
1350                         ipDSC->pwave[c].dwBufferLength =
1351                             This->notifies[c].dwOffset -
1352                             This->notifies[c-1].dwOffset;
1353                     }
1354                     ipDSC->pwave[c].dwBytesRecorded = 0;
1355                     ipDSC->pwave[c].dwUser = (DWORD)ipDSC;
1356                     ipDSC->pwave[c].dwFlags = 0;
1357                     ipDSC->pwave[c].dwLoops = 0;
1358                     hres = mmErr(waveInPrepareHeader(ipDSC->hwi,
1359                         &(ipDSC->pwave[c]),sizeof(WAVEHDR)));
1360                     if (hres != DS_OK) {
1361                         WARN("waveInPrepareHeader failed\n");
1362                         while (c--)
1363                             waveInUnprepareHeader(ipDSC->hwi,
1364                                 &(ipDSC->pwave[c]),sizeof(WAVEHDR));
1365                         break;
1366                     }
1367
1368                     hres = mmErr(waveInAddBuffer(ipDSC->hwi,
1369                         &(ipDSC->pwave[c]), sizeof(WAVEHDR)));
1370                     if (hres != DS_OK) {
1371                         WARN("waveInAddBuffer failed\n");
1372                         while (c--)
1373                             waveInUnprepareHeader(ipDSC->hwi,
1374                                 &(ipDSC->pwave[c]),sizeof(WAVEHDR));
1375                         break;
1376                     }
1377                 }
1378
1379                 memset(ipDSC->buffer,
1380                     (ipDSC->pwfx->wBitsPerSample == 8) ? 128 : 0, ipDSC->buflen);
1381             } else {
1382                 TRACE("no notifiers specified\n");
1383                 /* no notifiers specified so just create a single default header */
1384                 ipDSC->nrofpwaves = 1;
1385                 if (ipDSC->pwave)
1386                     ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave,sizeof(WAVEHDR));
1387                 else
1388                     ipDSC->pwave = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEHDR));
1389
1390                 ipDSC->pwave[0].lpData = ipDSC->buffer;
1391                 ipDSC->pwave[0].dwBufferLength = ipDSC->buflen;
1392                 ipDSC->pwave[0].dwBytesRecorded = 0;
1393                 ipDSC->pwave[0].dwUser = (DWORD)ipDSC;
1394                 ipDSC->pwave[0].dwFlags = 0;
1395                 ipDSC->pwave[0].dwLoops = 0;
1396
1397                 hres = mmErr(waveInPrepareHeader(ipDSC->hwi,
1398                     &(ipDSC->pwave[0]),sizeof(WAVEHDR)));
1399                 if (hres != DS_OK) {
1400                     WARN("waveInPrepareHeader failed\n");
1401                     waveInUnprepareHeader(ipDSC->hwi,
1402                         &(ipDSC->pwave[0]),sizeof(WAVEHDR));
1403                 }
1404                 hres = mmErr(waveInAddBuffer(ipDSC->hwi,
1405                     &(ipDSC->pwave[0]), sizeof(WAVEHDR)));
1406                 if (hres != DS_OK) {
1407                     WARN("waveInAddBuffer failed\n");
1408                     waveInUnprepareHeader(ipDSC->hwi,
1409                         &(ipDSC->pwave[0]),sizeof(WAVEHDR));
1410                 }
1411             }
1412         }
1413
1414         ipDSC->index = 0;
1415         ipDSC->read_position = 0;
1416
1417         if (hres == DS_OK) {
1418             /* start filling the first buffer */
1419             hres = mmErr(waveInStart(ipDSC->hwi));
1420             if (hres != DS_OK)
1421                 WARN("waveInStart failed\n");
1422         }
1423
1424         if (hres != DS_OK) {
1425             WARN("calling waveInClose because of error\n");
1426             waveInClose(This->dsound->hwi);
1427             This->dsound->hwi = 0;
1428         }
1429     } else {
1430         WARN("no driver\n");
1431         hres = DSERR_NODRIVER;
1432     }
1433
1434     TRACE("returning %08lx\n", hres);
1435     return hres;
1436 }
1437
1438 static HRESULT WINAPI
1439 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
1440 {
1441     HRESULT hres = DS_OK;
1442     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1443     TRACE( "(%p)\n", This );
1444
1445     if (This == NULL) {
1446         WARN("invalid parameter: This == NULL\n");
1447         return DSERR_INVALIDPARAM;
1448     }
1449
1450     if (This->dsound == NULL) {
1451         WARN("invalid parameter: This->dsound == NULL\n");
1452         return DSERR_INVALIDPARAM;
1453     }
1454
1455     EnterCriticalSection(&(This->dsound->lock));
1456
1457     TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1458     if (This->dsound->state == STATE_CAPTURING)
1459         This->dsound->state = STATE_STOPPING;
1460     else if (This->dsound->state == STATE_STARTING)
1461         This->dsound->state = STATE_STOPPED;
1462     TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]);
1463
1464     LeaveCriticalSection(&(This->dsound->lock));
1465
1466     if (This->dsound->driver) {
1467         hres = IDsCaptureDriverBuffer_Stop(This->dsound->hwbuf);
1468         if (hres != DS_OK)
1469             WARN("IDsCaptureDriverBuffer_Stop() failed\n");
1470     } else if (This->dsound->hwi) {
1471         hres = mmErr(waveInReset(This->dsound->hwi));
1472         if (hres != DS_OK)
1473             WARN("waveInReset() failed\n");
1474     } else {
1475         WARN("no driver\n");
1476         hres = DSERR_NODRIVER;
1477     }
1478
1479     TRACE("returning %08lx\n", hres);
1480     return hres;
1481 }
1482
1483 static HRESULT WINAPI
1484 IDirectSoundCaptureBufferImpl_Unlock(
1485     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1486     LPVOID lpvAudioPtr1,
1487     DWORD dwAudioBytes1,
1488     LPVOID lpvAudioPtr2,
1489     DWORD dwAudioBytes2 )
1490 {
1491     HRESULT hres = DS_OK;
1492     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1493     TRACE( "(%p,%p,%08lu,%p,%08lu)\n", This, lpvAudioPtr1, dwAudioBytes1,
1494         lpvAudioPtr2, dwAudioBytes2 );
1495
1496     if (This == NULL) {
1497         WARN("invalid parameter: This == NULL\n");
1498         return DSERR_INVALIDPARAM;
1499     }
1500
1501     if (lpvAudioPtr1 == NULL) {
1502         WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
1503         return DSERR_INVALIDPARAM;
1504     }
1505
1506     if (This->dsound->driver) {
1507         hres = IDsCaptureDriverBuffer_Unlock(This->dsound->hwbuf, lpvAudioPtr1,
1508                                              dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1509         if (hres != DS_OK)
1510             WARN("IDsCaptureDriverBuffer_Unlock failed\n");
1511     } else if (This->dsound->hwi) {
1512         This->dsound->read_position = (This->dsound->read_position +
1513             (dwAudioBytes1 + dwAudioBytes2)) % This->dsound->buflen;
1514     } else {
1515         WARN("invalid call\n");
1516         hres = DSERR_INVALIDCALL;
1517     }
1518
1519     TRACE("returning %08lx\n", hres);
1520     return hres;
1521 }
1522
1523 static HRESULT WINAPI
1524 IDirectSoundCaptureBufferImpl_GetObjectInPath(
1525     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1526     REFGUID rguidObject,
1527     DWORD dwIndex,
1528     REFGUID rguidInterface,
1529     LPVOID* ppObject )
1530 {
1531     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1532
1533     FIXME( "(%p,%s,%lu,%s,%p): stub\n", This, debugstr_guid(rguidObject),
1534         dwIndex, debugstr_guid(rguidInterface), ppObject );
1535
1536     return DS_OK;
1537 }
1538
1539 static HRESULT WINAPI
1540 IDirectSoundCaptureBufferImpl_GetFXStatus(
1541     LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1542     DWORD dwFXCount,
1543     LPDWORD pdwFXStatus )
1544 {
1545     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1546
1547     FIXME( "(%p,%lu,%p): stub\n", This, dwFXCount, pdwFXStatus );
1548
1549     return DS_OK;
1550 }
1551
1552 static IDirectSoundCaptureBuffer8Vtbl dscbvt =
1553 {
1554     /* IUnknown methods */
1555     IDirectSoundCaptureBufferImpl_QueryInterface,
1556     IDirectSoundCaptureBufferImpl_AddRef,
1557     IDirectSoundCaptureBufferImpl_Release,
1558
1559     /* IDirectSoundCaptureBuffer methods */
1560     IDirectSoundCaptureBufferImpl_GetCaps,
1561     IDirectSoundCaptureBufferImpl_GetCurrentPosition,
1562     IDirectSoundCaptureBufferImpl_GetFormat,
1563     IDirectSoundCaptureBufferImpl_GetStatus,
1564     IDirectSoundCaptureBufferImpl_Initialize,
1565     IDirectSoundCaptureBufferImpl_Lock,
1566     IDirectSoundCaptureBufferImpl_Start,
1567     IDirectSoundCaptureBufferImpl_Stop,
1568     IDirectSoundCaptureBufferImpl_Unlock,
1569
1570     /* IDirectSoundCaptureBuffer methods */
1571     IDirectSoundCaptureBufferImpl_GetObjectInPath,
1572     IDirectSoundCaptureBufferImpl_GetFXStatus
1573 };
1574
1575 /*******************************************************************************
1576  * DirectSoundCapture ClassFactory
1577  */
1578
1579 static HRESULT WINAPI
1580 DSCCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
1581 {
1582     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1583
1584     FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1585     return E_NOINTERFACE;
1586 }
1587
1588 static ULONG WINAPI
1589 DSCCF_AddRef(LPCLASSFACTORY iface)
1590 {
1591     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1592     TRACE("(%p) ref was %ld\n", This, This->ref);
1593     return InterlockedIncrement(&(This->ref));
1594 }
1595
1596 static ULONG WINAPI
1597 DSCCF_Release(LPCLASSFACTORY iface)
1598 {
1599     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1600     /* static class, won't be  freed */
1601     TRACE("(%p) ref was %ld\n", This, This->ref);
1602     return InterlockedDecrement(&(This->ref));
1603 }
1604
1605 static HRESULT WINAPI
1606 DSCCF_CreateInstance(
1607         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj )
1608 {
1609     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1610     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1611
1612     if (pOuter) {
1613         WARN("aggregation not supported\n");
1614         return CLASS_E_NOAGGREGATION;
1615     }
1616
1617     if (ppobj == NULL) {
1618         WARN("invalid parameter\n");
1619         return E_INVALIDARG;
1620     }
1621
1622     *ppobj = NULL;
1623
1624     if ( IsEqualGUID( &IID_IDirectSoundCapture8, riid ) )
1625         return DirectSoundCaptureCreate8(0,(LPDIRECTSOUNDCAPTURE8*)ppobj,pOuter);
1626
1627     WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); 
1628     return E_NOINTERFACE;
1629 }
1630
1631 static HRESULT WINAPI
1632 DSCCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
1633 {
1634     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1635     FIXME("(%p)->(%d),stub!\n",This,dolock);
1636     return S_OK;
1637 }
1638
1639 static IClassFactoryVtbl DSCCF_Vtbl =
1640 {
1641     DSCCF_QueryInterface,
1642     DSCCF_AddRef,
1643     DSCCF_Release,
1644     DSCCF_CreateInstance,
1645     DSCCF_LockServer
1646 };
1647
1648 IClassFactoryImpl DSOUND_CAPTURE_CF = { &DSCCF_Vtbl, 1 };
1649
1650 /***************************************************************************
1651  * DirectSoundFullDuplexCreate [DSOUND.10]
1652  *
1653  * Create and initialize a DirectSoundFullDuplex interface.
1654  *
1655  * PARAMS
1656  *    pcGuidCaptureDevice [I] Address of sound capture device GUID.
1657  *    pcGuidRenderDevice  [I] Address of sound render device GUID.
1658  *    pcDSCBufferDesc     [I] Address of capture buffer description.
1659  *    pcDSBufferDesc      [I] Address of  render buffer description.
1660  *    hWnd                [I] Handle to application window.
1661  *    dwLevel             [I] Cooperative level.
1662  *    ppDSFD              [O] Address where full duplex interface returned.
1663  *    ppDSCBuffer8        [0] Address where capture buffer interface returned.
1664  *    ppDSBuffer8         [0] Address where render buffer interface returned.
1665  *    pUnkOuter           [I] Must be NULL.
1666  *
1667  * RETURNS
1668  *    Success: DS_OK
1669  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1670  *             DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
1671  */
1672 HRESULT WINAPI
1673 DirectSoundFullDuplexCreate(
1674     LPCGUID pcGuidCaptureDevice,
1675     LPCGUID pcGuidRenderDevice,
1676     LPCDSCBUFFERDESC pcDSCBufferDesc,
1677     LPCDSBUFFERDESC pcDSBufferDesc,
1678     HWND hWnd,
1679     DWORD dwLevel,
1680     LPDIRECTSOUNDFULLDUPLEX *ppDSFD,
1681     LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8,
1682     LPDIRECTSOUNDBUFFER8 *ppDSBuffer8,
1683     LPUNKNOWN pUnkOuter)
1684 {
1685     IDirectSoundFullDuplexImpl** ippDSFD=(IDirectSoundFullDuplexImpl**)ppDSFD;
1686     TRACE("(%s,%s,%p,%p,%lx,%lx,%p,%p,%p,%p)\n", debugstr_guid(pcGuidCaptureDevice),
1687         debugstr_guid(pcGuidRenderDevice), pcDSCBufferDesc, pcDSBufferDesc,
1688         (DWORD)hWnd, dwLevel, ppDSFD, ppDSCBuffer8, ppDSBuffer8, pUnkOuter);
1689
1690     if ( pUnkOuter ) {
1691         WARN("pUnkOuter != 0\n");
1692         return DSERR_NOAGGREGATION;
1693     }
1694
1695     *ippDSFD = HeapAlloc(GetProcessHeap(),
1696         HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl));
1697
1698     if (*ippDSFD == NULL) {
1699         WARN("out of memory\n");
1700         return DSERR_OUTOFMEMORY;
1701     } else {
1702         HRESULT hres;
1703         IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)*ippDSFD;
1704
1705         This->ref = 1;
1706         This->lpVtbl = &dsfdvt;
1707
1708         InitializeCriticalSection( &(This->lock) );
1709         This->lock.DebugInfo->Spare[1] = (DWORD)"DSDUPLEX_lock";
1710
1711         hres = IDirectSoundFullDuplexImpl_Initialize( (LPDIRECTSOUNDFULLDUPLEX)This,
1712                                                       pcGuidCaptureDevice, pcGuidRenderDevice,
1713                                                       pcDSCBufferDesc, pcDSBufferDesc,
1714                                                       hWnd, dwLevel, ppDSCBuffer8, ppDSBuffer8);
1715         if (hres != DS_OK)
1716             WARN("IDirectSoundFullDuplexImpl_Initialize failed\n");
1717         return hres;
1718     }
1719 }
1720
1721 static HRESULT WINAPI
1722 IDirectSoundFullDuplexImpl_QueryInterface(
1723     LPDIRECTSOUNDFULLDUPLEX iface,
1724     REFIID riid,
1725     LPVOID* ppobj )
1726 {
1727     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
1728     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
1729
1730     if (ppobj == NULL) {
1731         WARN("invalid parameter\n");
1732         return E_INVALIDARG;
1733     }
1734
1735     *ppobj = NULL;
1736     return E_NOINTERFACE;
1737 }
1738
1739 static ULONG WINAPI
1740 IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface )
1741 {
1742     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
1743     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1744     return InterlockedIncrement(&(This->ref));
1745 }
1746
1747 static ULONG WINAPI
1748 IDirectSoundFullDuplexImpl_Release( LPDIRECTSOUNDFULLDUPLEX iface )
1749 {
1750     ULONG uRef;
1751     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
1752     TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1753
1754     uRef = InterlockedDecrement(&(This->ref));
1755     if ( uRef == 0 ) {
1756         This->lock.DebugInfo->Spare[1] = 0;
1757         DeleteCriticalSection( &(This->lock) );
1758         HeapFree( GetProcessHeap(), 0, This );
1759         TRACE("(%p) released\n",This);
1760     }
1761
1762     return uRef;
1763 }
1764
1765 static HRESULT WINAPI
1766 IDirectSoundFullDuplexImpl_Initialize(
1767     LPDIRECTSOUNDFULLDUPLEX iface,
1768     LPCGUID pCaptureGuid,
1769     LPCGUID pRendererGuid,
1770     LPCDSCBUFFERDESC lpDscBufferDesc,
1771     LPCDSBUFFERDESC lpDsBufferDesc,
1772     HWND hWnd,
1773     DWORD dwLevel,
1774     LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8,
1775     LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 )
1776 {
1777     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
1778     IDirectSoundCaptureBufferImpl** ippdscb=(IDirectSoundCaptureBufferImpl**)lplpDirectSoundCaptureBuffer8;
1779     IDirectSoundBufferImpl** ippdsc=(IDirectSoundBufferImpl**)lplpDirectSoundBuffer8;
1780
1781     FIXME( "(%p,%s,%s,%p,%p,%lx,%lx,%p,%p) stub!\n", This, debugstr_guid(pCaptureGuid),
1782         debugstr_guid(pRendererGuid), lpDscBufferDesc, lpDsBufferDesc, (DWORD)hWnd, dwLevel,
1783         ippdscb, ippdsc);
1784
1785     return E_FAIL;
1786 }
1787
1788 static IDirectSoundFullDuplexVtbl dsfdvt =
1789 {
1790     /* IUnknown methods */
1791     IDirectSoundFullDuplexImpl_QueryInterface,
1792     IDirectSoundFullDuplexImpl_AddRef,
1793     IDirectSoundFullDuplexImpl_Release,
1794
1795     /* IDirectSoundFullDuplex methods */
1796     IDirectSoundFullDuplexImpl_Initialize
1797 };
1798
1799 /*******************************************************************************
1800  * DirectSoundFullDuplex ClassFactory
1801  */
1802
1803 static HRESULT WINAPI
1804 DSFDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
1805 {
1806     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1807
1808     FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1809     return E_NOINTERFACE;
1810 }
1811
1812 static ULONG WINAPI
1813 DSFDCF_AddRef(LPCLASSFACTORY iface)
1814 {
1815     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1816     TRACE("(%p) ref was %ld\n", This, This->ref);
1817     return InterlockedIncrement(&(This->ref));
1818 }
1819
1820 static ULONG WINAPI
1821 DSFDCF_Release(LPCLASSFACTORY iface)
1822 {
1823     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1824     /* static class, won't be  freed */
1825     TRACE("(%p) ref was %ld\n", This, This->ref);
1826     return InterlockedDecrement(&(This->ref));
1827 }
1828
1829 static HRESULT WINAPI
1830 DSFDCF_CreateInstance(
1831     LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj )
1832 {
1833     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1834
1835     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1836
1837     if (pOuter) {
1838         WARN("aggregation not supported\n");
1839         return CLASS_E_NOAGGREGATION;
1840     }
1841
1842     if (ppobj == NULL) {
1843         WARN("invalid parameter\n");
1844         return E_INVALIDARG;
1845     }
1846
1847     *ppobj = NULL;
1848
1849     if ( IsEqualGUID( &IID_IDirectSoundFullDuplex, riid ) ) {
1850         /* FIXME: how do we do this one ? */
1851         FIXME("not implemented\n");
1852         return E_NOINTERFACE;
1853     }
1854
1855     WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); 
1856     return E_NOINTERFACE;
1857 }
1858
1859 static HRESULT WINAPI
1860 DSFDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
1861 {
1862     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1863     FIXME("(%p)->(%d),stub!\n",This,dolock);
1864     return S_OK;
1865 }
1866
1867 static IClassFactoryVtbl DSFDCF_Vtbl =
1868 {
1869     DSFDCF_QueryInterface,
1870     DSFDCF_AddRef,
1871     DSFDCF_Release,
1872     DSFDCF_CreateInstance,
1873     DSFDCF_LockServer
1874 };
1875
1876 IClassFactoryImpl DSOUND_FULLDUPLEX_CF = { &DSFDCF_Vtbl, 1 };