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);
47 static void capturebuffer_destroy(IDirectSoundCaptureBufferImpl *This)
49 if (This->device->state == STATE_CAPTURING)
50 This->device->state = STATE_STOPPING;
52 HeapFree(GetProcessHeap(),0, This->pdscbd);
54 if (This->device->client) {
55 IAudioClient_Release(This->device->client);
56 This->device->client = NULL;
59 if (This->device->capture) {
60 IAudioCaptureClient_Release(This->device->capture);
61 This->device->capture = NULL;
64 /* remove from DirectSoundCaptureDevice */
65 This->device->capture_buffer = NULL;
67 HeapFree(GetProcessHeap(), 0, This->notifies);
68 HeapFree(GetProcessHeap(), 0, This);
69 TRACE("(%p) released\n", This);
72 /*******************************************************************************
75 static inline struct IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
77 return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundNotify_iface);
80 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(IDirectSoundNotify *iface, REFIID riid,
83 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
85 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj);
87 return IDirectSoundCaptureBuffer_QueryInterface(&This->IDirectSoundCaptureBuffer8_iface, riid, ppobj);
90 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(IDirectSoundNotify *iface)
92 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
93 ULONG ref = InterlockedIncrement(&This->refn);
95 TRACE("(%p) ref was %d\n", This, ref - 1);
98 InterlockedIncrement(&This->numIfaces);
103 static ULONG WINAPI IDirectSoundNotifyImpl_Release(IDirectSoundNotify *iface)
105 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
106 ULONG ref = InterlockedDecrement(&This->refn);
108 TRACE("(%p) ref was %d\n", This, ref + 1);
110 if (!ref && !InterlockedDecrement(&This->numIfaces))
111 capturebuffer_destroy(This);
116 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSoundNotify *iface,
117 DWORD howmuch, const DSBPOSITIONNOTIFY *notify)
119 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
120 TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
122 if (howmuch > 0 && notify == NULL) {
123 WARN("invalid parameter: notify == NULL\n");
124 return DSERR_INVALIDPARAM;
127 if (TRACE_ON(dsound)) {
129 for (i=0;i<howmuch;i++)
130 TRACE("notify at %d to %p\n",
131 notify[i].dwOffset,notify[i].hEventNotify);
135 /* Make an internal copy of the caller-supplied array.
136 * Replace the existing copy if one is already present. */
138 This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->notifies,
139 howmuch * sizeof(DSBPOSITIONNOTIFY));
141 This->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
142 howmuch * sizeof(DSBPOSITIONNOTIFY));
144 if (!This->notifies) {
145 WARN("out of memory\n");
146 return DSERR_OUTOFMEMORY;
148 CopyMemory(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
149 This->nrofnotifies = howmuch;
151 HeapFree(GetProcessHeap(), 0, This->notifies);
152 This->notifies = NULL;
153 This->nrofnotifies = 0;
159 static const IDirectSoundNotifyVtbl dscnvt =
161 IDirectSoundNotifyImpl_QueryInterface,
162 IDirectSoundNotifyImpl_AddRef,
163 IDirectSoundNotifyImpl_Release,
164 IDirectSoundNotifyImpl_SetNotificationPositions
168 static const char * const captureStateString[] = {
176 /*******************************************************************************
177 * IDirectSoundCaptureBuffer
179 static inline IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8 *iface)
181 return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundCaptureBuffer8_iface);
184 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_QueryInterface(IDirectSoundCaptureBuffer8 *iface,
185 REFIID riid, void **ppobj)
187 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
189 TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
192 WARN("invalid parameter\n");
198 if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
199 IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
200 IDirectSoundCaptureBuffer8_AddRef(iface);
205 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
206 IDirectSoundNotify_AddRef(&This->IDirectSoundNotify_iface);
207 *ppobj = &This->IDirectSoundNotify_iface;
211 FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
212 return E_NOINTERFACE;
215 static ULONG WINAPI IDirectSoundCaptureBufferImpl_AddRef(IDirectSoundCaptureBuffer8 *iface)
217 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
218 ULONG ref = InterlockedIncrement(&This->ref);
220 TRACE("(%p) ref was %d\n", This, ref - 1);
223 InterlockedIncrement(&This->numIfaces);
228 static ULONG WINAPI IDirectSoundCaptureBufferImpl_Release(IDirectSoundCaptureBuffer8 *iface)
230 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
231 ULONG ref = InterlockedDecrement(&This->ref);
233 TRACE("(%p) ref was %d\n", This, ref + 1);
235 if (!ref && !InterlockedDecrement(&This->numIfaces))
236 capturebuffer_destroy(This);
241 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCaps(IDirectSoundCaptureBuffer8 *iface,
242 DSCBCAPS *lpDSCBCaps)
244 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
245 TRACE( "(%p,%p)\n", This, lpDSCBCaps );
247 if (lpDSCBCaps == NULL) {
248 WARN("invalid parameter: lpDSCBCaps == NULL\n");
249 return DSERR_INVALIDPARAM;
252 if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
253 WARN("invalid parameter: lpDSCBCaps->dwSize = %d\n", lpDSCBCaps->dwSize);
254 return DSERR_INVALIDPARAM;
257 if (This->device == NULL) {
258 WARN("invalid parameter: This->device == NULL\n");
259 return DSERR_INVALIDPARAM;
262 lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
263 lpDSCBCaps->dwFlags = This->flags;
264 lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
265 lpDSCBCaps->dwReserved = 0;
267 TRACE("returning DS_OK\n");
271 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCurrentPosition(IDirectSoundCaptureBuffer8 *iface,
272 DWORD *lpdwCapturePosition, DWORD *lpdwReadPosition)
274 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
276 TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
278 if (This->device == NULL) {
279 WARN("invalid parameter: This->device == NULL\n");
280 return DSERR_INVALIDPARAM;
283 EnterCriticalSection(&This->device->lock);
285 if (!This->device->client) {
286 LeaveCriticalSection(&This->device->lock);
288 return DSERR_NODRIVER;
291 if(lpdwCapturePosition)
292 *lpdwCapturePosition = This->device->write_pos_bytes;
295 *lpdwReadPosition = This->device->write_pos_bytes;
297 LeaveCriticalSection(&This->device->lock);
299 TRACE("cappos=%d readpos=%d\n", (lpdwCapturePosition?*lpdwCapturePosition:-1), (lpdwReadPosition?*lpdwReadPosition:-1));
300 TRACE("returning DS_OK\n");
305 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFormat(IDirectSoundCaptureBuffer8 *iface,
306 WAVEFORMATEX *lpwfxFormat, DWORD dwSizeAllocated, DWORD *lpdwSizeWritten)
308 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
309 HRESULT hres = DS_OK;
311 TRACE("(%p,%p,0x%08x,%p)\n", This, lpwfxFormat, dwSizeAllocated, lpdwSizeWritten);
313 if (This->device == NULL) {
314 WARN("invalid parameter: This->device == NULL\n");
315 return DSERR_INVALIDPARAM;
318 if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize))
319 dwSizeAllocated = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
321 if (lpwfxFormat) { /* NULL is valid (just want size) */
322 CopyMemory(lpwfxFormat, This->device->pwfx, dwSizeAllocated);
324 *lpdwSizeWritten = dwSizeAllocated;
327 *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
329 TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
330 hres = DSERR_INVALIDPARAM;
334 TRACE("returning %08x\n", hres);
338 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetStatus(IDirectSoundCaptureBuffer8 *iface,
341 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
343 TRACE( "(%p, %p), thread is %04x\n", This, lpdwStatus, GetCurrentThreadId() );
345 if (This->device == NULL) {
346 WARN("invalid parameter: This->device == NULL\n");
347 return DSERR_INVALIDPARAM;
350 if (lpdwStatus == NULL) {
351 WARN("invalid parameter: lpdwStatus == NULL\n");
352 return DSERR_INVALIDPARAM;
356 EnterCriticalSection(&(This->device->lock));
358 TRACE("old This->device->state=%s, old lpdwStatus=%08x\n",
359 captureStateString[This->device->state],*lpdwStatus);
360 if ((This->device->state == STATE_STARTING) ||
361 (This->device->state == STATE_CAPTURING)) {
362 *lpdwStatus |= DSCBSTATUS_CAPTURING;
363 if (This->flags & DSCBSTART_LOOPING)
364 *lpdwStatus |= DSCBSTATUS_LOOPING;
366 TRACE("new This->device->state=%s, new lpdwStatus=%08x\n",
367 captureStateString[This->device->state],*lpdwStatus);
368 LeaveCriticalSection(&(This->device->lock));
370 TRACE("status=%x\n", *lpdwStatus);
371 TRACE("returning DS_OK\n");
375 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Initialize(IDirectSoundCaptureBuffer8 *iface,
376 IDirectSoundCapture *lpDSC, const DSCBUFFERDESC *lpcDSCBDesc)
378 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
380 FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
385 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Lock(IDirectSoundCaptureBuffer8 *iface,
386 DWORD dwReadCusor, DWORD dwReadBytes, void **lplpvAudioPtr1, DWORD *lpdwAudioBytes1,
387 void **lplpvAudioPtr2, DWORD *lpdwAudioBytes2, DWORD dwFlags)
389 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
390 HRESULT hres = DS_OK;
392 TRACE( "(%p,%08u,%08u,%p,%p,%p,%p,0x%08x) at %d\n", This, dwReadCusor,
393 dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
394 lpdwAudioBytes2, dwFlags, GetTickCount() );
396 if (This->device == NULL) {
397 WARN("invalid parameter: This->device == NULL\n");
398 return DSERR_INVALIDPARAM;
401 if (lplpvAudioPtr1 == NULL) {
402 WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
403 return DSERR_INVALIDPARAM;
406 if (lpdwAudioBytes1 == NULL) {
407 WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
408 return DSERR_INVALIDPARAM;
411 EnterCriticalSection(&(This->device->lock));
413 if (This->device->client) {
414 *lplpvAudioPtr1 = This->device->buffer + dwReadCusor;
415 if ( (dwReadCusor + dwReadBytes) > This->device->buflen) {
416 *lpdwAudioBytes1 = This->device->buflen - dwReadCusor;
418 *lplpvAudioPtr2 = This->device->buffer;
420 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
422 *lpdwAudioBytes1 = dwReadBytes;
426 *lpdwAudioBytes2 = 0;
429 TRACE("invalid call\n");
430 hres = DSERR_INVALIDCALL; /* DSERR_NODRIVER ? */
433 LeaveCriticalSection(&(This->device->lock));
435 TRACE("returning %08x\n", hres);
439 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Start(IDirectSoundCaptureBuffer8 *iface,
442 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
445 TRACE( "(%p,0x%08x)\n", This, dwFlags );
447 if (This->device == NULL) {
448 WARN("invalid parameter: This->device == NULL\n");
449 return DSERR_INVALIDPARAM;
452 if ( !This->device->client ) {
454 return DSERR_NODRIVER;
457 EnterCriticalSection(&(This->device->lock));
459 This->flags = dwFlags;
460 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
461 if (This->device->state == STATE_STOPPED)
462 This->device->state = STATE_STARTING;
463 else if (This->device->state == STATE_STOPPING)
464 This->device->state = STATE_CAPTURING;
465 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
467 if (This->device->buffer)
468 FillMemory(This->device->buffer, This->device->buflen, (This->device->pwfx->wBitsPerSample == 8) ? 128 : 0);
470 hres = IAudioClient_Start(This->device->client);
472 WARN("Start failed: %08x\n", hres);
473 LeaveCriticalSection(&This->device->lock);
477 LeaveCriticalSection(&This->device->lock);
479 TRACE("returning DS_OK\n");
483 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Stop(IDirectSoundCaptureBuffer8 *iface)
485 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
488 TRACE("(%p)\n", This);
490 if (This->device == NULL) {
491 WARN("invalid parameter: This->device == NULL\n");
492 return DSERR_INVALIDPARAM;
495 EnterCriticalSection(&(This->device->lock));
497 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
498 if (This->device->state == STATE_CAPTURING)
499 This->device->state = STATE_STOPPING;
500 else if (This->device->state == STATE_STARTING)
501 This->device->state = STATE_STOPPED;
502 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
504 if(This->device->client){
505 hres = IAudioClient_Stop(This->device->client);
507 LeaveCriticalSection(&This->device->lock);
512 LeaveCriticalSection(&(This->device->lock));
514 TRACE("returning DS_OK\n");
518 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Unlock(IDirectSoundCaptureBuffer8 *iface,
519 void *lpvAudioPtr1, DWORD dwAudioBytes1, void *lpvAudioPtr2, DWORD dwAudioBytes2)
521 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
522 HRESULT hres = DS_OK;
524 TRACE( "(%p,%p,%08u,%p,%08u)\n", This, lpvAudioPtr1, dwAudioBytes1,
525 lpvAudioPtr2, dwAudioBytes2 );
527 if (lpvAudioPtr1 == NULL) {
528 WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
529 return DSERR_INVALIDPARAM;
532 if (!This->device->client) {
533 WARN("invalid call\n");
534 hres = DSERR_INVALIDCALL;
537 TRACE("returning %08x\n", hres);
541 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface,
542 REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
544 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
546 FIXME( "(%p,%s,%u,%s,%p): stub\n", This, debugstr_guid(rguidObject),
547 dwIndex, debugstr_guid(rguidInterface), ppObject );
552 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFXStatus(IDirectSoundCaptureBuffer8 *iface,
553 DWORD dwFXCount, DWORD *pdwFXStatus)
555 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
557 FIXME( "(%p,%u,%p): stub\n", This, dwFXCount, pdwFXStatus );
562 static const IDirectSoundCaptureBuffer8Vtbl dscbvt =
564 /* IUnknown methods */
565 IDirectSoundCaptureBufferImpl_QueryInterface,
566 IDirectSoundCaptureBufferImpl_AddRef,
567 IDirectSoundCaptureBufferImpl_Release,
569 /* IDirectSoundCaptureBuffer methods */
570 IDirectSoundCaptureBufferImpl_GetCaps,
571 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
572 IDirectSoundCaptureBufferImpl_GetFormat,
573 IDirectSoundCaptureBufferImpl_GetStatus,
574 IDirectSoundCaptureBufferImpl_Initialize,
575 IDirectSoundCaptureBufferImpl_Lock,
576 IDirectSoundCaptureBufferImpl_Start,
577 IDirectSoundCaptureBufferImpl_Stop,
578 IDirectSoundCaptureBufferImpl_Unlock,
580 /* IDirectSoundCaptureBuffer methods */
581 IDirectSoundCaptureBufferImpl_GetObjectInPath,
582 IDirectSoundCaptureBufferImpl_GetFXStatus
585 static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len)
588 for (i = 0; i < This->nrofnotifies; ++i) {
589 LPDSBPOSITIONNOTIFY event = This->notifies + i;
590 DWORD offset = event->dwOffset;
591 TRACE("checking %d, position %d, event = %p\n", i, offset, event->hEventNotify);
593 if (offset == DSBPN_OFFSETSTOP) {
595 SetEvent(event->hEventNotify);
596 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
602 if (offset >= from && offset < (from + len))
604 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
605 SetEvent(event->hEventNotify);
610 static HRESULT IDirectSoundCaptureBufferImpl_Create(
611 DirectSoundCaptureDevice *device,
612 IDirectSoundCaptureBufferImpl ** ppobj,
613 LPCDSCBUFFERDESC lpcDSCBufferDesc)
616 IDirectSoundCaptureBufferImpl *This;
617 TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
620 WARN("invalid parameter: ppobj == NULL\n");
621 return DSERR_INVALIDPARAM;
627 WARN("not initialized\n");
628 return DSERR_UNINITIALIZED;
631 if (lpcDSCBufferDesc == NULL) {
632 WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
633 return DSERR_INVALIDPARAM;
636 if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
637 (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
638 (lpcDSCBufferDesc->dwBufferBytes == 0) ||
639 (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { /* FIXME: DSERR_BADFORMAT ? */
640 WARN("invalid lpcDSCBufferDesc\n");
641 return DSERR_INVALIDPARAM;
644 wfex = lpcDSCBufferDesc->lpwfxFormat;
646 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
647 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
648 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
649 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
650 wfex->wBitsPerSample, wfex->cbSize);
652 device->pwfx = DSOUND_CopyFormat(wfex);
653 if ( device->pwfx == NULL )
654 return DSERR_OUTOFMEMORY;
656 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
657 sizeof(IDirectSoundCaptureBufferImpl));
659 if ( This == NULL ) {
660 WARN("out of memory\n");
661 return DSERR_OUTOFMEMORY;
670 This->device = device;
671 This->device->capture_buffer = This;
672 This->nrofnotifies = 0;
674 This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
675 lpcDSCBufferDesc->dwSize);
677 CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
680 This->device->capture_buffer = 0;
681 HeapFree( GetProcessHeap(), 0, This );
682 return DSERR_OUTOFMEMORY;
685 This->IDirectSoundCaptureBuffer8_iface.lpVtbl = &dscbvt;
686 This->IDirectSoundNotify_iface.lpVtbl = &dscnvt;
688 err = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
689 CLSCTX_INPROC_SERVER, NULL, (void**)&device->client);
691 WARN("Activate failed: %08x\n", err);
692 HeapFree(GetProcessHeap(), 0, This->pdscbd);
693 This->device->capture_buffer = 0;
694 HeapFree( GetProcessHeap(), 0, This );
698 err = IAudioClient_Initialize(device->client,
699 AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
700 200 * 100000, 50000, device->pwfx, NULL);
702 WARN("Initialize failed: %08x\n", err);
703 IAudioClient_Release(device->client);
704 device->client = NULL;
705 HeapFree(GetProcessHeap(), 0, This->pdscbd);
706 This->device->capture_buffer = 0;
707 HeapFree( GetProcessHeap(), 0, This );
711 err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
712 (void**)&device->capture);
714 WARN("GetService failed: %08x\n", err);
715 IAudioClient_Release(device->client);
716 device->client = NULL;
717 HeapFree(GetProcessHeap(), 0, This->pdscbd);
718 This->device->capture_buffer = 0;
719 HeapFree( GetProcessHeap(), 0, This );
723 buflen = lpcDSCBufferDesc->dwBufferBytes;
724 TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
726 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
728 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
729 if (newbuf == NULL) {
730 IAudioClient_Release(device->client);
731 device->client = NULL;
732 IAudioCaptureClient_Release(device->capture);
733 device->capture = NULL;
734 HeapFree(GetProcessHeap(), 0, This->pdscbd);
735 This->device->capture_buffer = 0;
736 HeapFree( GetProcessHeap(), 0, This );
737 return DSERR_OUTOFMEMORY;
739 device->buffer = newbuf;
740 device->buflen = buflen;
743 IDirectSoundCaptureBuffer_AddRef(&This->IDirectSoundCaptureBuffer8_iface);
746 TRACE("returning DS_OK\n");
751 /*******************************************************************************
752 * DirectSoundCaptureDevice
754 static HRESULT DirectSoundCaptureDevice_Create(
755 DirectSoundCaptureDevice ** ppDevice)
757 DirectSoundCaptureDevice * device;
758 TRACE("(%p)\n", ppDevice);
760 /* Allocate memory */
761 device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
763 if (device == NULL) {
764 WARN("out of memory\n");
765 return DSERR_OUTOFMEMORY;
769 device->state = STATE_STOPPED;
771 InitializeCriticalSection( &(device->lock) );
772 device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
779 static ULONG DirectSoundCaptureDevice_Release(
780 DirectSoundCaptureDevice * device)
782 ULONG ref = InterlockedDecrement(&(device->ref));
783 TRACE("(%p) ref was %d\n", device, ref + 1);
786 TRACE("deleting object\n");
788 timeKillEvent(device->timerID);
789 timeEndPeriod(DS_TIME_RES);
791 EnterCriticalSection(&DSOUND_capturers_lock);
792 list_remove(&device->entry);
793 LeaveCriticalSection(&DSOUND_capturers_lock);
795 if (device->capture_buffer)
796 IDirectSoundCaptureBufferImpl_Release(&device->capture_buffer->IDirectSoundCaptureBuffer8_iface);
799 IMMDevice_Release(device->mmdevice);
800 HeapFree(GetProcessHeap(), 0, device->pwfx);
801 device->lock.DebugInfo->Spare[0] = 0;
802 DeleteCriticalSection( &(device->lock) );
803 HeapFree(GetProcessHeap(), 0, device);
804 TRACE("(%p) released\n", device);
809 static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user,
810 DWORD_PTR dw1, DWORD_PTR dw2)
812 DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user;
813 UINT32 packet_frames, packet_bytes, avail_bytes;
821 EnterCriticalSection(&device->lock);
823 if(!device->capture_buffer || device->state == STATE_STOPPED){
824 LeaveCriticalSection(&device->lock);
828 if(device->state == STATE_STOPPING){
829 device->state = STATE_STOPPED;
830 LeaveCriticalSection(&device->lock);
834 if(device->state == STATE_STARTING)
835 device->state = STATE_CAPTURING;
837 hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
840 LeaveCriticalSection(&device->lock);
841 WARN("GetBuffer failed: %08x\n", hr);
845 packet_bytes = packet_frames * device->pwfx->nBlockAlign;
847 avail_bytes = device->buflen - device->write_pos_bytes;
848 if(avail_bytes > packet_bytes)
849 avail_bytes = packet_bytes;
851 memcpy(device->buffer + device->write_pos_bytes, buf, avail_bytes);
852 capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
854 packet_bytes -= avail_bytes;
855 if(packet_bytes > 0){
856 if(device->capture_buffer->flags & DSCBSTART_LOOPING){
857 memcpy(device->buffer, buf + avail_bytes, packet_bytes);
858 capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
860 device->state = STATE_STOPPED;
861 capture_CheckNotify(device->capture_buffer, 0, 0);
865 device->write_pos_bytes += avail_bytes + packet_bytes;
866 device->write_pos_bytes %= device->buflen;
868 hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
870 LeaveCriticalSection(&device->lock);
871 WARN("ReleaseBuffer failed: %08x\n", hr);
875 LeaveCriticalSection(&device->lock);
878 static struct _TestFormat {
883 } formats_to_test[] = {
884 { WAVE_FORMAT_1M08, 11025, 8, 1 },
885 { WAVE_FORMAT_1M16, 11025, 16, 1 },
886 { WAVE_FORMAT_1S08, 11025, 8, 2 },
887 { WAVE_FORMAT_1S16, 11025, 16, 2 },
888 { WAVE_FORMAT_2M08, 22050, 8, 1 },
889 { WAVE_FORMAT_2M16, 22050, 16, 1 },
890 { WAVE_FORMAT_2S08, 22050, 8, 2 },
891 { WAVE_FORMAT_2S16, 22050, 16, 2 },
892 { WAVE_FORMAT_4M08, 44100, 8, 1 },
893 { WAVE_FORMAT_4M16, 44100, 16, 1 },
894 { WAVE_FORMAT_4S08, 44100, 8, 2 },
895 { WAVE_FORMAT_4S16, 44100, 16, 2 },
896 { WAVE_FORMAT_48M08, 48000, 8, 1 },
897 { WAVE_FORMAT_48M16, 48000, 16, 1 },
898 { WAVE_FORMAT_48S08, 48000, 8, 2 },
899 { WAVE_FORMAT_48S16, 48000, 16, 2 },
900 { WAVE_FORMAT_96M08, 96000, 8, 1 },
901 { WAVE_FORMAT_96M16, 96000, 16, 1 },
902 { WAVE_FORMAT_96S08, 96000, 8, 2 },
903 { WAVE_FORMAT_96S16, 96000, 16, 2 },
907 static HRESULT DirectSoundCaptureDevice_Initialize(
908 DirectSoundCaptureDevice ** ppDevice,
914 struct _TestFormat *fmt;
915 DirectSoundCaptureDevice *device;
916 IAudioClient *client;
918 TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
920 /* Default device? */
921 if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
922 lpcGUID = &DSDEVID_DefaultCapture;
924 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
925 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
926 return DSERR_NODRIVER;
928 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
929 WARN("invalid parameter: lpcGUID\n");
930 return DSERR_INVALIDPARAM;
933 hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
937 EnterCriticalSection(&DSOUND_capturers_lock);
939 LIST_FOR_EACH_ENTRY(device, &DSOUND_capturers, DirectSoundCaptureDevice, entry){
940 if(IsEqualGUID(&device->guid, &devGUID)){
941 IMMDevice_Release(mmdevice);
942 LeaveCriticalSection(&DSOUND_capturers_lock);
943 return DSERR_ALLOCATED;
947 hr = DirectSoundCaptureDevice_Create(&device);
949 WARN("DirectSoundCaptureDevice_Create failed\n");
950 LeaveCriticalSection(&DSOUND_capturers_lock);
954 device->guid = devGUID;
956 device->mmdevice = mmdevice;
958 device->drvcaps.dwFlags = 0;
960 device->drvcaps.dwFormats = 0;
961 device->drvcaps.dwChannels = 0;
962 hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
963 CLSCTX_INPROC_SERVER, NULL, (void**)&client);
965 device->lock.DebugInfo->Spare[0] = 0;
966 DeleteCriticalSection(&device->lock);
967 HeapFree(GetProcessHeap(), 0, device);
968 LeaveCriticalSection(&DSOUND_capturers_lock);
969 return DSERR_NODRIVER;
972 for(fmt = formats_to_test; fmt->flag; ++fmt){
973 if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
974 device->drvcaps.dwFormats |= fmt->flag;
975 if(fmt->channels > device->drvcaps.dwChannels)
976 device->drvcaps.dwChannels = fmt->channels;
979 IAudioClient_Release(client);
981 device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
983 list_add_tail(&DSOUND_capturers, &device->entry);
987 LeaveCriticalSection(&DSOUND_capturers_lock);
993 /*****************************************************************************
994 * IDirectSoundCapture implementation structure
996 struct IDirectSoundCaptureImpl
998 IDirectSoundCapture IDirectSoundCapture_iface;
1000 DirectSoundCaptureDevice *device;
1003 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1005 return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1008 /***************************************************************************
1009 * IDirectSoundCaptureImpl
1011 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1012 REFIID riid, void **ppobj)
1014 TRACE( "(%p,%s,%p)\n", iface, debugstr_guid(riid), ppobj );
1016 if (ppobj == NULL) {
1017 WARN("invalid parameter\n");
1018 return E_INVALIDARG;
1023 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1024 IDirectSoundCapture_AddRef(iface);
1029 WARN("unsupported riid: %s\n", debugstr_guid(riid));
1030 return E_NOINTERFACE;
1033 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1035 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1036 ULONG ref = InterlockedIncrement(&(This->ref));
1038 TRACE("(%p) ref was %d\n", This, ref - 1);
1042 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1044 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1045 ULONG ref = InterlockedDecrement(&(This->ref));
1047 TRACE("(%p) ref was %d\n", This, ref + 1);
1051 DirectSoundCaptureDevice_Release(This->device);
1053 HeapFree( GetProcessHeap(), 0, This );
1054 TRACE("(%p) released\n", This);
1059 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1060 LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1063 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1066 TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1069 WARN("invalid parameter: pUnk != NULL\n");
1070 return DSERR_NOAGGREGATION;
1073 if (lpcDSCBufferDesc == NULL) {
1074 WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1075 return DSERR_INVALIDPARAM;
1078 if (lplpDSCaptureBuffer == NULL) {
1079 WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1080 return DSERR_INVALIDPARAM;
1084 WARN("invalid parameter: pUnk != NULL\n");
1085 return DSERR_INVALIDPARAM;
1088 /* FIXME: We can only have one buffer so what do we do here? */
1089 if (This->device->capture_buffer) {
1090 WARN("invalid parameter: already has buffer\n");
1091 return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */
1094 hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1095 (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1098 WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1103 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1104 LPDSCCAPS lpDSCCaps)
1106 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1108 TRACE("(%p,%p)\n",This,lpDSCCaps);
1110 if (This->device == NULL) {
1111 WARN("not initialized\n");
1112 return DSERR_UNINITIALIZED;
1115 if (lpDSCCaps== NULL) {
1116 WARN("invalid parameter: lpDSCCaps== NULL\n");
1117 return DSERR_INVALIDPARAM;
1120 if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1121 WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1122 return DSERR_INVALIDPARAM;
1125 lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1126 lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1127 lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1129 TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1130 lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1135 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1138 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1140 TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1142 if (This->device != NULL) {
1143 WARN("already initialized\n");
1144 return DSERR_ALREADYINITIALIZED;
1146 return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1149 static const IDirectSoundCaptureVtbl dscvt =
1151 /* IUnknown methods */
1152 IDirectSoundCaptureImpl_QueryInterface,
1153 IDirectSoundCaptureImpl_AddRef,
1154 IDirectSoundCaptureImpl_Release,
1156 /* IDirectSoundCapture methods */
1157 IDirectSoundCaptureImpl_CreateCaptureBuffer,
1158 IDirectSoundCaptureImpl_GetCaps,
1159 IDirectSoundCaptureImpl_Initialize
1162 static HRESULT IDirectSoundCaptureImpl_Create(
1163 LPDIRECTSOUNDCAPTURE8 * ppDSC)
1165 IDirectSoundCaptureImpl *pDSC;
1166 TRACE("(%p)\n", ppDSC);
1168 /* Allocate memory */
1169 pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
1171 WARN("out of memory\n");
1173 return DSERR_OUTOFMEMORY;
1176 pDSC->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1178 pDSC->device = NULL;
1180 *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
1185 HRESULT DSOUND_CaptureCreate(REFIID riid, IDirectSoundCapture **ppDSC)
1187 IDirectSoundCapture *pDSC;
1189 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC);
1191 if (!IsEqualIID(riid, &IID_IUnknown) &&
1192 !IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1194 return E_NOINTERFACE;
1197 /* Get dsound configuration */
1198 setup_dsound_options();
1200 hr = IDirectSoundCaptureImpl_Create(&pDSC);
1202 IDirectSoundCapture_AddRef(pDSC);
1205 WARN("IDirectSoundCaptureImpl_Create failed\n");
1212 HRESULT DSOUND_CaptureCreate8(
1214 LPDIRECTSOUNDCAPTURE8 *ppDSC8)
1216 LPDIRECTSOUNDCAPTURE8 pDSC8;
1218 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC8);
1220 if (!IsEqualIID(riid, &IID_IUnknown) &&
1221 !IsEqualIID(riid, &IID_IDirectSoundCapture8)) {
1223 return E_NOINTERFACE;
1226 /* Get dsound configuration */
1227 setup_dsound_options();
1229 hr = IDirectSoundCaptureImpl_Create(&pDSC8);
1231 IDirectSoundCapture_AddRef(pDSC8);
1234 WARN("IDirectSoundCaptureImpl_Create failed\n");
1241 /***************************************************************************
1242 * DirectSoundCaptureCreate [DSOUND.6]
1244 * Create and initialize a DirectSoundCapture interface.
1247 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1248 * lplpDSC [O] Address of a variable to receive the interface pointer.
1249 * pUnkOuter [I] Must be NULL.
1253 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1257 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1258 * or NULL for the default device or DSDEVID_DefaultCapture or
1259 * DSDEVID_DefaultVoiceCapture.
1261 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1263 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1264 IUnknown *pUnkOuter)
1267 IDirectSoundCapture *pDSC;
1269 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1271 if (ppDSC == NULL) {
1272 WARN("invalid parameter: ppDSC == NULL\n");
1273 return DSERR_INVALIDPARAM;
1277 WARN("invalid parameter: pUnkOuter != NULL\n");
1278 return DSERR_NOAGGREGATION;
1281 hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, &pDSC);
1283 hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1285 IDirectSoundCapture_Release(pDSC);
1295 /***************************************************************************
1296 * DirectSoundCaptureCreate8 [DSOUND.12]
1298 * Create and initialize a DirectSoundCapture interface.
1301 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1302 * lplpDSC [O] Address of a variable to receive the interface pointer.
1303 * pUnkOuter [I] Must be NULL.
1307 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1311 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1312 * or NULL for the default device or DSDEVID_DefaultCapture or
1313 * DSDEVID_DefaultVoiceCapture.
1315 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1317 HRESULT WINAPI DirectSoundCaptureCreate8(
1319 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1320 LPUNKNOWN pUnkOuter)
1323 LPDIRECTSOUNDCAPTURE8 pDSC8;
1324 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1326 if (ppDSC8 == NULL) {
1327 WARN("invalid parameter: ppDSC8 == NULL\n");
1328 return DSERR_INVALIDPARAM;
1332 WARN("invalid parameter: pUnkOuter != NULL\n");
1334 return DSERR_NOAGGREGATION;
1337 hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, &pDSC8);
1339 hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1341 IDirectSoundCapture_Release(pDSC8);