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 /*******************************************************************************
59 * IDirectSoundCaptureNotify
61 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface(
62 LPDIRECTSOUNDNOTIFY iface,
66 IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
67 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
69 if (This->dscb == NULL) {
70 WARN("invalid parameter\n");
74 return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
77 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
79 IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
80 ULONG ref = InterlockedIncrement(&(This->ref));
81 TRACE("(%p) ref was %d\n", This, ref - 1);
85 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
87 IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
88 ULONG ref = InterlockedDecrement(&(This->ref));
89 TRACE("(%p) ref was %d\n", This, ref + 1);
92 This->dscb->notify=NULL;
93 IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb);
94 HeapFree(GetProcessHeap(),0,This);
95 TRACE("(%p) released\n", This);
100 static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions(
101 LPDIRECTSOUNDNOTIFY iface,
103 LPCDSBPOSITIONNOTIFY notify)
105 IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
106 TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
108 if (howmuch > 0 && notify == NULL) {
109 WARN("invalid parameter: notify == NULL\n");
110 return DSERR_INVALIDPARAM;
113 if (TRACE_ON(dsound)) {
115 for (i=0;i<howmuch;i++)
116 TRACE("notify at %d to %p\n",
117 notify[i].dwOffset,notify[i].hEventNotify);
121 /* Make an internal copy of the caller-supplied array.
122 * Replace the existing copy if one is already present. */
123 if (This->dscb->notifies)
124 This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
125 This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
127 This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
128 howmuch * sizeof(DSBPOSITIONNOTIFY));
130 if (This->dscb->notifies == NULL) {
131 WARN("out of memory\n");
132 return DSERR_OUTOFMEMORY;
134 CopyMemory(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
135 This->dscb->nrofnotifies = howmuch;
137 HeapFree(GetProcessHeap(), 0, This->dscb->notifies);
138 This->dscb->notifies = NULL;
139 This->dscb->nrofnotifies = 0;
145 static const IDirectSoundNotifyVtbl dscnvt =
147 IDirectSoundCaptureNotifyImpl_QueryInterface,
148 IDirectSoundCaptureNotifyImpl_AddRef,
149 IDirectSoundCaptureNotifyImpl_Release,
150 IDirectSoundCaptureNotifyImpl_SetNotificationPositions,
153 static HRESULT IDirectSoundCaptureNotifyImpl_Create(
154 IDirectSoundCaptureBufferImpl *dscb,
155 IDirectSoundCaptureNotifyImpl **pdscn)
157 IDirectSoundCaptureNotifyImpl * dscn;
158 TRACE("(%p,%p)\n",dscb,pdscn);
160 dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscn));
163 WARN("out of memory\n");
164 return DSERR_OUTOFMEMORY;
168 dscn->lpVtbl = &dscnvt;
171 IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb);
178 static const char * const captureStateString[] = {
186 /*******************************************************************************
187 * IDirectSoundCaptureBuffer
189 static HRESULT WINAPI
190 IDirectSoundCaptureBufferImpl_QueryInterface(
191 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
195 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
198 TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
201 WARN("invalid parameter\n");
207 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
209 hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify);
214 IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
215 *ppobj = This->notify;
219 if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
220 IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
221 IDirectSoundCaptureBuffer8_AddRef(iface);
226 FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
227 return E_NOINTERFACE;
231 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
233 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
234 ULONG ref = InterlockedIncrement(&(This->ref));
235 TRACE("(%p) ref was %d\n", This, ref - 1);
240 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
242 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
243 ULONG ref = InterlockedDecrement(&(This->ref));
244 TRACE("(%p) ref was %d\n", This, ref + 1);
247 TRACE("deleting object\n");
248 if (This->device->state == STATE_CAPTURING)
249 This->device->state = STATE_STOPPING;
251 HeapFree(GetProcessHeap(),0, This->pdscbd);
253 if (This->device->client) {
254 IAudioClient_Release(This->device->client);
255 This->device->client = NULL;
258 if (This->device->capture) {
259 IAudioCaptureClient_Release(This->device->capture);
260 This->device->capture = NULL;
263 /* remove from DirectSoundCaptureDevice */
264 This->device->capture_buffer = NULL;
267 IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
269 HeapFree(GetProcessHeap(), 0, This->notifies);
270 HeapFree( GetProcessHeap(), 0, This );
271 TRACE("(%p) released\n", This);
276 static HRESULT WINAPI
277 IDirectSoundCaptureBufferImpl_GetCaps(
278 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
279 LPDSCBCAPS lpDSCBCaps )
281 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
282 TRACE( "(%p,%p)\n", This, lpDSCBCaps );
284 if (lpDSCBCaps == NULL) {
285 WARN("invalid parameter: lpDSCBCaps == NULL\n");
286 return DSERR_INVALIDPARAM;
289 if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
290 WARN("invalid parameter: lpDSCBCaps->dwSize = %d\n", lpDSCBCaps->dwSize);
291 return DSERR_INVALIDPARAM;
294 if (This->device == NULL) {
295 WARN("invalid parameter: This->device == NULL\n");
296 return DSERR_INVALIDPARAM;
299 lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
300 lpDSCBCaps->dwFlags = This->flags;
301 lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
302 lpDSCBCaps->dwReserved = 0;
304 TRACE("returning DS_OK\n");
308 static HRESULT WINAPI
309 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
310 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
311 LPDWORD lpdwCapturePosition,
312 LPDWORD lpdwReadPosition )
314 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
315 TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
317 if (This->device == NULL) {
318 WARN("invalid parameter: This->device == NULL\n");
319 return DSERR_INVALIDPARAM;
322 EnterCriticalSection(&This->device->lock);
324 if (!This->device->client) {
325 LeaveCriticalSection(&This->device->lock);
327 return DSERR_NODRIVER;
330 if(lpdwCapturePosition)
331 *lpdwCapturePosition = This->device->write_pos_bytes;
334 *lpdwReadPosition = This->device->write_pos_bytes;
336 LeaveCriticalSection(&This->device->lock);
338 TRACE("cappos=%d readpos=%d\n", (lpdwCapturePosition?*lpdwCapturePosition:-1), (lpdwReadPosition?*lpdwReadPosition:-1));
339 TRACE("returning DS_OK\n");
344 static HRESULT WINAPI
345 IDirectSoundCaptureBufferImpl_GetFormat(
346 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
347 LPWAVEFORMATEX lpwfxFormat,
348 DWORD dwSizeAllocated,
349 LPDWORD lpdwSizeWritten )
351 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
352 HRESULT hres = DS_OK;
353 TRACE( "(%p,%p,0x%08x,%p)\n", This, lpwfxFormat, dwSizeAllocated,
356 if (This->device == NULL) {
357 WARN("invalid parameter: This->device == NULL\n");
358 return DSERR_INVALIDPARAM;
361 if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize))
362 dwSizeAllocated = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
364 if (lpwfxFormat) { /* NULL is valid (just want size) */
365 CopyMemory(lpwfxFormat, This->device->pwfx, dwSizeAllocated);
367 *lpdwSizeWritten = dwSizeAllocated;
370 *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
372 TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
373 hres = DSERR_INVALIDPARAM;
377 TRACE("returning %08x\n", hres);
381 static HRESULT WINAPI
382 IDirectSoundCaptureBufferImpl_GetStatus(
383 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
386 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
387 TRACE( "(%p, %p), thread is %04x\n", This, lpdwStatus, GetCurrentThreadId() );
389 if (This->device == NULL) {
390 WARN("invalid parameter: This->device == NULL\n");
391 return DSERR_INVALIDPARAM;
394 if (lpdwStatus == NULL) {
395 WARN("invalid parameter: lpdwStatus == NULL\n");
396 return DSERR_INVALIDPARAM;
400 EnterCriticalSection(&(This->device->lock));
402 TRACE("old This->device->state=%s, old lpdwStatus=%08x\n",
403 captureStateString[This->device->state],*lpdwStatus);
404 if ((This->device->state == STATE_STARTING) ||
405 (This->device->state == STATE_CAPTURING)) {
406 *lpdwStatus |= DSCBSTATUS_CAPTURING;
407 if (This->flags & DSCBSTART_LOOPING)
408 *lpdwStatus |= DSCBSTATUS_LOOPING;
410 TRACE("new This->device->state=%s, new lpdwStatus=%08x\n",
411 captureStateString[This->device->state],*lpdwStatus);
412 LeaveCriticalSection(&(This->device->lock));
414 TRACE("status=%x\n", *lpdwStatus);
415 TRACE("returning DS_OK\n");
419 static HRESULT WINAPI
420 IDirectSoundCaptureBufferImpl_Initialize(
421 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
422 LPDIRECTSOUNDCAPTURE lpDSC,
423 LPCDSCBUFFERDESC lpcDSCBDesc )
425 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
427 FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
432 static HRESULT WINAPI
433 IDirectSoundCaptureBufferImpl_Lock(
434 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
437 LPVOID* lplpvAudioPtr1,
438 LPDWORD lpdwAudioBytes1,
439 LPVOID* lplpvAudioPtr2,
440 LPDWORD lpdwAudioBytes2,
443 HRESULT hres = DS_OK;
444 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
445 TRACE( "(%p,%08u,%08u,%p,%p,%p,%p,0x%08x) at %d\n", This, dwReadCusor,
446 dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
447 lpdwAudioBytes2, dwFlags, GetTickCount() );
449 if (This->device == NULL) {
450 WARN("invalid parameter: This->device == NULL\n");
451 return DSERR_INVALIDPARAM;
454 if (lplpvAudioPtr1 == NULL) {
455 WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
456 return DSERR_INVALIDPARAM;
459 if (lpdwAudioBytes1 == NULL) {
460 WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
461 return DSERR_INVALIDPARAM;
464 EnterCriticalSection(&(This->device->lock));
466 if (This->device->client) {
467 *lplpvAudioPtr1 = This->device->buffer + dwReadCusor;
468 if ( (dwReadCusor + dwReadBytes) > This->device->buflen) {
469 *lpdwAudioBytes1 = This->device->buflen - dwReadCusor;
471 *lplpvAudioPtr2 = This->device->buffer;
473 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
475 *lpdwAudioBytes1 = dwReadBytes;
479 *lpdwAudioBytes2 = 0;
482 TRACE("invalid call\n");
483 hres = DSERR_INVALIDCALL; /* DSERR_NODRIVER ? */
486 LeaveCriticalSection(&(This->device->lock));
488 TRACE("returning %08x\n", hres);
492 static HRESULT WINAPI
493 IDirectSoundCaptureBufferImpl_Start(
494 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
498 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
500 TRACE( "(%p,0x%08x)\n", This, dwFlags );
502 if (This->device == NULL) {
503 WARN("invalid parameter: This->device == NULL\n");
504 return DSERR_INVALIDPARAM;
507 if ( !This->device->client ) {
509 return DSERR_NODRIVER;
512 EnterCriticalSection(&(This->device->lock));
514 This->flags = dwFlags;
515 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
516 if (This->device->state == STATE_STOPPED)
517 This->device->state = STATE_STARTING;
518 else if (This->device->state == STATE_STOPPING)
519 This->device->state = STATE_CAPTURING;
520 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
522 if (This->device->buffer)
523 FillMemory(This->device->buffer, This->device->buflen, (This->device->pwfx->wBitsPerSample == 8) ? 128 : 0);
525 hres = IAudioClient_Start(This->device->client);
527 WARN("Start failed: %08x\n", hres);
528 LeaveCriticalSection(&This->device->lock);
532 LeaveCriticalSection(&This->device->lock);
534 TRACE("returning DS_OK\n");
538 static HRESULT WINAPI
539 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
542 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
543 TRACE( "(%p)\n", This );
545 if (This->device == NULL) {
546 WARN("invalid parameter: This->device == NULL\n");
547 return DSERR_INVALIDPARAM;
550 EnterCriticalSection(&(This->device->lock));
552 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
553 if (This->device->state == STATE_CAPTURING)
554 This->device->state = STATE_STOPPING;
555 else if (This->device->state == STATE_STARTING)
556 This->device->state = STATE_STOPPED;
557 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
559 if(This->device->client){
560 hres = IAudioClient_Stop(This->device->client);
562 LeaveCriticalSection(&This->device->lock);
567 LeaveCriticalSection(&(This->device->lock));
569 TRACE("returning DS_OK\n");
573 static HRESULT WINAPI
574 IDirectSoundCaptureBufferImpl_Unlock(
575 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
579 DWORD dwAudioBytes2 )
581 HRESULT hres = DS_OK;
582 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
583 TRACE( "(%p,%p,%08u,%p,%08u)\n", This, lpvAudioPtr1, dwAudioBytes1,
584 lpvAudioPtr2, dwAudioBytes2 );
586 if (lpvAudioPtr1 == NULL) {
587 WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
588 return DSERR_INVALIDPARAM;
591 if (!This->device->client) {
592 WARN("invalid call\n");
593 hres = DSERR_INVALIDCALL;
596 TRACE("returning %08x\n", hres);
600 static HRESULT WINAPI
601 IDirectSoundCaptureBufferImpl_GetObjectInPath(
602 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
605 REFGUID rguidInterface,
608 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
610 FIXME( "(%p,%s,%u,%s,%p): stub\n", This, debugstr_guid(rguidObject),
611 dwIndex, debugstr_guid(rguidInterface), ppObject );
616 static HRESULT WINAPI
617 IDirectSoundCaptureBufferImpl_GetFXStatus(
618 LPDIRECTSOUNDCAPTUREBUFFER8 iface,
620 LPDWORD pdwFXStatus )
622 IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
624 FIXME( "(%p,%u,%p): stub\n", This, dwFXCount, pdwFXStatus );
629 static const IDirectSoundCaptureBuffer8Vtbl dscbvt =
631 /* IUnknown methods */
632 IDirectSoundCaptureBufferImpl_QueryInterface,
633 IDirectSoundCaptureBufferImpl_AddRef,
634 IDirectSoundCaptureBufferImpl_Release,
636 /* IDirectSoundCaptureBuffer methods */
637 IDirectSoundCaptureBufferImpl_GetCaps,
638 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
639 IDirectSoundCaptureBufferImpl_GetFormat,
640 IDirectSoundCaptureBufferImpl_GetStatus,
641 IDirectSoundCaptureBufferImpl_Initialize,
642 IDirectSoundCaptureBufferImpl_Lock,
643 IDirectSoundCaptureBufferImpl_Start,
644 IDirectSoundCaptureBufferImpl_Stop,
645 IDirectSoundCaptureBufferImpl_Unlock,
647 /* IDirectSoundCaptureBuffer methods */
648 IDirectSoundCaptureBufferImpl_GetObjectInPath,
649 IDirectSoundCaptureBufferImpl_GetFXStatus
652 static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len)
655 for (i = 0; i < This->nrofnotifies; ++i) {
656 LPDSBPOSITIONNOTIFY event = This->notifies + i;
657 DWORD offset = event->dwOffset;
658 TRACE("checking %d, position %d, event = %p\n", i, offset, event->hEventNotify);
660 if (offset == DSBPN_OFFSETSTOP) {
662 SetEvent(event->hEventNotify);
663 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
669 if (offset >= from && offset < (from + len))
671 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
672 SetEvent(event->hEventNotify);
677 static HRESULT IDirectSoundCaptureBufferImpl_Create(
678 DirectSoundCaptureDevice *device,
679 IDirectSoundCaptureBufferImpl ** ppobj,
680 LPCDSCBUFFERDESC lpcDSCBufferDesc)
683 IDirectSoundCaptureBufferImpl *This;
684 TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
687 WARN("invalid parameter: ppobj == NULL\n");
688 return DSERR_INVALIDPARAM;
694 WARN("not initialized\n");
695 return DSERR_UNINITIALIZED;
698 if (lpcDSCBufferDesc == NULL) {
699 WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
700 return DSERR_INVALIDPARAM;
703 if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
704 (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
705 (lpcDSCBufferDesc->dwBufferBytes == 0) ||
706 (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { /* FIXME: DSERR_BADFORMAT ? */
707 WARN("invalid lpcDSCBufferDesc\n");
708 return DSERR_INVALIDPARAM;
711 wfex = lpcDSCBufferDesc->lpwfxFormat;
713 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
714 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
715 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
716 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
717 wfex->wBitsPerSample, wfex->cbSize);
719 device->pwfx = DSOUND_CopyFormat(wfex);
720 if ( device->pwfx == NULL )
721 return DSERR_OUTOFMEMORY;
723 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
724 sizeof(IDirectSoundCaptureBufferImpl));
726 if ( This == NULL ) {
727 WARN("out of memory\n");
728 return DSERR_OUTOFMEMORY;
735 This->device = device;
736 This->device->capture_buffer = This;
738 This->nrofnotifies = 0;
740 This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
741 lpcDSCBufferDesc->dwSize);
743 CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
746 This->device->capture_buffer = 0;
747 HeapFree( GetProcessHeap(), 0, This );
748 return DSERR_OUTOFMEMORY;
751 This->lpVtbl = &dscbvt;
753 err = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
754 CLSCTX_INPROC_SERVER, NULL, (void**)&device->client);
756 WARN("Activate failed: %08x\n", err);
757 HeapFree(GetProcessHeap(), 0, This->pdscbd);
758 This->device->capture_buffer = 0;
759 HeapFree( GetProcessHeap(), 0, This );
763 err = IAudioClient_Initialize(device->client,
764 AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
765 200 * 100000, 50000, device->pwfx, NULL);
767 WARN("Initialize failed: %08x\n", err);
768 IAudioClient_Release(device->client);
769 device->client = NULL;
770 HeapFree(GetProcessHeap(), 0, This->pdscbd);
771 This->device->capture_buffer = 0;
772 HeapFree( GetProcessHeap(), 0, This );
776 err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
777 (void**)&device->capture);
779 WARN("GetService failed: %08x\n", err);
780 IAudioClient_Release(device->client);
781 device->client = NULL;
782 HeapFree(GetProcessHeap(), 0, This->pdscbd);
783 This->device->capture_buffer = 0;
784 HeapFree( GetProcessHeap(), 0, This );
788 buflen = lpcDSCBufferDesc->dwBufferBytes;
789 TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
791 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
793 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
794 if (newbuf == NULL) {
795 IAudioClient_Release(device->client);
796 device->client = NULL;
797 IAudioCaptureClient_Release(device->capture);
798 device->capture = NULL;
799 HeapFree(GetProcessHeap(), 0, This->pdscbd);
800 This->device->capture_buffer = 0;
801 HeapFree( GetProcessHeap(), 0, This );
802 return DSERR_OUTOFMEMORY;
804 device->buffer = newbuf;
805 device->buflen = buflen;
810 TRACE("returning DS_OK\n");
815 /*******************************************************************************
816 * DirectSoundCaptureDevice
818 static HRESULT DirectSoundCaptureDevice_Create(
819 DirectSoundCaptureDevice ** ppDevice)
821 DirectSoundCaptureDevice * device;
822 TRACE("(%p)\n", ppDevice);
824 /* Allocate memory */
825 device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
827 if (device == NULL) {
828 WARN("out of memory\n");
829 return DSERR_OUTOFMEMORY;
833 device->state = STATE_STOPPED;
835 InitializeCriticalSection( &(device->lock) );
836 device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
843 static ULONG DirectSoundCaptureDevice_Release(
844 DirectSoundCaptureDevice * device)
846 ULONG ref = InterlockedDecrement(&(device->ref));
847 TRACE("(%p) ref was %d\n", device, ref + 1);
850 TRACE("deleting object\n");
852 timeKillEvent(device->timerID);
853 timeEndPeriod(DS_TIME_RES);
855 EnterCriticalSection(&DSOUND_capturers_lock);
856 list_remove(&device->entry);
857 LeaveCriticalSection(&DSOUND_capturers_lock);
859 if (device->capture_buffer)
860 IDirectSoundCaptureBufferImpl_Release(
861 (LPDIRECTSOUNDCAPTUREBUFFER8) device->capture_buffer);
864 IMMDevice_Release(device->mmdevice);
865 HeapFree(GetProcessHeap(), 0, device->pwfx);
866 device->lock.DebugInfo->Spare[0] = 0;
867 DeleteCriticalSection( &(device->lock) );
868 HeapFree(GetProcessHeap(), 0, device);
869 TRACE("(%p) released\n", device);
874 static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user,
875 DWORD_PTR dw1, DWORD_PTR dw2)
877 DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user;
878 UINT32 packet_frames, packet_bytes, avail_bytes;
886 EnterCriticalSection(&device->lock);
888 if(!device->capture_buffer || device->state == STATE_STOPPED){
889 LeaveCriticalSection(&device->lock);
893 if(device->state == STATE_STOPPING){
894 device->state = STATE_STOPPED;
895 LeaveCriticalSection(&device->lock);
899 if(device->state == STATE_STARTING)
900 device->state = STATE_CAPTURING;
902 hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
905 LeaveCriticalSection(&device->lock);
906 WARN("GetBuffer failed: %08x\n", hr);
910 packet_bytes = packet_frames * device->pwfx->nBlockAlign;
912 avail_bytes = device->buflen - device->write_pos_bytes;
913 if(avail_bytes > packet_bytes)
914 avail_bytes = packet_bytes;
916 memcpy(device->buffer + device->write_pos_bytes, buf, avail_bytes);
917 capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
919 packet_bytes -= avail_bytes;
920 if(packet_bytes > 0){
921 if(device->capture_buffer->flags & DSCBSTART_LOOPING){
922 memcpy(device->buffer, buf + avail_bytes, packet_bytes);
923 capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
925 device->state = STATE_STOPPED;
926 capture_CheckNotify(device->capture_buffer, 0, 0);
930 device->write_pos_bytes += avail_bytes + packet_bytes;
931 device->write_pos_bytes %= device->buflen;
933 hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
935 LeaveCriticalSection(&device->lock);
936 WARN("ReleaseBuffer failed: %08x\n", hr);
940 LeaveCriticalSection(&device->lock);
943 static struct _TestFormat {
948 } formats_to_test[] = {
949 { WAVE_FORMAT_1M08, 11025, 8, 1 },
950 { WAVE_FORMAT_1M16, 11025, 16, 1 },
951 { WAVE_FORMAT_1S08, 11025, 8, 2 },
952 { WAVE_FORMAT_1S16, 11025, 16, 2 },
953 { WAVE_FORMAT_2M08, 22050, 8, 1 },
954 { WAVE_FORMAT_2M16, 22050, 16, 1 },
955 { WAVE_FORMAT_2S08, 22050, 8, 2 },
956 { WAVE_FORMAT_2S16, 22050, 16, 2 },
957 { WAVE_FORMAT_4M08, 44100, 8, 1 },
958 { WAVE_FORMAT_4M16, 44100, 16, 1 },
959 { WAVE_FORMAT_4S08, 44100, 8, 2 },
960 { WAVE_FORMAT_4S16, 44100, 16, 2 },
961 { WAVE_FORMAT_48M08, 48000, 8, 1 },
962 { WAVE_FORMAT_48M16, 48000, 16, 1 },
963 { WAVE_FORMAT_48S08, 48000, 8, 2 },
964 { WAVE_FORMAT_48S16, 48000, 16, 2 },
965 { WAVE_FORMAT_96M08, 96000, 8, 1 },
966 { WAVE_FORMAT_96M16, 96000, 16, 1 },
967 { WAVE_FORMAT_96S08, 96000, 8, 2 },
968 { WAVE_FORMAT_96S16, 96000, 16, 2 },
972 static HRESULT DirectSoundCaptureDevice_Initialize(
973 DirectSoundCaptureDevice ** ppDevice,
979 struct _TestFormat *fmt;
980 DirectSoundCaptureDevice *device;
981 IAudioClient *client;
983 TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
985 /* Default device? */
986 if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
987 lpcGUID = &DSDEVID_DefaultCapture;
989 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
990 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
991 return DSERR_NODRIVER;
993 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
994 WARN("invalid parameter: lpcGUID\n");
995 return DSERR_INVALIDPARAM;
998 hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
1002 EnterCriticalSection(&DSOUND_capturers_lock);
1004 LIST_FOR_EACH_ENTRY(device, &DSOUND_capturers, DirectSoundCaptureDevice, entry){
1005 if(IsEqualGUID(&device->guid, &devGUID)){
1006 IMMDevice_Release(mmdevice);
1007 LeaveCriticalSection(&DSOUND_capturers_lock);
1008 return DSERR_ALLOCATED;
1012 hr = DirectSoundCaptureDevice_Create(&device);
1014 WARN("DirectSoundCaptureDevice_Create failed\n");
1015 LeaveCriticalSection(&DSOUND_capturers_lock);
1019 device->guid = devGUID;
1021 device->mmdevice = mmdevice;
1023 device->drvcaps.dwFlags = 0;
1025 device->drvcaps.dwFormats = 0;
1026 device->drvcaps.dwChannels = 0;
1027 hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
1028 CLSCTX_INPROC_SERVER, NULL, (void**)&client);
1030 DeleteCriticalSection(&device->lock);
1031 HeapFree(GetProcessHeap(), 0, device);
1032 LeaveCriticalSection(&DSOUND_capturers_lock);
1033 return DSERR_NODRIVER;
1036 for(fmt = formats_to_test; fmt->flag; ++fmt){
1037 if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
1038 device->drvcaps.dwFormats |= fmt->flag;
1039 if(fmt->channels > device->drvcaps.dwChannels)
1040 device->drvcaps.dwChannels = fmt->channels;
1043 IAudioClient_Release(client);
1045 device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
1047 list_add_tail(&DSOUND_capturers, &device->entry);
1051 LeaveCriticalSection(&DSOUND_capturers_lock);
1057 /*****************************************************************************
1058 * IDirectSoundCapture implementation structure
1060 struct IDirectSoundCaptureImpl
1062 IDirectSoundCapture IDirectSoundCapture_iface;
1064 DirectSoundCaptureDevice *device;
1067 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1069 return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1072 /***************************************************************************
1073 * IDirectSoundCaptureImpl
1075 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1076 REFIID riid, void **ppobj)
1078 TRACE( "(%p,%s,%p)\n", iface, debugstr_guid(riid), ppobj );
1080 if (ppobj == NULL) {
1081 WARN("invalid parameter\n");
1082 return E_INVALIDARG;
1087 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1088 IDirectSoundCapture_AddRef(iface);
1093 WARN("unsupported riid: %s\n", debugstr_guid(riid));
1094 return E_NOINTERFACE;
1097 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1099 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1100 ULONG ref = InterlockedIncrement(&(This->ref));
1102 TRACE("(%p) ref was %d\n", This, ref - 1);
1106 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1108 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1109 ULONG ref = InterlockedDecrement(&(This->ref));
1111 TRACE("(%p) ref was %d\n", This, ref + 1);
1115 DirectSoundCaptureDevice_Release(This->device);
1117 HeapFree( GetProcessHeap(), 0, This );
1118 TRACE("(%p) released\n", This);
1123 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1124 LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1127 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1130 TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1132 if (lpcDSCBufferDesc == NULL) {
1133 WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1134 return DSERR_INVALIDPARAM;
1137 if (lplpDSCaptureBuffer == NULL) {
1138 WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1139 return DSERR_INVALIDPARAM;
1143 WARN("invalid parameter: pUnk != NULL\n");
1144 return DSERR_INVALIDPARAM;
1147 /* FIXME: We can only have one buffer so what do we do here? */
1148 if (This->device->capture_buffer) {
1149 WARN("invalid parameter: already has buffer\n");
1150 return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */
1153 hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1154 (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1157 WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1162 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1163 LPDSCCAPS lpDSCCaps)
1165 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1167 TRACE("(%p,%p)\n",This,lpDSCCaps);
1169 if (This->device == NULL) {
1170 WARN("not initialized\n");
1171 return DSERR_UNINITIALIZED;
1174 if (lpDSCCaps== NULL) {
1175 WARN("invalid parameter: lpDSCCaps== NULL\n");
1176 return DSERR_INVALIDPARAM;
1179 if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1180 WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1181 return DSERR_INVALIDPARAM;
1184 lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1185 lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1186 lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1188 TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1189 lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1194 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1197 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1199 TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1201 if (This->device != NULL) {
1202 WARN("already initialized\n");
1203 return DSERR_ALREADYINITIALIZED;
1205 return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1208 static const IDirectSoundCaptureVtbl dscvt =
1210 /* IUnknown methods */
1211 IDirectSoundCaptureImpl_QueryInterface,
1212 IDirectSoundCaptureImpl_AddRef,
1213 IDirectSoundCaptureImpl_Release,
1215 /* IDirectSoundCapture methods */
1216 IDirectSoundCaptureImpl_CreateCaptureBuffer,
1217 IDirectSoundCaptureImpl_GetCaps,
1218 IDirectSoundCaptureImpl_Initialize
1221 static HRESULT IDirectSoundCaptureImpl_Create(
1222 LPDIRECTSOUNDCAPTURE8 * ppDSC)
1224 IDirectSoundCaptureImpl *pDSC;
1225 TRACE("(%p)\n", ppDSC);
1227 /* Allocate memory */
1228 pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
1230 WARN("out of memory\n");
1232 return DSERR_OUTOFMEMORY;
1235 pDSC->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1237 pDSC->device = NULL;
1239 *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
1244 HRESULT DSOUND_CaptureCreate(REFIID riid, IDirectSoundCapture **ppDSC)
1246 IDirectSoundCapture *pDSC;
1248 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC);
1250 if (!IsEqualIID(riid, &IID_IUnknown) &&
1251 !IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1253 return E_NOINTERFACE;
1256 /* Get dsound configuration */
1257 setup_dsound_options();
1259 hr = IDirectSoundCaptureImpl_Create(&pDSC);
1261 IDirectSoundCapture_AddRef(pDSC);
1264 WARN("IDirectSoundCaptureImpl_Create failed\n");
1271 HRESULT DSOUND_CaptureCreate8(
1273 LPDIRECTSOUNDCAPTURE8 *ppDSC8)
1275 LPDIRECTSOUNDCAPTURE8 pDSC8;
1277 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC8);
1279 if (!IsEqualIID(riid, &IID_IUnknown) &&
1280 !IsEqualIID(riid, &IID_IDirectSoundCapture8)) {
1282 return E_NOINTERFACE;
1285 /* Get dsound configuration */
1286 setup_dsound_options();
1288 hr = IDirectSoundCaptureImpl_Create(&pDSC8);
1290 IDirectSoundCapture_AddRef(pDSC8);
1293 WARN("IDirectSoundCaptureImpl_Create failed\n");
1300 /***************************************************************************
1301 * DirectSoundCaptureCreate [DSOUND.6]
1303 * Create and initialize a DirectSoundCapture interface.
1306 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1307 * lplpDSC [O] Address of a variable to receive the interface pointer.
1308 * pUnkOuter [I] Must be NULL.
1312 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1316 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1317 * or NULL for the default device or DSDEVID_DefaultCapture or
1318 * DSDEVID_DefaultVoiceCapture.
1320 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1322 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1323 IUnknown *pUnkOuter)
1326 IDirectSoundCapture *pDSC;
1328 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1330 if (ppDSC == NULL) {
1331 WARN("invalid parameter: ppDSC == NULL\n");
1332 return DSERR_INVALIDPARAM;
1336 WARN("invalid parameter: pUnkOuter != NULL\n");
1338 return DSERR_NOAGGREGATION;
1341 hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, &pDSC);
1343 hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1345 IDirectSoundCapture_Release(pDSC);
1355 /***************************************************************************
1356 * DirectSoundCaptureCreate8 [DSOUND.12]
1358 * Create and initialize a DirectSoundCapture interface.
1361 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1362 * lplpDSC [O] Address of a variable to receive the interface pointer.
1363 * pUnkOuter [I] Must be NULL.
1367 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1371 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1372 * or NULL for the default device or DSDEVID_DefaultCapture or
1373 * DSDEVID_DefaultVoiceCapture.
1375 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1377 HRESULT WINAPI DirectSoundCaptureCreate8(
1379 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1380 LPUNKNOWN pUnkOuter)
1383 LPDIRECTSOUNDCAPTURE8 pDSC8;
1384 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1386 if (ppDSC8 == NULL) {
1387 WARN("invalid parameter: ppDSC8 == NULL\n");
1388 return DSERR_INVALIDPARAM;
1392 WARN("invalid parameter: pUnkOuter != NULL\n");
1394 return DSERR_NOAGGREGATION;
1397 hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, &pDSC8);
1399 hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1401 IDirectSoundCapture_Release(pDSC8);