oledb32: Support DBSTATUS_S_ISNULL when converting to VARIANT.
[wine.git] / dlls / dsound / capture.c
blob01cf775f50f8ff6dd442057c70716f4e4b9b7e7e
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
31 #define NONAMELESSSTRUCT
32 #define NONAMELESSUNION
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winuser.h"
36 #include "mmsystem.h"
37 #include "mmddk.h"
38 #include "winternl.h"
39 #include "winnls.h"
40 #include "wine/debug.h"
41 #include "dsound.h"
42 #include "dsound_private.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
46 typedef struct DirectSoundCaptureDevice DirectSoundCaptureDevice;
48 /* IDirectSoundCaptureBuffer implementation structure */
49 typedef struct IDirectSoundCaptureBufferImpl
51 IDirectSoundCaptureBuffer8 IDirectSoundCaptureBuffer8_iface;
52 IDirectSoundNotify IDirectSoundNotify_iface;
53 LONG numIfaces; /* "in use interfaces" refcount */
54 LONG ref, refn;
55 /* IDirectSoundCaptureBuffer fields */
56 DirectSoundCaptureDevice *device;
57 DSCBUFFERDESC *pdscbd;
58 DWORD flags;
59 /* IDirectSoundNotify fields */
60 DSBPOSITIONNOTIFY *notifies;
61 int nrofnotifies;
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 UINT timerID;
76 CRITICAL_SECTION lock;
77 IMMDevice *mmdevice;
78 IAudioClient *client;
79 IAudioCaptureClient *capture;
80 struct list entry;
84 static void capturebuffer_destroy(IDirectSoundCaptureBufferImpl *This)
86 if (This->device->state == STATE_CAPTURING)
87 This->device->state = STATE_STOPPING;
89 HeapFree(GetProcessHeap(),0, This->pdscbd);
91 if (This->device->client) {
92 IAudioClient_Release(This->device->client);
93 This->device->client = NULL;
96 if (This->device->capture) {
97 IAudioCaptureClient_Release(This->device->capture);
98 This->device->capture = NULL;
101 /* remove from DirectSoundCaptureDevice */
102 This->device->capture_buffer = NULL;
104 HeapFree(GetProcessHeap(), 0, This->notifies);
105 HeapFree(GetProcessHeap(), 0, This);
106 TRACE("(%p) released\n", This);
109 /*******************************************************************************
110 * IDirectSoundNotify
112 static inline struct IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
114 return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundNotify_iface);
117 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(IDirectSoundNotify *iface, REFIID riid,
118 void **ppobj)
120 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
122 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj);
124 return IDirectSoundCaptureBuffer_QueryInterface(&This->IDirectSoundCaptureBuffer8_iface, riid, ppobj);
127 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(IDirectSoundNotify *iface)
129 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
130 ULONG ref = InterlockedIncrement(&This->refn);
132 TRACE("(%p) ref was %d\n", This, ref - 1);
134 if(ref == 1)
135 InterlockedIncrement(&This->numIfaces);
137 return ref;
140 static ULONG WINAPI IDirectSoundNotifyImpl_Release(IDirectSoundNotify *iface)
142 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
143 ULONG ref = InterlockedDecrement(&This->refn);
145 TRACE("(%p) ref was %d\n", This, ref + 1);
147 if (!ref && !InterlockedDecrement(&This->numIfaces))
148 capturebuffer_destroy(This);
150 return ref;
153 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSoundNotify *iface,
154 DWORD howmuch, const DSBPOSITIONNOTIFY *notify)
156 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
157 TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
159 if (howmuch > 0 && notify == NULL) {
160 WARN("invalid parameter: notify == NULL\n");
161 return DSERR_INVALIDPARAM;
164 if (TRACE_ON(dsound)) {
165 unsigned int i;
166 for (i=0;i<howmuch;i++)
167 TRACE("notify at %d to %p\n",
168 notify[i].dwOffset,notify[i].hEventNotify);
171 if (howmuch > 0) {
172 /* Make an internal copy of the caller-supplied array.
173 * Replace the existing copy if one is already present. */
174 if (This->notifies)
175 This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->notifies,
176 howmuch * sizeof(DSBPOSITIONNOTIFY));
177 else
178 This->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
179 howmuch * sizeof(DSBPOSITIONNOTIFY));
181 if (!This->notifies) {
182 WARN("out of memory\n");
183 return DSERR_OUTOFMEMORY;
185 CopyMemory(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
186 This->nrofnotifies = howmuch;
187 } else {
188 HeapFree(GetProcessHeap(), 0, This->notifies);
189 This->notifies = NULL;
190 This->nrofnotifies = 0;
193 return S_OK;
196 static const IDirectSoundNotifyVtbl dscnvt =
198 IDirectSoundNotifyImpl_QueryInterface,
199 IDirectSoundNotifyImpl_AddRef,
200 IDirectSoundNotifyImpl_Release,
201 IDirectSoundNotifyImpl_SetNotificationPositions
205 static const char * const captureStateString[] = {
206 "STATE_STOPPED",
207 "STATE_STARTING",
208 "STATE_CAPTURING",
209 "STATE_STOPPING"
213 /*******************************************************************************
214 * IDirectSoundCaptureBuffer
216 static inline IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8 *iface)
218 return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundCaptureBuffer8_iface);
221 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_QueryInterface(IDirectSoundCaptureBuffer8 *iface,
222 REFIID riid, void **ppobj)
224 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
226 TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
228 if (ppobj == NULL) {
229 WARN("invalid parameter\n");
230 return E_INVALIDARG;
233 *ppobj = NULL;
235 if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
236 IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
237 IDirectSoundCaptureBuffer8_AddRef(iface);
238 *ppobj = iface;
239 return S_OK;
242 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
243 IDirectSoundNotify_AddRef(&This->IDirectSoundNotify_iface);
244 *ppobj = &This->IDirectSoundNotify_iface;
245 return S_OK;
248 FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
249 return E_NOINTERFACE;
252 static ULONG WINAPI IDirectSoundCaptureBufferImpl_AddRef(IDirectSoundCaptureBuffer8 *iface)
254 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
255 ULONG ref = InterlockedIncrement(&This->ref);
257 TRACE("(%p) ref was %d\n", This, ref - 1);
259 if(ref == 1)
260 InterlockedIncrement(&This->numIfaces);
262 return ref;
265 static ULONG WINAPI IDirectSoundCaptureBufferImpl_Release(IDirectSoundCaptureBuffer8 *iface)
267 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
268 ULONG ref = InterlockedDecrement(&This->ref);
270 TRACE("(%p) ref was %d\n", This, ref + 1);
272 if (!ref && !InterlockedDecrement(&This->numIfaces))
273 capturebuffer_destroy(This);
275 return ref;
278 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCaps(IDirectSoundCaptureBuffer8 *iface,
279 DSCBCAPS *lpDSCBCaps)
281 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
282 TRACE( "(%p,%p)\n", This, lpDSCBCaps );
284 if (lpDSCBCaps == NULL) {
285 WARN("invalid parameter: lpDSCBCaps == NULL\n");
286 return DSERR_INVALIDPARAM;
289 if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
290 WARN("invalid parameter: lpDSCBCaps->dwSize = %d\n", lpDSCBCaps->dwSize);
291 return DSERR_INVALIDPARAM;
294 if (This->device == NULL) {
295 WARN("invalid parameter: This->device == NULL\n");
296 return DSERR_INVALIDPARAM;
299 lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
300 lpDSCBCaps->dwFlags = This->flags;
301 lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
302 lpDSCBCaps->dwReserved = 0;
304 TRACE("returning DS_OK\n");
305 return DS_OK;
308 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCurrentPosition(IDirectSoundCaptureBuffer8 *iface,
309 DWORD *lpdwCapturePosition, DWORD *lpdwReadPosition)
311 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
313 TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
315 if (This->device == NULL) {
316 WARN("invalid parameter: This->device == NULL\n");
317 return DSERR_INVALIDPARAM;
320 EnterCriticalSection(&This->device->lock);
322 if (!This->device->client) {
323 LeaveCriticalSection(&This->device->lock);
324 WARN("no driver\n");
325 return DSERR_NODRIVER;
328 if(lpdwCapturePosition)
329 *lpdwCapturePosition = This->device->write_pos_bytes;
331 if(lpdwReadPosition)
332 *lpdwReadPosition = This->device->write_pos_bytes;
334 LeaveCriticalSection(&This->device->lock);
336 TRACE("cappos=%d readpos=%d\n", (lpdwCapturePosition?*lpdwCapturePosition:-1), (lpdwReadPosition?*lpdwReadPosition:-1));
337 TRACE("returning DS_OK\n");
339 return DS_OK;
342 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFormat(IDirectSoundCaptureBuffer8 *iface,
343 WAVEFORMATEX *lpwfxFormat, DWORD dwSizeAllocated, DWORD *lpdwSizeWritten)
345 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
346 HRESULT hres = DS_OK;
348 TRACE("(%p,%p,0x%08x,%p)\n", This, lpwfxFormat, dwSizeAllocated, lpdwSizeWritten);
350 if (This->device == NULL) {
351 WARN("invalid parameter: This->device == NULL\n");
352 return DSERR_INVALIDPARAM;
355 if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize))
356 dwSizeAllocated = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
358 if (lpwfxFormat) { /* NULL is valid (just want size) */
359 CopyMemory(lpwfxFormat, This->device->pwfx, dwSizeAllocated);
360 if (lpdwSizeWritten)
361 *lpdwSizeWritten = dwSizeAllocated;
362 } else {
363 if (lpdwSizeWritten)
364 *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
365 else {
366 TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
367 hres = DSERR_INVALIDPARAM;
371 TRACE("returning %08x\n", hres);
372 return hres;
375 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetStatus(IDirectSoundCaptureBuffer8 *iface,
376 DWORD *lpdwStatus)
378 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
380 TRACE( "(%p, %p), thread is %04x\n", This, lpdwStatus, GetCurrentThreadId() );
382 if (This->device == NULL) {
383 WARN("invalid parameter: This->device == NULL\n");
384 return DSERR_INVALIDPARAM;
387 if (lpdwStatus == NULL) {
388 WARN("invalid parameter: lpdwStatus == NULL\n");
389 return DSERR_INVALIDPARAM;
392 *lpdwStatus = 0;
393 EnterCriticalSection(&(This->device->lock));
395 TRACE("old This->device->state=%s, old lpdwStatus=%08x\n",
396 captureStateString[This->device->state],*lpdwStatus);
397 if ((This->device->state == STATE_STARTING) ||
398 (This->device->state == STATE_CAPTURING)) {
399 *lpdwStatus |= DSCBSTATUS_CAPTURING;
400 if (This->flags & DSCBSTART_LOOPING)
401 *lpdwStatus |= DSCBSTATUS_LOOPING;
403 TRACE("new This->device->state=%s, new lpdwStatus=%08x\n",
404 captureStateString[This->device->state],*lpdwStatus);
405 LeaveCriticalSection(&(This->device->lock));
407 TRACE("status=%x\n", *lpdwStatus);
408 TRACE("returning DS_OK\n");
409 return DS_OK;
412 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Initialize(IDirectSoundCaptureBuffer8 *iface,
413 IDirectSoundCapture *lpDSC, const DSCBUFFERDESC *lpcDSCBDesc)
415 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
417 FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
419 return DS_OK;
422 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Lock(IDirectSoundCaptureBuffer8 *iface,
423 DWORD dwReadCusor, DWORD dwReadBytes, void **lplpvAudioPtr1, DWORD *lpdwAudioBytes1,
424 void **lplpvAudioPtr2, DWORD *lpdwAudioBytes2, DWORD dwFlags)
426 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
427 HRESULT hres = DS_OK;
429 TRACE( "(%p,%08u,%08u,%p,%p,%p,%p,0x%08x) at %d\n", This, dwReadCusor,
430 dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
431 lpdwAudioBytes2, dwFlags, GetTickCount() );
433 if (This->device == NULL) {
434 WARN("invalid parameter: This->device == NULL\n");
435 return DSERR_INVALIDPARAM;
438 if (lplpvAudioPtr1 == NULL) {
439 WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
440 return DSERR_INVALIDPARAM;
443 if (lpdwAudioBytes1 == NULL) {
444 WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
445 return DSERR_INVALIDPARAM;
448 EnterCriticalSection(&(This->device->lock));
450 if (This->device->client) {
451 *lplpvAudioPtr1 = This->device->buffer + dwReadCusor;
452 if ( (dwReadCusor + dwReadBytes) > This->device->buflen) {
453 *lpdwAudioBytes1 = This->device->buflen - dwReadCusor;
454 if (lplpvAudioPtr2)
455 *lplpvAudioPtr2 = This->device->buffer;
456 if (lpdwAudioBytes2)
457 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
458 } else {
459 *lpdwAudioBytes1 = dwReadBytes;
460 if (lplpvAudioPtr2)
461 *lplpvAudioPtr2 = 0;
462 if (lpdwAudioBytes2)
463 *lpdwAudioBytes2 = 0;
465 } else {
466 TRACE("invalid call\n");
467 hres = DSERR_INVALIDCALL; /* DSERR_NODRIVER ? */
470 LeaveCriticalSection(&(This->device->lock));
472 TRACE("returning %08x\n", hres);
473 return hres;
476 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Start(IDirectSoundCaptureBuffer8 *iface,
477 DWORD dwFlags)
479 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
480 HRESULT hres;
482 TRACE( "(%p,0x%08x)\n", This, dwFlags );
484 if (This->device == NULL) {
485 WARN("invalid parameter: This->device == NULL\n");
486 return DSERR_INVALIDPARAM;
489 if ( !This->device->client ) {
490 WARN("no driver\n");
491 return DSERR_NODRIVER;
494 EnterCriticalSection(&(This->device->lock));
496 if (This->device->state == STATE_STOPPED)
497 This->device->state = STATE_STARTING;
498 else if (This->device->state == STATE_STOPPING)
499 This->device->state = STATE_CAPTURING;
500 else
501 goto out;
502 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
503 This->flags = dwFlags;
505 if (This->device->buffer)
506 FillMemory(This->device->buffer, This->device->buflen, (This->device->pwfx->wBitsPerSample == 8) ? 128 : 0);
508 hres = IAudioClient_Start(This->device->client);
509 if(FAILED(hres)){
510 WARN("Start failed: %08x\n", hres);
511 LeaveCriticalSection(&This->device->lock);
512 return hres;
515 out:
516 LeaveCriticalSection(&This->device->lock);
518 TRACE("returning DS_OK\n");
519 return DS_OK;
522 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Stop(IDirectSoundCaptureBuffer8 *iface)
524 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
525 HRESULT hres;
527 TRACE("(%p)\n", This);
529 if (This->device == NULL) {
530 WARN("invalid parameter: This->device == NULL\n");
531 return DSERR_INVALIDPARAM;
534 EnterCriticalSection(&(This->device->lock));
536 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
537 if (This->device->state == STATE_CAPTURING)
538 This->device->state = STATE_STOPPING;
539 else if (This->device->state == STATE_STARTING)
540 This->device->state = STATE_STOPPED;
541 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
543 if(This->device->client){
544 hres = IAudioClient_Stop(This->device->client);
545 if(FAILED(hres)){
546 LeaveCriticalSection(&This->device->lock);
547 return hres;
551 LeaveCriticalSection(&(This->device->lock));
553 TRACE("returning DS_OK\n");
554 return DS_OK;
557 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Unlock(IDirectSoundCaptureBuffer8 *iface,
558 void *lpvAudioPtr1, DWORD dwAudioBytes1, void *lpvAudioPtr2, DWORD dwAudioBytes2)
560 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
561 HRESULT hres = DS_OK;
563 TRACE( "(%p,%p,%08u,%p,%08u)\n", This, lpvAudioPtr1, dwAudioBytes1,
564 lpvAudioPtr2, dwAudioBytes2 );
566 if (lpvAudioPtr1 == NULL) {
567 WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
568 return DSERR_INVALIDPARAM;
571 if (!This->device->client) {
572 WARN("invalid call\n");
573 hres = DSERR_INVALIDCALL;
576 TRACE("returning %08x\n", hres);
577 return hres;
580 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface,
581 REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
583 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
585 FIXME( "(%p,%s,%u,%s,%p): stub\n", This, debugstr_guid(rguidObject),
586 dwIndex, debugstr_guid(rguidInterface), ppObject );
588 if (!ppObject)
589 return DSERR_INVALIDPARAM;
591 *ppObject = NULL;
592 return DSERR_CONTROLUNAVAIL;
595 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFXStatus(IDirectSoundCaptureBuffer8 *iface,
596 DWORD dwFXCount, DWORD *pdwFXStatus)
598 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
600 FIXME( "(%p,%u,%p): stub\n", This, dwFXCount, pdwFXStatus );
602 return DS_OK;
605 static const IDirectSoundCaptureBuffer8Vtbl dscbvt =
607 /* IUnknown methods */
608 IDirectSoundCaptureBufferImpl_QueryInterface,
609 IDirectSoundCaptureBufferImpl_AddRef,
610 IDirectSoundCaptureBufferImpl_Release,
612 /* IDirectSoundCaptureBuffer methods */
613 IDirectSoundCaptureBufferImpl_GetCaps,
614 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
615 IDirectSoundCaptureBufferImpl_GetFormat,
616 IDirectSoundCaptureBufferImpl_GetStatus,
617 IDirectSoundCaptureBufferImpl_Initialize,
618 IDirectSoundCaptureBufferImpl_Lock,
619 IDirectSoundCaptureBufferImpl_Start,
620 IDirectSoundCaptureBufferImpl_Stop,
621 IDirectSoundCaptureBufferImpl_Unlock,
623 /* IDirectSoundCaptureBuffer methods */
624 IDirectSoundCaptureBufferImpl_GetObjectInPath,
625 IDirectSoundCaptureBufferImpl_GetFXStatus
628 static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len)
630 int i;
631 for (i = 0; i < This->nrofnotifies; ++i) {
632 LPDSBPOSITIONNOTIFY event = This->notifies + i;
633 DWORD offset = event->dwOffset;
634 TRACE("checking %d, position %d, event = %p\n", i, offset, event->hEventNotify);
636 if (offset == DSBPN_OFFSETSTOP) {
637 if (!from && !len) {
638 SetEvent(event->hEventNotify);
639 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
640 return;
642 else return;
645 if (offset >= from && offset < (from + len))
647 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
648 SetEvent(event->hEventNotify);
653 static HRESULT IDirectSoundCaptureBufferImpl_Create(
654 DirectSoundCaptureDevice *device,
655 IDirectSoundCaptureBufferImpl ** ppobj,
656 LPCDSCBUFFERDESC lpcDSCBufferDesc)
658 LPWAVEFORMATEX wfex;
659 IDirectSoundCaptureBufferImpl *This;
660 TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
662 if (ppobj == NULL) {
663 WARN("invalid parameter: ppobj == NULL\n");
664 return DSERR_INVALIDPARAM;
667 *ppobj = NULL;
669 if (!device) {
670 WARN("not initialized\n");
671 return DSERR_UNINITIALIZED;
674 if (lpcDSCBufferDesc == NULL) {
675 WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
676 return DSERR_INVALIDPARAM;
679 if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
680 (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
681 (lpcDSCBufferDesc->dwBufferBytes == 0) ||
682 (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { /* FIXME: DSERR_BADFORMAT ? */
683 WARN("invalid lpcDSCBufferDesc\n");
684 return DSERR_INVALIDPARAM;
687 wfex = lpcDSCBufferDesc->lpwfxFormat;
689 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
690 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
691 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
692 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
693 wfex->wBitsPerSample, wfex->cbSize);
695 device->pwfx = DSOUND_CopyFormat(wfex);
696 if ( device->pwfx == NULL )
697 return DSERR_OUTOFMEMORY;
699 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
700 sizeof(IDirectSoundCaptureBufferImpl));
702 if ( This == NULL ) {
703 WARN("out of memory\n");
704 return DSERR_OUTOFMEMORY;
705 } else {
706 HRESULT err = DS_OK;
707 LPBYTE newbuf;
708 DWORD buflen;
710 This->numIfaces = 0;
711 This->ref = 0;
712 This->refn = 0;
713 This->device = device;
714 This->device->capture_buffer = This;
715 This->nrofnotifies = 0;
717 This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
718 lpcDSCBufferDesc->dwSize);
719 if (This->pdscbd)
720 CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
721 else {
722 WARN("no memory\n");
723 This->device->capture_buffer = 0;
724 HeapFree( GetProcessHeap(), 0, This );
725 return DSERR_OUTOFMEMORY;
728 This->IDirectSoundCaptureBuffer8_iface.lpVtbl = &dscbvt;
729 This->IDirectSoundNotify_iface.lpVtbl = &dscnvt;
731 err = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
732 CLSCTX_INPROC_SERVER, NULL, (void**)&device->client);
733 if(FAILED(err)){
734 WARN("Activate failed: %08x\n", err);
735 HeapFree(GetProcessHeap(), 0, This->pdscbd);
736 This->device->capture_buffer = 0;
737 HeapFree( GetProcessHeap(), 0, This );
738 return err;
741 err = IAudioClient_Initialize(device->client,
742 AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
743 200 * 100000, 50000, device->pwfx, NULL);
744 if(FAILED(err)){
745 WARN("Initialize failed: %08x\n", err);
746 IAudioClient_Release(device->client);
747 device->client = NULL;
748 HeapFree(GetProcessHeap(), 0, This->pdscbd);
749 This->device->capture_buffer = 0;
750 HeapFree( GetProcessHeap(), 0, This );
751 if(err == AUDCLNT_E_UNSUPPORTED_FORMAT)
752 return DSERR_BADFORMAT;
753 return err;
756 err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
757 (void**)&device->capture);
758 if(FAILED(err)){
759 WARN("GetService failed: %08x\n", err);
760 IAudioClient_Release(device->client);
761 device->client = NULL;
762 HeapFree(GetProcessHeap(), 0, This->pdscbd);
763 This->device->capture_buffer = 0;
764 HeapFree( GetProcessHeap(), 0, This );
765 return err;
768 buflen = lpcDSCBufferDesc->dwBufferBytes;
769 TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
770 if (device->buffer)
771 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
772 else
773 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
774 if (newbuf == NULL) {
775 IAudioClient_Release(device->client);
776 device->client = NULL;
777 IAudioCaptureClient_Release(device->capture);
778 device->capture = NULL;
779 HeapFree(GetProcessHeap(), 0, This->pdscbd);
780 This->device->capture_buffer = 0;
781 HeapFree( GetProcessHeap(), 0, This );
782 return DSERR_OUTOFMEMORY;
784 device->buffer = newbuf;
785 device->buflen = buflen;
788 IDirectSoundCaptureBuffer_AddRef(&This->IDirectSoundCaptureBuffer8_iface);
789 *ppobj = This;
791 TRACE("returning DS_OK\n");
792 return DS_OK;
796 /*******************************************************************************
797 * DirectSoundCaptureDevice
799 static HRESULT DirectSoundCaptureDevice_Create(
800 DirectSoundCaptureDevice ** ppDevice)
802 DirectSoundCaptureDevice * device;
803 TRACE("(%p)\n", ppDevice);
805 /* Allocate memory */
806 device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
808 if (device == NULL) {
809 WARN("out of memory\n");
810 return DSERR_OUTOFMEMORY;
813 device->ref = 1;
814 device->state = STATE_STOPPED;
816 InitializeCriticalSection( &(device->lock) );
817 device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
819 *ppDevice = device;
821 return DS_OK;
824 static ULONG DirectSoundCaptureDevice_Release(
825 DirectSoundCaptureDevice * device)
827 ULONG ref = InterlockedDecrement(&(device->ref));
828 TRACE("(%p) ref was %d\n", device, ref + 1);
830 if (!ref) {
831 TRACE("deleting object\n");
833 timeKillEvent(device->timerID);
834 timeEndPeriod(DS_TIME_RES);
836 EnterCriticalSection(&DSOUND_capturers_lock);
837 list_remove(&device->entry);
838 LeaveCriticalSection(&DSOUND_capturers_lock);
840 if (device->capture_buffer)
841 IDirectSoundCaptureBufferImpl_Release(&device->capture_buffer->IDirectSoundCaptureBuffer8_iface);
843 if(device->mmdevice)
844 IMMDevice_Release(device->mmdevice);
845 HeapFree(GetProcessHeap(), 0, device->pwfx);
846 device->lock.DebugInfo->Spare[0] = 0;
847 DeleteCriticalSection( &(device->lock) );
848 HeapFree(GetProcessHeap(), 0, device);
849 TRACE("(%p) released\n", device);
851 return ref;
854 static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user,
855 DWORD_PTR dw1, DWORD_PTR dw2)
857 DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user;
858 UINT32 packet_frames, packet_bytes, avail_bytes, skip_bytes = 0;
859 DWORD flags;
860 BYTE *buf;
861 HRESULT hr;
863 if(!device->ref)
864 return;
866 EnterCriticalSection(&device->lock);
868 if(!device->capture_buffer || device->state == STATE_STOPPED){
869 LeaveCriticalSection(&device->lock);
870 return;
873 if(device->state == STATE_STOPPING){
874 device->state = STATE_STOPPED;
875 LeaveCriticalSection(&device->lock);
876 return;
879 if(device->state == STATE_STARTING)
880 device->state = STATE_CAPTURING;
882 hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
883 &flags, NULL, NULL);
884 if(FAILED(hr)){
885 LeaveCriticalSection(&device->lock);
886 WARN("GetBuffer failed: %08x\n", hr);
887 return;
890 packet_bytes = packet_frames * device->pwfx->nBlockAlign;
891 if(packet_bytes > device->buflen){
892 TRACE("audio glitch: dsound buffer too small for data\n");
893 skip_bytes = packet_bytes - device->buflen;
894 packet_bytes = device->buflen;
897 avail_bytes = device->buflen - device->write_pos_bytes;
898 if(avail_bytes > packet_bytes)
899 avail_bytes = packet_bytes;
901 memcpy(device->buffer + device->write_pos_bytes, buf + skip_bytes, avail_bytes);
902 capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
904 packet_bytes -= avail_bytes;
905 if(packet_bytes > 0){
906 if(device->capture_buffer->flags & DSCBSTART_LOOPING){
907 memcpy(device->buffer, buf + skip_bytes + avail_bytes, packet_bytes);
908 capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
909 }else{
910 device->state = STATE_STOPPED;
911 capture_CheckNotify(device->capture_buffer, 0, 0);
915 device->write_pos_bytes += avail_bytes + packet_bytes;
916 device->write_pos_bytes %= device->buflen;
918 hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
919 if(FAILED(hr)){
920 LeaveCriticalSection(&device->lock);
921 WARN("ReleaseBuffer failed: %08x\n", hr);
922 return;
925 LeaveCriticalSection(&device->lock);
928 static struct _TestFormat {
929 DWORD flag;
930 DWORD rate;
931 DWORD depth;
932 WORD channels;
933 } formats_to_test[] = {
934 { WAVE_FORMAT_1M08, 11025, 8, 1 },
935 { WAVE_FORMAT_1M16, 11025, 16, 1 },
936 { WAVE_FORMAT_1S08, 11025, 8, 2 },
937 { WAVE_FORMAT_1S16, 11025, 16, 2 },
938 { WAVE_FORMAT_2M08, 22050, 8, 1 },
939 { WAVE_FORMAT_2M16, 22050, 16, 1 },
940 { WAVE_FORMAT_2S08, 22050, 8, 2 },
941 { WAVE_FORMAT_2S16, 22050, 16, 2 },
942 { WAVE_FORMAT_4M08, 44100, 8, 1 },
943 { WAVE_FORMAT_4M16, 44100, 16, 1 },
944 { WAVE_FORMAT_4S08, 44100, 8, 2 },
945 { WAVE_FORMAT_4S16, 44100, 16, 2 },
946 { WAVE_FORMAT_48M08, 48000, 8, 1 },
947 { WAVE_FORMAT_48M16, 48000, 16, 1 },
948 { WAVE_FORMAT_48S08, 48000, 8, 2 },
949 { WAVE_FORMAT_48S16, 48000, 16, 2 },
950 { WAVE_FORMAT_96M08, 96000, 8, 1 },
951 { WAVE_FORMAT_96M16, 96000, 16, 1 },
952 { WAVE_FORMAT_96S08, 96000, 8, 2 },
953 { WAVE_FORMAT_96S16, 96000, 16, 2 },
957 static HRESULT DirectSoundCaptureDevice_Initialize(
958 DirectSoundCaptureDevice ** ppDevice,
959 LPCGUID lpcGUID)
961 HRESULT hr;
962 GUID devGUID;
963 IMMDevice *mmdevice;
964 struct _TestFormat *fmt;
965 DirectSoundCaptureDevice *device;
966 IAudioClient *client;
968 TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
970 /* Default device? */
971 if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
972 lpcGUID = &DSDEVID_DefaultCapture;
974 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
975 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
976 return DSERR_NODRIVER;
978 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
979 WARN("invalid parameter: lpcGUID\n");
980 return DSERR_INVALIDPARAM;
983 hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
984 if(FAILED(hr))
985 return hr;
987 EnterCriticalSection(&DSOUND_capturers_lock);
989 LIST_FOR_EACH_ENTRY(device, &DSOUND_capturers, DirectSoundCaptureDevice, entry){
990 if(IsEqualGUID(&device->guid, &devGUID)){
991 IMMDevice_Release(mmdevice);
992 LeaveCriticalSection(&DSOUND_capturers_lock);
993 return DSERR_ALLOCATED;
997 hr = DirectSoundCaptureDevice_Create(&device);
998 if (hr != DS_OK) {
999 WARN("DirectSoundCaptureDevice_Create failed\n");
1000 LeaveCriticalSection(&DSOUND_capturers_lock);
1001 return hr;
1004 device->guid = devGUID;
1006 device->mmdevice = mmdevice;
1008 device->drvcaps.dwFlags = 0;
1010 device->drvcaps.dwFormats = 0;
1011 device->drvcaps.dwChannels = 0;
1012 hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
1013 CLSCTX_INPROC_SERVER, NULL, (void**)&client);
1014 if(FAILED(hr)){
1015 device->lock.DebugInfo->Spare[0] = 0;
1016 DeleteCriticalSection(&device->lock);
1017 HeapFree(GetProcessHeap(), 0, device);
1018 LeaveCriticalSection(&DSOUND_capturers_lock);
1019 return DSERR_NODRIVER;
1022 for(fmt = formats_to_test; fmt->flag; ++fmt){
1023 if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
1024 device->drvcaps.dwFormats |= fmt->flag;
1025 if(fmt->channels > device->drvcaps.dwChannels)
1026 device->drvcaps.dwChannels = fmt->channels;
1029 IAudioClient_Release(client);
1031 device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
1033 list_add_tail(&DSOUND_capturers, &device->entry);
1035 *ppDevice = device;
1037 LeaveCriticalSection(&DSOUND_capturers_lock);
1039 return S_OK;
1043 /*****************************************************************************
1044 * IDirectSoundCapture implementation structure
1046 typedef struct IDirectSoundCaptureImpl
1048 IUnknown IUnknown_inner;
1049 IDirectSoundCapture IDirectSoundCapture_iface;
1050 LONG ref, refdsc, numIfaces;
1051 IUnknown *outer_unk; /* internal */
1052 DirectSoundCaptureDevice *device;
1053 BOOL has_dsc8;
1054 } IDirectSoundCaptureImpl;
1056 static void capture_destroy(IDirectSoundCaptureImpl *This)
1058 if (This->device)
1059 DirectSoundCaptureDevice_Release(This->device);
1060 HeapFree(GetProcessHeap(),0,This);
1061 TRACE("(%p) released\n", This);
1064 /*******************************************************************************
1065 * IUnknown Implementation for DirectSoundCapture
1067 static inline IDirectSoundCaptureImpl *impl_from_IUnknown(IUnknown *iface)
1069 return CONTAINING_RECORD(iface, IDirectSoundCaptureImpl, IUnknown_inner);
1072 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1074 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1076 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
1078 if (!ppv) {
1079 WARN("invalid parameter\n");
1080 return E_INVALIDARG;
1082 *ppv = NULL;
1084 if (IsEqualIID(riid, &IID_IUnknown))
1085 *ppv = &This->IUnknown_inner;
1086 else if (IsEqualIID(riid, &IID_IDirectSoundCapture))
1087 *ppv = &This->IDirectSoundCapture_iface;
1088 else {
1089 WARN("unknown IID %s\n", debugstr_guid(riid));
1090 return E_NOINTERFACE;
1093 IUnknown_AddRef((IUnknown*)*ppv);
1094 return S_OK;
1097 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
1099 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1100 ULONG ref = InterlockedIncrement(&This->ref);
1102 TRACE("(%p) ref=%d\n", This, ref);
1104 if(ref == 1)
1105 InterlockedIncrement(&This->numIfaces);
1106 return ref;
1109 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
1111 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1112 ULONG ref = InterlockedDecrement(&This->ref);
1114 TRACE("(%p) ref=%d\n", This, ref);
1116 if (!ref && !InterlockedDecrement(&This->numIfaces))
1117 capture_destroy(This);
1118 return ref;
1121 static const IUnknownVtbl unk_vtbl =
1123 IUnknownImpl_QueryInterface,
1124 IUnknownImpl_AddRef,
1125 IUnknownImpl_Release
1128 /***************************************************************************
1129 * IDirectSoundCaptureImpl
1131 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1133 return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1136 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1137 REFIID riid, void **ppv)
1139 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1140 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
1141 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1144 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1146 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1147 ULONG ref = InterlockedIncrement(&This->refdsc);
1149 TRACE("(%p) ref=%d\n", This, ref);
1151 if(ref == 1)
1152 InterlockedIncrement(&This->numIfaces);
1153 return ref;
1156 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1158 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1159 ULONG ref = InterlockedDecrement(&This->refdsc);
1161 TRACE("(%p) ref=%d\n", This, ref);
1163 if (!ref && !InterlockedDecrement(&This->numIfaces))
1164 capture_destroy(This);
1165 return ref;
1168 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1169 LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1170 IUnknown *pUnk)
1172 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1173 HRESULT hr;
1175 TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1177 if (pUnk) {
1178 WARN("invalid parameter: pUnk != NULL\n");
1179 return DSERR_NOAGGREGATION;
1182 if (lpcDSCBufferDesc == NULL) {
1183 WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1184 return DSERR_INVALIDPARAM;
1187 if (lplpDSCaptureBuffer == NULL) {
1188 WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1189 return DSERR_INVALIDPARAM;
1192 if (pUnk != NULL) {
1193 WARN("invalid parameter: pUnk != NULL\n");
1194 return DSERR_INVALIDPARAM;
1197 /* FIXME: We can only have one buffer so what do we do here? */
1198 if (This->device->capture_buffer) {
1199 WARN("invalid parameter: already has buffer\n");
1200 return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */
1203 hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1204 (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1206 if (hr != DS_OK)
1207 WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1209 return hr;
1212 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1213 LPDSCCAPS lpDSCCaps)
1215 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1217 TRACE("(%p,%p)\n",This,lpDSCCaps);
1219 if (This->device == NULL) {
1220 WARN("not initialized\n");
1221 return DSERR_UNINITIALIZED;
1224 if (lpDSCCaps== NULL) {
1225 WARN("invalid parameter: lpDSCCaps== NULL\n");
1226 return DSERR_INVALIDPARAM;
1229 if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1230 WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1231 return DSERR_INVALIDPARAM;
1234 lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1235 lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1236 lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1238 TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1239 lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1241 return DS_OK;
1244 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1245 LPCGUID lpcGUID)
1247 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1249 TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1251 if (This->device != NULL) {
1252 WARN("already initialized\n");
1253 return DSERR_ALREADYINITIALIZED;
1255 return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1258 static const IDirectSoundCaptureVtbl dscvt =
1260 /* IUnknown methods */
1261 IDirectSoundCaptureImpl_QueryInterface,
1262 IDirectSoundCaptureImpl_AddRef,
1263 IDirectSoundCaptureImpl_Release,
1265 /* IDirectSoundCapture methods */
1266 IDirectSoundCaptureImpl_CreateCaptureBuffer,
1267 IDirectSoundCaptureImpl_GetCaps,
1268 IDirectSoundCaptureImpl_Initialize
1271 HRESULT IDirectSoundCaptureImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_dsc8)
1273 IDirectSoundCaptureImpl *obj;
1274 HRESULT hr;
1276 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1278 *ppv = NULL;
1279 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
1280 if (obj == NULL) {
1281 WARN("out of memory\n");
1282 return DSERR_OUTOFMEMORY;
1285 setup_dsound_options();
1287 obj->IUnknown_inner.lpVtbl = &unk_vtbl;
1288 obj->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1289 obj->ref = 1;
1290 obj->refdsc = 0;
1291 obj->numIfaces = 1;
1292 obj->device = NULL;
1293 obj->has_dsc8 = has_dsc8;
1295 /* COM aggregation supported only internally */
1296 if (outer_unk)
1297 obj->outer_unk = outer_unk;
1298 else
1299 obj->outer_unk = &obj->IUnknown_inner;
1301 hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
1302 IUnknown_Release(&obj->IUnknown_inner);
1304 return hr;
1307 HRESULT DSOUND_CaptureCreate(REFIID riid, void **ppv)
1309 return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, FALSE);
1312 HRESULT DSOUND_CaptureCreate8(REFIID riid, void **ppv)
1314 return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, TRUE);
1317 /***************************************************************************
1318 * DirectSoundCaptureCreate [DSOUND.6]
1320 * Create and initialize a DirectSoundCapture interface.
1322 * PARAMS
1323 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1324 * lplpDSC [O] Address of a variable to receive the interface pointer.
1325 * pUnkOuter [I] Must be NULL.
1327 * RETURNS
1328 * Success: DS_OK
1329 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1330 * DSERR_OUTOFMEMORY
1332 * NOTES
1333 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1334 * or NULL for the default device or DSDEVID_DefaultCapture or
1335 * DSDEVID_DefaultVoiceCapture.
1337 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1339 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1340 IUnknown *pUnkOuter)
1342 HRESULT hr;
1343 IDirectSoundCapture *pDSC;
1345 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1347 if (ppDSC == NULL) {
1348 WARN("invalid parameter: ppDSC == NULL\n");
1349 return DSERR_INVALIDPARAM;
1352 if (pUnkOuter) {
1353 WARN("invalid parameter: pUnkOuter != NULL\n");
1354 return DSERR_NOAGGREGATION;
1357 hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, (void**)&pDSC);
1358 if (hr == DS_OK) {
1359 hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1360 if (hr != DS_OK) {
1361 IDirectSoundCapture_Release(pDSC);
1362 pDSC = 0;
1366 *ppDSC = pDSC;
1368 return hr;
1371 /***************************************************************************
1372 * DirectSoundCaptureCreate8 [DSOUND.12]
1374 * Create and initialize a DirectSoundCapture interface.
1376 * PARAMS
1377 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1378 * lplpDSC [O] Address of a variable to receive the interface pointer.
1379 * pUnkOuter [I] Must be NULL.
1381 * RETURNS
1382 * Success: DS_OK
1383 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1384 * DSERR_OUTOFMEMORY
1386 * NOTES
1387 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1388 * or NULL for the default device or DSDEVID_DefaultCapture or
1389 * DSDEVID_DefaultVoiceCapture.
1391 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1393 HRESULT WINAPI DirectSoundCaptureCreate8(
1394 LPCGUID lpcGUID,
1395 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1396 LPUNKNOWN pUnkOuter)
1398 HRESULT hr;
1399 LPDIRECTSOUNDCAPTURE8 pDSC8;
1400 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1402 if (ppDSC8 == NULL) {
1403 WARN("invalid parameter: ppDSC8 == NULL\n");
1404 return DSERR_INVALIDPARAM;
1407 if (pUnkOuter) {
1408 WARN("invalid parameter: pUnkOuter != NULL\n");
1409 *ppDSC8 = NULL;
1410 return DSERR_NOAGGREGATION;
1413 hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, (void**)&pDSC8);
1414 if (hr == DS_OK) {
1415 hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1416 if (hr != DS_OK) {
1417 IDirectSoundCapture_Release(pDSC8);
1418 pDSC8 = 0;
1422 *ppDSC8 = pDSC8;
1424 return hr;