3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2001 TransGaming Technologies, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * Implement FX support.
24 * Implement both IDirectSoundCaptureBuffer and IDirectSoundCaptureBuffer8
25 * Make DirectSoundCaptureCreate and DirectSoundCaptureCreate8 behave differently
31 #define NONAMELESSSTRUCT
32 #define NONAMELESSUNION
40 #include "wine/debug.h"
42 #include "dsound_private.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
47 static void capturebuffer_destroy(IDirectSoundCaptureBufferImpl *This)
49 if (This->device->state == STATE_CAPTURING)
50 This->device->state = STATE_STOPPING;
52 HeapFree(GetProcessHeap(),0, This->pdscbd);
54 if (This->device->client) {
55 IAudioClient_Release(This->device->client);
56 This->device->client = NULL;
59 if (This->device->capture) {
60 IAudioCaptureClient_Release(This->device->capture);
61 This->device->capture = NULL;
64 /* remove from DirectSoundCaptureDevice */
65 This->device->capture_buffer = NULL;
67 HeapFree(GetProcessHeap(), 0, This->notifies);
68 HeapFree(GetProcessHeap(), 0, This);
69 TRACE("(%p) released\n", This);
72 /*******************************************************************************
75 static inline struct IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
77 return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundNotify_iface);
80 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(IDirectSoundNotify *iface, REFIID riid,
83 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
85 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj);
87 return IDirectSoundCaptureBuffer_QueryInterface(&This->IDirectSoundCaptureBuffer8_iface, riid, ppobj);
90 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(IDirectSoundNotify *iface)
92 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
93 ULONG ref = InterlockedIncrement(&This->refn);
95 TRACE("(%p) ref was %d\n", This, ref - 1);
98 InterlockedIncrement(&This->numIfaces);
103 static ULONG WINAPI IDirectSoundNotifyImpl_Release(IDirectSoundNotify *iface)
105 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
106 ULONG ref = InterlockedDecrement(&This->refn);
108 TRACE("(%p) ref was %d\n", This, ref + 1);
110 if (!ref && !InterlockedDecrement(&This->numIfaces))
111 capturebuffer_destroy(This);
116 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSoundNotify *iface,
117 DWORD howmuch, const DSBPOSITIONNOTIFY *notify)
119 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
120 TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
122 if (howmuch > 0 && notify == NULL) {
123 WARN("invalid parameter: notify == NULL\n");
124 return DSERR_INVALIDPARAM;
127 if (TRACE_ON(dsound)) {
129 for (i=0;i<howmuch;i++)
130 TRACE("notify at %d to %p\n",
131 notify[i].dwOffset,notify[i].hEventNotify);
135 /* Make an internal copy of the caller-supplied array.
136 * Replace the existing copy if one is already present. */
138 This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->notifies,
139 howmuch * sizeof(DSBPOSITIONNOTIFY));
141 This->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
142 howmuch * sizeof(DSBPOSITIONNOTIFY));
144 if (!This->notifies) {
145 WARN("out of memory\n");
146 return DSERR_OUTOFMEMORY;
148 CopyMemory(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
149 This->nrofnotifies = howmuch;
151 HeapFree(GetProcessHeap(), 0, This->notifies);
152 This->notifies = NULL;
153 This->nrofnotifies = 0;
159 static const IDirectSoundNotifyVtbl dscnvt =
161 IDirectSoundNotifyImpl_QueryInterface,
162 IDirectSoundNotifyImpl_AddRef,
163 IDirectSoundNotifyImpl_Release,
164 IDirectSoundNotifyImpl_SetNotificationPositions
168 static const char * const captureStateString[] = {
176 /*******************************************************************************
177 * IDirectSoundCaptureBuffer
179 static inline IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8 *iface)
181 return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundCaptureBuffer8_iface);
184 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_QueryInterface(IDirectSoundCaptureBuffer8 *iface,
185 REFIID riid, void **ppobj)
187 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
189 TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
192 WARN("invalid parameter\n");
198 if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
199 IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
200 IDirectSoundCaptureBuffer8_AddRef(iface);
205 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
206 IDirectSoundNotify_AddRef(&This->IDirectSoundNotify_iface);
207 *ppobj = &This->IDirectSoundNotify_iface;
211 FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
212 return E_NOINTERFACE;
215 static ULONG WINAPI IDirectSoundCaptureBufferImpl_AddRef(IDirectSoundCaptureBuffer8 *iface)
217 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
218 ULONG ref = InterlockedIncrement(&This->ref);
220 TRACE("(%p) ref was %d\n", This, ref - 1);
223 InterlockedIncrement(&This->numIfaces);
228 static ULONG WINAPI IDirectSoundCaptureBufferImpl_Release(IDirectSoundCaptureBuffer8 *iface)
230 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
231 ULONG ref = InterlockedDecrement(&This->ref);
233 TRACE("(%p) ref was %d\n", This, ref + 1);
235 if (!ref && !InterlockedDecrement(&This->numIfaces))
236 capturebuffer_destroy(This);
241 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCaps(IDirectSoundCaptureBuffer8 *iface,
242 DSCBCAPS *lpDSCBCaps)
244 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
245 TRACE( "(%p,%p)\n", This, lpDSCBCaps );
247 if (lpDSCBCaps == NULL) {
248 WARN("invalid parameter: lpDSCBCaps == NULL\n");
249 return DSERR_INVALIDPARAM;
252 if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
253 WARN("invalid parameter: lpDSCBCaps->dwSize = %d\n", lpDSCBCaps->dwSize);
254 return DSERR_INVALIDPARAM;
257 if (This->device == NULL) {
258 WARN("invalid parameter: This->device == NULL\n");
259 return DSERR_INVALIDPARAM;
262 lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
263 lpDSCBCaps->dwFlags = This->flags;
264 lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
265 lpDSCBCaps->dwReserved = 0;
267 TRACE("returning DS_OK\n");
271 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCurrentPosition(IDirectSoundCaptureBuffer8 *iface,
272 DWORD *lpdwCapturePosition, DWORD *lpdwReadPosition)
274 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
276 TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
278 if (This->device == NULL) {
279 WARN("invalid parameter: This->device == NULL\n");
280 return DSERR_INVALIDPARAM;
283 EnterCriticalSection(&This->device->lock);
285 if (!This->device->client) {
286 LeaveCriticalSection(&This->device->lock);
288 return DSERR_NODRIVER;
291 if(lpdwCapturePosition)
292 *lpdwCapturePosition = This->device->write_pos_bytes;
295 *lpdwReadPosition = This->device->write_pos_bytes;
297 LeaveCriticalSection(&This->device->lock);
299 TRACE("cappos=%d readpos=%d\n", (lpdwCapturePosition?*lpdwCapturePosition:-1), (lpdwReadPosition?*lpdwReadPosition:-1));
300 TRACE("returning DS_OK\n");
305 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFormat(IDirectSoundCaptureBuffer8 *iface,
306 WAVEFORMATEX *lpwfxFormat, DWORD dwSizeAllocated, DWORD *lpdwSizeWritten)
308 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
309 HRESULT hres = DS_OK;
311 TRACE("(%p,%p,0x%08x,%p)\n", This, lpwfxFormat, dwSizeAllocated, lpdwSizeWritten);
313 if (This->device == NULL) {
314 WARN("invalid parameter: This->device == NULL\n");
315 return DSERR_INVALIDPARAM;
318 if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize))
319 dwSizeAllocated = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
321 if (lpwfxFormat) { /* NULL is valid (just want size) */
322 CopyMemory(lpwfxFormat, This->device->pwfx, dwSizeAllocated);
324 *lpdwSizeWritten = dwSizeAllocated;
327 *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
329 TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
330 hres = DSERR_INVALIDPARAM;
334 TRACE("returning %08x\n", hres);
338 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetStatus(IDirectSoundCaptureBuffer8 *iface,
341 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
343 TRACE( "(%p, %p), thread is %04x\n", This, lpdwStatus, GetCurrentThreadId() );
345 if (This->device == NULL) {
346 WARN("invalid parameter: This->device == NULL\n");
347 return DSERR_INVALIDPARAM;
350 if (lpdwStatus == NULL) {
351 WARN("invalid parameter: lpdwStatus == NULL\n");
352 return DSERR_INVALIDPARAM;
356 EnterCriticalSection(&(This->device->lock));
358 TRACE("old This->device->state=%s, old lpdwStatus=%08x\n",
359 captureStateString[This->device->state],*lpdwStatus);
360 if ((This->device->state == STATE_STARTING) ||
361 (This->device->state == STATE_CAPTURING)) {
362 *lpdwStatus |= DSCBSTATUS_CAPTURING;
363 if (This->flags & DSCBSTART_LOOPING)
364 *lpdwStatus |= DSCBSTATUS_LOOPING;
366 TRACE("new This->device->state=%s, new lpdwStatus=%08x\n",
367 captureStateString[This->device->state],*lpdwStatus);
368 LeaveCriticalSection(&(This->device->lock));
370 TRACE("status=%x\n", *lpdwStatus);
371 TRACE("returning DS_OK\n");
375 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Initialize(IDirectSoundCaptureBuffer8 *iface,
376 IDirectSoundCapture *lpDSC, const DSCBUFFERDESC *lpcDSCBDesc)
378 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
380 FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
385 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Lock(IDirectSoundCaptureBuffer8 *iface,
386 DWORD dwReadCusor, DWORD dwReadBytes, void **lplpvAudioPtr1, DWORD *lpdwAudioBytes1,
387 void **lplpvAudioPtr2, DWORD *lpdwAudioBytes2, DWORD dwFlags)
389 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
390 HRESULT hres = DS_OK;
392 TRACE( "(%p,%08u,%08u,%p,%p,%p,%p,0x%08x) at %d\n", This, dwReadCusor,
393 dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
394 lpdwAudioBytes2, dwFlags, GetTickCount() );
396 if (This->device == NULL) {
397 WARN("invalid parameter: This->device == NULL\n");
398 return DSERR_INVALIDPARAM;
401 if (lplpvAudioPtr1 == NULL) {
402 WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
403 return DSERR_INVALIDPARAM;
406 if (lpdwAudioBytes1 == NULL) {
407 WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
408 return DSERR_INVALIDPARAM;
411 EnterCriticalSection(&(This->device->lock));
413 if (This->device->client) {
414 *lplpvAudioPtr1 = This->device->buffer + dwReadCusor;
415 if ( (dwReadCusor + dwReadBytes) > This->device->buflen) {
416 *lpdwAudioBytes1 = This->device->buflen - dwReadCusor;
418 *lplpvAudioPtr2 = This->device->buffer;
420 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
422 *lpdwAudioBytes1 = dwReadBytes;
426 *lpdwAudioBytes2 = 0;
429 TRACE("invalid call\n");
430 hres = DSERR_INVALIDCALL; /* DSERR_NODRIVER ? */
433 LeaveCriticalSection(&(This->device->lock));
435 TRACE("returning %08x\n", hres);
439 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Start(IDirectSoundCaptureBuffer8 *iface,
442 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
445 TRACE( "(%p,0x%08x)\n", This, dwFlags );
447 if (This->device == NULL) {
448 WARN("invalid parameter: This->device == NULL\n");
449 return DSERR_INVALIDPARAM;
452 if ( !This->device->client ) {
454 return DSERR_NODRIVER;
457 EnterCriticalSection(&(This->device->lock));
459 This->flags = dwFlags;
460 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
461 if (This->device->state == STATE_STOPPED)
462 This->device->state = STATE_STARTING;
463 else if (This->device->state == STATE_STOPPING)
464 This->device->state = STATE_CAPTURING;
465 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
467 if (This->device->buffer)
468 FillMemory(This->device->buffer, This->device->buflen, (This->device->pwfx->wBitsPerSample == 8) ? 128 : 0);
470 hres = IAudioClient_Start(This->device->client);
472 WARN("Start failed: %08x\n", hres);
473 LeaveCriticalSection(&This->device->lock);
477 LeaveCriticalSection(&This->device->lock);
479 TRACE("returning DS_OK\n");
483 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Stop(IDirectSoundCaptureBuffer8 *iface)
485 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
488 TRACE("(%p)\n", This);
490 if (This->device == NULL) {
491 WARN("invalid parameter: This->device == NULL\n");
492 return DSERR_INVALIDPARAM;
495 EnterCriticalSection(&(This->device->lock));
497 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
498 if (This->device->state == STATE_CAPTURING)
499 This->device->state = STATE_STOPPING;
500 else if (This->device->state == STATE_STARTING)
501 This->device->state = STATE_STOPPED;
502 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
504 if(This->device->client){
505 hres = IAudioClient_Stop(This->device->client);
507 LeaveCriticalSection(&This->device->lock);
512 LeaveCriticalSection(&(This->device->lock));
514 TRACE("returning DS_OK\n");
518 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Unlock(IDirectSoundCaptureBuffer8 *iface,
519 void *lpvAudioPtr1, DWORD dwAudioBytes1, void *lpvAudioPtr2, DWORD dwAudioBytes2)
521 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
522 HRESULT hres = DS_OK;
524 TRACE( "(%p,%p,%08u,%p,%08u)\n", This, lpvAudioPtr1, dwAudioBytes1,
525 lpvAudioPtr2, dwAudioBytes2 );
527 if (lpvAudioPtr1 == NULL) {
528 WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
529 return DSERR_INVALIDPARAM;
532 if (!This->device->client) {
533 WARN("invalid call\n");
534 hres = DSERR_INVALIDCALL;
537 TRACE("returning %08x\n", hres);
541 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface,
542 REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
544 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
546 FIXME( "(%p,%s,%u,%s,%p): stub\n", This, debugstr_guid(rguidObject),
547 dwIndex, debugstr_guid(rguidInterface), ppObject );
552 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFXStatus(IDirectSoundCaptureBuffer8 *iface,
553 DWORD dwFXCount, DWORD *pdwFXStatus)
555 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
557 FIXME( "(%p,%u,%p): stub\n", This, dwFXCount, pdwFXStatus );
562 static const IDirectSoundCaptureBuffer8Vtbl dscbvt =
564 /* IUnknown methods */
565 IDirectSoundCaptureBufferImpl_QueryInterface,
566 IDirectSoundCaptureBufferImpl_AddRef,
567 IDirectSoundCaptureBufferImpl_Release,
569 /* IDirectSoundCaptureBuffer methods */
570 IDirectSoundCaptureBufferImpl_GetCaps,
571 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
572 IDirectSoundCaptureBufferImpl_GetFormat,
573 IDirectSoundCaptureBufferImpl_GetStatus,
574 IDirectSoundCaptureBufferImpl_Initialize,
575 IDirectSoundCaptureBufferImpl_Lock,
576 IDirectSoundCaptureBufferImpl_Start,
577 IDirectSoundCaptureBufferImpl_Stop,
578 IDirectSoundCaptureBufferImpl_Unlock,
580 /* IDirectSoundCaptureBuffer methods */
581 IDirectSoundCaptureBufferImpl_GetObjectInPath,
582 IDirectSoundCaptureBufferImpl_GetFXStatus
585 static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len)
588 for (i = 0; i < This->nrofnotifies; ++i) {
589 LPDSBPOSITIONNOTIFY event = This->notifies + i;
590 DWORD offset = event->dwOffset;
591 TRACE("checking %d, position %d, event = %p\n", i, offset, event->hEventNotify);
593 if (offset == DSBPN_OFFSETSTOP) {
595 SetEvent(event->hEventNotify);
596 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
602 if (offset >= from && offset < (from + len))
604 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
605 SetEvent(event->hEventNotify);
610 static HRESULT IDirectSoundCaptureBufferImpl_Create(
611 DirectSoundCaptureDevice *device,
612 IDirectSoundCaptureBufferImpl ** ppobj,
613 LPCDSCBUFFERDESC lpcDSCBufferDesc)
616 IDirectSoundCaptureBufferImpl *This;
617 TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
620 WARN("invalid parameter: ppobj == NULL\n");
621 return DSERR_INVALIDPARAM;
627 WARN("not initialized\n");
628 return DSERR_UNINITIALIZED;
631 if (lpcDSCBufferDesc == NULL) {
632 WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
633 return DSERR_INVALIDPARAM;
636 if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
637 (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
638 (lpcDSCBufferDesc->dwBufferBytes == 0) ||
639 (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { /* FIXME: DSERR_BADFORMAT ? */
640 WARN("invalid lpcDSCBufferDesc\n");
641 return DSERR_INVALIDPARAM;
644 wfex = lpcDSCBufferDesc->lpwfxFormat;
646 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
647 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
648 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
649 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
650 wfex->wBitsPerSample, wfex->cbSize);
652 device->pwfx = DSOUND_CopyFormat(wfex);
653 if ( device->pwfx == NULL )
654 return DSERR_OUTOFMEMORY;
656 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
657 sizeof(IDirectSoundCaptureBufferImpl));
659 if ( This == NULL ) {
660 WARN("out of memory\n");
661 return DSERR_OUTOFMEMORY;
670 This->device = device;
671 This->device->capture_buffer = This;
672 This->nrofnotifies = 0;
674 This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
675 lpcDSCBufferDesc->dwSize);
677 CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
680 This->device->capture_buffer = 0;
681 HeapFree( GetProcessHeap(), 0, This );
682 return DSERR_OUTOFMEMORY;
685 This->IDirectSoundCaptureBuffer8_iface.lpVtbl = &dscbvt;
686 This->IDirectSoundNotify_iface.lpVtbl = &dscnvt;
688 err = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
689 CLSCTX_INPROC_SERVER, NULL, (void**)&device->client);
691 WARN("Activate failed: %08x\n", err);
692 HeapFree(GetProcessHeap(), 0, This->pdscbd);
693 This->device->capture_buffer = 0;
694 HeapFree( GetProcessHeap(), 0, This );
698 err = IAudioClient_Initialize(device->client,
699 AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
700 200 * 100000, 50000, device->pwfx, NULL);
702 WARN("Initialize failed: %08x\n", err);
703 IAudioClient_Release(device->client);
704 device->client = NULL;
705 HeapFree(GetProcessHeap(), 0, This->pdscbd);
706 This->device->capture_buffer = 0;
707 HeapFree( GetProcessHeap(), 0, This );
708 if(err == AUDCLNT_E_UNSUPPORTED_FORMAT)
709 return DSERR_BADFORMAT;
713 err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
714 (void**)&device->capture);
716 WARN("GetService failed: %08x\n", err);
717 IAudioClient_Release(device->client);
718 device->client = NULL;
719 HeapFree(GetProcessHeap(), 0, This->pdscbd);
720 This->device->capture_buffer = 0;
721 HeapFree( GetProcessHeap(), 0, This );
725 buflen = lpcDSCBufferDesc->dwBufferBytes;
726 TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
728 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
730 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
731 if (newbuf == NULL) {
732 IAudioClient_Release(device->client);
733 device->client = NULL;
734 IAudioCaptureClient_Release(device->capture);
735 device->capture = NULL;
736 HeapFree(GetProcessHeap(), 0, This->pdscbd);
737 This->device->capture_buffer = 0;
738 HeapFree( GetProcessHeap(), 0, This );
739 return DSERR_OUTOFMEMORY;
741 device->buffer = newbuf;
742 device->buflen = buflen;
745 IDirectSoundCaptureBuffer_AddRef(&This->IDirectSoundCaptureBuffer8_iface);
748 TRACE("returning DS_OK\n");
753 /*******************************************************************************
754 * DirectSoundCaptureDevice
756 static HRESULT DirectSoundCaptureDevice_Create(
757 DirectSoundCaptureDevice ** ppDevice)
759 DirectSoundCaptureDevice * device;
760 TRACE("(%p)\n", ppDevice);
762 /* Allocate memory */
763 device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
765 if (device == NULL) {
766 WARN("out of memory\n");
767 return DSERR_OUTOFMEMORY;
771 device->state = STATE_STOPPED;
773 InitializeCriticalSection( &(device->lock) );
774 device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
781 static ULONG DirectSoundCaptureDevice_Release(
782 DirectSoundCaptureDevice * device)
784 ULONG ref = InterlockedDecrement(&(device->ref));
785 TRACE("(%p) ref was %d\n", device, ref + 1);
788 TRACE("deleting object\n");
790 timeKillEvent(device->timerID);
791 timeEndPeriod(DS_TIME_RES);
793 EnterCriticalSection(&DSOUND_capturers_lock);
794 list_remove(&device->entry);
795 LeaveCriticalSection(&DSOUND_capturers_lock);
797 if (device->capture_buffer)
798 IDirectSoundCaptureBufferImpl_Release(&device->capture_buffer->IDirectSoundCaptureBuffer8_iface);
801 IMMDevice_Release(device->mmdevice);
802 HeapFree(GetProcessHeap(), 0, device->pwfx);
803 device->lock.DebugInfo->Spare[0] = 0;
804 DeleteCriticalSection( &(device->lock) );
805 HeapFree(GetProcessHeap(), 0, device);
806 TRACE("(%p) released\n", device);
811 static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user,
812 DWORD_PTR dw1, DWORD_PTR dw2)
814 DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user;
815 UINT32 packet_frames, packet_bytes, avail_bytes;
823 EnterCriticalSection(&device->lock);
825 if(!device->capture_buffer || device->state == STATE_STOPPED){
826 LeaveCriticalSection(&device->lock);
830 if(device->state == STATE_STOPPING){
831 device->state = STATE_STOPPED;
832 LeaveCriticalSection(&device->lock);
836 if(device->state == STATE_STARTING)
837 device->state = STATE_CAPTURING;
839 hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
842 LeaveCriticalSection(&device->lock);
843 WARN("GetBuffer failed: %08x\n", hr);
847 packet_bytes = packet_frames * device->pwfx->nBlockAlign;
849 avail_bytes = device->buflen - device->write_pos_bytes;
850 if(avail_bytes > packet_bytes)
851 avail_bytes = packet_bytes;
853 memcpy(device->buffer + device->write_pos_bytes, buf, avail_bytes);
854 capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
856 packet_bytes -= avail_bytes;
857 if(packet_bytes > 0){
858 if(device->capture_buffer->flags & DSCBSTART_LOOPING){
859 memcpy(device->buffer, buf + avail_bytes, packet_bytes);
860 capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
862 device->state = STATE_STOPPED;
863 capture_CheckNotify(device->capture_buffer, 0, 0);
867 device->write_pos_bytes += avail_bytes + packet_bytes;
868 device->write_pos_bytes %= device->buflen;
870 hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
872 LeaveCriticalSection(&device->lock);
873 WARN("ReleaseBuffer failed: %08x\n", hr);
877 LeaveCriticalSection(&device->lock);
880 static struct _TestFormat {
885 } formats_to_test[] = {
886 { WAVE_FORMAT_1M08, 11025, 8, 1 },
887 { WAVE_FORMAT_1M16, 11025, 16, 1 },
888 { WAVE_FORMAT_1S08, 11025, 8, 2 },
889 { WAVE_FORMAT_1S16, 11025, 16, 2 },
890 { WAVE_FORMAT_2M08, 22050, 8, 1 },
891 { WAVE_FORMAT_2M16, 22050, 16, 1 },
892 { WAVE_FORMAT_2S08, 22050, 8, 2 },
893 { WAVE_FORMAT_2S16, 22050, 16, 2 },
894 { WAVE_FORMAT_4M08, 44100, 8, 1 },
895 { WAVE_FORMAT_4M16, 44100, 16, 1 },
896 { WAVE_FORMAT_4S08, 44100, 8, 2 },
897 { WAVE_FORMAT_4S16, 44100, 16, 2 },
898 { WAVE_FORMAT_48M08, 48000, 8, 1 },
899 { WAVE_FORMAT_48M16, 48000, 16, 1 },
900 { WAVE_FORMAT_48S08, 48000, 8, 2 },
901 { WAVE_FORMAT_48S16, 48000, 16, 2 },
902 { WAVE_FORMAT_96M08, 96000, 8, 1 },
903 { WAVE_FORMAT_96M16, 96000, 16, 1 },
904 { WAVE_FORMAT_96S08, 96000, 8, 2 },
905 { WAVE_FORMAT_96S16, 96000, 16, 2 },
909 static HRESULT DirectSoundCaptureDevice_Initialize(
910 DirectSoundCaptureDevice ** ppDevice,
916 struct _TestFormat *fmt;
917 DirectSoundCaptureDevice *device;
918 IAudioClient *client;
920 TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
922 /* Default device? */
923 if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
924 lpcGUID = &DSDEVID_DefaultCapture;
926 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
927 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
928 return DSERR_NODRIVER;
930 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
931 WARN("invalid parameter: lpcGUID\n");
932 return DSERR_INVALIDPARAM;
935 hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
939 EnterCriticalSection(&DSOUND_capturers_lock);
941 LIST_FOR_EACH_ENTRY(device, &DSOUND_capturers, DirectSoundCaptureDevice, entry){
942 if(IsEqualGUID(&device->guid, &devGUID)){
943 IMMDevice_Release(mmdevice);
944 LeaveCriticalSection(&DSOUND_capturers_lock);
945 return DSERR_ALLOCATED;
949 hr = DirectSoundCaptureDevice_Create(&device);
951 WARN("DirectSoundCaptureDevice_Create failed\n");
952 LeaveCriticalSection(&DSOUND_capturers_lock);
956 device->guid = devGUID;
958 device->mmdevice = mmdevice;
960 device->drvcaps.dwFlags = 0;
962 device->drvcaps.dwFormats = 0;
963 device->drvcaps.dwChannels = 0;
964 hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
965 CLSCTX_INPROC_SERVER, NULL, (void**)&client);
967 device->lock.DebugInfo->Spare[0] = 0;
968 DeleteCriticalSection(&device->lock);
969 HeapFree(GetProcessHeap(), 0, device);
970 LeaveCriticalSection(&DSOUND_capturers_lock);
971 return DSERR_NODRIVER;
974 for(fmt = formats_to_test; fmt->flag; ++fmt){
975 if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
976 device->drvcaps.dwFormats |= fmt->flag;
977 if(fmt->channels > device->drvcaps.dwChannels)
978 device->drvcaps.dwChannels = fmt->channels;
981 IAudioClient_Release(client);
983 device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
985 list_add_tail(&DSOUND_capturers, &device->entry);
989 LeaveCriticalSection(&DSOUND_capturers_lock);
995 /*****************************************************************************
996 * IDirectSoundCapture implementation structure
998 typedef struct IDirectSoundCaptureImpl
1000 IUnknown IUnknown_inner;
1001 IDirectSoundCapture IDirectSoundCapture_iface;
1002 LONG ref, refdsc, numIfaces;
1003 IUnknown *outer_unk; /* internal */
1004 DirectSoundCaptureDevice *device;
1006 } IDirectSoundCaptureImpl;
1008 static void capture_destroy(IDirectSoundCaptureImpl *This)
1011 DirectSoundCaptureDevice_Release(This->device);
1012 HeapFree(GetProcessHeap(),0,This);
1013 TRACE("(%p) released\n", This);
1016 /*******************************************************************************
1017 * IUnknown Implementation for DirectSoundCapture
1019 static inline IDirectSoundCaptureImpl *impl_from_IUnknown(IUnknown *iface)
1021 return CONTAINING_RECORD(iface, IDirectSoundCaptureImpl, IUnknown_inner);
1024 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1026 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1028 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
1031 WARN("invalid parameter\n");
1032 return E_INVALIDARG;
1036 if (IsEqualIID(riid, &IID_IUnknown))
1037 *ppv = &This->IUnknown_inner;
1038 else if (IsEqualIID(riid, &IID_IDirectSoundCapture))
1039 *ppv = &This->IDirectSoundCapture_iface;
1041 WARN("unknown IID %s\n", debugstr_guid(riid));
1042 return E_NOINTERFACE;
1045 IUnknown_AddRef((IUnknown*)*ppv);
1049 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
1051 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1052 ULONG ref = InterlockedIncrement(&This->ref);
1054 TRACE("(%p) ref=%d\n", This, ref);
1057 InterlockedIncrement(&This->numIfaces);
1061 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
1063 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1064 ULONG ref = InterlockedDecrement(&This->ref);
1066 TRACE("(%p) ref=%d\n", This, ref);
1068 if (!ref && !InterlockedDecrement(&This->numIfaces))
1069 capture_destroy(This);
1073 static const IUnknownVtbl unk_vtbl =
1075 IUnknownImpl_QueryInterface,
1076 IUnknownImpl_AddRef,
1077 IUnknownImpl_Release
1080 /***************************************************************************
1081 * IDirectSoundCaptureImpl
1083 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1085 return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1088 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1089 REFIID riid, void **ppv)
1091 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1092 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
1093 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1096 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1098 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1099 ULONG ref = InterlockedIncrement(&This->refdsc);
1101 TRACE("(%p) ref=%d\n", This, ref);
1104 InterlockedIncrement(&This->numIfaces);
1108 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1110 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1111 ULONG ref = InterlockedDecrement(&This->refdsc);
1113 TRACE("(%p) ref=%d\n", This, ref);
1115 if (!ref && !InterlockedDecrement(&This->numIfaces))
1116 capture_destroy(This);
1120 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1121 LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1124 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1127 TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1130 WARN("invalid parameter: pUnk != NULL\n");
1131 return DSERR_NOAGGREGATION;
1134 if (lpcDSCBufferDesc == NULL) {
1135 WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1136 return DSERR_INVALIDPARAM;
1139 if (lplpDSCaptureBuffer == NULL) {
1140 WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1141 return DSERR_INVALIDPARAM;
1145 WARN("invalid parameter: pUnk != NULL\n");
1146 return DSERR_INVALIDPARAM;
1149 /* FIXME: We can only have one buffer so what do we do here? */
1150 if (This->device->capture_buffer) {
1151 WARN("invalid parameter: already has buffer\n");
1152 return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */
1155 hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1156 (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1159 WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1164 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1165 LPDSCCAPS lpDSCCaps)
1167 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1169 TRACE("(%p,%p)\n",This,lpDSCCaps);
1171 if (This->device == NULL) {
1172 WARN("not initialized\n");
1173 return DSERR_UNINITIALIZED;
1176 if (lpDSCCaps== NULL) {
1177 WARN("invalid parameter: lpDSCCaps== NULL\n");
1178 return DSERR_INVALIDPARAM;
1181 if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1182 WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1183 return DSERR_INVALIDPARAM;
1186 lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1187 lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1188 lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1190 TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1191 lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1196 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1199 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1201 TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1203 if (This->device != NULL) {
1204 WARN("already initialized\n");
1205 return DSERR_ALREADYINITIALIZED;
1207 return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1210 static const IDirectSoundCaptureVtbl dscvt =
1212 /* IUnknown methods */
1213 IDirectSoundCaptureImpl_QueryInterface,
1214 IDirectSoundCaptureImpl_AddRef,
1215 IDirectSoundCaptureImpl_Release,
1217 /* IDirectSoundCapture methods */
1218 IDirectSoundCaptureImpl_CreateCaptureBuffer,
1219 IDirectSoundCaptureImpl_GetCaps,
1220 IDirectSoundCaptureImpl_Initialize
1223 HRESULT IDirectSoundCaptureImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_dsc8)
1225 IDirectSoundCaptureImpl *obj;
1228 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1231 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
1233 WARN("out of memory\n");
1234 return DSERR_OUTOFMEMORY;
1237 setup_dsound_options();
1239 obj->IUnknown_inner.lpVtbl = &unk_vtbl;
1240 obj->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1245 obj->has_dsc8 = has_dsc8;
1247 /* COM aggregation supported only internally */
1249 obj->outer_unk = outer_unk;
1251 obj->outer_unk = &obj->IUnknown_inner;
1253 hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
1254 IUnknown_Release(&obj->IUnknown_inner);
1259 HRESULT DSOUND_CaptureCreate(REFIID riid, void **ppv)
1261 return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, FALSE);
1264 HRESULT DSOUND_CaptureCreate8(REFIID riid, void **ppv)
1266 return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, TRUE);
1269 /***************************************************************************
1270 * DirectSoundCaptureCreate [DSOUND.6]
1272 * Create and initialize a DirectSoundCapture interface.
1275 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1276 * lplpDSC [O] Address of a variable to receive the interface pointer.
1277 * pUnkOuter [I] Must be NULL.
1281 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1285 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1286 * or NULL for the default device or DSDEVID_DefaultCapture or
1287 * DSDEVID_DefaultVoiceCapture.
1289 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1291 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1292 IUnknown *pUnkOuter)
1295 IDirectSoundCapture *pDSC;
1297 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1299 if (ppDSC == NULL) {
1300 WARN("invalid parameter: ppDSC == NULL\n");
1301 return DSERR_INVALIDPARAM;
1305 WARN("invalid parameter: pUnkOuter != NULL\n");
1306 return DSERR_NOAGGREGATION;
1309 hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, (void**)&pDSC);
1311 hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1313 IDirectSoundCapture_Release(pDSC);
1323 /***************************************************************************
1324 * DirectSoundCaptureCreate8 [DSOUND.12]
1326 * Create and initialize a DirectSoundCapture interface.
1329 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1330 * lplpDSC [O] Address of a variable to receive the interface pointer.
1331 * pUnkOuter [I] Must be NULL.
1335 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1339 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1340 * or NULL for the default device or DSDEVID_DefaultCapture or
1341 * DSDEVID_DefaultVoiceCapture.
1343 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1345 HRESULT WINAPI DirectSoundCaptureCreate8(
1347 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1348 LPUNKNOWN pUnkOuter)
1351 LPDIRECTSOUNDCAPTURE8 pDSC8;
1352 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1354 if (ppDSC8 == NULL) {
1355 WARN("invalid parameter: ppDSC8 == NULL\n");
1356 return DSERR_INVALIDPARAM;
1360 WARN("invalid parameter: pUnkOuter != NULL\n");
1362 return DSERR_NOAGGREGATION;
1365 hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, (void**)&pDSC8);
1367 hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1369 IDirectSoundCapture_Release(pDSC8);