vbscript: Fix memory leak in owned safearray iterator.
[wine.git] / dlls / dsound / capture.c
blob6ddae8286cd478349f6b0025298cbdc7c53009a0
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 COBJMACROS
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winuser.h"
35 #include "mmsystem.h"
36 #include "mmddk.h"
37 #include "winnls.h"
38 #include "wine/debug.h"
39 #include "dsound.h"
40 #include "dsound_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
44 typedef struct DirectSoundCaptureDevice DirectSoundCaptureDevice;
46 /* IDirectSoundCaptureBuffer implementation structure */
47 typedef struct IDirectSoundCaptureBufferImpl
49 IDirectSoundCaptureBuffer8 IDirectSoundCaptureBuffer8_iface;
50 IDirectSoundNotify IDirectSoundNotify_iface;
51 LONG numIfaces; /* "in use interfaces" refcount */
52 LONG ref, refn, has_dsc8;
53 /* IDirectSoundCaptureBuffer fields */
54 DirectSoundCaptureDevice *device;
55 DSCBUFFERDESC *pdscbd;
56 DWORD flags;
57 /* IDirectSoundNotify fields */
58 DSBPOSITIONNOTIFY *notifies;
59 int nrofnotifies;
60 HANDLE thread;
61 HANDLE sleepev;
62 } IDirectSoundCaptureBufferImpl;
64 /* DirectSoundCaptureDevice implementation structure */
65 struct DirectSoundCaptureDevice
67 GUID guid;
68 LONG ref;
69 DSCCAPS drvcaps;
70 BYTE *buffer;
71 DWORD buflen, write_pos_bytes;
72 WAVEFORMATEX *pwfx;
73 IDirectSoundCaptureBufferImpl *capture_buffer;
74 DWORD state;
75 CRITICAL_SECTION lock;
76 IMMDevice *mmdevice;
77 IAudioClient *client;
78 IAudioCaptureClient *capture;
79 struct list entry;
82 static DWORD WINAPI DSOUND_capture_thread(void *user);
84 static void capturebuffer_destroy(IDirectSoundCaptureBufferImpl *This)
86 if (This->device->state == STATE_CAPTURING)
87 This->device->state = STATE_STOPPING;
89 if(This->thread){
90 SetEvent(This->sleepev);
91 WaitForSingleObject(This->thread, INFINITE);
92 CloseHandle(This->thread);
94 CloseHandle(This->sleepev);
96 HeapFree(GetProcessHeap(),0, This->pdscbd);
98 if (This->device->client) {
99 IAudioClient_Release(This->device->client);
100 This->device->client = NULL;
103 if (This->device->capture) {
104 IAudioCaptureClient_Release(This->device->capture);
105 This->device->capture = NULL;
108 /* remove from DirectSoundCaptureDevice */
109 This->device->capture_buffer = NULL;
111 HeapFree(GetProcessHeap(), 0, This->notifies);
112 TRACE("(%p) released\n", This);
113 HeapFree(GetProcessHeap(), 0, This);
116 /*******************************************************************************
117 * IDirectSoundNotify
119 static inline struct IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
121 return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundNotify_iface);
124 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(IDirectSoundNotify *iface, REFIID riid,
125 void **ppobj)
127 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
129 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj);
131 return IDirectSoundCaptureBuffer8_QueryInterface(&This->IDirectSoundCaptureBuffer8_iface, riid, ppobj);
134 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(IDirectSoundNotify *iface)
136 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
137 ULONG ref = InterlockedIncrement(&This->refn);
139 TRACE("(%p) ref %ld\n", This, ref);
141 if(ref == 1)
142 InterlockedIncrement(&This->numIfaces);
144 return ref;
147 static ULONG WINAPI IDirectSoundNotifyImpl_Release(IDirectSoundNotify *iface)
149 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
150 ULONG ref = InterlockedDecrement(&This->refn);
152 TRACE("(%p) ref %ld\n", This, ref);
154 if (!ref && !InterlockedDecrement(&This->numIfaces))
155 capturebuffer_destroy(This);
157 return ref;
160 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSoundNotify *iface,
161 DWORD howmuch, const DSBPOSITIONNOTIFY *notify)
163 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
164 TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
166 if (howmuch > 0 && notify == NULL) {
167 WARN("invalid parameter: notify == NULL\n");
168 return DSERR_INVALIDPARAM;
171 if (TRACE_ON(dsound)) {
172 unsigned int i;
173 for (i=0;i<howmuch;i++)
174 TRACE("notify at %ld to %p\n",
175 notify[i].dwOffset,notify[i].hEventNotify);
178 if (howmuch > 0) {
179 /* Make an internal copy of the caller-supplied array.
180 * Replace the existing copy if one is already present. */
181 if (This->notifies)
182 This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->notifies,
183 howmuch * sizeof(DSBPOSITIONNOTIFY));
184 else
185 This->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
186 howmuch * sizeof(DSBPOSITIONNOTIFY));
188 if (!This->notifies) {
189 WARN("out of memory\n");
190 return DSERR_OUTOFMEMORY;
192 CopyMemory(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
193 This->nrofnotifies = howmuch;
194 } else {
195 HeapFree(GetProcessHeap(), 0, This->notifies);
196 This->notifies = NULL;
197 This->nrofnotifies = 0;
200 return S_OK;
203 static const IDirectSoundNotifyVtbl dscnvt =
205 IDirectSoundNotifyImpl_QueryInterface,
206 IDirectSoundNotifyImpl_AddRef,
207 IDirectSoundNotifyImpl_Release,
208 IDirectSoundNotifyImpl_SetNotificationPositions
212 static const char * const captureStateString[] = {
213 "STATE_STOPPED",
214 "STATE_STARTING",
215 "STATE_CAPTURING",
216 "STATE_STOPPING"
220 /*******************************************************************************
221 * IDirectSoundCaptureBuffer
223 static inline IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8 *iface)
225 return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundCaptureBuffer8_iface);
228 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_QueryInterface(IDirectSoundCaptureBuffer8 *iface,
229 REFIID riid, void **ppobj)
231 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
233 TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
235 if (ppobj == NULL) {
236 WARN("invalid parameter\n");
237 return E_INVALIDARG;
240 *ppobj = NULL;
242 if ( IsEqualIID( &IID_IUnknown, riid ) ||
243 IsEqualIID( &IID_IDirectSoundCaptureBuffer, riid ) ||
244 (This->has_dsc8 && IsEqualIID( &IID_IDirectSoundCaptureBuffer8, riid )) ) {
245 IDirectSoundCaptureBuffer8_AddRef(iface);
246 *ppobj = iface;
247 return S_OK;
250 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
251 IDirectSoundNotify_AddRef(&This->IDirectSoundNotify_iface);
252 *ppobj = &This->IDirectSoundNotify_iface;
253 return S_OK;
256 FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
257 return E_NOINTERFACE;
260 static ULONG WINAPI IDirectSoundCaptureBufferImpl_AddRef(IDirectSoundCaptureBuffer8 *iface)
262 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
263 ULONG ref = InterlockedIncrement(&This->ref);
265 TRACE("(%p) ref %ld\n", This, ref);
267 if(ref == 1)
268 InterlockedIncrement(&This->numIfaces);
270 return ref;
273 static ULONG WINAPI IDirectSoundCaptureBufferImpl_Release(IDirectSoundCaptureBuffer8 *iface)
275 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
276 ULONG ref = InterlockedDecrement(&This->ref);
278 TRACE("(%p) ref %ld\n", This, ref);
280 if (!ref && !InterlockedDecrement(&This->numIfaces))
281 capturebuffer_destroy(This);
283 return ref;
286 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCaps(IDirectSoundCaptureBuffer8 *iface,
287 DSCBCAPS *lpDSCBCaps)
289 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
290 TRACE( "(%p,%p)\n", This, lpDSCBCaps );
292 if (lpDSCBCaps == NULL) {
293 WARN("invalid parameter: lpDSCBCaps == NULL\n");
294 return DSERR_INVALIDPARAM;
297 if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
298 WARN("invalid parameter: lpDSCBCaps->dwSize = %ld\n", lpDSCBCaps->dwSize);
299 return DSERR_INVALIDPARAM;
302 if (This->device == NULL) {
303 WARN("invalid parameter: This->device == NULL\n");
304 return DSERR_INVALIDPARAM;
307 lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
308 lpDSCBCaps->dwFlags = This->flags;
309 lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
310 lpDSCBCaps->dwReserved = 0;
312 TRACE("returning DS_OK\n");
313 return DS_OK;
316 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCurrentPosition(IDirectSoundCaptureBuffer8 *iface,
317 DWORD *lpdwCapturePosition, DWORD *lpdwReadPosition)
319 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
321 TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
323 if (This->device == NULL) {
324 WARN("invalid parameter: This->device == NULL\n");
325 return DSERR_INVALIDPARAM;
328 EnterCriticalSection(&This->device->lock);
330 if (!This->device->client) {
331 LeaveCriticalSection(&This->device->lock);
332 WARN("no driver\n");
333 return DSERR_NODRIVER;
336 if(lpdwCapturePosition)
337 *lpdwCapturePosition = This->device->write_pos_bytes;
339 if(lpdwReadPosition)
340 *lpdwReadPosition = This->device->write_pos_bytes;
342 LeaveCriticalSection(&This->device->lock);
344 TRACE("cappos=%ld readpos=%ld\n", (lpdwCapturePosition?*lpdwCapturePosition:-1), (lpdwReadPosition?*lpdwReadPosition:-1));
345 TRACE("returning DS_OK\n");
347 return DS_OK;
350 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFormat(IDirectSoundCaptureBuffer8 *iface,
351 WAVEFORMATEX *lpwfxFormat, DWORD dwSizeAllocated, DWORD *lpdwSizeWritten)
353 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
354 HRESULT hres = DS_OK;
356 TRACE("(%p,%p,0x%08lx,%p)\n", This, lpwfxFormat, dwSizeAllocated, lpdwSizeWritten);
358 if (This->device == NULL) {
359 WARN("invalid parameter: This->device == NULL\n");
360 return DSERR_INVALIDPARAM;
363 if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize))
364 dwSizeAllocated = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
366 if (lpwfxFormat) { /* NULL is valid (just want size) */
367 CopyMemory(lpwfxFormat, This->device->pwfx, dwSizeAllocated);
368 if (lpdwSizeWritten)
369 *lpdwSizeWritten = dwSizeAllocated;
370 } else {
371 if (lpdwSizeWritten)
372 *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
373 else {
374 TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
375 hres = DSERR_INVALIDPARAM;
379 TRACE("returning %08lx\n", hres);
380 return hres;
383 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetStatus(IDirectSoundCaptureBuffer8 *iface,
384 DWORD *lpdwStatus)
386 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
388 TRACE( "(%p, %p)\n", This, lpdwStatus );
390 if (This->device == NULL) {
391 WARN("invalid parameter: This->device == NULL\n");
392 return DSERR_INVALIDPARAM;
395 if (lpdwStatus == NULL) {
396 WARN("invalid parameter: lpdwStatus == NULL\n");
397 return DSERR_INVALIDPARAM;
400 *lpdwStatus = 0;
401 EnterCriticalSection(&(This->device->lock));
403 TRACE("old This->device->state=%s, old lpdwStatus=%08lx\n",
404 captureStateString[This->device->state],*lpdwStatus);
405 if ((This->device->state == STATE_STARTING) ||
406 (This->device->state == STATE_CAPTURING)) {
407 *lpdwStatus |= DSCBSTATUS_CAPTURING;
408 if (This->flags & DSCBSTART_LOOPING)
409 *lpdwStatus |= DSCBSTATUS_LOOPING;
411 TRACE("new This->device->state=%s, new lpdwStatus=%08lx\n",
412 captureStateString[This->device->state],*lpdwStatus);
413 LeaveCriticalSection(&(This->device->lock));
415 TRACE("status=%lx\n", *lpdwStatus);
416 TRACE("returning DS_OK\n");
417 return DS_OK;
420 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Initialize(IDirectSoundCaptureBuffer8 *iface,
421 IDirectSoundCapture *lpDSC, const DSCBUFFERDESC *lpcDSCBDesc)
423 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
425 FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
427 return DS_OK;
430 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Lock(IDirectSoundCaptureBuffer8 *iface,
431 DWORD dwReadCusor, DWORD dwReadBytes, void **lplpvAudioPtr1, DWORD *lpdwAudioBytes1,
432 void **lplpvAudioPtr2, DWORD *lpdwAudioBytes2, DWORD dwFlags)
434 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
435 HRESULT hres = DS_OK;
437 TRACE( "(%p,%08lu,%08lu,%p,%p,%p,%p,0x%08lx) at %ld\n", This, dwReadCusor,
438 dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
439 lpdwAudioBytes2, dwFlags, GetTickCount() );
441 if (This->device == NULL) {
442 WARN("invalid parameter: This->device == NULL\n");
443 return DSERR_INVALIDPARAM;
446 if (lplpvAudioPtr1 == NULL) {
447 WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
448 return DSERR_INVALIDPARAM;
451 if (lpdwAudioBytes1 == NULL) {
452 WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
453 return DSERR_INVALIDPARAM;
456 EnterCriticalSection(&(This->device->lock));
458 if (This->device->client) {
459 *lplpvAudioPtr1 = This->device->buffer + dwReadCusor;
460 if ( (dwReadCusor + dwReadBytes) > This->device->buflen) {
461 *lpdwAudioBytes1 = This->device->buflen - dwReadCusor;
462 if (lplpvAudioPtr2)
463 *lplpvAudioPtr2 = This->device->buffer;
464 if (lpdwAudioBytes2)
465 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
466 } else {
467 *lpdwAudioBytes1 = dwReadBytes;
468 if (lplpvAudioPtr2)
469 *lplpvAudioPtr2 = 0;
470 if (lpdwAudioBytes2)
471 *lpdwAudioBytes2 = 0;
473 } else {
474 TRACE("invalid call\n");
475 hres = DSERR_INVALIDCALL; /* DSERR_NODRIVER ? */
478 LeaveCriticalSection(&(This->device->lock));
480 TRACE("returning %08lx\n", hres);
481 return hres;
484 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Start(IDirectSoundCaptureBuffer8 *iface,
485 DWORD dwFlags)
487 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
488 HRESULT hres;
490 TRACE( "(%p,0x%08lx)\n", This, dwFlags );
492 if (This->device == NULL) {
493 WARN("invalid parameter: This->device == NULL\n");
494 return DSERR_INVALIDPARAM;
497 if ( !This->device->client ) {
498 WARN("no driver\n");
499 return DSERR_NODRIVER;
502 EnterCriticalSection(&(This->device->lock));
504 if (This->device->state == STATE_STOPPED)
505 This->device->state = STATE_STARTING;
506 else if (This->device->state == STATE_STOPPING)
507 This->device->state = STATE_CAPTURING;
508 else
509 goto out;
510 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
511 This->flags = dwFlags;
513 if (This->device->buffer)
514 FillMemory(This->device->buffer, This->device->buflen, (This->device->pwfx->wBitsPerSample == 8) ? 128 : 0);
516 hres = IAudioClient_Start(This->device->client);
517 if(FAILED(hres)){
518 WARN("Start failed: %08lx\n", hres);
519 LeaveCriticalSection(&This->device->lock);
520 return hres;
523 out:
524 LeaveCriticalSection(&This->device->lock);
526 TRACE("returning DS_OK\n");
527 return DS_OK;
530 static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len);
532 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Stop(IDirectSoundCaptureBuffer8 *iface)
534 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
535 HRESULT hres;
537 TRACE("(%p)\n", This);
539 if (This->device == NULL) {
540 WARN("invalid parameter: This->device == NULL\n");
541 return DSERR_INVALIDPARAM;
544 EnterCriticalSection(&(This->device->lock));
546 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
547 if (This->device->state == STATE_CAPTURING)
548 This->device->state = STATE_STOPPING;
549 else if (This->device->state == STATE_STARTING) {
550 This->device->state = STATE_STOPPED;
551 capture_CheckNotify(This->device->capture_buffer, 0, 0);
553 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
555 if(This->device->client){
556 hres = IAudioClient_Stop(This->device->client);
557 if(FAILED(hres)){
558 LeaveCriticalSection(&This->device->lock);
559 return hres;
563 LeaveCriticalSection(&(This->device->lock));
565 TRACE("returning DS_OK\n");
566 return DS_OK;
569 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Unlock(IDirectSoundCaptureBuffer8 *iface,
570 void *lpvAudioPtr1, DWORD dwAudioBytes1, void *lpvAudioPtr2, DWORD dwAudioBytes2)
572 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
573 HRESULT hres = DS_OK;
575 TRACE( "(%p,%p,%08lu,%p,%08lu)\n", This, lpvAudioPtr1, dwAudioBytes1,
576 lpvAudioPtr2, dwAudioBytes2 );
578 if (lpvAudioPtr1 == NULL) {
579 WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
580 return DSERR_INVALIDPARAM;
583 if (!This->device->client) {
584 WARN("invalid call\n");
585 hres = DSERR_INVALIDCALL;
588 TRACE("returning %08lx\n", hres);
589 return hres;
592 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface,
593 REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
595 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
597 FIXME( "(%p,%s,%lu,%s,%p): stub\n", This, debugstr_guid(rguidObject),
598 dwIndex, debugstr_guid(rguidInterface), ppObject );
600 if (!ppObject)
601 return DSERR_INVALIDPARAM;
603 *ppObject = NULL;
604 return DSERR_CONTROLUNAVAIL;
607 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFXStatus(IDirectSoundCaptureBuffer8 *iface,
608 DWORD dwFXCount, DWORD *pdwFXStatus)
610 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
612 FIXME( "(%p,%lu,%p): stub\n", This, dwFXCount, pdwFXStatus );
614 return DS_OK;
617 static const IDirectSoundCaptureBuffer8Vtbl dscbvt =
619 /* IUnknown methods */
620 IDirectSoundCaptureBufferImpl_QueryInterface,
621 IDirectSoundCaptureBufferImpl_AddRef,
622 IDirectSoundCaptureBufferImpl_Release,
624 /* IDirectSoundCaptureBuffer methods */
625 IDirectSoundCaptureBufferImpl_GetCaps,
626 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
627 IDirectSoundCaptureBufferImpl_GetFormat,
628 IDirectSoundCaptureBufferImpl_GetStatus,
629 IDirectSoundCaptureBufferImpl_Initialize,
630 IDirectSoundCaptureBufferImpl_Lock,
631 IDirectSoundCaptureBufferImpl_Start,
632 IDirectSoundCaptureBufferImpl_Stop,
633 IDirectSoundCaptureBufferImpl_Unlock,
635 /* IDirectSoundCaptureBuffer methods */
636 IDirectSoundCaptureBufferImpl_GetObjectInPath,
637 IDirectSoundCaptureBufferImpl_GetFXStatus
640 static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len)
642 int i;
643 for (i = 0; i < This->nrofnotifies; ++i) {
644 LPDSBPOSITIONNOTIFY event = This->notifies + i;
645 DWORD offset = event->dwOffset;
646 TRACE("checking %d, position %ld, event = %p\n", i, offset, event->hEventNotify);
648 if (offset == DSBPN_OFFSETSTOP) {
649 if (!from && !len) {
650 SetEvent(event->hEventNotify);
651 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
652 return;
654 else return;
657 if (offset >= from && offset < (from + len))
659 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
660 SetEvent(event->hEventNotify);
665 static HRESULT IDirectSoundCaptureBufferImpl_Create(
666 DirectSoundCaptureDevice *device,
667 IDirectSoundCaptureBufferImpl ** ppobj,
668 LPCDSCBUFFERDESC lpcDSCBufferDesc)
670 LPWAVEFORMATEX wfex;
671 IDirectSoundCaptureBufferImpl *This;
672 TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
674 if (ppobj == NULL) {
675 WARN("invalid parameter: ppobj == NULL\n");
676 return DSERR_INVALIDPARAM;
679 *ppobj = NULL;
681 if (!device) {
682 WARN("not initialized\n");
683 return DSERR_UNINITIALIZED;
686 if (lpcDSCBufferDesc == NULL) {
687 WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
688 return DSERR_INVALIDPARAM;
691 if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
692 (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
693 (lpcDSCBufferDesc->dwBufferBytes == 0) ||
694 (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { /* FIXME: DSERR_BADFORMAT ? */
695 WARN("invalid lpcDSCBufferDesc\n");
696 return DSERR_INVALIDPARAM;
699 wfex = lpcDSCBufferDesc->lpwfxFormat;
701 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
702 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
703 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
704 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
705 wfex->wBitsPerSample, wfex->cbSize);
707 device->pwfx = DSOUND_CopyFormat(wfex);
708 if ( device->pwfx == NULL )
709 return DSERR_OUTOFMEMORY;
711 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
712 sizeof(IDirectSoundCaptureBufferImpl));
714 if ( This == NULL ) {
715 WARN("out of memory\n");
716 return DSERR_OUTOFMEMORY;
717 } else {
718 HRESULT err = DS_OK;
719 LPBYTE newbuf;
720 DWORD buflen;
722 This->numIfaces = 0;
723 This->ref = 0;
724 This->refn = 0;
725 This->device = device;
726 This->device->capture_buffer = This;
727 This->nrofnotifies = 0;
729 This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
730 lpcDSCBufferDesc->dwSize);
731 if (This->pdscbd)
732 CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
733 else {
734 WARN("no memory\n");
735 This->device->capture_buffer = 0;
736 HeapFree( GetProcessHeap(), 0, This );
737 return DSERR_OUTOFMEMORY;
740 This->IDirectSoundCaptureBuffer8_iface.lpVtbl = &dscbvt;
741 This->IDirectSoundNotify_iface.lpVtbl = &dscnvt;
743 err = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
744 CLSCTX_INPROC_SERVER, NULL, (void**)&device->client);
745 if(FAILED(err)){
746 WARN("Activate failed: %08lx\n", err);
747 HeapFree(GetProcessHeap(), 0, This->pdscbd);
748 This->device->capture_buffer = 0;
749 HeapFree( GetProcessHeap(), 0, This );
750 return err;
753 err = IAudioClient_Initialize(device->client,
754 AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST | AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
755 200 * 100000, 0, device->pwfx, NULL);
756 if(FAILED(err)){
757 WARN("Initialize failed: %08lx\n", err);
758 IAudioClient_Release(device->client);
759 device->client = NULL;
760 HeapFree(GetProcessHeap(), 0, This->pdscbd);
761 This->device->capture_buffer = 0;
762 HeapFree( GetProcessHeap(), 0, This );
763 if(err == AUDCLNT_E_UNSUPPORTED_FORMAT)
764 return DSERR_BADFORMAT;
765 return err;
768 This->sleepev = CreateEventW(NULL, 0, 0, NULL);
770 err = IAudioClient_SetEventHandle(device->client, This->sleepev);
771 if(FAILED(err)){
772 WARN("SetEventHandle failed: %08lx\n", err);
773 IAudioClient_Release(device->client);
774 device->client = NULL;
775 CloseHandle(This->sleepev);
776 HeapFree(GetProcessHeap(), 0, This->pdscbd);
777 This->device->capture_buffer = 0;
778 HeapFree( GetProcessHeap(), 0, This );
779 return err;
782 err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
783 (void**)&device->capture);
784 if(FAILED(err)){
785 WARN("GetService failed: %08lx\n", err);
786 IAudioClient_Release(device->client);
787 device->client = NULL;
788 CloseHandle(This->sleepev);
789 HeapFree(GetProcessHeap(), 0, This->pdscbd);
790 This->device->capture_buffer = 0;
791 HeapFree( GetProcessHeap(), 0, This );
792 return err;
795 buflen = lpcDSCBufferDesc->dwBufferBytes;
796 TRACE("desired buflen=%ld, old buffer=%p\n", buflen, device->buffer);
797 if (device->buffer)
798 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
799 else
800 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
801 if (newbuf == NULL) {
802 IAudioClient_Release(device->client);
803 device->client = NULL;
804 IAudioCaptureClient_Release(device->capture);
805 device->capture = NULL;
806 CloseHandle(This->sleepev);
807 HeapFree(GetProcessHeap(), 0, This->pdscbd);
808 This->device->capture_buffer = 0;
809 HeapFree( GetProcessHeap(), 0, This );
810 return DSERR_OUTOFMEMORY;
812 device->buffer = newbuf;
813 device->buflen = buflen;
814 This->thread = CreateThread(NULL, 0, DSOUND_capture_thread, This, 0, NULL);
817 IDirectSoundCaptureBuffer8_AddRef(&This->IDirectSoundCaptureBuffer8_iface);
818 *ppobj = This;
820 TRACE("returning DS_OK\n");
821 return DS_OK;
825 /*******************************************************************************
826 * DirectSoundCaptureDevice
828 static HRESULT DirectSoundCaptureDevice_Create(
829 DirectSoundCaptureDevice ** ppDevice)
831 DirectSoundCaptureDevice * device;
832 TRACE("(%p)\n", ppDevice);
834 /* Allocate memory */
835 device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
837 if (device == NULL) {
838 WARN("out of memory\n");
839 return DSERR_OUTOFMEMORY;
842 device->ref = 1;
843 device->state = STATE_STOPPED;
845 InitializeCriticalSection( &(device->lock) );
846 device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
848 *ppDevice = device;
850 return DS_OK;
853 static ULONG DirectSoundCaptureDevice_Release(
854 DirectSoundCaptureDevice * device)
856 ULONG ref = InterlockedDecrement(&(device->ref));
857 TRACE("(%p) ref %ld\n", device, ref);
859 if (!ref) {
860 TRACE("deleting object\n");
862 EnterCriticalSection(&DSOUND_capturers_lock);
863 list_remove(&device->entry);
864 LeaveCriticalSection(&DSOUND_capturers_lock);
866 if (device->capture_buffer)
867 IDirectSoundCaptureBufferImpl_Release(&device->capture_buffer->IDirectSoundCaptureBuffer8_iface);
869 if(device->mmdevice)
870 IMMDevice_Release(device->mmdevice);
871 HeapFree(GetProcessHeap(), 0, device->pwfx);
872 device->lock.DebugInfo->Spare[0] = 0;
873 DeleteCriticalSection( &(device->lock) );
874 TRACE("(%p) released\n", device);
875 HeapFree(GetProcessHeap(), 0, device);
877 return ref;
880 static HRESULT DSOUND_capture_data(DirectSoundCaptureDevice *device)
882 if(!device->capture_buffer || device->state == STATE_STOPPED)
883 return S_FALSE;
885 if(device->state == STATE_STOPPING){
886 device->state = STATE_STOPPED;
887 capture_CheckNotify(device->capture_buffer, 0, 0);
888 return S_FALSE;
891 if(device->state == STATE_STARTING)
892 device->state = STATE_CAPTURING;
894 while(1){
895 HRESULT hr;
896 UINT32 packet_frames, packet_bytes, avail_bytes, skip_bytes = 0;
897 DWORD flags;
898 BYTE *buf;
900 hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
901 &flags, NULL, NULL);
902 if(FAILED(hr)){
903 WARN("GetBuffer failed: %08lx\n", hr);
904 return hr;
906 if(hr == AUDCLNT_S_BUFFER_EMPTY)
907 break;
909 packet_bytes = packet_frames * device->pwfx->nBlockAlign;
910 if(packet_bytes > device->buflen){
911 TRACE("audio glitch: dsound buffer too small for data\n");
912 skip_bytes = packet_bytes - device->buflen;
913 packet_bytes = device->buflen;
916 avail_bytes = device->buflen - device->write_pos_bytes;
917 if(avail_bytes > packet_bytes)
918 avail_bytes = packet_bytes;
920 memcpy(device->buffer + device->write_pos_bytes, buf + skip_bytes, avail_bytes);
921 capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
923 packet_bytes -= avail_bytes;
924 if(packet_bytes > 0){
925 if(device->capture_buffer->flags & DSCBSTART_LOOPING){
926 memcpy(device->buffer, buf + skip_bytes + avail_bytes, packet_bytes);
927 capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
928 }else{
929 device->state = STATE_STOPPED;
930 capture_CheckNotify(device->capture_buffer, 0, 0);
934 device->write_pos_bytes += avail_bytes + packet_bytes;
935 device->write_pos_bytes %= device->buflen;
937 hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
938 if(FAILED(hr)){
939 WARN("ReleaseBuffer failed: %08lx\n", hr);
940 return hr;
944 return S_OK;
947 static DWORD WINAPI DSOUND_capture_thread(void *user)
949 IDirectSoundCaptureBufferImpl *buffer = user;
950 HRESULT hr;
951 DWORD ret, wait_ms;
952 REFERENCE_TIME period;
954 SetThreadDescription(GetCurrentThread(), L"wine_dsound_capture");
956 hr = IAudioClient_GetDevicePeriod(buffer->device->client, &period, NULL);
957 if(FAILED(hr)){
958 WARN("GetDevicePeriod failed: %08lx\n", hr);
959 wait_ms = 5;
960 }else
961 wait_ms = MulDiv(5, period, 10000);
963 while(buffer->ref){
964 ret = WaitForSingleObject(buffer->sleepev, wait_ms);
966 if(!buffer->device->ref)
967 break;
969 if(ret == WAIT_OBJECT_0){
970 EnterCriticalSection(&buffer->device->lock);
972 DSOUND_capture_data(buffer->device);
974 LeaveCriticalSection(&buffer->device->lock);
975 }else if(ret != WAIT_TIMEOUT)
976 WARN("WaitForSingleObject failed: %lu\n", GetLastError());
979 return 0;
982 static struct _TestFormat {
983 DWORD flag;
984 DWORD rate;
985 DWORD depth;
986 WORD channels;
987 } formats_to_test[] = {
988 { WAVE_FORMAT_1M08, 11025, 8, 1 },
989 { WAVE_FORMAT_1M16, 11025, 16, 1 },
990 { WAVE_FORMAT_1S08, 11025, 8, 2 },
991 { WAVE_FORMAT_1S16, 11025, 16, 2 },
992 { WAVE_FORMAT_2M08, 22050, 8, 1 },
993 { WAVE_FORMAT_2M16, 22050, 16, 1 },
994 { WAVE_FORMAT_2S08, 22050, 8, 2 },
995 { WAVE_FORMAT_2S16, 22050, 16, 2 },
996 { WAVE_FORMAT_4M08, 44100, 8, 1 },
997 { WAVE_FORMAT_4M16, 44100, 16, 1 },
998 { WAVE_FORMAT_4S08, 44100, 8, 2 },
999 { WAVE_FORMAT_4S16, 44100, 16, 2 },
1000 { WAVE_FORMAT_48M08, 48000, 8, 1 },
1001 { WAVE_FORMAT_48M16, 48000, 16, 1 },
1002 { WAVE_FORMAT_48S08, 48000, 8, 2 },
1003 { WAVE_FORMAT_48S16, 48000, 16, 2 },
1004 { WAVE_FORMAT_96M08, 96000, 8, 1 },
1005 { WAVE_FORMAT_96M16, 96000, 16, 1 },
1006 { WAVE_FORMAT_96S08, 96000, 8, 2 },
1007 { WAVE_FORMAT_96S16, 96000, 16, 2 },
1011 static HRESULT DirectSoundCaptureDevice_Initialize(
1012 DirectSoundCaptureDevice ** ppDevice,
1013 LPCGUID lpcGUID)
1015 HRESULT hr;
1016 GUID devGUID;
1017 IMMDevice *mmdevice;
1018 struct _TestFormat *fmt;
1019 DirectSoundCaptureDevice *device;
1020 IAudioClient *client;
1022 TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
1024 /* Default device? */
1025 if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
1026 lpcGUID = &DSDEVID_DefaultCapture;
1028 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
1029 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
1030 return DSERR_NODRIVER;
1032 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1033 WARN("invalid parameter: lpcGUID\n");
1034 return DSERR_INVALIDPARAM;
1037 hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
1038 if(FAILED(hr))
1039 return hr;
1041 EnterCriticalSection(&DSOUND_capturers_lock);
1043 hr = DirectSoundCaptureDevice_Create(&device);
1044 if (hr != DS_OK) {
1045 WARN("DirectSoundCaptureDevice_Create failed\n");
1046 LeaveCriticalSection(&DSOUND_capturers_lock);
1047 return hr;
1050 device->guid = devGUID;
1052 device->mmdevice = mmdevice;
1054 device->drvcaps.dwFlags = 0;
1056 device->drvcaps.dwFormats = 0;
1057 device->drvcaps.dwChannels = 0;
1058 hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
1059 CLSCTX_INPROC_SERVER, NULL, (void**)&client);
1060 if(FAILED(hr)){
1061 device->lock.DebugInfo->Spare[0] = 0;
1062 DeleteCriticalSection(&device->lock);
1063 HeapFree(GetProcessHeap(), 0, device);
1064 LeaveCriticalSection(&DSOUND_capturers_lock);
1065 return DSERR_NODRIVER;
1068 for(fmt = formats_to_test; fmt->flag; ++fmt){
1069 if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
1070 device->drvcaps.dwFormats |= fmt->flag;
1071 if(fmt->channels > device->drvcaps.dwChannels)
1072 device->drvcaps.dwChannels = fmt->channels;
1075 IAudioClient_Release(client);
1077 list_add_tail(&DSOUND_capturers, &device->entry);
1079 *ppDevice = device;
1081 LeaveCriticalSection(&DSOUND_capturers_lock);
1083 return S_OK;
1087 /*****************************************************************************
1088 * IDirectSoundCapture implementation structure
1090 typedef struct IDirectSoundCaptureImpl
1092 IUnknown IUnknown_inner;
1093 IDirectSoundCapture IDirectSoundCapture_iface;
1094 LONG ref, refdsc, numIfaces;
1095 IUnknown *outer_unk; /* internal */
1096 DirectSoundCaptureDevice *device;
1097 BOOL has_dsc8;
1098 } IDirectSoundCaptureImpl;
1100 static void capture_destroy(IDirectSoundCaptureImpl *This)
1102 if (This->device)
1103 DirectSoundCaptureDevice_Release(This->device);
1104 TRACE("(%p) released\n", This);
1105 HeapFree(GetProcessHeap(),0,This);
1108 /*******************************************************************************
1109 * IUnknown Implementation for DirectSoundCapture
1111 static inline IDirectSoundCaptureImpl *impl_from_IUnknown(IUnknown *iface)
1113 return CONTAINING_RECORD(iface, IDirectSoundCaptureImpl, IUnknown_inner);
1116 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1118 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1120 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
1122 if (!ppv) {
1123 WARN("invalid parameter\n");
1124 return E_INVALIDARG;
1126 *ppv = NULL;
1128 if (IsEqualIID(riid, &IID_IUnknown))
1129 *ppv = &This->IUnknown_inner;
1130 else if (IsEqualIID(riid, &IID_IDirectSoundCapture))
1131 *ppv = &This->IDirectSoundCapture_iface;
1132 else {
1133 WARN("unknown IID %s\n", debugstr_guid(riid));
1134 return E_NOINTERFACE;
1137 IUnknown_AddRef((IUnknown*)*ppv);
1138 return S_OK;
1141 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
1143 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1144 ULONG ref = InterlockedIncrement(&This->ref);
1146 TRACE("(%p) ref=%ld\n", This, ref);
1148 if(ref == 1)
1149 InterlockedIncrement(&This->numIfaces);
1150 return ref;
1153 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
1155 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1156 ULONG ref = InterlockedDecrement(&This->ref);
1158 TRACE("(%p) ref=%ld\n", This, ref);
1160 if (!ref && !InterlockedDecrement(&This->numIfaces))
1161 capture_destroy(This);
1162 return ref;
1165 static const IUnknownVtbl unk_vtbl =
1167 IUnknownImpl_QueryInterface,
1168 IUnknownImpl_AddRef,
1169 IUnknownImpl_Release
1172 /***************************************************************************
1173 * IDirectSoundCaptureImpl
1175 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1177 return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1180 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1181 REFIID riid, void **ppv)
1183 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1184 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
1185 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1188 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1190 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1191 ULONG ref = InterlockedIncrement(&This->refdsc);
1193 TRACE("(%p) ref=%ld\n", This, ref);
1195 if(ref == 1)
1196 InterlockedIncrement(&This->numIfaces);
1197 return ref;
1200 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1202 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1203 ULONG ref = InterlockedDecrement(&This->refdsc);
1205 TRACE("(%p) ref=%ld\n", This, ref);
1207 if (!ref && !InterlockedDecrement(&This->numIfaces))
1208 capture_destroy(This);
1209 return ref;
1212 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1213 LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1214 IUnknown *pUnk)
1216 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1217 HRESULT hr;
1219 TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1221 if (pUnk) {
1222 WARN("invalid parameter: pUnk != NULL\n");
1223 return DSERR_NOAGGREGATION;
1226 if (lpcDSCBufferDesc == NULL) {
1227 WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1228 return DSERR_INVALIDPARAM;
1231 if (lplpDSCaptureBuffer == NULL) {
1232 WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1233 return DSERR_INVALIDPARAM;
1236 /* FIXME: We can only have one buffer so what do we do here? */
1237 if (This->device->capture_buffer) {
1238 WARN("invalid parameter: already has buffer\n");
1239 return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */
1242 hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1243 (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1245 if (hr != DS_OK)
1246 WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1247 else
1248 This->device->capture_buffer->has_dsc8 = This->has_dsc8;
1250 return hr;
1253 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1254 LPDSCCAPS lpDSCCaps)
1256 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1258 TRACE("(%p,%p)\n",This,lpDSCCaps);
1260 if (This->device == NULL) {
1261 WARN("not initialized\n");
1262 return DSERR_UNINITIALIZED;
1265 if (lpDSCCaps== NULL) {
1266 WARN("invalid parameter: lpDSCCaps== NULL\n");
1267 return DSERR_INVALIDPARAM;
1270 if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1271 WARN("invalid parameter: lpDSCCaps->dwSize = %ld\n", lpDSCCaps->dwSize);
1272 return DSERR_INVALIDPARAM;
1275 lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1276 lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1277 lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1279 TRACE("(flags=0x%08lx,format=0x%08lx,channels=%ld)\n",lpDSCCaps->dwFlags,
1280 lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1282 return DS_OK;
1285 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1286 LPCGUID lpcGUID)
1288 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1290 TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1292 if (This->device != NULL) {
1293 WARN("already initialized\n");
1294 return DSERR_ALREADYINITIALIZED;
1296 return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1299 static const IDirectSoundCaptureVtbl dscvt =
1301 /* IUnknown methods */
1302 IDirectSoundCaptureImpl_QueryInterface,
1303 IDirectSoundCaptureImpl_AddRef,
1304 IDirectSoundCaptureImpl_Release,
1306 /* IDirectSoundCapture methods */
1307 IDirectSoundCaptureImpl_CreateCaptureBuffer,
1308 IDirectSoundCaptureImpl_GetCaps,
1309 IDirectSoundCaptureImpl_Initialize
1312 HRESULT IDirectSoundCaptureImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_dsc8)
1314 IDirectSoundCaptureImpl *obj;
1315 HRESULT hr;
1317 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1319 *ppv = NULL;
1320 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
1321 if (obj == NULL) {
1322 WARN("out of memory\n");
1323 return DSERR_OUTOFMEMORY;
1326 setup_dsound_options();
1328 obj->IUnknown_inner.lpVtbl = &unk_vtbl;
1329 obj->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1330 obj->ref = 1;
1331 obj->refdsc = 0;
1332 obj->numIfaces = 1;
1333 obj->device = NULL;
1334 obj->has_dsc8 = has_dsc8;
1336 /* COM aggregation supported only internally */
1337 if (outer_unk)
1338 obj->outer_unk = outer_unk;
1339 else
1340 obj->outer_unk = &obj->IUnknown_inner;
1342 hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
1343 IUnknown_Release(&obj->IUnknown_inner);
1345 return hr;
1348 HRESULT DSOUND_CaptureCreate(REFIID riid, void **ppv)
1350 return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, FALSE);
1353 HRESULT DSOUND_CaptureCreate8(REFIID riid, void **ppv)
1355 return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, TRUE);
1358 /***************************************************************************
1359 * DirectSoundCaptureCreate [DSOUND.6]
1361 * Create and initialize a DirectSoundCapture interface.
1363 * PARAMS
1364 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1365 * lplpDSC [O] Address of a variable to receive the interface pointer.
1366 * pUnkOuter [I] Must be NULL.
1368 * RETURNS
1369 * Success: DS_OK
1370 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1371 * DSERR_OUTOFMEMORY
1373 * NOTES
1374 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1375 * or NULL for the default device or DSDEVID_DefaultCapture or
1376 * DSDEVID_DefaultVoiceCapture.
1378 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1380 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1381 IUnknown *pUnkOuter)
1383 HRESULT hr;
1384 IDirectSoundCapture *pDSC;
1386 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1388 if (ppDSC == NULL) {
1389 WARN("invalid parameter: ppDSC == NULL\n");
1390 return DSERR_INVALIDPARAM;
1393 if (pUnkOuter) {
1394 WARN("invalid parameter: pUnkOuter != NULL\n");
1395 return DSERR_NOAGGREGATION;
1398 hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, (void**)&pDSC);
1399 if (hr == DS_OK) {
1400 hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1401 if (hr != DS_OK) {
1402 IDirectSoundCapture_Release(pDSC);
1403 pDSC = 0;
1407 *ppDSC = pDSC;
1409 return hr;
1412 /***************************************************************************
1413 * DirectSoundCaptureCreate8 [DSOUND.12]
1415 * Create and initialize a DirectSoundCapture interface.
1417 * PARAMS
1418 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1419 * lplpDSC [O] Address of a variable to receive the interface pointer.
1420 * pUnkOuter [I] Must be NULL.
1422 * RETURNS
1423 * Success: DS_OK
1424 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1425 * DSERR_OUTOFMEMORY
1427 * NOTES
1428 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1429 * or NULL for the default device or DSDEVID_DefaultCapture or
1430 * DSDEVID_DefaultVoiceCapture.
1432 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1434 HRESULT WINAPI DirectSoundCaptureCreate8(
1435 LPCGUID lpcGUID,
1436 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1437 LPUNKNOWN pUnkOuter)
1439 HRESULT hr;
1440 LPDIRECTSOUNDCAPTURE8 pDSC8;
1441 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1443 if (ppDSC8 == NULL) {
1444 WARN("invalid parameter: ppDSC8 == NULL\n");
1445 return DSERR_INVALIDPARAM;
1448 if (pUnkOuter) {
1449 WARN("invalid parameter: pUnkOuter != NULL\n");
1450 *ppDSC8 = NULL;
1451 return DSERR_NOAGGREGATION;
1454 hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, (void**)&pDSC8);
1455 if (hr == DS_OK) {
1456 hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1457 if (hr != DS_OK) {
1458 IDirectSoundCapture_Release(pDSC8);
1459 pDSC8 = 0;
1463 *ppDSC8 = pDSC8;
1465 return hr;