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 /*****************************************************************************
48 * IDirectSoundCaptureNotify implementation structure
50 struct IDirectSoundCaptureNotifyImpl
53 const IDirectSoundNotifyVtbl *lpVtbl;
55 IDirectSoundCaptureBufferImpl* dscb;
58 /*******************************************************************************
61 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(IDirectSoundNotify *iface, REFIID riid,
64 IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
65 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
67 if (This->dscb == NULL) {
68 WARN("invalid parameter\n");
72 return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
75 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(IDirectSoundNotify *iface)
77 IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
78 ULONG ref = InterlockedIncrement(&(This->ref));
79 TRACE("(%p) ref was %d\n", This, ref - 1);
83 static ULONG WINAPI IDirectSoundNotifyImpl_Release(IDirectSoundNotify *iface)
85 IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
86 ULONG ref = InterlockedDecrement(&(This->ref));
87 TRACE("(%p) ref was %d\n", This, ref + 1);
90 This->dscb->notify=NULL;
91 IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb);
92 HeapFree(GetProcessHeap(),0,This);
93 TRACE("(%p) released\n", This);
98 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSoundNotify *iface,
99 DWORD howmuch, const DSBPOSITIONNOTIFY *notify)
101 IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
102 TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
104 if (howmuch > 0 && notify == NULL) {
105 WARN("invalid parameter: notify == NULL\n");
106 return DSERR_INVALIDPARAM;
109 if (TRACE_ON(dsound)) {
111 for (i=0;i<howmuch;i++)
112 TRACE("notify at %d to %p\n",
113 notify[i].dwOffset,notify[i].hEventNotify);
117 /* Make an internal copy of the caller-supplied array.
118 * Replace the existing copy if one is already present. */
119 if (This->dscb->notifies)
120 This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
121 This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
123 This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
124 howmuch * sizeof(DSBPOSITIONNOTIFY));
126 if (This->dscb->notifies == NULL) {
127 WARN("out of memory\n");
128 return DSERR_OUTOFMEMORY;
130 CopyMemory(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
131 This->dscb->nrofnotifies = howmuch;
133 HeapFree(GetProcessHeap(), 0, This->dscb->notifies);
134 This->dscb->notifies = NULL;
135 This->dscb->nrofnotifies = 0;
141 static const IDirectSoundNotifyVtbl dscnvt =
143 IDirectSoundNotifyImpl_QueryInterface,
144 IDirectSoundNotifyImpl_AddRef,
145 IDirectSoundNotifyImpl_Release,
146 IDirectSoundNotifyImpl_SetNotificationPositions
149 static HRESULT IDirectSoundCaptureNotifyImpl_Create(
150 IDirectSoundCaptureBufferImpl *dscb,
151 IDirectSoundCaptureNotifyImpl **pdscn)
153 IDirectSoundCaptureNotifyImpl * dscn;
154 TRACE("(%p,%p)\n",dscb,pdscn);
156 dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscn));
159 WARN("out of memory\n");
160 return DSERR_OUTOFMEMORY;
164 dscn->lpVtbl = &dscnvt;
167 IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb);
174 static const char * const captureStateString[] = {
182 /*******************************************************************************
183 * IDirectSoundCaptureBuffer
185 static inline IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8 *iface)
187 return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundCaptureBuffer8_iface);
190 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_QueryInterface(IDirectSoundCaptureBuffer8 *iface,
191 REFIID riid, void **ppobj)
193 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
196 TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
199 WARN("invalid parameter\n");
205 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
207 hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify);
212 IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
213 *ppobj = This->notify;
217 if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
218 IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
219 IDirectSoundCaptureBuffer8_AddRef(iface);
224 FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
225 return E_NOINTERFACE;
228 static ULONG WINAPI IDirectSoundCaptureBufferImpl_AddRef(IDirectSoundCaptureBuffer8 *iface)
230 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
231 ULONG ref = InterlockedIncrement(&(This->ref));
233 TRACE("(%p) ref was %d\n", This, ref - 1);
237 static ULONG WINAPI IDirectSoundCaptureBufferImpl_Release(IDirectSoundCaptureBuffer8 *iface)
239 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
240 ULONG ref = InterlockedDecrement(&(This->ref));
242 TRACE("(%p) ref was %d\n", This, ref + 1);
245 TRACE("deleting object\n");
246 if (This->device->state == STATE_CAPTURING)
247 This->device->state = STATE_STOPPING;
249 HeapFree(GetProcessHeap(),0, This->pdscbd);
251 if (This->device->client) {
252 IAudioClient_Release(This->device->client);
253 This->device->client = NULL;
256 if (This->device->capture) {
257 IAudioCaptureClient_Release(This->device->capture);
258 This->device->capture = NULL;
261 /* remove from DirectSoundCaptureDevice */
262 This->device->capture_buffer = NULL;
265 IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
267 HeapFree(GetProcessHeap(), 0, This->notifies);
268 HeapFree( GetProcessHeap(), 0, This );
269 TRACE("(%p) released\n", This);
274 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCaps(IDirectSoundCaptureBuffer8 *iface,
275 DSCBCAPS *lpDSCBCaps)
277 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
278 TRACE( "(%p,%p)\n", This, lpDSCBCaps );
280 if (lpDSCBCaps == NULL) {
281 WARN("invalid parameter: lpDSCBCaps == NULL\n");
282 return DSERR_INVALIDPARAM;
285 if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
286 WARN("invalid parameter: lpDSCBCaps->dwSize = %d\n", lpDSCBCaps->dwSize);
287 return DSERR_INVALIDPARAM;
290 if (This->device == NULL) {
291 WARN("invalid parameter: This->device == NULL\n");
292 return DSERR_INVALIDPARAM;
295 lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
296 lpDSCBCaps->dwFlags = This->flags;
297 lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
298 lpDSCBCaps->dwReserved = 0;
300 TRACE("returning DS_OK\n");
304 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCurrentPosition(IDirectSoundCaptureBuffer8 *iface,
305 DWORD *lpdwCapturePosition, DWORD *lpdwReadPosition)
307 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
309 TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
311 if (This->device == NULL) {
312 WARN("invalid parameter: This->device == NULL\n");
313 return DSERR_INVALIDPARAM;
316 EnterCriticalSection(&This->device->lock);
318 if (!This->device->client) {
319 LeaveCriticalSection(&This->device->lock);
321 return DSERR_NODRIVER;
324 if(lpdwCapturePosition)
325 *lpdwCapturePosition = This->device->write_pos_bytes;
328 *lpdwReadPosition = This->device->write_pos_bytes;
330 LeaveCriticalSection(&This->device->lock);
332 TRACE("cappos=%d readpos=%d\n", (lpdwCapturePosition?*lpdwCapturePosition:-1), (lpdwReadPosition?*lpdwReadPosition:-1));
333 TRACE("returning DS_OK\n");
338 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFormat(IDirectSoundCaptureBuffer8 *iface,
339 WAVEFORMATEX *lpwfxFormat, DWORD dwSizeAllocated, DWORD *lpdwSizeWritten)
341 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
342 HRESULT hres = DS_OK;
344 TRACE("(%p,%p,0x%08x,%p)\n", This, lpwfxFormat, dwSizeAllocated, lpdwSizeWritten);
346 if (This->device == NULL) {
347 WARN("invalid parameter: This->device == NULL\n");
348 return DSERR_INVALIDPARAM;
351 if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize))
352 dwSizeAllocated = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
354 if (lpwfxFormat) { /* NULL is valid (just want size) */
355 CopyMemory(lpwfxFormat, This->device->pwfx, dwSizeAllocated);
357 *lpdwSizeWritten = dwSizeAllocated;
360 *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
362 TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
363 hres = DSERR_INVALIDPARAM;
367 TRACE("returning %08x\n", hres);
371 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetStatus(IDirectSoundCaptureBuffer8 *iface,
374 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
376 TRACE( "(%p, %p), thread is %04x\n", This, lpdwStatus, GetCurrentThreadId() );
378 if (This->device == NULL) {
379 WARN("invalid parameter: This->device == NULL\n");
380 return DSERR_INVALIDPARAM;
383 if (lpdwStatus == NULL) {
384 WARN("invalid parameter: lpdwStatus == NULL\n");
385 return DSERR_INVALIDPARAM;
389 EnterCriticalSection(&(This->device->lock));
391 TRACE("old This->device->state=%s, old lpdwStatus=%08x\n",
392 captureStateString[This->device->state],*lpdwStatus);
393 if ((This->device->state == STATE_STARTING) ||
394 (This->device->state == STATE_CAPTURING)) {
395 *lpdwStatus |= DSCBSTATUS_CAPTURING;
396 if (This->flags & DSCBSTART_LOOPING)
397 *lpdwStatus |= DSCBSTATUS_LOOPING;
399 TRACE("new This->device->state=%s, new lpdwStatus=%08x\n",
400 captureStateString[This->device->state],*lpdwStatus);
401 LeaveCriticalSection(&(This->device->lock));
403 TRACE("status=%x\n", *lpdwStatus);
404 TRACE("returning DS_OK\n");
408 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Initialize(IDirectSoundCaptureBuffer8 *iface,
409 IDirectSoundCapture *lpDSC, const DSCBUFFERDESC *lpcDSCBDesc)
411 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
413 FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
418 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Lock(IDirectSoundCaptureBuffer8 *iface,
419 DWORD dwReadCusor, DWORD dwReadBytes, void **lplpvAudioPtr1, DWORD *lpdwAudioBytes1,
420 void **lplpvAudioPtr2, DWORD *lpdwAudioBytes2, DWORD dwFlags)
422 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
423 HRESULT hres = DS_OK;
425 TRACE( "(%p,%08u,%08u,%p,%p,%p,%p,0x%08x) at %d\n", This, dwReadCusor,
426 dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
427 lpdwAudioBytes2, dwFlags, GetTickCount() );
429 if (This->device == NULL) {
430 WARN("invalid parameter: This->device == NULL\n");
431 return DSERR_INVALIDPARAM;
434 if (lplpvAudioPtr1 == NULL) {
435 WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
436 return DSERR_INVALIDPARAM;
439 if (lpdwAudioBytes1 == NULL) {
440 WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
441 return DSERR_INVALIDPARAM;
444 EnterCriticalSection(&(This->device->lock));
446 if (This->device->client) {
447 *lplpvAudioPtr1 = This->device->buffer + dwReadCusor;
448 if ( (dwReadCusor + dwReadBytes) > This->device->buflen) {
449 *lpdwAudioBytes1 = This->device->buflen - dwReadCusor;
451 *lplpvAudioPtr2 = This->device->buffer;
453 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
455 *lpdwAudioBytes1 = dwReadBytes;
459 *lpdwAudioBytes2 = 0;
462 TRACE("invalid call\n");
463 hres = DSERR_INVALIDCALL; /* DSERR_NODRIVER ? */
466 LeaveCriticalSection(&(This->device->lock));
468 TRACE("returning %08x\n", hres);
472 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Start(IDirectSoundCaptureBuffer8 *iface,
475 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
478 TRACE( "(%p,0x%08x)\n", This, dwFlags );
480 if (This->device == NULL) {
481 WARN("invalid parameter: This->device == NULL\n");
482 return DSERR_INVALIDPARAM;
485 if ( !This->device->client ) {
487 return DSERR_NODRIVER;
490 EnterCriticalSection(&(This->device->lock));
492 This->flags = dwFlags;
493 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
494 if (This->device->state == STATE_STOPPED)
495 This->device->state = STATE_STARTING;
496 else if (This->device->state == STATE_STOPPING)
497 This->device->state = STATE_CAPTURING;
498 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
500 if (This->device->buffer)
501 FillMemory(This->device->buffer, This->device->buflen, (This->device->pwfx->wBitsPerSample == 8) ? 128 : 0);
503 hres = IAudioClient_Start(This->device->client);
505 WARN("Start failed: %08x\n", hres);
506 LeaveCriticalSection(&This->device->lock);
510 LeaveCriticalSection(&This->device->lock);
512 TRACE("returning DS_OK\n");
516 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Stop(IDirectSoundCaptureBuffer8 *iface)
518 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
521 TRACE("(%p)\n", This);
523 if (This->device == NULL) {
524 WARN("invalid parameter: This->device == NULL\n");
525 return DSERR_INVALIDPARAM;
528 EnterCriticalSection(&(This->device->lock));
530 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
531 if (This->device->state == STATE_CAPTURING)
532 This->device->state = STATE_STOPPING;
533 else if (This->device->state == STATE_STARTING)
534 This->device->state = STATE_STOPPED;
535 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
537 if(This->device->client){
538 hres = IAudioClient_Stop(This->device->client);
540 LeaveCriticalSection(&This->device->lock);
545 LeaveCriticalSection(&(This->device->lock));
547 TRACE("returning DS_OK\n");
551 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Unlock(IDirectSoundCaptureBuffer8 *iface,
552 void *lpvAudioPtr1, DWORD dwAudioBytes1, void *lpvAudioPtr2, DWORD dwAudioBytes2)
554 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
555 HRESULT hres = DS_OK;
557 TRACE( "(%p,%p,%08u,%p,%08u)\n", This, lpvAudioPtr1, dwAudioBytes1,
558 lpvAudioPtr2, dwAudioBytes2 );
560 if (lpvAudioPtr1 == NULL) {
561 WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
562 return DSERR_INVALIDPARAM;
565 if (!This->device->client) {
566 WARN("invalid call\n");
567 hres = DSERR_INVALIDCALL;
570 TRACE("returning %08x\n", hres);
574 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface,
575 REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
577 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
579 FIXME( "(%p,%s,%u,%s,%p): stub\n", This, debugstr_guid(rguidObject),
580 dwIndex, debugstr_guid(rguidInterface), ppObject );
585 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFXStatus(IDirectSoundCaptureBuffer8 *iface,
586 DWORD dwFXCount, DWORD *pdwFXStatus)
588 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
590 FIXME( "(%p,%u,%p): stub\n", This, dwFXCount, pdwFXStatus );
595 static const IDirectSoundCaptureBuffer8Vtbl dscbvt =
597 /* IUnknown methods */
598 IDirectSoundCaptureBufferImpl_QueryInterface,
599 IDirectSoundCaptureBufferImpl_AddRef,
600 IDirectSoundCaptureBufferImpl_Release,
602 /* IDirectSoundCaptureBuffer methods */
603 IDirectSoundCaptureBufferImpl_GetCaps,
604 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
605 IDirectSoundCaptureBufferImpl_GetFormat,
606 IDirectSoundCaptureBufferImpl_GetStatus,
607 IDirectSoundCaptureBufferImpl_Initialize,
608 IDirectSoundCaptureBufferImpl_Lock,
609 IDirectSoundCaptureBufferImpl_Start,
610 IDirectSoundCaptureBufferImpl_Stop,
611 IDirectSoundCaptureBufferImpl_Unlock,
613 /* IDirectSoundCaptureBuffer methods */
614 IDirectSoundCaptureBufferImpl_GetObjectInPath,
615 IDirectSoundCaptureBufferImpl_GetFXStatus
618 static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len)
621 for (i = 0; i < This->nrofnotifies; ++i) {
622 LPDSBPOSITIONNOTIFY event = This->notifies + i;
623 DWORD offset = event->dwOffset;
624 TRACE("checking %d, position %d, event = %p\n", i, offset, event->hEventNotify);
626 if (offset == DSBPN_OFFSETSTOP) {
628 SetEvent(event->hEventNotify);
629 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
635 if (offset >= from && offset < (from + len))
637 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
638 SetEvent(event->hEventNotify);
643 static HRESULT IDirectSoundCaptureBufferImpl_Create(
644 DirectSoundCaptureDevice *device,
645 IDirectSoundCaptureBufferImpl ** ppobj,
646 LPCDSCBUFFERDESC lpcDSCBufferDesc)
649 IDirectSoundCaptureBufferImpl *This;
650 TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
653 WARN("invalid parameter: ppobj == NULL\n");
654 return DSERR_INVALIDPARAM;
660 WARN("not initialized\n");
661 return DSERR_UNINITIALIZED;
664 if (lpcDSCBufferDesc == NULL) {
665 WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
666 return DSERR_INVALIDPARAM;
669 if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
670 (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
671 (lpcDSCBufferDesc->dwBufferBytes == 0) ||
672 (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { /* FIXME: DSERR_BADFORMAT ? */
673 WARN("invalid lpcDSCBufferDesc\n");
674 return DSERR_INVALIDPARAM;
677 wfex = lpcDSCBufferDesc->lpwfxFormat;
679 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
680 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
681 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
682 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
683 wfex->wBitsPerSample, wfex->cbSize);
685 device->pwfx = DSOUND_CopyFormat(wfex);
686 if ( device->pwfx == NULL )
687 return DSERR_OUTOFMEMORY;
689 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
690 sizeof(IDirectSoundCaptureBufferImpl));
692 if ( This == NULL ) {
693 WARN("out of memory\n");
694 return DSERR_OUTOFMEMORY;
701 This->device = device;
702 This->device->capture_buffer = This;
704 This->nrofnotifies = 0;
706 This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
707 lpcDSCBufferDesc->dwSize);
709 CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
712 This->device->capture_buffer = 0;
713 HeapFree( GetProcessHeap(), 0, This );
714 return DSERR_OUTOFMEMORY;
717 This->IDirectSoundCaptureBuffer8_iface.lpVtbl = &dscbvt;
719 err = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
720 CLSCTX_INPROC_SERVER, NULL, (void**)&device->client);
722 WARN("Activate failed: %08x\n", err);
723 HeapFree(GetProcessHeap(), 0, This->pdscbd);
724 This->device->capture_buffer = 0;
725 HeapFree( GetProcessHeap(), 0, This );
729 err = IAudioClient_Initialize(device->client,
730 AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
731 200 * 100000, 50000, device->pwfx, NULL);
733 WARN("Initialize failed: %08x\n", err);
734 IAudioClient_Release(device->client);
735 device->client = NULL;
736 HeapFree(GetProcessHeap(), 0, This->pdscbd);
737 This->device->capture_buffer = 0;
738 HeapFree( GetProcessHeap(), 0, This );
742 err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
743 (void**)&device->capture);
745 WARN("GetService failed: %08x\n", err);
746 IAudioClient_Release(device->client);
747 device->client = NULL;
748 HeapFree(GetProcessHeap(), 0, This->pdscbd);
749 This->device->capture_buffer = 0;
750 HeapFree( GetProcessHeap(), 0, This );
754 buflen = lpcDSCBufferDesc->dwBufferBytes;
755 TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
757 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
759 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
760 if (newbuf == NULL) {
761 IAudioClient_Release(device->client);
762 device->client = NULL;
763 IAudioCaptureClient_Release(device->capture);
764 device->capture = NULL;
765 HeapFree(GetProcessHeap(), 0, This->pdscbd);
766 This->device->capture_buffer = 0;
767 HeapFree( GetProcessHeap(), 0, This );
768 return DSERR_OUTOFMEMORY;
770 device->buffer = newbuf;
771 device->buflen = buflen;
776 TRACE("returning DS_OK\n");
781 /*******************************************************************************
782 * DirectSoundCaptureDevice
784 static HRESULT DirectSoundCaptureDevice_Create(
785 DirectSoundCaptureDevice ** ppDevice)
787 DirectSoundCaptureDevice * device;
788 TRACE("(%p)\n", ppDevice);
790 /* Allocate memory */
791 device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
793 if (device == NULL) {
794 WARN("out of memory\n");
795 return DSERR_OUTOFMEMORY;
799 device->state = STATE_STOPPED;
801 InitializeCriticalSection( &(device->lock) );
802 device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
809 static ULONG DirectSoundCaptureDevice_Release(
810 DirectSoundCaptureDevice * device)
812 ULONG ref = InterlockedDecrement(&(device->ref));
813 TRACE("(%p) ref was %d\n", device, ref + 1);
816 TRACE("deleting object\n");
818 timeKillEvent(device->timerID);
819 timeEndPeriod(DS_TIME_RES);
821 EnterCriticalSection(&DSOUND_capturers_lock);
822 list_remove(&device->entry);
823 LeaveCriticalSection(&DSOUND_capturers_lock);
825 if (device->capture_buffer)
826 IDirectSoundCaptureBufferImpl_Release(&device->capture_buffer->IDirectSoundCaptureBuffer8_iface);
829 IMMDevice_Release(device->mmdevice);
830 HeapFree(GetProcessHeap(), 0, device->pwfx);
831 device->lock.DebugInfo->Spare[0] = 0;
832 DeleteCriticalSection( &(device->lock) );
833 HeapFree(GetProcessHeap(), 0, device);
834 TRACE("(%p) released\n", device);
839 static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user,
840 DWORD_PTR dw1, DWORD_PTR dw2)
842 DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user;
843 UINT32 packet_frames, packet_bytes, avail_bytes;
851 EnterCriticalSection(&device->lock);
853 if(!device->capture_buffer || device->state == STATE_STOPPED){
854 LeaveCriticalSection(&device->lock);
858 if(device->state == STATE_STOPPING){
859 device->state = STATE_STOPPED;
860 LeaveCriticalSection(&device->lock);
864 if(device->state == STATE_STARTING)
865 device->state = STATE_CAPTURING;
867 hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
870 LeaveCriticalSection(&device->lock);
871 WARN("GetBuffer failed: %08x\n", hr);
875 packet_bytes = packet_frames * device->pwfx->nBlockAlign;
877 avail_bytes = device->buflen - device->write_pos_bytes;
878 if(avail_bytes > packet_bytes)
879 avail_bytes = packet_bytes;
881 memcpy(device->buffer + device->write_pos_bytes, buf, avail_bytes);
882 capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
884 packet_bytes -= avail_bytes;
885 if(packet_bytes > 0){
886 if(device->capture_buffer->flags & DSCBSTART_LOOPING){
887 memcpy(device->buffer, buf + avail_bytes, packet_bytes);
888 capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
890 device->state = STATE_STOPPED;
891 capture_CheckNotify(device->capture_buffer, 0, 0);
895 device->write_pos_bytes += avail_bytes + packet_bytes;
896 device->write_pos_bytes %= device->buflen;
898 hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
900 LeaveCriticalSection(&device->lock);
901 WARN("ReleaseBuffer failed: %08x\n", hr);
905 LeaveCriticalSection(&device->lock);
908 static struct _TestFormat {
913 } formats_to_test[] = {
914 { WAVE_FORMAT_1M08, 11025, 8, 1 },
915 { WAVE_FORMAT_1M16, 11025, 16, 1 },
916 { WAVE_FORMAT_1S08, 11025, 8, 2 },
917 { WAVE_FORMAT_1S16, 11025, 16, 2 },
918 { WAVE_FORMAT_2M08, 22050, 8, 1 },
919 { WAVE_FORMAT_2M16, 22050, 16, 1 },
920 { WAVE_FORMAT_2S08, 22050, 8, 2 },
921 { WAVE_FORMAT_2S16, 22050, 16, 2 },
922 { WAVE_FORMAT_4M08, 44100, 8, 1 },
923 { WAVE_FORMAT_4M16, 44100, 16, 1 },
924 { WAVE_FORMAT_4S08, 44100, 8, 2 },
925 { WAVE_FORMAT_4S16, 44100, 16, 2 },
926 { WAVE_FORMAT_48M08, 48000, 8, 1 },
927 { WAVE_FORMAT_48M16, 48000, 16, 1 },
928 { WAVE_FORMAT_48S08, 48000, 8, 2 },
929 { WAVE_FORMAT_48S16, 48000, 16, 2 },
930 { WAVE_FORMAT_96M08, 96000, 8, 1 },
931 { WAVE_FORMAT_96M16, 96000, 16, 1 },
932 { WAVE_FORMAT_96S08, 96000, 8, 2 },
933 { WAVE_FORMAT_96S16, 96000, 16, 2 },
937 static HRESULT DirectSoundCaptureDevice_Initialize(
938 DirectSoundCaptureDevice ** ppDevice,
944 struct _TestFormat *fmt;
945 DirectSoundCaptureDevice *device;
946 IAudioClient *client;
948 TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
950 /* Default device? */
951 if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
952 lpcGUID = &DSDEVID_DefaultCapture;
954 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
955 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
956 return DSERR_NODRIVER;
958 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
959 WARN("invalid parameter: lpcGUID\n");
960 return DSERR_INVALIDPARAM;
963 hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
967 EnterCriticalSection(&DSOUND_capturers_lock);
969 LIST_FOR_EACH_ENTRY(device, &DSOUND_capturers, DirectSoundCaptureDevice, entry){
970 if(IsEqualGUID(&device->guid, &devGUID)){
971 IMMDevice_Release(mmdevice);
972 LeaveCriticalSection(&DSOUND_capturers_lock);
973 return DSERR_ALLOCATED;
977 hr = DirectSoundCaptureDevice_Create(&device);
979 WARN("DirectSoundCaptureDevice_Create failed\n");
980 LeaveCriticalSection(&DSOUND_capturers_lock);
984 device->guid = devGUID;
986 device->mmdevice = mmdevice;
988 device->drvcaps.dwFlags = 0;
990 device->drvcaps.dwFormats = 0;
991 device->drvcaps.dwChannels = 0;
992 hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
993 CLSCTX_INPROC_SERVER, NULL, (void**)&client);
995 device->lock.DebugInfo->Spare[0] = 0;
996 DeleteCriticalSection(&device->lock);
997 HeapFree(GetProcessHeap(), 0, device);
998 LeaveCriticalSection(&DSOUND_capturers_lock);
999 return DSERR_NODRIVER;
1002 for(fmt = formats_to_test; fmt->flag; ++fmt){
1003 if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
1004 device->drvcaps.dwFormats |= fmt->flag;
1005 if(fmt->channels > device->drvcaps.dwChannels)
1006 device->drvcaps.dwChannels = fmt->channels;
1009 IAudioClient_Release(client);
1011 device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
1013 list_add_tail(&DSOUND_capturers, &device->entry);
1017 LeaveCriticalSection(&DSOUND_capturers_lock);
1023 /*****************************************************************************
1024 * IDirectSoundCapture implementation structure
1026 struct IDirectSoundCaptureImpl
1028 IDirectSoundCapture IDirectSoundCapture_iface;
1030 DirectSoundCaptureDevice *device;
1033 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1035 return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1038 /***************************************************************************
1039 * IDirectSoundCaptureImpl
1041 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1042 REFIID riid, void **ppobj)
1044 TRACE( "(%p,%s,%p)\n", iface, debugstr_guid(riid), ppobj );
1046 if (ppobj == NULL) {
1047 WARN("invalid parameter\n");
1048 return E_INVALIDARG;
1053 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1054 IDirectSoundCapture_AddRef(iface);
1059 WARN("unsupported riid: %s\n", debugstr_guid(riid));
1060 return E_NOINTERFACE;
1063 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1065 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1066 ULONG ref = InterlockedIncrement(&(This->ref));
1068 TRACE("(%p) ref was %d\n", This, ref - 1);
1072 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1074 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1075 ULONG ref = InterlockedDecrement(&(This->ref));
1077 TRACE("(%p) ref was %d\n", This, ref + 1);
1081 DirectSoundCaptureDevice_Release(This->device);
1083 HeapFree( GetProcessHeap(), 0, This );
1084 TRACE("(%p) released\n", This);
1089 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1090 LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1093 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1096 TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1098 if (lpcDSCBufferDesc == NULL) {
1099 WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1100 return DSERR_INVALIDPARAM;
1103 if (lplpDSCaptureBuffer == NULL) {
1104 WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1105 return DSERR_INVALIDPARAM;
1109 WARN("invalid parameter: pUnk != NULL\n");
1110 return DSERR_INVALIDPARAM;
1113 /* FIXME: We can only have one buffer so what do we do here? */
1114 if (This->device->capture_buffer) {
1115 WARN("invalid parameter: already has buffer\n");
1116 return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */
1119 hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1120 (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1123 WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1128 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1129 LPDSCCAPS lpDSCCaps)
1131 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1133 TRACE("(%p,%p)\n",This,lpDSCCaps);
1135 if (This->device == NULL) {
1136 WARN("not initialized\n");
1137 return DSERR_UNINITIALIZED;
1140 if (lpDSCCaps== NULL) {
1141 WARN("invalid parameter: lpDSCCaps== NULL\n");
1142 return DSERR_INVALIDPARAM;
1145 if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1146 WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1147 return DSERR_INVALIDPARAM;
1150 lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1151 lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1152 lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1154 TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1155 lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1160 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1163 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1165 TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1167 if (This->device != NULL) {
1168 WARN("already initialized\n");
1169 return DSERR_ALREADYINITIALIZED;
1171 return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1174 static const IDirectSoundCaptureVtbl dscvt =
1176 /* IUnknown methods */
1177 IDirectSoundCaptureImpl_QueryInterface,
1178 IDirectSoundCaptureImpl_AddRef,
1179 IDirectSoundCaptureImpl_Release,
1181 /* IDirectSoundCapture methods */
1182 IDirectSoundCaptureImpl_CreateCaptureBuffer,
1183 IDirectSoundCaptureImpl_GetCaps,
1184 IDirectSoundCaptureImpl_Initialize
1187 static HRESULT IDirectSoundCaptureImpl_Create(
1188 LPDIRECTSOUNDCAPTURE8 * ppDSC)
1190 IDirectSoundCaptureImpl *pDSC;
1191 TRACE("(%p)\n", ppDSC);
1193 /* Allocate memory */
1194 pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
1196 WARN("out of memory\n");
1198 return DSERR_OUTOFMEMORY;
1201 pDSC->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1203 pDSC->device = NULL;
1205 *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
1210 HRESULT DSOUND_CaptureCreate(REFIID riid, IDirectSoundCapture **ppDSC)
1212 IDirectSoundCapture *pDSC;
1214 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC);
1216 if (!IsEqualIID(riid, &IID_IUnknown) &&
1217 !IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1219 return E_NOINTERFACE;
1222 /* Get dsound configuration */
1223 setup_dsound_options();
1225 hr = IDirectSoundCaptureImpl_Create(&pDSC);
1227 IDirectSoundCapture_AddRef(pDSC);
1230 WARN("IDirectSoundCaptureImpl_Create failed\n");
1237 HRESULT DSOUND_CaptureCreate8(
1239 LPDIRECTSOUNDCAPTURE8 *ppDSC8)
1241 LPDIRECTSOUNDCAPTURE8 pDSC8;
1243 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC8);
1245 if (!IsEqualIID(riid, &IID_IUnknown) &&
1246 !IsEqualIID(riid, &IID_IDirectSoundCapture8)) {
1248 return E_NOINTERFACE;
1251 /* Get dsound configuration */
1252 setup_dsound_options();
1254 hr = IDirectSoundCaptureImpl_Create(&pDSC8);
1256 IDirectSoundCapture_AddRef(pDSC8);
1259 WARN("IDirectSoundCaptureImpl_Create failed\n");
1266 /***************************************************************************
1267 * DirectSoundCaptureCreate [DSOUND.6]
1269 * Create and initialize a DirectSoundCapture interface.
1272 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1273 * lplpDSC [O] Address of a variable to receive the interface pointer.
1274 * pUnkOuter [I] Must be NULL.
1278 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1282 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1283 * or NULL for the default device or DSDEVID_DefaultCapture or
1284 * DSDEVID_DefaultVoiceCapture.
1286 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1288 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1289 IUnknown *pUnkOuter)
1292 IDirectSoundCapture *pDSC;
1294 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1296 if (ppDSC == NULL) {
1297 WARN("invalid parameter: ppDSC == NULL\n");
1298 return DSERR_INVALIDPARAM;
1302 WARN("invalid parameter: pUnkOuter != NULL\n");
1304 return DSERR_NOAGGREGATION;
1307 hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, &pDSC);
1309 hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1311 IDirectSoundCapture_Release(pDSC);
1321 /***************************************************************************
1322 * DirectSoundCaptureCreate8 [DSOUND.12]
1324 * Create and initialize a DirectSoundCapture interface.
1327 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1328 * lplpDSC [O] Address of a variable to receive the interface pointer.
1329 * pUnkOuter [I] Must be NULL.
1333 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1337 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1338 * or NULL for the default device or DSDEVID_DefaultCapture or
1339 * DSDEVID_DefaultVoiceCapture.
1341 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1343 HRESULT WINAPI DirectSoundCaptureCreate8(
1345 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1346 LPUNKNOWN pUnkOuter)
1349 LPDIRECTSOUNDCAPTURE8 pDSC8;
1350 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1352 if (ppDSC8 == NULL) {
1353 WARN("invalid parameter: ppDSC8 == NULL\n");
1354 return DSERR_INVALIDPARAM;
1358 WARN("invalid parameter: pUnkOuter != NULL\n");
1360 return DSERR_NOAGGREGATION;
1363 hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, &pDSC8);
1365 hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1367 IDirectSoundCapture_Release(pDSC8);