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 TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
686 WARN("invalid parameter: ppobj == NULL\n");
687 return DSERR_INVALIDPARAM;
691 WARN("not initialized\n");
693 return DSERR_UNINITIALIZED;
696 if (lpcDSCBufferDesc == NULL) {
697 WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
699 return DSERR_INVALIDPARAM;
702 if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
703 (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
704 (lpcDSCBufferDesc->dwBufferBytes == 0) ||
705 (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { /* FIXME: DSERR_BADFORMAT ? */
706 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 ) {
722 return DSERR_OUTOFMEMORY;
725 *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
726 sizeof(IDirectSoundCaptureBufferImpl));
728 if ( *ppobj == NULL ) {
729 WARN("out of memory\n");
731 return DSERR_OUTOFMEMORY;
736 IDirectSoundCaptureBufferImpl *This = *ppobj;
739 This->device = device;
740 This->device->capture_buffer = This;
742 This->nrofnotifies = 0;
744 This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
745 lpcDSCBufferDesc->dwSize);
747 CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
750 This->device->capture_buffer = 0;
751 HeapFree( GetProcessHeap(), 0, This );
753 return DSERR_OUTOFMEMORY;
756 This->lpVtbl = &dscbvt;
758 err = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
759 CLSCTX_INPROC_SERVER, NULL, (void**)&device->client);
761 WARN("Activate failed: %08x\n", err);
762 HeapFree(GetProcessHeap(), 0, This->pdscbd);
763 This->device->capture_buffer = 0;
764 HeapFree( GetProcessHeap(), 0, This );
769 err = IAudioClient_Initialize(device->client,
770 AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
771 200 * 100000, 50000, device->pwfx, NULL);
773 WARN("Initialize failed: %08x\n", err);
774 IAudioClient_Release(device->client);
775 device->client = NULL;
776 HeapFree(GetProcessHeap(), 0, This->pdscbd);
777 This->device->capture_buffer = 0;
778 HeapFree( GetProcessHeap(), 0, This );
783 err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
784 (void**)&device->capture);
786 WARN("GetService failed: %08x\n", err);
787 IAudioClient_Release(device->client);
788 device->client = NULL;
789 HeapFree(GetProcessHeap(), 0, This->pdscbd);
790 This->device->capture_buffer = 0;
791 HeapFree( GetProcessHeap(), 0, This );
796 buflen = lpcDSCBufferDesc->dwBufferBytes;
797 TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
799 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
801 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
802 if (newbuf == NULL) {
803 IAudioClient_Release(device->client);
804 device->client = NULL;
805 IAudioCaptureClient_Release(device->capture);
806 device->capture = NULL;
807 HeapFree(GetProcessHeap(), 0, This->pdscbd);
808 This->device->capture_buffer = 0;
809 HeapFree( GetProcessHeap(), 0, This );
811 return DSERR_OUTOFMEMORY;
813 device->buffer = newbuf;
814 device->buflen = buflen;
817 TRACE("returning DS_OK\n");
822 /*******************************************************************************
823 * DirectSoundCaptureDevice
825 static HRESULT DirectSoundCaptureDevice_Create(
826 DirectSoundCaptureDevice ** ppDevice)
828 DirectSoundCaptureDevice * device;
829 TRACE("(%p)\n", ppDevice);
831 /* Allocate memory */
832 device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
834 if (device == NULL) {
835 WARN("out of memory\n");
836 return DSERR_OUTOFMEMORY;
840 device->state = STATE_STOPPED;
842 InitializeCriticalSection( &(device->lock) );
843 device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
850 static ULONG DirectSoundCaptureDevice_Release(
851 DirectSoundCaptureDevice * device)
853 ULONG ref = InterlockedDecrement(&(device->ref));
854 TRACE("(%p) ref was %d\n", device, ref + 1);
857 TRACE("deleting object\n");
859 timeKillEvent(device->timerID);
860 timeEndPeriod(DS_TIME_RES);
862 EnterCriticalSection(&DSOUND_capturers_lock);
863 list_remove(&device->entry);
864 LeaveCriticalSection(&DSOUND_capturers_lock);
866 if (device->capture_buffer)
867 IDirectSoundCaptureBufferImpl_Release(
868 (LPDIRECTSOUNDCAPTUREBUFFER8) device->capture_buffer);
871 IMMDevice_Release(device->mmdevice);
872 HeapFree(GetProcessHeap(), 0, device->pwfx);
873 device->lock.DebugInfo->Spare[0] = 0;
874 DeleteCriticalSection( &(device->lock) );
875 HeapFree(GetProcessHeap(), 0, device);
876 TRACE("(%p) released\n", device);
881 static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user,
882 DWORD_PTR dw1, DWORD_PTR dw2)
884 DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user;
885 UINT32 packet_frames, packet_bytes, avail_bytes;
893 EnterCriticalSection(&device->lock);
895 if(!device->capture_buffer || device->state == STATE_STOPPED){
896 LeaveCriticalSection(&device->lock);
900 if(device->state == STATE_STOPPING){
901 device->state = STATE_STOPPED;
902 LeaveCriticalSection(&device->lock);
906 if(device->state == STATE_STARTING)
907 device->state = STATE_CAPTURING;
909 hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
912 LeaveCriticalSection(&device->lock);
913 WARN("GetBuffer failed: %08x\n", hr);
917 packet_bytes = packet_frames * device->pwfx->nBlockAlign;
919 avail_bytes = device->buflen - device->write_pos_bytes;
920 if(avail_bytes > packet_bytes)
921 avail_bytes = packet_bytes;
923 memcpy(device->buffer + device->write_pos_bytes, buf, avail_bytes);
924 capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
926 packet_bytes -= avail_bytes;
927 if(packet_bytes > 0){
928 if(device->capture_buffer->flags & DSCBSTART_LOOPING){
929 memcpy(device->buffer, buf + avail_bytes, packet_bytes);
930 capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
932 device->state = STATE_STOPPED;
933 capture_CheckNotify(device->capture_buffer, 0, 0);
937 device->write_pos_bytes += avail_bytes + packet_bytes;
938 device->write_pos_bytes %= device->buflen;
940 hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
942 LeaveCriticalSection(&device->lock);
943 WARN("ReleaseBuffer failed: %08x\n", hr);
947 LeaveCriticalSection(&device->lock);
950 static struct _TestFormat {
955 } formats_to_test[] = {
956 { WAVE_FORMAT_1M08, 11025, 8, 1 },
957 { WAVE_FORMAT_1M16, 11025, 16, 1 },
958 { WAVE_FORMAT_1S08, 11025, 8, 2 },
959 { WAVE_FORMAT_1S16, 11025, 16, 2 },
960 { WAVE_FORMAT_2M08, 22050, 8, 1 },
961 { WAVE_FORMAT_2M16, 22050, 16, 1 },
962 { WAVE_FORMAT_2S08, 22050, 8, 2 },
963 { WAVE_FORMAT_2S16, 22050, 16, 2 },
964 { WAVE_FORMAT_4M08, 44100, 8, 1 },
965 { WAVE_FORMAT_4M16, 44100, 16, 1 },
966 { WAVE_FORMAT_4S08, 44100, 8, 2 },
967 { WAVE_FORMAT_4S16, 44100, 16, 2 },
968 { WAVE_FORMAT_48M08, 48000, 8, 1 },
969 { WAVE_FORMAT_48M16, 48000, 16, 1 },
970 { WAVE_FORMAT_48S08, 48000, 8, 2 },
971 { WAVE_FORMAT_48S16, 48000, 16, 2 },
972 { WAVE_FORMAT_96M08, 96000, 8, 1 },
973 { WAVE_FORMAT_96M16, 96000, 16, 1 },
974 { WAVE_FORMAT_96S08, 96000, 8, 2 },
975 { WAVE_FORMAT_96S16, 96000, 16, 2 },
979 static HRESULT DirectSoundCaptureDevice_Initialize(
980 DirectSoundCaptureDevice ** ppDevice,
986 struct _TestFormat *fmt;
987 DirectSoundCaptureDevice *device;
988 IAudioClient *client;
990 TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
992 /* Default device? */
993 if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
994 lpcGUID = &DSDEVID_DefaultCapture;
996 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
997 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
998 return DSERR_NODRIVER;
1000 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1001 WARN("invalid parameter: lpcGUID\n");
1002 return DSERR_INVALIDPARAM;
1005 hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
1009 EnterCriticalSection(&DSOUND_capturers_lock);
1011 LIST_FOR_EACH_ENTRY(device, &DSOUND_capturers, DirectSoundCaptureDevice, entry){
1012 if(IsEqualGUID(&device->guid, &devGUID)){
1013 IMMDevice_Release(mmdevice);
1014 LeaveCriticalSection(&DSOUND_capturers_lock);
1015 return DSERR_ALLOCATED;
1019 hr = DirectSoundCaptureDevice_Create(&device);
1021 WARN("DirectSoundCaptureDevice_Create failed\n");
1022 LeaveCriticalSection(&DSOUND_capturers_lock);
1026 device->guid = devGUID;
1028 device->mmdevice = mmdevice;
1030 device->drvcaps.dwFlags = 0;
1032 device->drvcaps.dwFormats = 0;
1033 device->drvcaps.dwChannels = 0;
1034 hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
1035 CLSCTX_INPROC_SERVER, NULL, (void**)&client);
1037 DeleteCriticalSection(&device->lock);
1038 HeapFree(GetProcessHeap(), 0, device);
1039 return DSERR_NODRIVER;
1042 for(fmt = formats_to_test; fmt->flag; ++fmt){
1043 if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
1044 device->drvcaps.dwFormats |= fmt->flag;
1045 if(fmt->channels > device->drvcaps.dwChannels)
1046 device->drvcaps.dwChannels = fmt->channels;
1049 IAudioClient_Release(client);
1051 device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
1053 list_add_tail(&DSOUND_capturers, &device->entry);
1057 LeaveCriticalSection(&DSOUND_capturers_lock);
1063 /*****************************************************************************
1064 * IDirectSoundCapture implementation structure
1066 struct IDirectSoundCaptureImpl
1068 IDirectSoundCapture IDirectSoundCapture_iface;
1070 DirectSoundCaptureDevice *device;
1073 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1075 return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1078 /***************************************************************************
1079 * IDirectSoundCaptureImpl
1081 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1082 REFIID riid, void **ppobj)
1084 TRACE( "(%p,%s,%p)\n", iface, debugstr_guid(riid), ppobj );
1086 if (ppobj == NULL) {
1087 WARN("invalid parameter\n");
1088 return E_INVALIDARG;
1093 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1094 IDirectSoundCapture_AddRef(iface);
1099 WARN("unsupported riid: %s\n", debugstr_guid(riid));
1100 return E_NOINTERFACE;
1103 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1105 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1106 ULONG ref = InterlockedIncrement(&(This->ref));
1108 TRACE("(%p) ref was %d\n", This, ref - 1);
1112 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1114 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1115 ULONG ref = InterlockedDecrement(&(This->ref));
1117 TRACE("(%p) ref was %d\n", This, ref + 1);
1121 DirectSoundCaptureDevice_Release(This->device);
1123 HeapFree( GetProcessHeap(), 0, This );
1124 TRACE("(%p) released\n", This);
1129 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1130 LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1133 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1136 TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1138 if (lpcDSCBufferDesc == NULL) {
1139 WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1140 return DSERR_INVALIDPARAM;
1143 if (lplpDSCaptureBuffer == NULL) {
1144 WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1145 return DSERR_INVALIDPARAM;
1149 WARN("invalid parameter: pUnk != NULL\n");
1150 return DSERR_INVALIDPARAM;
1153 /* FIXME: We can only have one buffer so what do we do here? */
1154 if (This->device->capture_buffer) {
1155 WARN("invalid parameter: already has buffer\n");
1156 return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */
1159 hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1160 (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1163 WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1168 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1169 LPDSCCAPS lpDSCCaps)
1171 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1173 TRACE("(%p,%p)\n",This,lpDSCCaps);
1175 if (This->device == NULL) {
1176 WARN("not initialized\n");
1177 return DSERR_UNINITIALIZED;
1180 if (lpDSCCaps== NULL) {
1181 WARN("invalid parameter: lpDSCCaps== NULL\n");
1182 return DSERR_INVALIDPARAM;
1185 if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1186 WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1187 return DSERR_INVALIDPARAM;
1190 lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1191 lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1192 lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1194 TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1195 lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1200 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1203 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1205 TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1207 if (This->device != NULL) {
1208 WARN("already initialized\n");
1209 return DSERR_ALREADYINITIALIZED;
1211 return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1214 static const IDirectSoundCaptureVtbl dscvt =
1216 /* IUnknown methods */
1217 IDirectSoundCaptureImpl_QueryInterface,
1218 IDirectSoundCaptureImpl_AddRef,
1219 IDirectSoundCaptureImpl_Release,
1221 /* IDirectSoundCapture methods */
1222 IDirectSoundCaptureImpl_CreateCaptureBuffer,
1223 IDirectSoundCaptureImpl_GetCaps,
1224 IDirectSoundCaptureImpl_Initialize
1227 static HRESULT IDirectSoundCaptureImpl_Create(
1228 LPDIRECTSOUNDCAPTURE8 * ppDSC)
1230 IDirectSoundCaptureImpl *pDSC;
1231 TRACE("(%p)\n", ppDSC);
1233 /* Allocate memory */
1234 pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
1236 WARN("out of memory\n");
1238 return DSERR_OUTOFMEMORY;
1241 pDSC->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1243 pDSC->device = NULL;
1245 *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
1250 HRESULT DSOUND_CaptureCreate(REFIID riid, IDirectSoundCapture **ppDSC)
1252 IDirectSoundCapture *pDSC;
1254 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC);
1256 if (!IsEqualIID(riid, &IID_IUnknown) &&
1257 !IsEqualIID(riid, &IID_IDirectSoundCapture)) {
1259 return E_NOINTERFACE;
1262 /* Get dsound configuration */
1263 setup_dsound_options();
1265 hr = IDirectSoundCaptureImpl_Create(&pDSC);
1267 IDirectSoundCapture_AddRef(pDSC);
1270 WARN("IDirectSoundCaptureImpl_Create failed\n");
1277 HRESULT DSOUND_CaptureCreate8(
1279 LPDIRECTSOUNDCAPTURE8 *ppDSC8)
1281 LPDIRECTSOUNDCAPTURE8 pDSC8;
1283 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC8);
1285 if (!IsEqualIID(riid, &IID_IUnknown) &&
1286 !IsEqualIID(riid, &IID_IDirectSoundCapture8)) {
1288 return E_NOINTERFACE;
1291 /* Get dsound configuration */
1292 setup_dsound_options();
1294 hr = IDirectSoundCaptureImpl_Create(&pDSC8);
1296 IDirectSoundCapture_AddRef(pDSC8);
1299 WARN("IDirectSoundCaptureImpl_Create failed\n");
1306 /***************************************************************************
1307 * DirectSoundCaptureCreate [DSOUND.6]
1309 * Create and initialize a DirectSoundCapture interface.
1312 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1313 * lplpDSC [O] Address of a variable to receive the interface pointer.
1314 * pUnkOuter [I] Must be NULL.
1318 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1322 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1323 * or NULL for the default device or DSDEVID_DefaultCapture or
1324 * DSDEVID_DefaultVoiceCapture.
1326 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1328 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1329 IUnknown *pUnkOuter)
1332 IDirectSoundCapture *pDSC;
1334 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1336 if (ppDSC == NULL) {
1337 WARN("invalid parameter: ppDSC == NULL\n");
1338 return DSERR_INVALIDPARAM;
1342 WARN("invalid parameter: pUnkOuter != NULL\n");
1344 return DSERR_NOAGGREGATION;
1347 hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, &pDSC);
1349 hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1351 IDirectSoundCapture_Release(pDSC);
1361 /***************************************************************************
1362 * DirectSoundCaptureCreate8 [DSOUND.12]
1364 * Create and initialize a DirectSoundCapture interface.
1367 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1368 * lplpDSC [O] Address of a variable to receive the interface pointer.
1369 * pUnkOuter [I] Must be NULL.
1373 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1377 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1378 * or NULL for the default device or DSDEVID_DefaultCapture or
1379 * DSDEVID_DefaultVoiceCapture.
1381 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1383 HRESULT WINAPI DirectSoundCaptureCreate8(
1385 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1386 LPUNKNOWN pUnkOuter)
1389 LPDIRECTSOUNDCAPTURE8 pDSC8;
1390 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1392 if (ppDSC8 == NULL) {
1393 WARN("invalid parameter: ppDSC8 == NULL\n");
1394 return DSERR_INVALIDPARAM;
1398 WARN("invalid parameter: pUnkOuter != NULL\n");
1400 return DSERR_NOAGGREGATION;
1403 hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, &pDSC8);
1405 hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1407 IDirectSoundCapture_Release(pDSC8);