wine.inf: We should not override existing associations.
[wine/hacks.git] / dlls / dsound / capture.c
blob1d2f64972ce5c845f73d85c71d836f1c7364b716
1 /* DirectSoundCapture
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2001 TransGaming Technologies, Inc.
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.
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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * TODO:
23 * Implement FX support.
24 * Implement both IDirectSoundCaptureBuffer and IDirectSoundCaptureBuffer8
25 * Make DirectSoundCaptureCreate and DirectSoundCaptureCreate8 behave differently
28 #include <stdarg.h>
30 #define NONAMELESSSTRUCT
31 #define NONAMELESSUNION
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winuser.h"
35 #include "mmsystem.h"
36 #include "mmddk.h"
37 #include "winreg.h"
38 #include "winternl.h"
39 #include "winnls.h"
40 #include "wine/debug.h"
41 #include "dsound.h"
42 #include "dsdriver.h"
43 #include "dsound_private.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
47 /*****************************************************************************
48 * IDirectSoundCapture implementation structure
50 struct IDirectSoundCaptureImpl
52 /* IUnknown fields */
53 const IDirectSoundCaptureVtbl *lpVtbl;
54 LONG ref;
56 DirectSoundCaptureDevice *device;
59 static HRESULT IDirectSoundCaptureImpl_Create(LPDIRECTSOUNDCAPTURE8 * ppds);
62 /*****************************************************************************
63 * IDirectSoundCaptureNotify implementation structure
65 struct IDirectSoundCaptureNotifyImpl
67 /* IUnknown fields */
68 const IDirectSoundNotifyVtbl *lpVtbl;
69 LONG ref;
70 IDirectSoundCaptureBufferImpl* dscb;
73 static HRESULT IDirectSoundCaptureNotifyImpl_Create(IDirectSoundCaptureBufferImpl *dscb,
74 IDirectSoundCaptureNotifyImpl ** pdscn);
77 DirectSoundCaptureDevice * DSOUND_capture[MAXWAVEDRIVERS];
79 static HRESULT DirectSoundCaptureDevice_Create(DirectSoundCaptureDevice ** ppDevice);
81 static const char * captureStateString[] = {
82 "STATE_STOPPED",
83 "STATE_STARTING",
84 "STATE_CAPTURING",
85 "STATE_STOPPING"
88 static HRESULT DSOUND_CaptureCreate(
89 LPDIRECTSOUNDCAPTURE *ppDSC,
90 IUnknown *pUnkOuter)
92 LPDIRECTSOUNDCAPTURE pDSC;
93 HRESULT hr;
94 TRACE("(%p,%p)\n",ppDSC,pUnkOuter);
96 /* Get dsound configuration */
97 setup_dsound_options();
99 hr = IDirectSoundCaptureImpl_Create(&pDSC);
100 if (hr == DS_OK) {
101 IDirectSoundCapture_AddRef(pDSC);
102 *ppDSC = pDSC;
103 } else {
104 WARN("IDirectSoundCaptureImpl_Create failed\n");
105 *ppDSC = 0;
108 return hr;
111 static HRESULT DSOUND_CaptureCreate8(
112 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
113 IUnknown *pUnkOuter)
115 LPDIRECTSOUNDCAPTURE8 pDSC8;
116 HRESULT hr;
117 TRACE("(%p,%p)\n",ppDSC8,pUnkOuter);
119 /* Get dsound configuration */
120 setup_dsound_options();
122 hr = IDirectSoundCaptureImpl_Create(&pDSC8);
123 if (hr == DS_OK) {
124 IDirectSoundCapture_AddRef(pDSC8);
125 *ppDSC8 = pDSC8;
126 } else {
127 WARN("IDirectSoundCaptureImpl_Create failed\n");
128 *ppDSC8 = 0;
131 return hr;
134 /***************************************************************************
135 * DirectSoundCaptureCreate [DSOUND.6]
137 * Create and initialize a DirectSoundCapture interface.
139 * PARAMS
140 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
141 * lplpDSC [O] Address of a variable to receive the interface pointer.
142 * pUnkOuter [I] Must be NULL.
144 * RETURNS
145 * Success: DS_OK
146 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
147 * DSERR_OUTOFMEMORY
149 * NOTES
150 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
151 * or NULL for the default device or DSDEVID_DefaultCapture or
152 * DSDEVID_DefaultVoiceCapture.
154 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
156 HRESULT WINAPI DirectSoundCaptureCreate(
157 LPCGUID lpcGUID,
158 LPDIRECTSOUNDCAPTURE *ppDSC,
159 LPUNKNOWN pUnkOuter)
161 HRESULT hr;
162 LPDIRECTSOUNDCAPTURE pDSC;
163 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
165 if (ppDSC == NULL) {
166 WARN("invalid parameter: ppDSC == NULL\n");
167 return DSERR_INVALIDPARAM;
170 if (pUnkOuter) {
171 WARN("invalid parameter: pUnkOuter != NULL\n");
172 *ppDSC = NULL;
173 return DSERR_NOAGGREGATION;
176 hr = DSOUND_CaptureCreate(&pDSC, (IUnknown *)pUnkOuter);
177 if (hr == DS_OK) {
178 hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
179 if (hr != DS_OK) {
180 IDirectSoundCapture_Release(pDSC);
181 pDSC = 0;
185 *ppDSC = pDSC;
187 return hr;
190 /***************************************************************************
191 * DirectSoundCaptureCreate8 [DSOUND.12]
193 * Create and initialize a DirectSoundCapture interface.
195 * PARAMS
196 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
197 * lplpDSC [O] Address of a variable to receive the interface pointer.
198 * pUnkOuter [I] Must be NULL.
200 * RETURNS
201 * Success: DS_OK
202 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
203 * DSERR_OUTOFMEMORY
205 * NOTES
206 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
207 * or NULL for the default device or DSDEVID_DefaultCapture or
208 * DSDEVID_DefaultVoiceCapture.
210 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
212 HRESULT WINAPI DirectSoundCaptureCreate8(
213 LPCGUID lpcGUID,
214 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
215 LPUNKNOWN pUnkOuter)
217 HRESULT hr;
218 LPDIRECTSOUNDCAPTURE8 pDSC8;
219 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
221 if (ppDSC8 == NULL) {
222 WARN("invalid parameter: ppDSC8 == NULL\n");
223 return DSERR_INVALIDPARAM;
226 if (pUnkOuter) {
227 WARN("invalid parameter: pUnkOuter != NULL\n");
228 *ppDSC8 = NULL;
229 return DSERR_NOAGGREGATION;
232 hr = DSOUND_CaptureCreate8(&pDSC8, (IUnknown *)pUnkOuter);
233 if (hr == DS_OK) {
234 hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
235 if (hr != DS_OK) {
236 IDirectSoundCapture_Release(pDSC8);
237 pDSC8 = 0;
241 *ppDSC8 = pDSC8;
243 return hr;
246 /***************************************************************************
247 * DirectSoundCaptureEnumerateA [DSOUND.7]
249 * Enumerate all DirectSound drivers installed in the system.
251 * PARAMS
252 * lpDSEnumCallback [I] Address of callback function.
253 * lpContext [I] Address of user defined context passed to callback function.
255 * RETURNS
256 * Success: DS_OK
257 * Failure: DSERR_INVALIDPARAM
259 HRESULT WINAPI
260 DirectSoundCaptureEnumerateA(
261 LPDSENUMCALLBACKA lpDSEnumCallback,
262 LPVOID lpContext)
264 unsigned devs, wid;
265 DSDRIVERDESC desc;
266 GUID guid;
267 int err;
269 TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
271 if (lpDSEnumCallback == NULL) {
272 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
273 return DSERR_INVALIDPARAM;
276 devs = waveInGetNumDevs();
277 if (devs > 0) {
278 if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) {
279 for (wid = 0; wid < devs; ++wid) {
280 if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) {
281 err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
282 if (err == DS_OK) {
283 TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
284 "Primary Sound Capture Driver",desc.szDrvname,lpContext);
285 if (lpDSEnumCallback(NULL, "Primary Sound Capture Driver", desc.szDrvname, lpContext) == FALSE)
286 return DS_OK;
293 for (wid = 0; wid < devs; ++wid) {
294 err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
295 if (err == DS_OK) {
296 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
297 debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext);
298 if (lpDSEnumCallback(&DSOUND_capture_guids[wid], desc.szDesc, desc.szDrvname, lpContext) == FALSE)
299 return DS_OK;
303 return DS_OK;
306 /***************************************************************************
307 * DirectSoundCaptureEnumerateW [DSOUND.8]
309 * Enumerate all DirectSound drivers installed in the system.
311 * PARAMS
312 * lpDSEnumCallback [I] Address of callback function.
313 * lpContext [I] Address of user defined context passed to callback function.
315 * RETURNS
316 * Success: DS_OK
317 * Failure: DSERR_INVALIDPARAM
319 HRESULT WINAPI
320 DirectSoundCaptureEnumerateW(
321 LPDSENUMCALLBACKW lpDSEnumCallback,
322 LPVOID lpContext)
324 unsigned devs, wid;
325 DSDRIVERDESC desc;
326 GUID guid;
327 int err;
328 WCHAR wDesc[MAXPNAMELEN];
329 WCHAR wName[MAXPNAMELEN];
331 TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
333 if (lpDSEnumCallback == NULL) {
334 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
335 return DSERR_INVALIDPARAM;
338 devs = waveInGetNumDevs();
339 if (devs > 0) {
340 if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) {
341 for (wid = 0; wid < devs; ++wid) {
342 if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) {
343 err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
344 if (err == DS_OK) {
345 TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
346 "Primary Sound Capture Driver",desc.szDrvname,lpContext);
347 MultiByteToWideChar( CP_ACP, 0, "Primary Sound Capture Driver", -1,
348 wDesc, sizeof(wDesc)/sizeof(WCHAR) );
349 MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1,
350 wName, sizeof(wName)/sizeof(WCHAR) );
351 if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE)
352 return DS_OK;
359 for (wid = 0; wid < devs; ++wid) {
360 err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
361 if (err == DS_OK) {
362 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
363 debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext);
364 MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1,
365 wDesc, sizeof(wDesc)/sizeof(WCHAR) );
366 MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1,
367 wName, sizeof(wName)/sizeof(WCHAR) );
368 if (lpDSEnumCallback((LPGUID)&DSOUND_capture_guids[wid], wDesc, wName, lpContext) == FALSE)
369 return DS_OK;
373 return DS_OK;
376 static void CALLBACK
377 DSOUND_capture_callback(
378 HWAVEIN hwi,
379 UINT msg,
380 DWORD dwUser,
381 DWORD dw1,
382 DWORD dw2 )
384 DirectSoundCaptureDevice * This = (DirectSoundCaptureDevice*)dwUser;
385 TRACE("(%p,%08x(%s),%08lx,%08lx,%08lx) entering at %ld\n",hwi,msg,
386 msg == MM_WIM_OPEN ? "MM_WIM_OPEN" : msg == MM_WIM_CLOSE ? "MM_WIM_CLOSE" :
387 msg == MM_WIM_DATA ? "MM_WIM_DATA" : "UNKNOWN",dwUser,dw1,dw2,GetTickCount());
389 if (msg == MM_WIM_DATA) {
390 LPWAVEHDR pHdr = (LPWAVEHDR)dw1;
391 EnterCriticalSection( &(This->lock) );
392 TRACE("DirectSoundCapture msg=MM_WIM_DATA, old This->state=%s, old This->index=%d\n",
393 captureStateString[This->state],This->index);
394 if (This->state != STATE_STOPPED) {
395 int index = This->index;
396 if (This->state == STATE_STARTING) {
397 This->read_position = pHdr->dwBytesRecorded;
398 This->state = STATE_CAPTURING;
400 if (This->capture_buffer->nrofnotifies)
401 SetEvent(This->capture_buffer->notifies[This->index].hEventNotify);
402 This->index = (This->index + 1) % This->nrofpwaves;
403 if ( (This->index == 0) && !(This->capture_buffer->flags & DSCBSTART_LOOPING) ) {
404 TRACE("end of buffer\n");
405 This->state = STATE_STOPPED;
406 } else {
407 if (This->state == STATE_CAPTURING) {
408 waveInAddBuffer(hwi, &(This->pwave[index]), sizeof(WAVEHDR));
409 } else if (This->state == STATE_STOPPING) {
410 TRACE("stopping\n");
411 This->state = STATE_STOPPED;
415 TRACE("DirectSoundCapture new This->state=%s, new This->index=%d\n",
416 captureStateString[This->state],This->index);
417 LeaveCriticalSection( &(This->lock) );
420 TRACE("completed\n");
423 /***************************************************************************
424 * IDirectSoundCaptureImpl
426 static HRESULT WINAPI
427 IDirectSoundCaptureImpl_QueryInterface(
428 LPDIRECTSOUNDCAPTURE iface,
429 REFIID riid,
430 LPVOID* ppobj )
432 IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
433 TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
435 if (ppobj == NULL) {
436 WARN("invalid parameter\n");
437 return E_INVALIDARG;
440 *ppobj = NULL;
442 if (IsEqualIID(riid, &IID_IUnknown)) {
443 IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This);
444 *ppobj = This;
445 return DS_OK;
446 } else if (IsEqualIID(riid, &IID_IDirectSoundCapture)) {
447 IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This);
448 *ppobj = This;
449 return DS_OK;
452 WARN("unsupported riid: %s\n", debugstr_guid(riid));
453 return E_NOINTERFACE;
456 static ULONG WINAPI
457 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface )
459 IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
460 ULONG ref = InterlockedIncrement(&(This->ref));
461 TRACE("(%p) ref was %ld\n", This, ref - 1);
462 return ref;
465 static ULONG WINAPI
466 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface )
468 IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
469 ULONG ref = InterlockedDecrement(&(This->ref));
470 TRACE("(%p) ref was %ld\n", This, ref + 1);
472 if (!ref) {
473 if (This->device)
474 DirectSoundCaptureDevice_Release(This->device);
476 HeapFree( GetProcessHeap(), 0, This );
477 TRACE("(%p) released\n", This);
479 return ref;
482 HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(
483 LPDIRECTSOUNDCAPTURE iface,
484 LPCDSCBUFFERDESC lpcDSCBufferDesc,
485 LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
486 LPUNKNOWN pUnk )
488 HRESULT hr;
489 IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
491 TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
493 if (lpcDSCBufferDesc == NULL) {
494 WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
495 return DSERR_INVALIDPARAM;
498 if (lplpDSCaptureBuffer == NULL) {
499 WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
500 return DSERR_INVALIDPARAM;
503 if (pUnk != NULL) {
504 WARN("invalid parameter: pUnk != NULL\n");
505 return DSERR_INVALIDPARAM;
508 /* FIXME: We can only have one buffer so what do we do here? */
509 if (This->device->capture_buffer) {
510 WARN("lnvalid parameter: already has buffer\n");
511 return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */
514 hr = IDirectSoundCaptureBufferImpl_Create(This->device,
515 (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
517 if (hr != DS_OK)
518 WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
520 return hr;
523 HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(
524 LPDIRECTSOUNDCAPTURE iface,
525 LPDSCCAPS lpDSCCaps )
527 IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
528 TRACE("(%p,%p)\n",This,lpDSCCaps);
530 if (This->device == NULL) {
531 WARN("not initialized\n");
532 return DSERR_UNINITIALIZED;
535 if (lpDSCCaps== NULL) {
536 WARN("invalid parameter: lpDSCCaps== NULL\n");
537 return DSERR_INVALIDPARAM;
540 if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
541 WARN("invalid parameter: lpDSCCaps->dwSize = %ld\n", lpDSCCaps->dwSize);
542 return DSERR_INVALIDPARAM;
545 lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
546 lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
547 lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
549 TRACE("(flags=0x%08lx,format=0x%08lx,channels=%ld)\n",lpDSCCaps->dwFlags,
550 lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
552 return DS_OK;
555 HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(
556 LPDIRECTSOUNDCAPTURE iface,
557 LPCGUID lpcGUID )
559 IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
560 TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
562 if (This->device != NULL) {
563 WARN("already initialized\n");
564 return DSERR_ALREADYINITIALIZED;
567 return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
570 static const IDirectSoundCaptureVtbl dscvt =
572 /* IUnknown methods */
573 IDirectSoundCaptureImpl_QueryInterface,
574 IDirectSoundCaptureImpl_AddRef,
575 IDirectSoundCaptureImpl_Release,
577 /* IDirectSoundCapture methods */
578 IDirectSoundCaptureImpl_CreateCaptureBuffer,
579 IDirectSoundCaptureImpl_GetCaps,
580 IDirectSoundCaptureImpl_Initialize
583 static HRESULT IDirectSoundCaptureImpl_Create(
584 LPDIRECTSOUNDCAPTURE8 * ppDSC)
586 IDirectSoundCaptureImpl *pDSC;
587 TRACE("(%p)\n", ppDSC);
589 /* Allocate memory */
590 pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
591 if (pDSC == NULL) {
592 WARN("out of memory\n");
593 *ppDSC = NULL;
594 return DSERR_OUTOFMEMORY;
597 pDSC->lpVtbl = &dscvt;
598 pDSC->ref = 0;
599 pDSC->device = NULL;
601 *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
603 return DS_OK;
606 /*******************************************************************************
607 * IDirectSoundCaptureNotify
609 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface(
610 LPDIRECTSOUNDNOTIFY iface,
611 REFIID riid,
612 LPVOID *ppobj)
614 IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
615 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
617 if (This->dscb == NULL) {
618 WARN("invalid parameter\n");
619 return E_INVALIDARG;
622 return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
625 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
627 IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
628 ULONG ref = InterlockedIncrement(&(This->ref));
629 TRACE("(%p) ref was %ld\n", This, ref - 1);
630 return ref;
633 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
635 IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
636 ULONG ref = InterlockedDecrement(&(This->ref));
637 TRACE("(%p) ref was %ld\n", This, ref + 1);
639 if (!ref) {
640 if (This->dscb->hwnotify)
641 IDsDriverNotify_Release(This->dscb->hwnotify);
642 This->dscb->notify=NULL;
643 IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb);
644 HeapFree(GetProcessHeap(),0,This);
645 TRACE("(%p) released\n", This);
647 return ref;
650 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions(
651 LPDIRECTSOUNDNOTIFY iface,
652 DWORD howmuch,
653 LPCDSBPOSITIONNOTIFY notify)
655 IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
656 TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
658 if (howmuch > 0 && notify == NULL) {
659 WARN("invalid parameter: notify == NULL\n");
660 return DSERR_INVALIDPARAM;
663 if (TRACE_ON(dsound)) {
664 unsigned int i;
665 for (i=0;i<howmuch;i++)
666 TRACE("notify at %ld to %p\n",
667 notify[i].dwOffset,notify[i].hEventNotify);
670 if (This->dscb->hwnotify) {
671 HRESULT hres;
672 hres = IDsDriverNotify_SetNotificationPositions(This->dscb->hwnotify, howmuch, notify);
673 if (hres != DS_OK)
674 WARN("IDsDriverNotify_SetNotificationPositions failed\n");
675 return hres;
676 } else if (howmuch > 0) {
677 /* Make an internal copy of the caller-supplied array.
678 * Replace the existing copy if one is already present. */
679 if (This->dscb->notifies)
680 This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
681 This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
682 else
683 This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
684 howmuch * sizeof(DSBPOSITIONNOTIFY));
686 if (This->dscb->notifies == NULL) {
687 WARN("out of memory\n");
688 return DSERR_OUTOFMEMORY;
690 CopyMemory(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
691 This->dscb->nrofnotifies = howmuch;
692 } else {
693 HeapFree(GetProcessHeap(), 0, This->dscb->notifies);
694 This->dscb->notifies = NULL;
695 This->dscb->nrofnotifies = 0;
698 return S_OK;
701 static const IDirectSoundNotifyVtbl dscnvt =
703 IDirectSoundCaptureNotifyImpl_QueryInterface,
704 IDirectSoundCaptureNotifyImpl_AddRef,
705 IDirectSoundCaptureNotifyImpl_Release,
706 IDirectSoundCaptureNotifyImpl_SetNotificationPositions,
709 static HRESULT IDirectSoundCaptureNotifyImpl_Create(
710 IDirectSoundCaptureBufferImpl *dscb,
711 IDirectSoundCaptureNotifyImpl **pdscn)
713 IDirectSoundCaptureNotifyImpl * dscn;
714 TRACE("(%p,%p)\n",dscb,pdscn);
716 dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscn));
718 if (dscn == NULL) {
719 WARN("out of memory\n");
720 return DSERR_OUTOFMEMORY;
723 dscn->ref = 0;
724 dscn->lpVtbl = &dscnvt;
725 dscn->dscb = dscb;
726 dscb->notify = dscn;
727 IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb);
729 *pdscn = dscn;
730 return DS_OK;
733 /*******************************************************************************
734 * IDirectSoundCaptureBuffer
736 static HRESULT WINAPI
737 IDirectSoundCaptureBufferImpl_QueryInterface(
738 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
739 REFIID riid,
740 LPVOID* ppobj )
742 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
743 HRESULT hres;
744 TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
746 if (ppobj == NULL) {
747 WARN("invalid parameter\n");
748 return E_INVALIDARG;
751 *ppobj = NULL;
753 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
754 if (!This->notify)
755 hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify);
756 if (This->notify) {
757 if (This->device->hwbuf) {
758 hres = IDsCaptureDriverBuffer_QueryInterface(This->device->hwbuf,
759 &IID_IDsDriverNotify, (LPVOID*)&(This->hwnotify));
760 if (hres != DS_OK) {
761 WARN("IDsCaptureDriverBuffer_QueryInterface failed\n");
762 *ppobj = 0;
763 return hres;
767 IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
768 *ppobj = (LPVOID)This->notify;
769 return DS_OK;
772 WARN("IID_IDirectSoundNotify\n");
773 return E_FAIL;
776 if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
777 IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
778 IDirectSoundCaptureBuffer8_AddRef(iface);
779 *ppobj = This;
780 return NO_ERROR;
783 FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
784 return E_NOINTERFACE;
787 static ULONG WINAPI
788 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
790 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
791 ULONG ref = InterlockedIncrement(&(This->ref));
792 TRACE("(%p) ref was %ld\n", This, ref - 1);
793 return ref;
796 static ULONG WINAPI
797 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
799 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
800 ULONG ref = InterlockedDecrement(&(This->ref));
801 TRACE("(%p) ref was %ld\n", This, ref + 1);
803 if (!ref) {
804 TRACE("deleting object\n");
805 if (This->device->state == STATE_CAPTURING)
806 This->device->state = STATE_STOPPING;
808 HeapFree(GetProcessHeap(),0, This->pdscbd);
810 if (This->device->hwi) {
811 waveInReset(This->device->hwi);
812 waveInClose(This->device->hwi);
813 HeapFree(GetProcessHeap(),0, This->device->pwave);
814 This->device->pwave = 0;
815 This->device->hwi = 0;
818 if (This->device->hwbuf)
819 IDsCaptureDriverBuffer_Release(This->device->hwbuf);
821 /* remove from DirectSoundCaptureDevice */
822 This->device->capture_buffer = NULL;
824 if (This->notify)
825 IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
827 HeapFree(GetProcessHeap(), 0, This->notifies);
828 HeapFree( GetProcessHeap(), 0, This );
829 TRACE("(%p) released\n", This);
831 return ref;
834 static HRESULT WINAPI
835 IDirectSoundCaptureBufferImpl_GetCaps(
836 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
837 LPDSCBCAPS lpDSCBCaps )
839 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
840 TRACE( "(%p,%p)\n", This, lpDSCBCaps );
842 if (lpDSCBCaps == NULL) {
843 WARN("invalid parameter: lpDSCBCaps == NULL\n");
844 return DSERR_INVALIDPARAM;
847 if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
848 WARN("invalid parameter: lpDSCBCaps->dwSize = %ld\n", lpDSCBCaps->dwSize);
849 return DSERR_INVALIDPARAM;
852 if (This->device == NULL) {
853 WARN("invalid parameter: This->device == NULL\n");
854 return DSERR_INVALIDPARAM;
857 lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
858 lpDSCBCaps->dwFlags = This->flags;
859 lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
860 lpDSCBCaps->dwReserved = 0;
862 TRACE("returning DS_OK\n");
863 return DS_OK;
866 static HRESULT WINAPI
867 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
868 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
869 LPDWORD lpdwCapturePosition,
870 LPDWORD lpdwReadPosition )
872 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
873 HRESULT hres = DS_OK;
874 TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
876 if (This->device == NULL) {
877 WARN("invalid parameter: This->device == NULL\n");
878 return DSERR_INVALIDPARAM;
881 if (This->device->driver) {
882 hres = IDsCaptureDriverBuffer_GetPosition(This->device->hwbuf, lpdwCapturePosition, lpdwReadPosition );
883 if (hres != DS_OK)
884 WARN("IDsCaptureDriverBuffer_GetPosition failed\n");
885 } else if (This->device->hwi) {
886 EnterCriticalSection(&(This->device->lock));
887 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
888 if (lpdwCapturePosition) {
889 MMTIME mtime;
890 mtime.wType = TIME_BYTES;
891 waveInGetPosition(This->device->hwi, &mtime, sizeof(mtime));
892 TRACE("mtime.u.cb=%ld,This->device->buflen=%ld\n", mtime.u.cb,
893 This->device->buflen);
894 mtime.u.cb = mtime.u.cb % This->device->buflen;
895 *lpdwCapturePosition = mtime.u.cb;
898 if (lpdwReadPosition) {
899 if (This->device->state == STATE_STARTING) {
900 if (lpdwCapturePosition)
901 This->device->read_position = *lpdwCapturePosition;
902 This->device->state = STATE_CAPTURING;
904 *lpdwReadPosition = This->device->read_position;
906 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
907 LeaveCriticalSection(&(This->device->lock));
908 if (lpdwCapturePosition) TRACE("*lpdwCapturePosition=%ld\n",*lpdwCapturePosition);
909 if (lpdwReadPosition) TRACE("*lpdwReadPosition=%ld\n",*lpdwReadPosition);
910 } else {
911 WARN("no driver\n");
912 hres = DSERR_NODRIVER;
915 TRACE("returning %08lx\n", hres);
916 return hres;
919 static HRESULT WINAPI
920 IDirectSoundCaptureBufferImpl_GetFormat(
921 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
922 LPWAVEFORMATEX lpwfxFormat,
923 DWORD dwSizeAllocated,
924 LPDWORD lpdwSizeWritten )
926 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
927 HRESULT hres = DS_OK;
928 TRACE( "(%p,%p,0x%08lx,%p)\n", This, lpwfxFormat, dwSizeAllocated,
929 lpdwSizeWritten );
931 if (This->device == NULL) {
932 WARN("invalid parameter: This->device == NULL\n");
933 return DSERR_INVALIDPARAM;
936 if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize))
937 dwSizeAllocated = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
939 if (lpwfxFormat) { /* NULL is valid (just want size) */
940 CopyMemory(lpwfxFormat, This->device->pwfx, dwSizeAllocated);
941 if (lpdwSizeWritten)
942 *lpdwSizeWritten = dwSizeAllocated;
943 } else {
944 if (lpdwSizeWritten)
945 *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
946 else {
947 TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
948 hres = DSERR_INVALIDPARAM;
952 TRACE("returning %08lx\n", hres);
953 return hres;
956 static HRESULT WINAPI
957 IDirectSoundCaptureBufferImpl_GetStatus(
958 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
959 LPDWORD lpdwStatus )
961 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
962 TRACE( "(%p, %p), thread is %04lx\n", This, lpdwStatus, GetCurrentThreadId() );
964 if (This->device == NULL) {
965 WARN("invalid parameter: This->device == NULL\n");
966 return DSERR_INVALIDPARAM;
969 if (lpdwStatus == NULL) {
970 WARN("invalid parameter: lpdwStatus == NULL\n");
971 return DSERR_INVALIDPARAM;
974 *lpdwStatus = 0;
975 EnterCriticalSection(&(This->device->lock));
977 TRACE("old This->device->state=%s, old lpdwStatus=%08lx\n",
978 captureStateString[This->device->state],*lpdwStatus);
979 if ((This->device->state == STATE_STARTING) ||
980 (This->device->state == STATE_CAPTURING)) {
981 *lpdwStatus |= DSCBSTATUS_CAPTURING;
982 if (This->flags & DSCBSTART_LOOPING)
983 *lpdwStatus |= DSCBSTATUS_LOOPING;
985 TRACE("new This->device->state=%s, new lpdwStatus=%08lx\n",
986 captureStateString[This->device->state],*lpdwStatus);
987 LeaveCriticalSection(&(This->device->lock));
989 TRACE("status=%lx\n", *lpdwStatus);
990 TRACE("returning DS_OK\n");
991 return DS_OK;
994 static HRESULT WINAPI
995 IDirectSoundCaptureBufferImpl_Initialize(
996 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
997 LPDIRECTSOUNDCAPTURE lpDSC,
998 LPCDSCBUFFERDESC lpcDSCBDesc )
1000 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1002 FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
1004 return DS_OK;
1007 static HRESULT WINAPI
1008 IDirectSoundCaptureBufferImpl_Lock(
1009 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1010 DWORD dwReadCusor,
1011 DWORD dwReadBytes,
1012 LPVOID* lplpvAudioPtr1,
1013 LPDWORD lpdwAudioBytes1,
1014 LPVOID* lplpvAudioPtr2,
1015 LPDWORD lpdwAudioBytes2,
1016 DWORD dwFlags )
1018 HRESULT hres = DS_OK;
1019 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1020 TRACE( "(%p,%08lu,%08lu,%p,%p,%p,%p,0x%08lx) at %ld\n", This, dwReadCusor,
1021 dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
1022 lpdwAudioBytes2, dwFlags, GetTickCount() );
1024 if (This->device == NULL) {
1025 WARN("invalid parameter: This->device == NULL\n");
1026 return DSERR_INVALIDPARAM;
1029 if (lplpvAudioPtr1 == NULL) {
1030 WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
1031 return DSERR_INVALIDPARAM;
1034 if (lpdwAudioBytes1 == NULL) {
1035 WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
1036 return DSERR_INVALIDPARAM;
1039 EnterCriticalSection(&(This->device->lock));
1041 if (This->device->driver) {
1042 hres = IDsCaptureDriverBuffer_Lock(This->device->hwbuf, lplpvAudioPtr1,
1043 lpdwAudioBytes1, lplpvAudioPtr2,
1044 lpdwAudioBytes2, dwReadCusor,
1045 dwReadBytes, dwFlags);
1046 if (hres != DS_OK)
1047 WARN("IDsCaptureDriverBuffer_Lock failed\n");
1048 } else if (This->device->hwi) {
1049 *lplpvAudioPtr1 = This->device->buffer + dwReadCusor;
1050 if ( (dwReadCusor + dwReadBytes) > This->device->buflen) {
1051 *lpdwAudioBytes1 = This->device->buflen - dwReadCusor;
1052 if (lplpvAudioPtr2)
1053 *lplpvAudioPtr2 = This->device->buffer;
1054 if (lpdwAudioBytes2)
1055 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
1056 } else {
1057 *lpdwAudioBytes1 = dwReadBytes;
1058 if (lplpvAudioPtr2)
1059 *lplpvAudioPtr2 = 0;
1060 if (lpdwAudioBytes2)
1061 *lpdwAudioBytes2 = 0;
1063 } else {
1064 TRACE("invalid call\n");
1065 hres = DSERR_INVALIDCALL; /* DSERR_NODRIVER ? */
1068 LeaveCriticalSection(&(This->device->lock));
1070 TRACE("returning %08lx\n", hres);
1071 return hres;
1074 static HRESULT WINAPI
1075 IDirectSoundCaptureBufferImpl_Start(
1076 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1077 DWORD dwFlags )
1079 HRESULT hres = DS_OK;
1080 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1081 TRACE( "(%p,0x%08lx)\n", This, dwFlags );
1083 if (This->device == NULL) {
1084 WARN("invalid parameter: This->device == NULL\n");
1085 return DSERR_INVALIDPARAM;
1088 if ( (This->device->driver == 0) && (This->device->hwi == 0) ) {
1089 WARN("no driver\n");
1090 return DSERR_NODRIVER;
1093 EnterCriticalSection(&(This->device->lock));
1095 This->flags = dwFlags;
1096 TRACE("old This->state=%s\n",captureStateString[This->device->state]);
1097 if (This->device->state == STATE_STOPPED)
1098 This->device->state = STATE_STARTING;
1099 else if (This->device->state == STATE_STOPPING)
1100 This->device->state = STATE_CAPTURING;
1101 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
1103 LeaveCriticalSection(&(This->device->lock));
1105 if (This->device->driver) {
1106 hres = IDsCaptureDriverBuffer_Start(This->device->hwbuf, dwFlags);
1107 if (hres != DS_OK)
1108 WARN("IDsCaptureDriverBuffer_Start failed\n");
1109 } else if (This->device->hwi) {
1110 DirectSoundCaptureDevice *device = This->device;
1112 if (device->buffer) {
1113 if (This->nrofnotifies) {
1114 int c;
1116 device->nrofpwaves = This->nrofnotifies;
1117 TRACE("nrofnotifies=%d\n", This->nrofnotifies);
1119 /* prepare headers */
1120 if (device->pwave)
1121 device->pwave = HeapReAlloc(GetProcessHeap(),0,device->pwave,
1122 device->nrofpwaves*sizeof(WAVEHDR));
1123 else
1124 device->pwave = HeapAlloc(GetProcessHeap(),0,
1125 device->nrofpwaves*sizeof(WAVEHDR));
1127 for (c = 0; c < device->nrofpwaves; c++) {
1128 if (This->notifies[c].dwOffset == DSBPN_OFFSETSTOP) {
1129 TRACE("got DSBPN_OFFSETSTOP\n");
1130 device->nrofpwaves = c;
1131 break;
1133 if (c == 0) {
1134 device->pwave[0].lpData = (LPSTR)device->buffer;
1135 device->pwave[0].dwBufferLength =
1136 This->notifies[0].dwOffset + 1;
1137 } else {
1138 device->pwave[c].lpData = (LPSTR)device->buffer +
1139 This->notifies[c-1].dwOffset + 1;
1140 device->pwave[c].dwBufferLength =
1141 This->notifies[c].dwOffset -
1142 This->notifies[c-1].dwOffset;
1144 device->pwave[c].dwBytesRecorded = 0;
1145 device->pwave[c].dwUser = (DWORD)device;
1146 device->pwave[c].dwFlags = 0;
1147 device->pwave[c].dwLoops = 0;
1148 hres = mmErr(waveInPrepareHeader(device->hwi,
1149 &(device->pwave[c]),sizeof(WAVEHDR)));
1150 if (hres != DS_OK) {
1151 WARN("waveInPrepareHeader failed\n");
1152 while (c--)
1153 waveInUnprepareHeader(device->hwi,
1154 &(device->pwave[c]),sizeof(WAVEHDR));
1155 break;
1158 hres = mmErr(waveInAddBuffer(device->hwi,
1159 &(device->pwave[c]), sizeof(WAVEHDR)));
1160 if (hres != DS_OK) {
1161 WARN("waveInAddBuffer failed\n");
1162 while (c--)
1163 waveInUnprepareHeader(device->hwi,
1164 &(device->pwave[c]),sizeof(WAVEHDR));
1165 break;
1169 FillMemory(device->buffer, device->buflen,
1170 (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
1171 } else {
1172 TRACE("no notifiers specified\n");
1173 /* no notifiers specified so just create a single default header */
1174 device->nrofpwaves = 1;
1175 if (device->pwave)
1176 device->pwave = HeapReAlloc(GetProcessHeap(),0,device->pwave,sizeof(WAVEHDR));
1177 else
1178 device->pwave = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEHDR));
1180 device->pwave[0].lpData = (LPSTR)device->buffer;
1181 device->pwave[0].dwBufferLength = device->buflen;
1182 device->pwave[0].dwBytesRecorded = 0;
1183 device->pwave[0].dwUser = (DWORD)device;
1184 device->pwave[0].dwFlags = 0;
1185 device->pwave[0].dwLoops = 0;
1187 hres = mmErr(waveInPrepareHeader(device->hwi,
1188 &(device->pwave[0]),sizeof(WAVEHDR)));
1189 if (hres != DS_OK) {
1190 WARN("waveInPrepareHeader failed\n");
1191 waveInUnprepareHeader(device->hwi,
1192 &(device->pwave[0]),sizeof(WAVEHDR));
1194 hres = mmErr(waveInAddBuffer(device->hwi,
1195 &(device->pwave[0]), sizeof(WAVEHDR)));
1196 if (hres != DS_OK) {
1197 WARN("waveInAddBuffer failed\n");
1198 waveInUnprepareHeader(device->hwi,
1199 &(device->pwave[0]),sizeof(WAVEHDR));
1204 device->index = 0;
1205 device->read_position = 0;
1207 if (hres == DS_OK) {
1208 /* start filling the first buffer */
1209 hres = mmErr(waveInStart(device->hwi));
1210 if (hres != DS_OK)
1211 WARN("waveInStart failed\n");
1214 if (hres != DS_OK) {
1215 WARN("calling waveInClose because of error\n");
1216 waveInClose(device->hwi);
1217 device->hwi = 0;
1219 } else {
1220 WARN("no driver\n");
1221 hres = DSERR_NODRIVER;
1224 TRACE("returning %08lx\n", hres);
1225 return hres;
1228 static HRESULT WINAPI
1229 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
1231 HRESULT hres = DS_OK;
1232 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1233 TRACE( "(%p)\n", This );
1235 if (This->device == NULL) {
1236 WARN("invalid parameter: This->device == NULL\n");
1237 return DSERR_INVALIDPARAM;
1240 EnterCriticalSection(&(This->device->lock));
1242 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
1243 if (This->device->state == STATE_CAPTURING)
1244 This->device->state = STATE_STOPPING;
1245 else if (This->device->state == STATE_STARTING)
1246 This->device->state = STATE_STOPPED;
1247 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
1249 LeaveCriticalSection(&(This->device->lock));
1251 if (This->device->driver) {
1252 hres = IDsCaptureDriverBuffer_Stop(This->device->hwbuf);
1253 if (hres != DS_OK)
1254 WARN("IDsCaptureDriverBuffer_Stop() failed\n");
1255 } else if (This->device->hwi) {
1256 hres = mmErr(waveInReset(This->device->hwi));
1257 if (hres != DS_OK)
1258 WARN("waveInReset() failed\n");
1259 } else {
1260 WARN("no driver\n");
1261 hres = DSERR_NODRIVER;
1264 TRACE("returning %08lx\n", hres);
1265 return hres;
1268 static HRESULT WINAPI
1269 IDirectSoundCaptureBufferImpl_Unlock(
1270 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1271 LPVOID lpvAudioPtr1,
1272 DWORD dwAudioBytes1,
1273 LPVOID lpvAudioPtr2,
1274 DWORD dwAudioBytes2 )
1276 HRESULT hres = DS_OK;
1277 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1278 TRACE( "(%p,%p,%08lu,%p,%08lu)\n", This, lpvAudioPtr1, dwAudioBytes1,
1279 lpvAudioPtr2, dwAudioBytes2 );
1281 if (lpvAudioPtr1 == NULL) {
1282 WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
1283 return DSERR_INVALIDPARAM;
1286 if (This->device->driver) {
1287 hres = IDsCaptureDriverBuffer_Unlock(This->device->hwbuf, lpvAudioPtr1,
1288 dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1289 if (hres != DS_OK)
1290 WARN("IDsCaptureDriverBuffer_Unlock failed\n");
1291 } else if (This->device->hwi) {
1292 This->device->read_position = (This->device->read_position +
1293 (dwAudioBytes1 + dwAudioBytes2)) % This->device->buflen;
1294 } else {
1295 WARN("invalid call\n");
1296 hres = DSERR_INVALIDCALL;
1299 TRACE("returning %08lx\n", hres);
1300 return hres;
1303 static HRESULT WINAPI
1304 IDirectSoundCaptureBufferImpl_GetObjectInPath(
1305 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1306 REFGUID rguidObject,
1307 DWORD dwIndex,
1308 REFGUID rguidInterface,
1309 LPVOID* ppObject )
1311 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1313 FIXME( "(%p,%s,%lu,%s,%p): stub\n", This, debugstr_guid(rguidObject),
1314 dwIndex, debugstr_guid(rguidInterface), ppObject );
1316 return DS_OK;
1319 static HRESULT WINAPI
1320 IDirectSoundCaptureBufferImpl_GetFXStatus(
1321 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
1322 DWORD dwFXCount,
1323 LPDWORD pdwFXStatus )
1325 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
1327 FIXME( "(%p,%lu,%p): stub\n", This, dwFXCount, pdwFXStatus );
1329 return DS_OK;
1332 static const IDirectSoundCaptureBuffer8Vtbl dscbvt =
1334 /* IUnknown methods */
1335 IDirectSoundCaptureBufferImpl_QueryInterface,
1336 IDirectSoundCaptureBufferImpl_AddRef,
1337 IDirectSoundCaptureBufferImpl_Release,
1339 /* IDirectSoundCaptureBuffer methods */
1340 IDirectSoundCaptureBufferImpl_GetCaps,
1341 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
1342 IDirectSoundCaptureBufferImpl_GetFormat,
1343 IDirectSoundCaptureBufferImpl_GetStatus,
1344 IDirectSoundCaptureBufferImpl_Initialize,
1345 IDirectSoundCaptureBufferImpl_Lock,
1346 IDirectSoundCaptureBufferImpl_Start,
1347 IDirectSoundCaptureBufferImpl_Stop,
1348 IDirectSoundCaptureBufferImpl_Unlock,
1350 /* IDirectSoundCaptureBuffer methods */
1351 IDirectSoundCaptureBufferImpl_GetObjectInPath,
1352 IDirectSoundCaptureBufferImpl_GetFXStatus
1355 HRESULT IDirectSoundCaptureBufferImpl_Create(
1356 DirectSoundCaptureDevice *device,
1357 IDirectSoundCaptureBufferImpl ** ppobj,
1358 LPCDSCBUFFERDESC lpcDSCBufferDesc)
1360 LPWAVEFORMATEX wfex;
1361 TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
1363 if (ppobj == NULL) {
1364 WARN("invalid parameter: ppobj == NULL\n");
1365 return DSERR_INVALIDPARAM;
1368 if (!device) {
1369 WARN("not initialized\n");
1370 *ppobj = NULL;
1371 return DSERR_UNINITIALIZED;
1374 if (lpcDSCBufferDesc == NULL) {
1375 WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
1376 *ppobj = NULL;
1377 return DSERR_INVALIDPARAM;
1380 if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
1381 (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
1382 (lpcDSCBufferDesc->dwBufferBytes == 0) ||
1383 (lpcDSCBufferDesc->lpwfxFormat == NULL) ) {
1384 WARN("invalid lpcDSCBufferDesc\n");
1385 *ppobj = NULL;
1386 return DSERR_INVALIDPARAM;
1389 wfex = lpcDSCBufferDesc->lpwfxFormat;
1391 if (wfex) {
1392 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1393 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1394 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
1395 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
1396 wfex->wBitsPerSample, wfex->cbSize);
1398 if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
1399 device->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX));
1400 CopyMemory(device->pwfx, wfex, sizeof(WAVEFORMATEX));
1401 device->pwfx->cbSize = 0;
1402 } else {
1403 device->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)+wfex->cbSize);
1404 CopyMemory(device->pwfx, wfex, sizeof(WAVEFORMATEX)+wfex->cbSize);
1406 } else {
1407 WARN("lpcDSCBufferDesc->lpwfxFormat == 0\n");
1408 *ppobj = NULL;
1409 return DSERR_INVALIDPARAM; /* FIXME: DSERR_BADFORMAT ? */
1412 *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1413 sizeof(IDirectSoundCaptureBufferImpl));
1415 if ( *ppobj == NULL ) {
1416 WARN("out of memory\n");
1417 *ppobj = NULL;
1418 return DSERR_OUTOFMEMORY;
1419 } else {
1420 HRESULT err = DS_OK;
1421 LPBYTE newbuf;
1422 DWORD buflen;
1423 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)*ppobj;
1425 This->ref = 1;
1426 This->device = device;
1427 This->device->capture_buffer = This;
1428 This->notify = NULL;
1429 This->nrofnotifies = 0;
1430 This->hwnotify = NULL;
1432 This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1433 lpcDSCBufferDesc->dwSize);
1434 if (This->pdscbd)
1435 CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
1436 else {
1437 WARN("no memory\n");
1438 This->device->capture_buffer = 0;
1439 HeapFree( GetProcessHeap(), 0, This );
1440 *ppobj = NULL;
1441 return DSERR_OUTOFMEMORY;
1444 This->lpVtbl = &dscbvt;
1446 if (device->driver) {
1447 if (This->device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1448 FIXME("DSDDESC_DOMMSYSTEMOPEN not supported\n");
1450 if (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
1451 /* allocate buffer from system memory */
1452 buflen = lpcDSCBufferDesc->dwBufferBytes;
1453 TRACE("desired buflen=%ld, old buffer=%p\n", buflen, device->buffer);
1454 if (device->buffer)
1455 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
1456 else
1457 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
1459 if (newbuf == NULL) {
1460 WARN("failed to allocate capture buffer\n");
1461 err = DSERR_OUTOFMEMORY;
1462 /* but the old buffer might still exist and must be re-prepared */
1463 } else {
1464 device->buffer = newbuf;
1465 device->buflen = buflen;
1467 } else {
1468 /* let driver allocate memory */
1469 device->buflen = lpcDSCBufferDesc->dwBufferBytes;
1470 /* FIXME: */
1471 HeapFree( GetProcessHeap(), 0, device->buffer);
1472 device->buffer = NULL;
1475 err = IDsCaptureDriver_CreateCaptureBuffer(device->driver,
1476 device->pwfx,0,0,&(device->buflen),&(device->buffer),(LPVOID*)&(device->hwbuf));
1477 if (err != DS_OK) {
1478 WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n");
1479 This->device->capture_buffer = 0;
1480 HeapFree( GetProcessHeap(), 0, This );
1481 *ppobj = NULL;
1482 return err;
1484 } else {
1485 DWORD flags = CALLBACK_FUNCTION;
1486 if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
1487 flags |= WAVE_DIRECTSOUND;
1488 err = mmErr(waveInOpen(&(device->hwi),
1489 device->drvdesc.dnDevNode, device->pwfx,
1490 (DWORD_PTR)DSOUND_capture_callback, (DWORD)device, flags));
1491 if (err != DS_OK) {
1492 WARN("waveInOpen failed\n");
1493 This->device->capture_buffer = 0;
1494 HeapFree( GetProcessHeap(), 0, This );
1495 *ppobj = NULL;
1496 return err;
1499 buflen = lpcDSCBufferDesc->dwBufferBytes;
1500 TRACE("desired buflen=%ld, old buffer=%p\n", buflen, device->buffer);
1501 if (device->buffer)
1502 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
1503 else
1504 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
1505 if (newbuf == NULL) {
1506 WARN("failed to allocate capture buffer\n");
1507 err = DSERR_OUTOFMEMORY;
1508 /* but the old buffer might still exist and must be re-prepared */
1509 } else {
1510 device->buffer = newbuf;
1511 device->buflen = buflen;
1516 TRACE("returning DS_OK\n");
1517 return DS_OK;
1520 /*******************************************************************************
1521 * DirectSoundCaptureDevice
1523 HRESULT DirectSoundCaptureDevice_Initialize(
1524 DirectSoundCaptureDevice ** ppDevice,
1525 LPCGUID lpcGUID)
1527 HRESULT err = DSERR_INVALIDPARAM;
1528 unsigned wid, widn;
1529 BOOLEAN found = FALSE;
1530 GUID devGUID;
1531 DirectSoundCaptureDevice *device = *ppDevice;
1532 TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
1534 /* Default device? */
1535 if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
1536 lpcGUID = &DSDEVID_DefaultCapture;
1538 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1539 WARN("invalid parameter: lpcGUID\n");
1540 return DSERR_INVALIDPARAM;
1543 widn = waveInGetNumDevs();
1544 if (!widn) {
1545 WARN("no audio devices found\n");
1546 return DSERR_NODRIVER;
1549 /* enumerate WINMM audio devices and find the one we want */
1550 for (wid=0; wid<widn; wid++) {
1551 if (IsEqualGUID( &devGUID, &DSOUND_capture_guids[wid]) ) {
1552 found = TRUE;
1553 break;
1557 if (found == FALSE) {
1558 WARN("No device found matching given ID!\n");
1559 return DSERR_NODRIVER;
1562 if (DSOUND_capture[wid]) {
1563 WARN("already in use\n");
1564 return DSERR_ALLOCATED;
1567 err = DirectSoundCaptureDevice_Create(&(device));
1568 if (err != DS_OK) {
1569 WARN("DirectSoundCaptureDevice_Create failed\n");
1570 return err;
1573 *ppDevice = device;
1574 device->guid = devGUID;
1576 err = mmErr(waveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD_PTR)&(device->driver),0));
1577 if ( (err != DS_OK) && (err != DSERR_UNSUPPORTED) ) {
1578 WARN("waveInMessage failed; err=%lx\n",err);
1579 return err;
1581 err = DS_OK;
1583 /* Disable the direct sound driver to force emulation if requested. */
1584 if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
1585 device->driver = NULL;
1587 /* Get driver description */
1588 if (device->driver) {
1589 TRACE("using DirectSound driver\n");
1590 err = IDsCaptureDriver_GetDriverDesc(device->driver, &(device->drvdesc));
1591 if (err != DS_OK) {
1592 WARN("IDsCaptureDriver_GetDriverDesc failed\n");
1593 return err;
1595 } else {
1596 TRACE("using WINMM\n");
1597 /* if no DirectSound interface available, use WINMM API instead */
1598 device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN |
1599 DSDDESC_DOMMSYSTEMSETFORMAT;
1602 device->drvdesc.dnDevNode = wid;
1604 /* open the DirectSound driver if available */
1605 if (device->driver && (err == DS_OK))
1606 err = IDsCaptureDriver_Open(device->driver);
1608 if (err == DS_OK) {
1609 *ppDevice = device;
1611 /* the driver is now open, so it's now allowed to call GetCaps */
1612 if (device->driver) {
1613 device->drvcaps.dwSize = sizeof(device->drvcaps);
1614 err = IDsCaptureDriver_GetCaps(device->driver,&(device->drvcaps));
1615 if (err != DS_OK) {
1616 WARN("IDsCaptureDriver_GetCaps failed\n");
1617 return err;
1619 } else /*if (device->hwi)*/ {
1620 WAVEINCAPSA wic;
1621 err = mmErr(waveInGetDevCapsA((UINT)device->drvdesc.dnDevNode, &wic, sizeof(wic)));
1623 if (err == DS_OK) {
1624 device->drvcaps.dwFlags = 0;
1625 lstrcpynA(device->drvdesc.szDrvname, wic.szPname,
1626 sizeof(device->drvdesc.szDrvname));
1628 device->drvcaps.dwFlags |= DSCCAPS_EMULDRIVER;
1629 device->drvcaps.dwFormats = wic.dwFormats;
1630 device->drvcaps.dwChannels = wic.wChannels;
1635 return err;
1638 static HRESULT DirectSoundCaptureDevice_Create(
1639 DirectSoundCaptureDevice ** ppDevice)
1641 DirectSoundCaptureDevice * device;
1642 TRACE("(%p)\n", ppDevice);
1644 /* Allocate memory */
1645 device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
1647 if (device == NULL) {
1648 WARN("out of memory\n");
1649 return DSERR_OUTOFMEMORY;
1652 device->ref = 1;
1653 device->state = STATE_STOPPED;
1655 InitializeCriticalSection( &(device->lock) );
1656 device->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSCAPTURE_lock";
1658 *ppDevice = device;
1660 return DS_OK;
1663 ULONG DirectSoundCaptureDevice_AddRef(
1664 DirectSoundCaptureDevice * device)
1666 ULONG ref = InterlockedIncrement(&(device->ref));
1667 TRACE("(%p) ref was %ld\n", device, ref - 1);
1668 return ref;
1671 ULONG DirectSoundCaptureDevice_Release(
1672 DirectSoundCaptureDevice * device)
1674 ULONG ref = InterlockedDecrement(&(device->ref));
1675 TRACE("(%p) ref was %ld\n", device, ref + 1);
1677 if (!ref) {
1678 TRACE("deleting object\n");
1679 if (device->capture_buffer)
1680 IDirectSoundCaptureBufferImpl_Release(
1681 (LPDIRECTSOUNDCAPTUREBUFFER8) device->capture_buffer);
1683 if (device->driver) {
1684 IDsCaptureDriver_Close(device->driver);
1685 IDsCaptureDriver_Release(device->driver);
1688 HeapFree(GetProcessHeap(), 0, device->pwfx);
1689 device->lock.DebugInfo->Spare[0] = 0;
1690 DeleteCriticalSection( &(device->lock) );
1691 DSOUND_capture[device->drvdesc.dnDevNode] = NULL;
1692 HeapFree(GetProcessHeap(), 0, device);
1693 TRACE("(%p) released\n", device);
1695 return ref;
1698 /*******************************************************************************
1699 * DirectSoundCapture ClassFactory
1702 static HRESULT WINAPI
1703 DSCCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
1705 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1707 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1708 return E_NOINTERFACE;
1711 static ULONG WINAPI
1712 DSCCF_AddRef(LPCLASSFACTORY iface)
1714 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1715 ULONG ref = InterlockedIncrement(&(This->ref));
1716 TRACE("(%p) ref was %ld\n", This, ref - 1);
1717 return ref;
1720 static ULONG WINAPI
1721 DSCCF_Release(LPCLASSFACTORY iface)
1723 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1724 ULONG ref = InterlockedDecrement(&(This->ref));
1725 TRACE("(%p) ref was %ld\n", This, ref + 1);
1726 /* static class, won't be freed */
1727 return ref;
1730 static HRESULT WINAPI
1731 DSCCF_CreateInstance(
1732 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj )
1734 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1735 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1737 if (pOuter) {
1738 WARN("aggregation not supported\n");
1739 return CLASS_E_NOAGGREGATION;
1742 if (ppobj == NULL) {
1743 WARN("invalid parameter\n");
1744 return E_INVALIDARG;
1747 *ppobj = NULL;
1749 if ( IsEqualGUID( &IID_IDirectSoundCapture, riid ) )
1750 return DSOUND_CaptureCreate8((LPDIRECTSOUNDCAPTURE*)ppobj,pOuter);
1752 WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);
1753 return E_NOINTERFACE;
1756 static HRESULT WINAPI
1757 DSCCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
1759 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1760 FIXME("(%p)->(%d),stub!\n",This,dolock);
1761 return S_OK;
1764 static const IClassFactoryVtbl DSCCF_Vtbl =
1766 DSCCF_QueryInterface,
1767 DSCCF_AddRef,
1768 DSCCF_Release,
1769 DSCCF_CreateInstance,
1770 DSCCF_LockServer
1773 IClassFactoryImpl DSOUND_CAPTURE_CF = { &DSCCF_Vtbl, 1 };