1 /* DirectSound capture buffer interface
3 * Copyright 2009 Maarten Lankhorst
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #define NONAMELESSSTRUCT
26 #define NONAMELESSUNION
35 #include "wine/debug.h"
38 #include "dsound_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
51 #include "dsound_private.h"
53 #ifndef DSCBPN_OFFSET_STOP
54 #define DSCBPN_OFFSET_STOP 0xffffffff
57 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM
, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
61 typedef struct DSCImpl DSCImpl
;
62 typedef struct DSCBuffer DSCBuffer
;
65 /* IDirectSoundCapture and IDirectSoundCapture8 are aliases */
66 IDirectSoundCapture IDirectSoundCapture_iface
;
72 CRITICAL_SECTION crst
;
76 IDirectSoundCaptureBuffer8 IDirectSoundCaptureBuffer8_iface
;
77 IDirectSoundNotify IDirectSoundNotify_iface
;
89 DSBPOSITIONNOTIFY
*notify
;
98 BOOL playing
, looping
;
101 static const IDirectSoundCaptureVtbl DSC_Vtbl
;
102 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl
;
103 static const IDirectSoundNotifyVtbl DSCNot_Vtbl
;
105 static void DSCImpl_Destroy(DSCImpl
*This
);
107 static void trigger_notifies(DSCBuffer
*buf
, DWORD lastpos
, DWORD curpos
)
111 if(lastpos
== curpos
)
114 for(i
= 0;i
< buf
->nnotify
;++i
)
116 DSBPOSITIONNOTIFY
*not = &buf
->notify
[i
];
117 HANDLE event
= not->hEventNotify
;
118 DWORD ofs
= not->dwOffset
;
120 if (ofs
== DSCBPN_OFFSET_STOP
)
123 /* Wraparound case */
126 if(ofs
< curpos
|| ofs
>= lastpos
)
128 TRACE("Triggering notification %"LONGFMT
"u (%"LONGFMT
"u) from buffer %p\n", i
, ofs
, buf
);
135 if(ofs
>= lastpos
&& ofs
< curpos
)
137 TRACE("Triggering notification %"LONGFMT
"u (%"LONGFMT
"u) from buffer %p\n", i
, ofs
, buf
);
143 static DWORD CALLBACK
DSCBuffer_thread(void *param
)
145 DSCImpl
*This
= param
;
150 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL
);
152 while(GetMessageA(&msg
, NULL
, 0, 0))
154 if(msg
.message
!= WM_USER
)
159 alcGetIntegerv(buf
->dev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
163 EnterCriticalSection(&This
->crst
);
165 avail
*= buf
->format
->nBlockAlign
;
166 if(avail
+ buf
->pos
> buf
->buf_size
)
167 avail
= buf
->buf_size
- buf
->pos
;
169 alcCaptureSamples(buf
->dev
, buf
->buf
+ buf
->pos
, avail
/buf
->format
->nBlockAlign
);
170 trigger_notifies(buf
, buf
->pos
, buf
->pos
+ avail
);
173 if(buf
->pos
== buf
->buf_size
)
177 IDirectSoundCaptureBuffer8_Stop(&buf
->IDirectSoundCaptureBuffer8_iface
);
180 alcGetIntegerv(buf
->dev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
181 if(avail
) goto more_samples
;
185 LeaveCriticalSection(&This
->crst
);
192 static void CALLBACK
DSCBuffer_timer(UINT timerID
, UINT msg
, DWORD_PTR dwUser
,
193 DWORD_PTR dw1
, DWORD_PTR dw2
)
199 PostThreadMessageA(dwUser
, WM_USER
, 0, 0);
202 static void DSCBuffer_starttimer(DSCBuffer
*This
)
205 ALint refresh
= FAKE_REFRESH_COUNT
;
206 DWORD triggertime
, res
= DS_TIME_RES
;
211 timeGetDevCaps(&time
, sizeof(TIMECAPS
));
212 triggertime
= 1000 / refresh
;
213 if (triggertime
< time
.wPeriodMin
)
214 triggertime
= time
.wPeriodMin
;
215 TRACE("Calling timer every %"LONGFMT
"u ms for %i refreshes per second\n", triggertime
, refresh
);
216 if (res
< time
.wPeriodMin
)
217 res
= time
.wPeriodMin
;
218 if (timeBeginPeriod(res
) == TIMERR_NOCANDO
)
219 WARN("Could not set minimum resolution, don't expect sound\n");
220 This
->timer_res
= res
;
221 This
->timer_id
= timeSetEvent(triggertime
, res
, DSCBuffer_timer
, This
->thread_id
, TIME_PERIODIC
|TIME_KILL_SYNCHRONOUS
);
224 static HRESULT
DSCBuffer_Create(DSCBuffer
**buf
, DSCImpl
*parent
)
226 DSCBuffer
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
227 if(!This
) return E_OUTOFMEMORY
;
229 This
->IDirectSoundCaptureBuffer8_iface
.lpVtbl
= (IDirectSoundCaptureBuffer8Vtbl
*)&DSCBuffer_Vtbl
;
230 This
->IDirectSoundNotify_iface
.lpVtbl
= (IDirectSoundNotifyVtbl
*)&DSCNot_Vtbl
;
232 This
->all_ref
= This
->ref
= 1;
234 This
->parent
= parent
;
236 This
->thread_hdl
= CreateThread(NULL
, 0, DSCBuffer_thread
, This
->parent
, 0, &This
->thread_id
);
237 if(This
->thread_hdl
== NULL
)
239 HeapFree(GetProcessHeap(), 0, This
);
240 return DSERR_OUTOFMEMORY
;
247 static void DSCBuffer_Destroy(DSCBuffer
*This
)
251 timeKillEvent(This
->timer_id
);
252 timeEndPeriod(This
->timer_res
);
256 PostThreadMessageA(This
->thread_id
, WM_QUIT
, 0, 0);
257 if(WaitForSingleObject(This
->thread_hdl
, 1000) != WAIT_OBJECT_0
)
258 ERR("Thread wait timed out");
259 CloseHandle(This
->thread_hdl
);
265 alcCaptureStop(This
->dev
);
266 alcCaptureCloseDevice(This
->dev
);
268 This
->parent
->buf
= NULL
;
270 HeapFree(GetProcessHeap(), 0, This
->notify
);
271 HeapFree(GetProcessHeap(), 0, This
->format
);
272 HeapFree(GetProcessHeap(), 0, This
->buf
);
273 HeapFree(GetProcessHeap(), 0, This
);
276 static inline DSCBuffer
*impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8
*iface
)
278 return CONTAINING_RECORD(iface
, DSCBuffer
, IDirectSoundCaptureBuffer8_iface
);
281 static HRESULT WINAPI
DSCBuffer_QueryInterface(IDirectSoundCaptureBuffer8
*iface
, REFIID riid
, void **ppv
)
283 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
285 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
291 if (IsEqualIID(riid
, &IID_IDirectSoundNotify
))
292 *ppv
= &This
->IDirectSoundNotify_iface
;
293 else if (IsEqualIID(riid
, &IID_IUnknown
) ||
294 IsEqualIID(riid
, &IID_IDirectSoundCaptureBuffer
) ||
295 IsEqualIID(riid
, &IID_IDirectSoundCaptureBuffer8
))
296 *ppv
= &This
->IDirectSoundCaptureBuffer8_iface
;
299 return E_NOINTERFACE
;
300 IUnknown_AddRef((IUnknown
*)*ppv
);
304 static ULONG WINAPI
DSCBuffer_AddRef(IDirectSoundCaptureBuffer8
*iface
)
306 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
309 InterlockedIncrement(&This
->all_ref
);
310 ref
= InterlockedIncrement(&This
->ref
);
311 TRACE("Reference count incremented to %"LONGFMT
"i\n", ref
);
316 static ULONG WINAPI
DSCBuffer_Release(IDirectSoundCaptureBuffer8
*iface
)
318 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
321 ref
= InterlockedDecrement(&This
->ref
);
322 TRACE("Reference count decremented to %"LONGFMT
"i\n", ref
);
323 if(InterlockedDecrement(&This
->all_ref
) == 0)
324 DSCBuffer_Destroy(This
);
329 static HRESULT WINAPI
DSCBuffer_GetCaps(IDirectSoundCaptureBuffer8
*iface
, DSCBCAPS
*caps
)
331 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
333 if (!caps
|| caps
->dwSize
< sizeof(*caps
))
334 return DSERR_INVALIDPARAM
;
335 caps
->dwSize
= sizeof(*caps
);
337 caps
->dwBufferBytes
= This
->buf_size
;
341 static HRESULT WINAPI
DSCBuffer_GetCurrentPosition(IDirectSoundCaptureBuffer8
*iface
, DWORD
*cappos
, DWORD
*readpos
)
343 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
346 EnterCriticalSection(&This
->parent
->crst
);
350 pos2
= This
->format
->nSamplesPerSec
/ 100;
351 pos2
*= This
->format
->nBlockAlign
;
353 if (!This
->looping
&& pos2
>= This
->buf_size
)
356 pos2
%= This
->buf_size
;
360 LeaveCriticalSection(&This
->parent
->crst
);
362 if(cappos
) *cappos
= pos1
;
363 if(readpos
) *readpos
= pos2
;
368 static HRESULT WINAPI
DSCBuffer_GetFormat(IDirectSoundCaptureBuffer8
*iface
, WAVEFORMATEX
*wfx
, DWORD size
, DWORD
*written
)
370 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
372 TRACE("(%p)->(%p, %"LONGFMT
"u, %p)\n", iface
, wfx
, size
, written
);
374 if (size
> sizeof(WAVEFORMATEX
) + This
->format
->cbSize
)
375 size
= sizeof(WAVEFORMATEX
) + This
->format
->cbSize
;
379 CopyMemory(wfx
, This
->format
, size
);
384 *written
= sizeof(WAVEFORMATEX
) + This
->format
->cbSize
;
386 return DSERR_INVALIDPARAM
;
391 static HRESULT WINAPI
DSCBuffer_GetStatus(IDirectSoundCaptureBuffer8
*iface
, DWORD
*status
)
393 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
395 TRACE("(%p)->(%p)\n", iface
, status
);
398 return DSERR_INVALIDPARAM
;
399 EnterCriticalSection(&This
->parent
->crst
);
403 *status
|= DSCBSTATUS_CAPTURING
;
405 *status
|= DSCBSTATUS_LOOPING
;
407 LeaveCriticalSection(&This
->parent
->crst
);
412 static HRESULT WINAPI
DSCBuffer_Initialize(IDirectSoundCaptureBuffer8
*iface
, IDirectSoundCapture
*parent
, const DSCBUFFERDESC
*desc
)
414 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
415 WAVEFORMATEX
*format
;
416 ALenum buf_format
= -1;
418 TRACE("(%p)->(%p, %p)\n", iface
, parent
, desc
);
421 return DSERR_ALREADYINITIALIZED
;
423 if (!desc
->lpwfxFormat
)
424 return DSERR_INVALIDPARAM
;
426 format
= desc
->lpwfxFormat
;
427 if (format
->nChannels
> 2)
429 WARN("nChannels > 2 not supported for recording\n");
430 return DSERR_INVALIDPARAM
;
434 This
->format
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE
));
436 return DSERR_OUTOFMEMORY
;
438 if (format
->wFormatTag
== WAVE_FORMAT_PCM
||
439 format
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
441 if (format
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
443 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)format
;
444 if (format
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
))
445 return DSERR_INVALIDPARAM
;
446 else if (format
->cbSize
> sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
)
447 && format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
))
448 return DSERR_CONTROLUNAVAIL
;
449 else if (!IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))
450 return DSERR_BADFORMAT
;
453 if (format
->nChannels
== 1)
455 switch (format
->wBitsPerSample
)
457 case 8: buf_format
= AL_FORMAT_MONO8
; break;
458 case 16: buf_format
= AL_FORMAT_MONO16
; break;
460 WARN("Unsupported bpp %u\n", format
->wBitsPerSample
);
461 return DSERR_BADFORMAT
;
464 else if (format
->nChannels
== 2)
466 switch (format
->wBitsPerSample
)
468 case 8: buf_format
= AL_FORMAT_STEREO8
; break;
469 case 16: buf_format
= AL_FORMAT_STEREO16
; break;
471 WARN("Unsupported bpp %u\n", format
->wBitsPerSample
);
472 return DSERR_BADFORMAT
;
475 memcpy(This
->format
, format
, sizeof(*format
) + format
->cbSize
);
476 if (format
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
477 This
->format
->cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
479 This
->format
->cbSize
= 0;
480 This
->format
->nBlockAlign
= This
->format
->wBitsPerSample
* This
->format
->nChannels
/ 8;
481 This
->format
->nAvgBytesPerSec
= This
->format
->nSamplesPerSec
* This
->format
->nBlockAlign
;
483 else if (format
->wFormatTag
)
484 WARN("Unhandled formattag %x\n", format
->wFormatTag
);
486 This
->buf_size
= desc
->dwBufferBytes
;
489 WARN("Could not get OpenAL format\n");
490 return DSERR_INVALIDPARAM
;
493 This
->dev
= alcCaptureOpenDevice(This
->parent
->device
, This
->format
->nSamplesPerSec
, buf_format
, This
->buf_size
/ This
->format
->nBlockAlign
);
496 ERR("couldn't open device %s %x@%"LONGFMT
"u, reason: %04x\n", This
->parent
->device
, buf_format
, This
->format
->nSamplesPerSec
, alcGetError(NULL
));
497 return DSERR_INVALIDPARAM
;
500 This
->buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->buf_size
);
503 alcCaptureCloseDevice(This
->dev
);
504 WARN("Out of memory\n");
505 return DSERR_INVALIDPARAM
;
511 static HRESULT WINAPI
DSCBuffer_Lock(IDirectSoundCaptureBuffer8
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
513 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
517 TRACE("(%p)->(%"LONGFMT
"u, %"LONGFMT
"u, %p, %p, %p, %p, %#"LONGFMT
"x)\n", iface
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
519 EnterCriticalSection(&This
->parent
->crst
);
520 hr
= DSERR_INVALIDPARAM
;
522 if(ptr1
) *ptr1
= NULL
;
524 if(ptr2
) *ptr2
= NULL
;
527 if (ofs
>= This
->buf_size
)
529 WARN("Invalid ofs %"LONGFMT
"u\n", ofs
);
534 WARN("Invalid pointer/len %p %p\n", ptr1
, len1
);
537 if((flags
&DSCBLOCK_ENTIREBUFFER
))
538 bytes
= This
->buf_size
;
539 else if(bytes
> This
->buf_size
)
541 WARN("Invalid size %"LONGFMT
"u\n", bytes
);
545 if (ofs
+ bytes
>= This
->buf_size
)
547 *len1
= This
->buf_size
- ofs
;
548 remain
= bytes
- *len1
;
555 *ptr1
= This
->buf
+ ofs
;
557 if (ptr2
&& len2
&& remain
)
565 LeaveCriticalSection(&This
->parent
->crst
);
569 static HRESULT WINAPI
DSCBuffer_Start(IDirectSoundCaptureBuffer8
*iface
, DWORD flags
)
571 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
573 TRACE("(%p)->(%08"LONGFMT
"x)\n", iface
, flags
);
575 EnterCriticalSection(&This
->parent
->crst
);
578 DSCBuffer_starttimer(This
);
580 alcCaptureStart(This
->dev
);
582 This
->looping
= !!(flags
& DSCBSTART_LOOPING
);
583 LeaveCriticalSection(&This
->parent
->crst
);
587 static HRESULT WINAPI
DSCBuffer_Stop(IDirectSoundCaptureBuffer8
*iface
)
589 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
591 TRACE("(%p)->()\n", iface
);
593 EnterCriticalSection(&This
->parent
->crst
);
597 for(i
= 0;i
< This
->nnotify
;++i
)
599 if(This
->notify
[i
].dwOffset
== DSCBPN_OFFSET_STOP
)
600 SetEvent(This
->notify
[i
].hEventNotify
);
603 This
->playing
= This
->looping
= 0;
604 alcCaptureStop(This
->dev
);
606 LeaveCriticalSection(&This
->parent
->crst
);
610 static HRESULT WINAPI
DSCBuffer_Unlock(IDirectSoundCaptureBuffer8
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
612 TRACE("(%p)->(%p, %"LONGFMT
"u, %p, %"LONGFMT
"u)\n", iface
, ptr1
, len1
, ptr2
, len2
);
615 return DSERR_INVALIDPARAM
;
619 static HRESULT WINAPI
DSCBuffer_GetObjectInPath(IDirectSoundCaptureBuffer8
*iface
, REFGUID guid
, DWORD num
, REFGUID riid
, void **ppv
)
621 FIXME("(%p)->(%s, %"LONGFMT
"u, %s, %p) stub\n", iface
, debugstr_guid(guid
), num
, debugstr_guid(riid
), ppv
);
625 static HRESULT WINAPI
DSCBuffer_GetFXStatus(IDirectSoundCaptureBuffer8
*iface
, DWORD count
, DWORD
*status
)
627 FIXME("(%p)->(%"LONGFMT
"u, %p) stub\n", iface
, count
, status
);
631 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl
=
633 DSCBuffer_QueryInterface
,
637 DSCBuffer_GetCurrentPosition
,
640 DSCBuffer_Initialize
,
645 DSCBuffer_GetObjectInPath
,
646 DSCBuffer_GetFXStatus
649 static inline DSCBuffer
*impl_from_IDirectSoundNotify(IDirectSoundNotify
*iface
)
651 return CONTAINING_RECORD(iface
, DSCBuffer
, IDirectSoundNotify_iface
);
654 static HRESULT WINAPI
DSCBufferNot_QueryInterface(IDirectSoundNotify
*iface
, REFIID riid
, void **ppv
)
656 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
657 return IDirectSoundCaptureBuffer_QueryInterface((IDirectSoundCaptureBuffer
*)This
, riid
, ppv
);
660 static ULONG WINAPI
DSCBufferNot_AddRef(IDirectSoundNotify
*iface
)
662 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
665 InterlockedIncrement(&This
->all_ref
);
666 ret
= InterlockedIncrement(&This
->not_ref
);
667 TRACE("new refcount %"LONGFMT
"d\n", ret
);
671 static ULONG WINAPI
DSCBufferNot_Release(IDirectSoundNotify
*iface
)
673 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
676 ret
= InterlockedDecrement(&This
->not_ref
);
677 TRACE("new refcount %"LONGFMT
"d\n", ret
);
678 if(InterlockedDecrement(&This
->all_ref
) == 0)
679 DSCBuffer_Destroy(This
);
684 static HRESULT WINAPI
DSCBufferNot_SetNotificationPositions(IDirectSoundNotify
*iface
, DWORD count
, const DSBPOSITIONNOTIFY
*notifications
)
686 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
687 DSBPOSITIONNOTIFY
*nots
;
691 TRACE("(%p)->(%"LONGFMT
"u, %p))\n", iface
, count
, notifications
);
693 EnterCriticalSection(&This
->parent
->crst
);
694 hr
= DSERR_INVALIDPARAM
;
695 if (count
&& !notifications
)
698 hr
= DSCBuffer_GetStatus(&This
->IDirectSoundCaptureBuffer8_iface
, &state
);
702 hr
= DSERR_INVALIDCALL
;
703 if (state
& DSCBSTATUS_CAPTURING
)
708 HeapFree(GetProcessHeap(), 0, This
->notify
);
715 hr
= DSERR_INVALIDPARAM
;
716 for (i
= 0; i
< count
; ++i
)
718 if (notifications
[i
].dwOffset
>= This
->buf_size
719 && notifications
[i
].dwOffset
!= DSCBPN_OFFSET_STOP
)
723 nots
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(*nots
));
726 memcpy(nots
, notifications
, count
*sizeof(*nots
));
727 HeapFree(GetProcessHeap(), 0, This
->notify
);
729 This
->nnotify
= count
;
734 LeaveCriticalSection(&This
->parent
->crst
);
738 static const IDirectSoundNotifyVtbl DSCNot_Vtbl
=
740 DSCBufferNot_QueryInterface
,
742 DSCBufferNot_Release
,
743 DSCBufferNot_SetNotificationPositions
747 static inline DSCImpl
*impl_from_IDirectSoundCapture(IDirectSoundCapture
*iface
)
749 return CONTAINING_RECORD(iface
, DSCImpl
, IDirectSoundCapture_iface
);
752 HRESULT
DSOUND_CaptureCreate(REFIID riid
, void **cap
)
758 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
759 if(!This
) return DSERR_OUTOFMEMORY
;
761 This
->IDirectSoundCapture_iface
.lpVtbl
= (IDirectSoundCaptureVtbl
*)&DSC_Vtbl
;
763 InitializeCriticalSection(&This
->crst
);
764 This
->crst
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DSCImpl.crst");
766 if(FAILED(IDirectSoundCapture_QueryInterface(&This
->IDirectSoundCapture_iface
, riid
, cap
)))
768 DSCImpl_Destroy(This
);
769 return E_NOINTERFACE
;
774 static void DSCImpl_Destroy(DSCImpl
*This
)
776 EnterCriticalSection(&This
->crst
);
778 DSCBuffer_Destroy(This
->buf
);
779 LeaveCriticalSection(&This
->crst
);
781 HeapFree(GetProcessHeap(), 0, This
->device
);
783 This
->crst
.DebugInfo
->Spare
[0] = 0;
784 DeleteCriticalSection(&This
->crst
);
786 HeapFree(GetProcessHeap(), 0, This
);
789 static HRESULT WINAPI
DSCImpl_QueryInterface(IDirectSoundCapture
*iface
, REFIID riid
, void **ppv
)
791 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
793 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
796 if(IsEqualIID(riid
, &IID_IUnknown
) ||
797 IsEqualIID(riid
, &IID_IDirectSoundCapture
))
798 *ppv
= &This
->IDirectSoundCapture_iface
;
800 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
804 IUnknown_AddRef((IUnknown
*)*ppv
);
808 return E_NOINTERFACE
;
811 static ULONG WINAPI
DSCImpl_AddRef(IDirectSoundCapture
*iface
)
813 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
816 ref
= InterlockedIncrement(&This
->ref
);
817 TRACE("Reference count incremented to %"LONGFMT
"i\n", ref
);
822 static ULONG WINAPI
DSCImpl_Release(IDirectSoundCapture
*iface
)
824 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
827 ref
= InterlockedDecrement(&This
->ref
);
828 TRACE("Reference count decremented to %"LONGFMT
"i\n", ref
);
830 DSCImpl_Destroy(This
);
835 static HRESULT WINAPI
DSCImpl_CreateCaptureBuffer(IDirectSoundCapture
*iface
, const DSCBUFFERDESC
*desc
, IDirectSoundCaptureBuffer
**ppv
, IUnknown
*unk
)
837 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
840 TRACE("(%p)->(%p, %p, %p)\n", iface
, desc
, ppv
, unk
);
844 WARN("Aggregation isn't supported\n");
845 return DSERR_NOAGGREGATION
;
848 if(!desc
|| desc
->dwSize
< sizeof(DSCBUFFERDESC1
))
850 WARN("Passed invalid description %p %"LONGFMT
"u\n", desc
, desc
?desc
->dwSize
:0);
851 return DSERR_INVALIDPARAM
;
855 WARN("Passed null pointer\n");
856 return DSERR_INVALIDPARAM
;
860 EnterCriticalSection(&This
->crst
);
863 hr
= DSERR_UNINITIALIZED
;
864 WARN("Not initialized\n");
869 hr
= DSERR_ALLOCATED
;
870 WARN("Capture buffer already allocated\n");
874 hr
= DSCBuffer_Create(&This
->buf
, This
);
877 hr
= IDirectSoundCaptureBuffer8_Initialize(&This
->buf
->IDirectSoundCaptureBuffer8_iface
, iface
, desc
);
879 *ppv
= (IDirectSoundCaptureBuffer
*)&This
->buf
->IDirectSoundCaptureBuffer8_iface
;
882 DSCBuffer_Destroy(This
->buf
);
888 LeaveCriticalSection(&This
->crst
);
892 static HRESULT WINAPI
DSCImpl_GetCaps(IDirectSoundCapture
*iface
, DSCCAPS
*caps
)
894 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
896 TRACE("(%p)->(%p)\n", iface
, caps
);
899 WARN("Not initialized\n");
900 return DSERR_UNINITIALIZED
;
904 WARN("Caps is null\n");
905 return DSERR_INVALIDPARAM
;
907 if(caps
->dwSize
< sizeof(*caps
)) {
908 WARN("Invalid size %"LONGFMT
"d\n", caps
->dwSize
);
909 return DSERR_INVALIDPARAM
;
913 /* Support all WAVE_FORMAT formats specified in mmsystem.h */
914 caps
->dwFormats
= 0x000fffff;
915 caps
->dwChannels
= 2;
920 static HRESULT WINAPI
DSCImpl_Initialize(IDirectSoundCapture
*iface
, const GUID
*devguid
)
922 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
924 const ALCchar
*devs
, *drv_name
;
928 TRACE("(%p)->(%p)\n", iface
, devguid
);
932 ERR("OpenAL not loaded!\n");
933 return DSERR_NODRIVER
;
937 WARN("Already initialized\n");
938 return DSERR_ALREADYINITIALIZED
;
941 if(!devguid
|| IsEqualGUID(devguid
, &GUID_NULL
))
942 devguid
= &DSDEVID_DefaultCapture
;
944 hr
= GetDeviceID(devguid
, &guid
);
946 return DSERR_INVALIDPARAM
;
949 EnterCriticalSection(&This
->crst
);
950 EnterCriticalSection(&openal_crst
);
951 devs
= DSOUND_getcapturedevicestrings();
955 if(memcmp(devguid
, &DSOUND_capture_guid
, sizeof(GUID
)-1) ||
958 WARN("No driver found\n");
964 const ALCchar
*str
= devs
;
967 str
+= strlen(str
) + 1;
970 WARN("No driver string found\n");
979 This
->device
= HeapAlloc(GetProcessHeap(), 0, strlen(drv_name
)+1);
982 WARN("Out of memory to allocate %s\n", drv_name
);
985 strcpy(This
->device
, drv_name
);
989 LeaveCriticalSection(&openal_crst
);
990 LeaveCriticalSection(&This
->crst
);
994 static const IDirectSoundCaptureVtbl DSC_Vtbl
=
996 DSCImpl_QueryInterface
,
999 DSCImpl_CreateCaptureBuffer
,