rasapi32: Update spec file.
[wine/zf.git] / dlls / dsound / capture.c
blob2fb3ce8c4a683302cb29acdbe4838f8cb906149a
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 HeapFree(GetProcessHeap(), 0, This);
113 TRACE("(%p) released\n", 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 %d\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 %d\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%08x,%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 %d 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 %d\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 %d\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 = %d\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=%d readpos=%d\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%08x,%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 %08x\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=%08x\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=%08x\n",
412 captureStateString[This->device->state],*lpdwStatus);
413 LeaveCriticalSection(&(This->device->lock));
415 TRACE("status=%x\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,%08u,%08u,%p,%p,%p,%p,0x%08x) at %d\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 %08x\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%08x)\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: %08x\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,%08u,%p,%08u)\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 %08x\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,%u,%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,%u,%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 %d, 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=%d,"
702 "bytespersec=%d,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: %08x\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: %08x\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: %08x\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: %08x\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=%d, 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 %d\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 HeapFree(GetProcessHeap(), 0, device);
875 TRACE("(%p) released\n", 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: %08x\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: %08x\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 hr = IAudioClient_GetDevicePeriod(buffer->device->client, &period, NULL);
955 if(FAILED(hr)){
956 WARN("GetDevicePeriod failed: %08x\n", hr);
957 wait_ms = 5;
958 }else
959 wait_ms = MulDiv(5, period, 10000);
961 while(buffer->ref){
962 ret = WaitForSingleObject(buffer->sleepev, wait_ms);
964 if(!buffer->device->ref)
965 break;
967 if(ret == WAIT_OBJECT_0){
968 EnterCriticalSection(&buffer->device->lock);
970 DSOUND_capture_data(buffer->device);
972 LeaveCriticalSection(&buffer->device->lock);
973 }else if(ret != WAIT_TIMEOUT)
974 WARN("WaitForSingleObject failed: %u\n", GetLastError());
977 return 0;
980 static struct _TestFormat {
981 DWORD flag;
982 DWORD rate;
983 DWORD depth;
984 WORD channels;
985 } formats_to_test[] = {
986 { WAVE_FORMAT_1M08, 11025, 8, 1 },
987 { WAVE_FORMAT_1M16, 11025, 16, 1 },
988 { WAVE_FORMAT_1S08, 11025, 8, 2 },
989 { WAVE_FORMAT_1S16, 11025, 16, 2 },
990 { WAVE_FORMAT_2M08, 22050, 8, 1 },
991 { WAVE_FORMAT_2M16, 22050, 16, 1 },
992 { WAVE_FORMAT_2S08, 22050, 8, 2 },
993 { WAVE_FORMAT_2S16, 22050, 16, 2 },
994 { WAVE_FORMAT_4M08, 44100, 8, 1 },
995 { WAVE_FORMAT_4M16, 44100, 16, 1 },
996 { WAVE_FORMAT_4S08, 44100, 8, 2 },
997 { WAVE_FORMAT_4S16, 44100, 16, 2 },
998 { WAVE_FORMAT_48M08, 48000, 8, 1 },
999 { WAVE_FORMAT_48M16, 48000, 16, 1 },
1000 { WAVE_FORMAT_48S08, 48000, 8, 2 },
1001 { WAVE_FORMAT_48S16, 48000, 16, 2 },
1002 { WAVE_FORMAT_96M08, 96000, 8, 1 },
1003 { WAVE_FORMAT_96M16, 96000, 16, 1 },
1004 { WAVE_FORMAT_96S08, 96000, 8, 2 },
1005 { WAVE_FORMAT_96S16, 96000, 16, 2 },
1009 static HRESULT DirectSoundCaptureDevice_Initialize(
1010 DirectSoundCaptureDevice ** ppDevice,
1011 LPCGUID lpcGUID)
1013 HRESULT hr;
1014 GUID devGUID;
1015 IMMDevice *mmdevice;
1016 struct _TestFormat *fmt;
1017 DirectSoundCaptureDevice *device;
1018 IAudioClient *client;
1020 TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
1022 /* Default device? */
1023 if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
1024 lpcGUID = &DSDEVID_DefaultCapture;
1026 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
1027 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
1028 return DSERR_NODRIVER;
1030 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1031 WARN("invalid parameter: lpcGUID\n");
1032 return DSERR_INVALIDPARAM;
1035 hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
1036 if(FAILED(hr))
1037 return hr;
1039 EnterCriticalSection(&DSOUND_capturers_lock);
1041 hr = DirectSoundCaptureDevice_Create(&device);
1042 if (hr != DS_OK) {
1043 WARN("DirectSoundCaptureDevice_Create failed\n");
1044 LeaveCriticalSection(&DSOUND_capturers_lock);
1045 return hr;
1048 device->guid = devGUID;
1050 device->mmdevice = mmdevice;
1052 device->drvcaps.dwFlags = 0;
1054 device->drvcaps.dwFormats = 0;
1055 device->drvcaps.dwChannels = 0;
1056 hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
1057 CLSCTX_INPROC_SERVER, NULL, (void**)&client);
1058 if(FAILED(hr)){
1059 device->lock.DebugInfo->Spare[0] = 0;
1060 DeleteCriticalSection(&device->lock);
1061 HeapFree(GetProcessHeap(), 0, device);
1062 LeaveCriticalSection(&DSOUND_capturers_lock);
1063 return DSERR_NODRIVER;
1066 for(fmt = formats_to_test; fmt->flag; ++fmt){
1067 if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
1068 device->drvcaps.dwFormats |= fmt->flag;
1069 if(fmt->channels > device->drvcaps.dwChannels)
1070 device->drvcaps.dwChannels = fmt->channels;
1073 IAudioClient_Release(client);
1075 list_add_tail(&DSOUND_capturers, &device->entry);
1077 *ppDevice = device;
1079 LeaveCriticalSection(&DSOUND_capturers_lock);
1081 return S_OK;
1085 /*****************************************************************************
1086 * IDirectSoundCapture implementation structure
1088 typedef struct IDirectSoundCaptureImpl
1090 IUnknown IUnknown_inner;
1091 IDirectSoundCapture IDirectSoundCapture_iface;
1092 LONG ref, refdsc, numIfaces;
1093 IUnknown *outer_unk; /* internal */
1094 DirectSoundCaptureDevice *device;
1095 BOOL has_dsc8;
1096 } IDirectSoundCaptureImpl;
1098 static void capture_destroy(IDirectSoundCaptureImpl *This)
1100 if (This->device)
1101 DirectSoundCaptureDevice_Release(This->device);
1102 HeapFree(GetProcessHeap(),0,This);
1103 TRACE("(%p) released\n", This);
1106 /*******************************************************************************
1107 * IUnknown Implementation for DirectSoundCapture
1109 static inline IDirectSoundCaptureImpl *impl_from_IUnknown(IUnknown *iface)
1111 return CONTAINING_RECORD(iface, IDirectSoundCaptureImpl, IUnknown_inner);
1114 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1116 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1118 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
1120 if (!ppv) {
1121 WARN("invalid parameter\n");
1122 return E_INVALIDARG;
1124 *ppv = NULL;
1126 if (IsEqualIID(riid, &IID_IUnknown))
1127 *ppv = &This->IUnknown_inner;
1128 else if (IsEqualIID(riid, &IID_IDirectSoundCapture))
1129 *ppv = &This->IDirectSoundCapture_iface;
1130 else {
1131 WARN("unknown IID %s\n", debugstr_guid(riid));
1132 return E_NOINTERFACE;
1135 IUnknown_AddRef((IUnknown*)*ppv);
1136 return S_OK;
1139 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
1141 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1142 ULONG ref = InterlockedIncrement(&This->ref);
1144 TRACE("(%p) ref=%d\n", This, ref);
1146 if(ref == 1)
1147 InterlockedIncrement(&This->numIfaces);
1148 return ref;
1151 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
1153 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1154 ULONG ref = InterlockedDecrement(&This->ref);
1156 TRACE("(%p) ref=%d\n", This, ref);
1158 if (!ref && !InterlockedDecrement(&This->numIfaces))
1159 capture_destroy(This);
1160 return ref;
1163 static const IUnknownVtbl unk_vtbl =
1165 IUnknownImpl_QueryInterface,
1166 IUnknownImpl_AddRef,
1167 IUnknownImpl_Release
1170 /***************************************************************************
1171 * IDirectSoundCaptureImpl
1173 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1175 return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1178 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1179 REFIID riid, void **ppv)
1181 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1182 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
1183 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1186 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1188 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1189 ULONG ref = InterlockedIncrement(&This->refdsc);
1191 TRACE("(%p) ref=%d\n", This, ref);
1193 if(ref == 1)
1194 InterlockedIncrement(&This->numIfaces);
1195 return ref;
1198 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1200 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1201 ULONG ref = InterlockedDecrement(&This->refdsc);
1203 TRACE("(%p) ref=%d\n", This, ref);
1205 if (!ref && !InterlockedDecrement(&This->numIfaces))
1206 capture_destroy(This);
1207 return ref;
1210 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1211 LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1212 IUnknown *pUnk)
1214 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1215 HRESULT hr;
1217 TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1219 if (pUnk) {
1220 WARN("invalid parameter: pUnk != NULL\n");
1221 return DSERR_NOAGGREGATION;
1224 if (lpcDSCBufferDesc == NULL) {
1225 WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1226 return DSERR_INVALIDPARAM;
1229 if (lplpDSCaptureBuffer == NULL) {
1230 WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1231 return DSERR_INVALIDPARAM;
1234 /* FIXME: We can only have one buffer so what do we do here? */
1235 if (This->device->capture_buffer) {
1236 WARN("invalid parameter: already has buffer\n");
1237 return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */
1240 hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1241 (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1243 if (hr != DS_OK)
1244 WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1245 else
1246 This->device->capture_buffer->has_dsc8 = This->has_dsc8;
1248 return hr;
1251 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1252 LPDSCCAPS lpDSCCaps)
1254 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1256 TRACE("(%p,%p)\n",This,lpDSCCaps);
1258 if (This->device == NULL) {
1259 WARN("not initialized\n");
1260 return DSERR_UNINITIALIZED;
1263 if (lpDSCCaps== NULL) {
1264 WARN("invalid parameter: lpDSCCaps== NULL\n");
1265 return DSERR_INVALIDPARAM;
1268 if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1269 WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1270 return DSERR_INVALIDPARAM;
1273 lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1274 lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1275 lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1277 TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1278 lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1280 return DS_OK;
1283 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1284 LPCGUID lpcGUID)
1286 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1288 TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1290 if (This->device != NULL) {
1291 WARN("already initialized\n");
1292 return DSERR_ALREADYINITIALIZED;
1294 return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1297 static const IDirectSoundCaptureVtbl dscvt =
1299 /* IUnknown methods */
1300 IDirectSoundCaptureImpl_QueryInterface,
1301 IDirectSoundCaptureImpl_AddRef,
1302 IDirectSoundCaptureImpl_Release,
1304 /* IDirectSoundCapture methods */
1305 IDirectSoundCaptureImpl_CreateCaptureBuffer,
1306 IDirectSoundCaptureImpl_GetCaps,
1307 IDirectSoundCaptureImpl_Initialize
1310 HRESULT IDirectSoundCaptureImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_dsc8)
1312 IDirectSoundCaptureImpl *obj;
1313 HRESULT hr;
1315 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1317 *ppv = NULL;
1318 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
1319 if (obj == NULL) {
1320 WARN("out of memory\n");
1321 return DSERR_OUTOFMEMORY;
1324 setup_dsound_options();
1326 obj->IUnknown_inner.lpVtbl = &unk_vtbl;
1327 obj->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1328 obj->ref = 1;
1329 obj->refdsc = 0;
1330 obj->numIfaces = 1;
1331 obj->device = NULL;
1332 obj->has_dsc8 = has_dsc8;
1334 /* COM aggregation supported only internally */
1335 if (outer_unk)
1336 obj->outer_unk = outer_unk;
1337 else
1338 obj->outer_unk = &obj->IUnknown_inner;
1340 hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
1341 IUnknown_Release(&obj->IUnknown_inner);
1343 return hr;
1346 HRESULT DSOUND_CaptureCreate(REFIID riid, void **ppv)
1348 return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, FALSE);
1351 HRESULT DSOUND_CaptureCreate8(REFIID riid, void **ppv)
1353 return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, TRUE);
1356 /***************************************************************************
1357 * DirectSoundCaptureCreate [DSOUND.6]
1359 * Create and initialize a DirectSoundCapture interface.
1361 * PARAMS
1362 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1363 * lplpDSC [O] Address of a variable to receive the interface pointer.
1364 * pUnkOuter [I] Must be NULL.
1366 * RETURNS
1367 * Success: DS_OK
1368 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1369 * DSERR_OUTOFMEMORY
1371 * NOTES
1372 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1373 * or NULL for the default device or DSDEVID_DefaultCapture or
1374 * DSDEVID_DefaultVoiceCapture.
1376 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1378 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1379 IUnknown *pUnkOuter)
1381 HRESULT hr;
1382 IDirectSoundCapture *pDSC;
1384 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1386 if (ppDSC == NULL) {
1387 WARN("invalid parameter: ppDSC == NULL\n");
1388 return DSERR_INVALIDPARAM;
1391 if (pUnkOuter) {
1392 WARN("invalid parameter: pUnkOuter != NULL\n");
1393 return DSERR_NOAGGREGATION;
1396 hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, (void**)&pDSC);
1397 if (hr == DS_OK) {
1398 hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1399 if (hr != DS_OK) {
1400 IDirectSoundCapture_Release(pDSC);
1401 pDSC = 0;
1405 *ppDSC = pDSC;
1407 return hr;
1410 /***************************************************************************
1411 * DirectSoundCaptureCreate8 [DSOUND.12]
1413 * Create and initialize a DirectSoundCapture interface.
1415 * PARAMS
1416 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1417 * lplpDSC [O] Address of a variable to receive the interface pointer.
1418 * pUnkOuter [I] Must be NULL.
1420 * RETURNS
1421 * Success: DS_OK
1422 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1423 * DSERR_OUTOFMEMORY
1425 * NOTES
1426 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1427 * or NULL for the default device or DSDEVID_DefaultCapture or
1428 * DSDEVID_DefaultVoiceCapture.
1430 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1432 HRESULT WINAPI DirectSoundCaptureCreate8(
1433 LPCGUID lpcGUID,
1434 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1435 LPUNKNOWN pUnkOuter)
1437 HRESULT hr;
1438 LPDIRECTSOUNDCAPTURE8 pDSC8;
1439 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1441 if (ppDSC8 == NULL) {
1442 WARN("invalid parameter: ppDSC8 == NULL\n");
1443 return DSERR_INVALIDPARAM;
1446 if (pUnkOuter) {
1447 WARN("invalid parameter: pUnkOuter != NULL\n");
1448 *ppDSC8 = NULL;
1449 return DSERR_NOAGGREGATION;
1452 hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, (void**)&pDSC8);
1453 if (hr == DS_OK) {
1454 hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1455 if (hr != DS_OK) {
1456 IDirectSoundCapture_Release(pDSC8);
1457 pDSC8 = 0;
1461 *ppDSC8 = pDSC8;
1463 return hr;