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
23 * Implement FX support.
24 * Implement both IDirectSoundCaptureBuffer and IDirectSoundCaptureBuffer8
25 * Make DirectSoundCaptureCreate and DirectSoundCaptureCreate8 behave differently
31 #define NONAMELESSSTRUCT
32 #define NONAMELESSUNION
40 #include "wine/debug.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 */
55 /* IDirectSoundCaptureBuffer fields */
56 DirectSoundCaptureDevice *device;
57 DSCBUFFERDESC *pdscbd;
59 /* IDirectSoundNotify fields */
60 DSBPOSITIONNOTIFY *notifies;
62 } IDirectSoundCaptureBufferImpl;
64 /* DirectSoundCaptureDevice implementation structure */
65 struct DirectSoundCaptureDevice
71 DWORD buflen, write_pos_bytes;
73 IDirectSoundCaptureBufferImpl *capture_buffer;
76 CRITICAL_SECTION lock;
79 IAudioCaptureClient *capture;
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 /*******************************************************************************
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,
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);
135 InterlockedIncrement(&This->numIfaces);
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);
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)) {
166 for (i=0;i<howmuch;i++)
167 TRACE("notify at %d to %p\n",
168 notify[i].dwOffset,notify[i].hEventNotify);
172 /* Make an internal copy of the caller-supplied array.
173 * Replace the existing copy if one is already present. */
175 This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->notifies,
176 howmuch * sizeof(DSBPOSITIONNOTIFY));
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;
188 HeapFree(GetProcessHeap(), 0, This->notifies);
189 This->notifies = NULL;
190 This->nrofnotifies = 0;
196 static const IDirectSoundNotifyVtbl dscnvt =
198 IDirectSoundNotifyImpl_QueryInterface,
199 IDirectSoundNotifyImpl_AddRef,
200 IDirectSoundNotifyImpl_Release,
201 IDirectSoundNotifyImpl_SetNotificationPositions
205 static const char * const captureStateString[] = {
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 );
229 WARN("invalid parameter\n");
235 if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
236 IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
237 IDirectSoundCaptureBuffer8_AddRef(iface);
242 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
243 IDirectSoundNotify_AddRef(&This->IDirectSoundNotify_iface);
244 *ppobj = &This->IDirectSoundNotify_iface;
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);
260 InterlockedIncrement(&This->numIfaces);
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);
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");
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);
325 return DSERR_NODRIVER;
328 if(lpdwCapturePosition)
329 *lpdwCapturePosition = This->device->write_pos_bytes;
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");
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);
361 *lpdwSizeWritten = dwSizeAllocated;
364 *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
366 TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
367 hres = DSERR_INVALIDPARAM;
371 TRACE("returning %08x\n", hres);
375 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetStatus(IDirectSoundCaptureBuffer8 *iface,
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;
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");
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 );
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;
455 *lplpvAudioPtr2 = This->device->buffer;
457 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
459 *lpdwAudioBytes1 = dwReadBytes;
463 *lpdwAudioBytes2 = 0;
466 TRACE("invalid call\n");
467 hres = DSERR_INVALIDCALL; /* DSERR_NODRIVER ? */
470 LeaveCriticalSection(&(This->device->lock));
472 TRACE("returning %08x\n", hres);
476 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Start(IDirectSoundCaptureBuffer8 *iface,
479 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
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 ) {
491 return DSERR_NODRIVER;
494 EnterCriticalSection(&(This->device->lock));
496 This->flags = dwFlags;
497 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
498 if (This->device->state == STATE_STOPPED)
499 This->device->state = STATE_STARTING;
500 else if (This->device->state == STATE_STOPPING)
501 This->device->state = STATE_CAPTURING;
502 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
504 if (This->device->buffer)
505 FillMemory(This->device->buffer, This->device->buflen, (This->device->pwfx->wBitsPerSample == 8) ? 128 : 0);
507 hres = IAudioClient_Start(This->device->client);
509 WARN("Start failed: %08x\n", hres);
510 LeaveCriticalSection(&This->device->lock);
514 LeaveCriticalSection(&This->device->lock);
516 TRACE("returning DS_OK\n");
520 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Stop(IDirectSoundCaptureBuffer8 *iface)
522 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
525 TRACE("(%p)\n", This);
527 if (This->device == NULL) {
528 WARN("invalid parameter: This->device == NULL\n");
529 return DSERR_INVALIDPARAM;
532 EnterCriticalSection(&(This->device->lock));
534 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
535 if (This->device->state == STATE_CAPTURING)
536 This->device->state = STATE_STOPPING;
537 else if (This->device->state == STATE_STARTING)
538 This->device->state = STATE_STOPPED;
539 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
541 if(This->device->client){
542 hres = IAudioClient_Stop(This->device->client);
544 LeaveCriticalSection(&This->device->lock);
549 LeaveCriticalSection(&(This->device->lock));
551 TRACE("returning DS_OK\n");
555 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Unlock(IDirectSoundCaptureBuffer8 *iface,
556 void *lpvAudioPtr1, DWORD dwAudioBytes1, void *lpvAudioPtr2, DWORD dwAudioBytes2)
558 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
559 HRESULT hres = DS_OK;
561 TRACE( "(%p,%p,%08u,%p,%08u)\n", This, lpvAudioPtr1, dwAudioBytes1,
562 lpvAudioPtr2, dwAudioBytes2 );
564 if (lpvAudioPtr1 == NULL) {
565 WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
566 return DSERR_INVALIDPARAM;
569 if (!This->device->client) {
570 WARN("invalid call\n");
571 hres = DSERR_INVALIDCALL;
574 TRACE("returning %08x\n", hres);
578 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface,
579 REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
581 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
583 FIXME( "(%p,%s,%u,%s,%p): stub\n", This, debugstr_guid(rguidObject),
584 dwIndex, debugstr_guid(rguidInterface), ppObject );
589 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFXStatus(IDirectSoundCaptureBuffer8 *iface,
590 DWORD dwFXCount, DWORD *pdwFXStatus)
592 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
594 FIXME( "(%p,%u,%p): stub\n", This, dwFXCount, pdwFXStatus );
599 static const IDirectSoundCaptureBuffer8Vtbl dscbvt =
601 /* IUnknown methods */
602 IDirectSoundCaptureBufferImpl_QueryInterface,
603 IDirectSoundCaptureBufferImpl_AddRef,
604 IDirectSoundCaptureBufferImpl_Release,
606 /* IDirectSoundCaptureBuffer methods */
607 IDirectSoundCaptureBufferImpl_GetCaps,
608 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
609 IDirectSoundCaptureBufferImpl_GetFormat,
610 IDirectSoundCaptureBufferImpl_GetStatus,
611 IDirectSoundCaptureBufferImpl_Initialize,
612 IDirectSoundCaptureBufferImpl_Lock,
613 IDirectSoundCaptureBufferImpl_Start,
614 IDirectSoundCaptureBufferImpl_Stop,
615 IDirectSoundCaptureBufferImpl_Unlock,
617 /* IDirectSoundCaptureBuffer methods */
618 IDirectSoundCaptureBufferImpl_GetObjectInPath,
619 IDirectSoundCaptureBufferImpl_GetFXStatus
622 static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len)
625 for (i = 0; i < This->nrofnotifies; ++i) {
626 LPDSBPOSITIONNOTIFY event = This->notifies + i;
627 DWORD offset = event->dwOffset;
628 TRACE("checking %d, position %d, event = %p\n", i, offset, event->hEventNotify);
630 if (offset == DSBPN_OFFSETSTOP) {
632 SetEvent(event->hEventNotify);
633 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
639 if (offset >= from && offset < (from + len))
641 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
642 SetEvent(event->hEventNotify);
647 static HRESULT IDirectSoundCaptureBufferImpl_Create(
648 DirectSoundCaptureDevice *device,
649 IDirectSoundCaptureBufferImpl ** ppobj,
650 LPCDSCBUFFERDESC lpcDSCBufferDesc)
653 IDirectSoundCaptureBufferImpl *This;
654 TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
657 WARN("invalid parameter: ppobj == NULL\n");
658 return DSERR_INVALIDPARAM;
664 WARN("not initialized\n");
665 return DSERR_UNINITIALIZED;
668 if (lpcDSCBufferDesc == NULL) {
669 WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
670 return DSERR_INVALIDPARAM;
673 if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
674 (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
675 (lpcDSCBufferDesc->dwBufferBytes == 0) ||
676 (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { /* FIXME: DSERR_BADFORMAT ? */
677 WARN("invalid lpcDSCBufferDesc\n");
678 return DSERR_INVALIDPARAM;
681 wfex = lpcDSCBufferDesc->lpwfxFormat;
683 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
684 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
685 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
686 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
687 wfex->wBitsPerSample, wfex->cbSize);
689 device->pwfx = DSOUND_CopyFormat(wfex);
690 if ( device->pwfx == NULL )
691 return DSERR_OUTOFMEMORY;
693 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
694 sizeof(IDirectSoundCaptureBufferImpl));
696 if ( This == NULL ) {
697 WARN("out of memory\n");
698 return DSERR_OUTOFMEMORY;
707 This->device = device;
708 This->device->capture_buffer = This;
709 This->nrofnotifies = 0;
711 This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
712 lpcDSCBufferDesc->dwSize);
714 CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
717 This->device->capture_buffer = 0;
718 HeapFree( GetProcessHeap(), 0, This );
719 return DSERR_OUTOFMEMORY;
722 This->IDirectSoundCaptureBuffer8_iface.lpVtbl = &dscbvt;
723 This->IDirectSoundNotify_iface.lpVtbl = &dscnvt;
725 err = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
726 CLSCTX_INPROC_SERVER, NULL, (void**)&device->client);
728 WARN("Activate failed: %08x\n", err);
729 HeapFree(GetProcessHeap(), 0, This->pdscbd);
730 This->device->capture_buffer = 0;
731 HeapFree( GetProcessHeap(), 0, This );
735 err = IAudioClient_Initialize(device->client,
736 AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
737 200 * 100000, 50000, device->pwfx, NULL);
739 WARN("Initialize failed: %08x\n", err);
740 IAudioClient_Release(device->client);
741 device->client = NULL;
742 HeapFree(GetProcessHeap(), 0, This->pdscbd);
743 This->device->capture_buffer = 0;
744 HeapFree( GetProcessHeap(), 0, This );
745 if(err == AUDCLNT_E_UNSUPPORTED_FORMAT)
746 return DSERR_BADFORMAT;
750 err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
751 (void**)&device->capture);
753 WARN("GetService failed: %08x\n", err);
754 IAudioClient_Release(device->client);
755 device->client = NULL;
756 HeapFree(GetProcessHeap(), 0, This->pdscbd);
757 This->device->capture_buffer = 0;
758 HeapFree( GetProcessHeap(), 0, This );
762 buflen = lpcDSCBufferDesc->dwBufferBytes;
763 TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
765 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
767 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
768 if (newbuf == NULL) {
769 IAudioClient_Release(device->client);
770 device->client = NULL;
771 IAudioCaptureClient_Release(device->capture);
772 device->capture = NULL;
773 HeapFree(GetProcessHeap(), 0, This->pdscbd);
774 This->device->capture_buffer = 0;
775 HeapFree( GetProcessHeap(), 0, This );
776 return DSERR_OUTOFMEMORY;
778 device->buffer = newbuf;
779 device->buflen = buflen;
782 IDirectSoundCaptureBuffer_AddRef(&This->IDirectSoundCaptureBuffer8_iface);
785 TRACE("returning DS_OK\n");
790 /*******************************************************************************
791 * DirectSoundCaptureDevice
793 static HRESULT DirectSoundCaptureDevice_Create(
794 DirectSoundCaptureDevice ** ppDevice)
796 DirectSoundCaptureDevice * device;
797 TRACE("(%p)\n", ppDevice);
799 /* Allocate memory */
800 device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
802 if (device == NULL) {
803 WARN("out of memory\n");
804 return DSERR_OUTOFMEMORY;
808 device->state = STATE_STOPPED;
810 InitializeCriticalSection( &(device->lock) );
811 device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
818 static ULONG DirectSoundCaptureDevice_Release(
819 DirectSoundCaptureDevice * device)
821 ULONG ref = InterlockedDecrement(&(device->ref));
822 TRACE("(%p) ref was %d\n", device, ref + 1);
825 TRACE("deleting object\n");
827 timeKillEvent(device->timerID);
828 timeEndPeriod(DS_TIME_RES);
830 EnterCriticalSection(&DSOUND_capturers_lock);
831 list_remove(&device->entry);
832 LeaveCriticalSection(&DSOUND_capturers_lock);
834 if (device->capture_buffer)
835 IDirectSoundCaptureBufferImpl_Release(&device->capture_buffer->IDirectSoundCaptureBuffer8_iface);
838 IMMDevice_Release(device->mmdevice);
839 HeapFree(GetProcessHeap(), 0, device->pwfx);
840 device->lock.DebugInfo->Spare[0] = 0;
841 DeleteCriticalSection( &(device->lock) );
842 HeapFree(GetProcessHeap(), 0, device);
843 TRACE("(%p) released\n", device);
848 static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user,
849 DWORD_PTR dw1, DWORD_PTR dw2)
851 DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user;
852 UINT32 packet_frames, packet_bytes, avail_bytes;
860 EnterCriticalSection(&device->lock);
862 if(!device->capture_buffer || device->state == STATE_STOPPED){
863 LeaveCriticalSection(&device->lock);
867 if(device->state == STATE_STOPPING){
868 device->state = STATE_STOPPED;
869 LeaveCriticalSection(&device->lock);
873 if(device->state == STATE_STARTING)
874 device->state = STATE_CAPTURING;
876 hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
879 LeaveCriticalSection(&device->lock);
880 WARN("GetBuffer failed: %08x\n", hr);
884 packet_bytes = packet_frames * device->pwfx->nBlockAlign;
886 avail_bytes = device->buflen - device->write_pos_bytes;
887 if(avail_bytes > packet_bytes)
888 avail_bytes = packet_bytes;
890 memcpy(device->buffer + device->write_pos_bytes, buf, avail_bytes);
891 capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
893 packet_bytes -= avail_bytes;
894 if(packet_bytes > 0){
895 if(device->capture_buffer->flags & DSCBSTART_LOOPING){
896 memcpy(device->buffer, buf + avail_bytes, packet_bytes);
897 capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
899 device->state = STATE_STOPPED;
900 capture_CheckNotify(device->capture_buffer, 0, 0);
904 device->write_pos_bytes += avail_bytes + packet_bytes;
905 device->write_pos_bytes %= device->buflen;
907 hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
909 LeaveCriticalSection(&device->lock);
910 WARN("ReleaseBuffer failed: %08x\n", hr);
914 LeaveCriticalSection(&device->lock);
917 static struct _TestFormat {
922 } formats_to_test[] = {
923 { WAVE_FORMAT_1M08, 11025, 8, 1 },
924 { WAVE_FORMAT_1M16, 11025, 16, 1 },
925 { WAVE_FORMAT_1S08, 11025, 8, 2 },
926 { WAVE_FORMAT_1S16, 11025, 16, 2 },
927 { WAVE_FORMAT_2M08, 22050, 8, 1 },
928 { WAVE_FORMAT_2M16, 22050, 16, 1 },
929 { WAVE_FORMAT_2S08, 22050, 8, 2 },
930 { WAVE_FORMAT_2S16, 22050, 16, 2 },
931 { WAVE_FORMAT_4M08, 44100, 8, 1 },
932 { WAVE_FORMAT_4M16, 44100, 16, 1 },
933 { WAVE_FORMAT_4S08, 44100, 8, 2 },
934 { WAVE_FORMAT_4S16, 44100, 16, 2 },
935 { WAVE_FORMAT_48M08, 48000, 8, 1 },
936 { WAVE_FORMAT_48M16, 48000, 16, 1 },
937 { WAVE_FORMAT_48S08, 48000, 8, 2 },
938 { WAVE_FORMAT_48S16, 48000, 16, 2 },
939 { WAVE_FORMAT_96M08, 96000, 8, 1 },
940 { WAVE_FORMAT_96M16, 96000, 16, 1 },
941 { WAVE_FORMAT_96S08, 96000, 8, 2 },
942 { WAVE_FORMAT_96S16, 96000, 16, 2 },
946 static HRESULT DirectSoundCaptureDevice_Initialize(
947 DirectSoundCaptureDevice ** ppDevice,
953 struct _TestFormat *fmt;
954 DirectSoundCaptureDevice *device;
955 IAudioClient *client;
957 TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
959 /* Default device? */
960 if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
961 lpcGUID = &DSDEVID_DefaultCapture;
963 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
964 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
965 return DSERR_NODRIVER;
967 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
968 WARN("invalid parameter: lpcGUID\n");
969 return DSERR_INVALIDPARAM;
972 hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
976 EnterCriticalSection(&DSOUND_capturers_lock);
978 LIST_FOR_EACH_ENTRY(device, &DSOUND_capturers, DirectSoundCaptureDevice, entry){
979 if(IsEqualGUID(&device->guid, &devGUID)){
980 IMMDevice_Release(mmdevice);
981 LeaveCriticalSection(&DSOUND_capturers_lock);
982 return DSERR_ALLOCATED;
986 hr = DirectSoundCaptureDevice_Create(&device);
988 WARN("DirectSoundCaptureDevice_Create failed\n");
989 LeaveCriticalSection(&DSOUND_capturers_lock);
993 device->guid = devGUID;
995 device->mmdevice = mmdevice;
997 device->drvcaps.dwFlags = 0;
999 device->drvcaps.dwFormats = 0;
1000 device->drvcaps.dwChannels = 0;
1001 hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
1002 CLSCTX_INPROC_SERVER, NULL, (void**)&client);
1004 device->lock.DebugInfo->Spare[0] = 0;
1005 DeleteCriticalSection(&device->lock);
1006 HeapFree(GetProcessHeap(), 0, device);
1007 LeaveCriticalSection(&DSOUND_capturers_lock);
1008 return DSERR_NODRIVER;
1011 for(fmt = formats_to_test; fmt->flag; ++fmt){
1012 if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
1013 device->drvcaps.dwFormats |= fmt->flag;
1014 if(fmt->channels > device->drvcaps.dwChannels)
1015 device->drvcaps.dwChannels = fmt->channels;
1018 IAudioClient_Release(client);
1020 device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
1022 list_add_tail(&DSOUND_capturers, &device->entry);
1026 LeaveCriticalSection(&DSOUND_capturers_lock);
1032 /*****************************************************************************
1033 * IDirectSoundCapture implementation structure
1035 typedef struct IDirectSoundCaptureImpl
1037 IUnknown IUnknown_inner;
1038 IDirectSoundCapture IDirectSoundCapture_iface;
1039 LONG ref, refdsc, numIfaces;
1040 IUnknown *outer_unk; /* internal */
1041 DirectSoundCaptureDevice *device;
1043 } IDirectSoundCaptureImpl;
1045 static void capture_destroy(IDirectSoundCaptureImpl *This)
1048 DirectSoundCaptureDevice_Release(This->device);
1049 HeapFree(GetProcessHeap(),0,This);
1050 TRACE("(%p) released\n", This);
1053 /*******************************************************************************
1054 * IUnknown Implementation for DirectSoundCapture
1056 static inline IDirectSoundCaptureImpl *impl_from_IUnknown(IUnknown *iface)
1058 return CONTAINING_RECORD(iface, IDirectSoundCaptureImpl, IUnknown_inner);
1061 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1063 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1065 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
1068 WARN("invalid parameter\n");
1069 return E_INVALIDARG;
1073 if (IsEqualIID(riid, &IID_IUnknown))
1074 *ppv = &This->IUnknown_inner;
1075 else if (IsEqualIID(riid, &IID_IDirectSoundCapture))
1076 *ppv = &This->IDirectSoundCapture_iface;
1078 WARN("unknown IID %s\n", debugstr_guid(riid));
1079 return E_NOINTERFACE;
1082 IUnknown_AddRef((IUnknown*)*ppv);
1086 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
1088 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1089 ULONG ref = InterlockedIncrement(&This->ref);
1091 TRACE("(%p) ref=%d\n", This, ref);
1094 InterlockedIncrement(&This->numIfaces);
1098 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
1100 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1101 ULONG ref = InterlockedDecrement(&This->ref);
1103 TRACE("(%p) ref=%d\n", This, ref);
1105 if (!ref && !InterlockedDecrement(&This->numIfaces))
1106 capture_destroy(This);
1110 static const IUnknownVtbl unk_vtbl =
1112 IUnknownImpl_QueryInterface,
1113 IUnknownImpl_AddRef,
1114 IUnknownImpl_Release
1117 /***************************************************************************
1118 * IDirectSoundCaptureImpl
1120 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1122 return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1125 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1126 REFIID riid, void **ppv)
1128 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1129 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
1130 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1133 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1135 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1136 ULONG ref = InterlockedIncrement(&This->refdsc);
1138 TRACE("(%p) ref=%d\n", This, ref);
1141 InterlockedIncrement(&This->numIfaces);
1145 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1147 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1148 ULONG ref = InterlockedDecrement(&This->refdsc);
1150 TRACE("(%p) ref=%d\n", This, ref);
1152 if (!ref && !InterlockedDecrement(&This->numIfaces))
1153 capture_destroy(This);
1157 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1158 LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1161 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1164 TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1167 WARN("invalid parameter: pUnk != NULL\n");
1168 return DSERR_NOAGGREGATION;
1171 if (lpcDSCBufferDesc == NULL) {
1172 WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1173 return DSERR_INVALIDPARAM;
1176 if (lplpDSCaptureBuffer == NULL) {
1177 WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1178 return DSERR_INVALIDPARAM;
1182 WARN("invalid parameter: pUnk != NULL\n");
1183 return DSERR_INVALIDPARAM;
1186 /* FIXME: We can only have one buffer so what do we do here? */
1187 if (This->device->capture_buffer) {
1188 WARN("invalid parameter: already has buffer\n");
1189 return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */
1192 hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1193 (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1196 WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1201 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1202 LPDSCCAPS lpDSCCaps)
1204 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1206 TRACE("(%p,%p)\n",This,lpDSCCaps);
1208 if (This->device == NULL) {
1209 WARN("not initialized\n");
1210 return DSERR_UNINITIALIZED;
1213 if (lpDSCCaps== NULL) {
1214 WARN("invalid parameter: lpDSCCaps== NULL\n");
1215 return DSERR_INVALIDPARAM;
1218 if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1219 WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1220 return DSERR_INVALIDPARAM;
1223 lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1224 lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1225 lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1227 TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1228 lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1233 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1236 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1238 TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1240 if (This->device != NULL) {
1241 WARN("already initialized\n");
1242 return DSERR_ALREADYINITIALIZED;
1244 return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1247 static const IDirectSoundCaptureVtbl dscvt =
1249 /* IUnknown methods */
1250 IDirectSoundCaptureImpl_QueryInterface,
1251 IDirectSoundCaptureImpl_AddRef,
1252 IDirectSoundCaptureImpl_Release,
1254 /* IDirectSoundCapture methods */
1255 IDirectSoundCaptureImpl_CreateCaptureBuffer,
1256 IDirectSoundCaptureImpl_GetCaps,
1257 IDirectSoundCaptureImpl_Initialize
1260 HRESULT IDirectSoundCaptureImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_dsc8)
1262 IDirectSoundCaptureImpl *obj;
1265 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1268 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
1270 WARN("out of memory\n");
1271 return DSERR_OUTOFMEMORY;
1274 setup_dsound_options();
1276 obj->IUnknown_inner.lpVtbl = &unk_vtbl;
1277 obj->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1282 obj->has_dsc8 = has_dsc8;
1284 /* COM aggregation supported only internally */
1286 obj->outer_unk = outer_unk;
1288 obj->outer_unk = &obj->IUnknown_inner;
1290 hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
1291 IUnknown_Release(&obj->IUnknown_inner);
1296 HRESULT DSOUND_CaptureCreate(REFIID riid, void **ppv)
1298 return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, FALSE);
1301 HRESULT DSOUND_CaptureCreate8(REFIID riid, void **ppv)
1303 return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, TRUE);
1306 /***************************************************************************
1307 * DirectSoundCaptureCreate [DSOUND.6]
1309 * Create and initialize a DirectSoundCapture interface.
1312 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1313 * lplpDSC [O] Address of a variable to receive the interface pointer.
1314 * pUnkOuter [I] Must be NULL.
1318 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1322 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1323 * or NULL for the default device or DSDEVID_DefaultCapture or
1324 * DSDEVID_DefaultVoiceCapture.
1326 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1328 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1329 IUnknown *pUnkOuter)
1332 IDirectSoundCapture *pDSC;
1334 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1336 if (ppDSC == NULL) {
1337 WARN("invalid parameter: ppDSC == NULL\n");
1338 return DSERR_INVALIDPARAM;
1342 WARN("invalid parameter: pUnkOuter != NULL\n");
1343 return DSERR_NOAGGREGATION;
1346 hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, (void**)&pDSC);
1348 hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1350 IDirectSoundCapture_Release(pDSC);
1360 /***************************************************************************
1361 * DirectSoundCaptureCreate8 [DSOUND.12]
1363 * Create and initialize a DirectSoundCapture interface.
1366 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1367 * lplpDSC [O] Address of a variable to receive the interface pointer.
1368 * pUnkOuter [I] Must be NULL.
1372 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1376 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1377 * or NULL for the default device or DSDEVID_DefaultCapture or
1378 * DSDEVID_DefaultVoiceCapture.
1380 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1382 HRESULT WINAPI DirectSoundCaptureCreate8(
1384 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1385 LPUNKNOWN pUnkOuter)
1388 LPDIRECTSOUNDCAPTURE8 pDSC8;
1389 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1391 if (ppDSC8 == NULL) {
1392 WARN("invalid parameter: ppDSC8 == NULL\n");
1393 return DSERR_INVALIDPARAM;
1397 WARN("invalid parameter: pUnkOuter != NULL\n");
1399 return DSERR_NOAGGREGATION;
1402 hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, (void**)&pDSC8);
1404 hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1406 IDirectSoundCapture_Release(pDSC8);