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 );
708 if(err == AUDCLNT_E_UNSUPPORTED_FORMAT)
709 return DSERR_BADFORMAT;
713 err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
714 (void**)&device->capture);
716 WARN("GetService failed: %08x\n", err);
717 IAudioClient_Release(device->client);
718 device->client = NULL;
719 HeapFree(GetProcessHeap(), 0, This->pdscbd);
720 This->device->capture_buffer = 0;
721 HeapFree( GetProcessHeap(), 0, This );
725 buflen = lpcDSCBufferDesc->dwBufferBytes;
726 TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
728 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
730 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
731 if (newbuf == NULL) {
732 IAudioClient_Release(device->client);
733 device->client = NULL;
734 IAudioCaptureClient_Release(device->capture);
735 device->capture = NULL;
736 HeapFree(GetProcessHeap(), 0, This->pdscbd);
737 This->device->capture_buffer = 0;
738 HeapFree( GetProcessHeap(), 0, This );
739 return DSERR_OUTOFMEMORY;
741 device->buffer = newbuf;
742 device->buflen = buflen;
745 IDirectSoundCaptureBuffer_AddRef(&This->IDirectSoundCaptureBuffer8_iface);
748 TRACE("returning DS_OK\n");
753 /*******************************************************************************
754 * DirectSoundCaptureDevice
756 static HRESULT DirectSoundCaptureDevice_Create(
757 DirectSoundCaptureDevice ** ppDevice)
759 DirectSoundCaptureDevice * device;
760 TRACE("(%p)\n", ppDevice);
762 /* Allocate memory */
763 device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
765 if (device == NULL) {
766 WARN("out of memory\n");
767 return DSERR_OUTOFMEMORY;
771 device->state = STATE_STOPPED;
773 InitializeCriticalSection( &(device->lock) );
774 device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
781 static ULONG DirectSoundCaptureDevice_Release(
782 DirectSoundCaptureDevice * device)
784 ULONG ref = InterlockedDecrement(&(device->ref));
785 TRACE("(%p) ref was %d\n", device, ref + 1);
788 TRACE("deleting object\n");
790 timeKillEvent(device->timerID);
791 timeEndPeriod(DS_TIME_RES);
793 EnterCriticalSection(&DSOUND_capturers_lock);
794 list_remove(&device->entry);
795 LeaveCriticalSection(&DSOUND_capturers_lock);
797 if (device->capture_buffer)
798 IDirectSoundCaptureBufferImpl_Release(&device->capture_buffer->IDirectSoundCaptureBuffer8_iface);
801 IMMDevice_Release(device->mmdevice);
802 HeapFree(GetProcessHeap(), 0, device->pwfx);
803 device->lock.DebugInfo->Spare[0] = 0;
804 DeleteCriticalSection( &(device->lock) );
805 HeapFree(GetProcessHeap(), 0, device);
806 TRACE("(%p) released\n", device);
811 static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user,
812 DWORD_PTR dw1, DWORD_PTR dw2)
814 DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user;
815 UINT32 packet_frames, packet_bytes, avail_bytes;
823 EnterCriticalSection(&device->lock);
825 if(!device->capture_buffer || device->state == STATE_STOPPED){
826 LeaveCriticalSection(&device->lock);
830 if(device->state == STATE_STOPPING){
831 device->state = STATE_STOPPED;
832 LeaveCriticalSection(&device->lock);
836 if(device->state == STATE_STARTING)
837 device->state = STATE_CAPTURING;
839 hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
842 LeaveCriticalSection(&device->lock);
843 WARN("GetBuffer failed: %08x\n", hr);
847 packet_bytes = packet_frames * device->pwfx->nBlockAlign;
849 avail_bytes = device->buflen - device->write_pos_bytes;
850 if(avail_bytes > packet_bytes)
851 avail_bytes = packet_bytes;
853 memcpy(device->buffer + device->write_pos_bytes, buf, avail_bytes);
854 capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
856 packet_bytes -= avail_bytes;
857 if(packet_bytes > 0){
858 if(device->capture_buffer->flags & DSCBSTART_LOOPING){
859 memcpy(device->buffer, buf + avail_bytes, packet_bytes);
860 capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
862 device->state = STATE_STOPPED;
863 capture_CheckNotify(device->capture_buffer, 0, 0);
867 device->write_pos_bytes += avail_bytes + packet_bytes;
868 device->write_pos_bytes %= device->buflen;
870 hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
872 LeaveCriticalSection(&device->lock);
873 WARN("ReleaseBuffer failed: %08x\n", hr);
877 LeaveCriticalSection(&device->lock);
880 static struct _TestFormat {
885 } formats_to_test[] = {
886 { WAVE_FORMAT_1M08, 11025, 8, 1 },
887 { WAVE_FORMAT_1M16, 11025, 16, 1 },
888 { WAVE_FORMAT_1S08, 11025, 8, 2 },
889 { WAVE_FORMAT_1S16, 11025, 16, 2 },
890 { WAVE_FORMAT_2M08, 22050, 8, 1 },
891 { WAVE_FORMAT_2M16, 22050, 16, 1 },
892 { WAVE_FORMAT_2S08, 22050, 8, 2 },
893 { WAVE_FORMAT_2S16, 22050, 16, 2 },
894 { WAVE_FORMAT_4M08, 44100, 8, 1 },
895 { WAVE_FORMAT_4M16, 44100, 16, 1 },
896 { WAVE_FORMAT_4S08, 44100, 8, 2 },
897 { WAVE_FORMAT_4S16, 44100, 16, 2 },
898 { WAVE_FORMAT_48M08, 48000, 8, 1 },
899 { WAVE_FORMAT_48M16, 48000, 16, 1 },
900 { WAVE_FORMAT_48S08, 48000, 8, 2 },
901 { WAVE_FORMAT_48S16, 48000, 16, 2 },
902 { WAVE_FORMAT_96M08, 96000, 8, 1 },
903 { WAVE_FORMAT_96M16, 96000, 16, 1 },
904 { WAVE_FORMAT_96S08, 96000, 8, 2 },
905 { WAVE_FORMAT_96S16, 96000, 16, 2 },
909 static HRESULT DirectSoundCaptureDevice_Initialize(
910 DirectSoundCaptureDevice ** ppDevice,
916 struct _TestFormat *fmt;
917 DirectSoundCaptureDevice *device;
918 IAudioClient *client;
920 TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
922 /* Default device? */
923 if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
924 lpcGUID = &DSDEVID_DefaultCapture;
926 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
927 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
928 return DSERR_NODRIVER;
930 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
931 WARN("invalid parameter: lpcGUID\n");
932 return DSERR_INVALIDPARAM;
935 hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
939 EnterCriticalSection(&DSOUND_capturers_lock);
941 LIST_FOR_EACH_ENTRY(device, &DSOUND_capturers, DirectSoundCaptureDevice, entry){
942 if(IsEqualGUID(&device->guid, &devGUID)){
943 IMMDevice_Release(mmdevice);
944 LeaveCriticalSection(&DSOUND_capturers_lock);
945 return DSERR_ALLOCATED;
949 hr = DirectSoundCaptureDevice_Create(&device);
951 WARN("DirectSoundCaptureDevice_Create failed\n");
952 LeaveCriticalSection(&DSOUND_capturers_lock);
956 device->guid = devGUID;
958 device->mmdevice = mmdevice;
960 device->drvcaps.dwFlags = 0;
962 device->drvcaps.dwFormats = 0;
963 device->drvcaps.dwChannels = 0;
964 hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
965 CLSCTX_INPROC_SERVER, NULL, (void**)&client);
967 device->lock.DebugInfo->Spare[0] = 0;
968 DeleteCriticalSection(&device->lock);
969 HeapFree(GetProcessHeap(), 0, device);
970 LeaveCriticalSection(&DSOUND_capturers_lock);
971 return DSERR_NODRIVER;
974 for(fmt = formats_to_test; fmt->flag; ++fmt){
975 if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
976 device->drvcaps.dwFormats |= fmt->flag;
977 if(fmt->channels > device->drvcaps.dwChannels)
978 device->drvcaps.dwChannels = fmt->channels;
981 IAudioClient_Release(client);
983 device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
985 list_add_tail(&DSOUND_capturers, &device->entry);
989 LeaveCriticalSection(&DSOUND_capturers_lock);
995 /*****************************************************************************
996 * IDirectSoundCapture implementation structure
998 struct IDirectSoundCaptureImpl
1000 IDirectSoundCapture IDirectSoundCapture_iface;
1002 DirectSoundCaptureDevice *device;
1005 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1007 return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1010 /***************************************************************************
1011 * IDirectSoundCaptureImpl
1013 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1014 REFIID riid, void **ppobj)
1016 TRACE( "(%p,%s,%p)\n", iface, debugstr_guid(riid), ppobj );
1018 if (ppobj == NULL) {
1019 WARN("invalid parameter\n");
1020 return E_INVALIDARG;
1025 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1026 IDirectSoundCapture_AddRef(iface);
1031 WARN("unsupported riid: %s\n", debugstr_guid(riid));
1032 return E_NOINTERFACE;
1035 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1037 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1038 ULONG ref = InterlockedIncrement(&(This->ref));
1040 TRACE("(%p) ref was %d\n", This, ref - 1);
1044 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1046 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1047 ULONG ref = InterlockedDecrement(&(This->ref));
1049 TRACE("(%p) ref was %d\n", This, ref + 1);
1053 DirectSoundCaptureDevice_Release(This->device);
1055 HeapFree( GetProcessHeap(), 0, This );
1056 TRACE("(%p) released\n", This);
1061 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1062 LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1065 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1068 TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1071 WARN("invalid parameter: pUnk != NULL\n");
1072 return DSERR_NOAGGREGATION;
1075 if (lpcDSCBufferDesc == NULL) {
1076 WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1077 return DSERR_INVALIDPARAM;
1080 if (lplpDSCaptureBuffer == NULL) {
1081 WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1082 return DSERR_INVALIDPARAM;
1086 WARN("invalid parameter: pUnk != NULL\n");
1087 return DSERR_INVALIDPARAM;
1090 /* FIXME: We can only have one buffer so what do we do here? */
1091 if (This->device->capture_buffer) {
1092 WARN("invalid parameter: already has buffer\n");
1093 return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */
1096 hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1097 (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1100 WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1105 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1106 LPDSCCAPS lpDSCCaps)
1108 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1110 TRACE("(%p,%p)\n",This,lpDSCCaps);
1112 if (This->device == NULL) {
1113 WARN("not initialized\n");
1114 return DSERR_UNINITIALIZED;
1117 if (lpDSCCaps== NULL) {
1118 WARN("invalid parameter: lpDSCCaps== NULL\n");
1119 return DSERR_INVALIDPARAM;
1122 if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1123 WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1124 return DSERR_INVALIDPARAM;
1127 lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1128 lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1129 lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1131 TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1132 lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1137 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1140 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1142 TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1144 if (This->device != NULL) {
1145 WARN("already initialized\n");
1146 return DSERR_ALREADYINITIALIZED;
1148 return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1151 static const IDirectSoundCaptureVtbl dscvt =
1153 /* IUnknown methods */
1154 IDirectSoundCaptureImpl_QueryInterface,
1155 IDirectSoundCaptureImpl_AddRef,
1156 IDirectSoundCaptureImpl_Release,
1158 /* IDirectSoundCapture methods */
1159 IDirectSoundCaptureImpl_CreateCaptureBuffer,
1160 IDirectSoundCaptureImpl_GetCaps,
1161 IDirectSoundCaptureImpl_Initialize
1164 static HRESULT IDirectSoundCaptureImpl_Create(
1165 LPDIRECTSOUNDCAPTURE8 * ppDSC)
1167 IDirectSoundCaptureImpl *pDSC;
1168 TRACE("(%p)\n", ppDSC);
1170 /* Allocate memory */
1171 pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
1173 WARN("out of memory\n");
1175 return DSERR_OUTOFMEMORY;
1178 pDSC->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1180 pDSC->device = NULL;
1182 *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
1187 HRESULT DSOUND_CaptureCreate(REFIID riid, IDirectSoundCapture **ppDSC)
1189 IDirectSoundCapture *pDSC;
1191 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC);
1193 if (!IsEqualIID(riid, &IID_IUnknown) &&
1194 !IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1196 return E_NOINTERFACE;
1199 /* Get dsound configuration */
1200 setup_dsound_options();
1202 hr = IDirectSoundCaptureImpl_Create(&pDSC);
1204 IDirectSoundCapture_AddRef(pDSC);
1207 WARN("IDirectSoundCaptureImpl_Create failed\n");
1214 HRESULT DSOUND_CaptureCreate8(
1216 LPDIRECTSOUNDCAPTURE8 *ppDSC8)
1218 LPDIRECTSOUNDCAPTURE8 pDSC8;
1220 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC8);
1222 if (!IsEqualIID(riid, &IID_IUnknown) &&
1223 !IsEqualIID(riid, &IID_IDirectSoundCapture8)) {
1225 return E_NOINTERFACE;
1228 /* Get dsound configuration */
1229 setup_dsound_options();
1231 hr = IDirectSoundCaptureImpl_Create(&pDSC8);
1233 IDirectSoundCapture_AddRef(pDSC8);
1236 WARN("IDirectSoundCaptureImpl_Create failed\n");
1243 /***************************************************************************
1244 * DirectSoundCaptureCreate [DSOUND.6]
1246 * Create and initialize a DirectSoundCapture interface.
1249 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1250 * lplpDSC [O] Address of a variable to receive the interface pointer.
1251 * pUnkOuter [I] Must be NULL.
1255 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1259 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1260 * or NULL for the default device or DSDEVID_DefaultCapture or
1261 * DSDEVID_DefaultVoiceCapture.
1263 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1265 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1266 IUnknown *pUnkOuter)
1269 IDirectSoundCapture *pDSC;
1271 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1273 if (ppDSC == NULL) {
1274 WARN("invalid parameter: ppDSC == NULL\n");
1275 return DSERR_INVALIDPARAM;
1279 WARN("invalid parameter: pUnkOuter != NULL\n");
1280 return DSERR_NOAGGREGATION;
1283 hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, &pDSC);
1285 hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1287 IDirectSoundCapture_Release(pDSC);
1297 /***************************************************************************
1298 * DirectSoundCaptureCreate8 [DSOUND.12]
1300 * Create and initialize a DirectSoundCapture interface.
1303 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1304 * lplpDSC [O] Address of a variable to receive the interface pointer.
1305 * pUnkOuter [I] Must be NULL.
1309 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1313 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1314 * or NULL for the default device or DSDEVID_DefaultCapture or
1315 * DSDEVID_DefaultVoiceCapture.
1317 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1319 HRESULT WINAPI DirectSoundCaptureCreate8(
1321 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1322 LPUNKNOWN pUnkOuter)
1325 LPDIRECTSOUNDCAPTURE8 pDSC8;
1326 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1328 if (ppDSC8 == NULL) {
1329 WARN("invalid parameter: ppDSC8 == NULL\n");
1330 return DSERR_INVALIDPARAM;
1334 WARN("invalid parameter: pUnkOuter != NULL\n");
1336 return DSERR_NOAGGREGATION;
1339 hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, &pDSC8);
1341 hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1343 IDirectSoundCapture_Release(pDSC8);