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
;
87 WAVEFORMATEXTENSIBLE format
;
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
.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
.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
->buf
);
272 HeapFree(GetProcessHeap(), 0, This
);
275 static inline DSCBuffer
*impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8
*iface
)
277 return CONTAINING_RECORD(iface
, DSCBuffer
, IDirectSoundCaptureBuffer8_iface
);
280 static HRESULT WINAPI
DSCBuffer_QueryInterface(IDirectSoundCaptureBuffer8
*iface
, REFIID riid
, void **ppv
)
282 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
284 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
290 if (IsEqualIID(riid
, &IID_IDirectSoundNotify
))
291 *ppv
= &This
->IDirectSoundNotify_iface
;
292 else if (IsEqualIID(riid
, &IID_IUnknown
) ||
293 IsEqualIID(riid
, &IID_IDirectSoundCaptureBuffer
) ||
294 IsEqualIID(riid
, &IID_IDirectSoundCaptureBuffer8
))
295 *ppv
= &This
->IDirectSoundCaptureBuffer8_iface
;
298 return E_NOINTERFACE
;
299 IUnknown_AddRef((IUnknown
*)*ppv
);
303 static ULONG WINAPI
DSCBuffer_AddRef(IDirectSoundCaptureBuffer8
*iface
)
305 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
308 InterlockedIncrement(&This
->all_ref
);
309 ref
= InterlockedIncrement(&This
->ref
);
310 TRACE("Reference count incremented to %"LONGFMT
"i\n", ref
);
315 static ULONG WINAPI
DSCBuffer_Release(IDirectSoundCaptureBuffer8
*iface
)
317 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
320 ref
= InterlockedDecrement(&This
->ref
);
321 TRACE("Reference count decremented to %"LONGFMT
"i\n", ref
);
322 if(InterlockedDecrement(&This
->all_ref
) == 0)
323 DSCBuffer_Destroy(This
);
328 static HRESULT WINAPI
DSCBuffer_GetCaps(IDirectSoundCaptureBuffer8
*iface
, DSCBCAPS
*caps
)
330 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
332 if (!caps
|| caps
->dwSize
< sizeof(*caps
))
333 return DSERR_INVALIDPARAM
;
334 caps
->dwSize
= sizeof(*caps
);
336 caps
->dwBufferBytes
= This
->buf_size
;
340 static HRESULT WINAPI
DSCBuffer_GetCurrentPosition(IDirectSoundCaptureBuffer8
*iface
, DWORD
*cappos
, DWORD
*readpos
)
342 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
345 EnterCriticalSection(&This
->parent
->crst
);
349 pos2
= This
->format
.Format
.nSamplesPerSec
/ 100;
350 pos2
*= This
->format
.Format
.nBlockAlign
;
352 if (!This
->looping
&& pos2
>= This
->buf_size
)
355 pos2
%= This
->buf_size
;
359 LeaveCriticalSection(&This
->parent
->crst
);
361 if(cappos
) *cappos
= pos1
;
362 if(readpos
) *readpos
= pos2
;
367 static HRESULT WINAPI
DSCBuffer_GetFormat(IDirectSoundCaptureBuffer8
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
369 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
373 TRACE("(%p)->(%p, %"LONGFMT
"u, %p)\n", iface
, wfx
, allocated
, written
);
377 WARN("Cannot report format or format size\n");
378 return DSERR_INVALIDPARAM
;
381 size
= sizeof(This
->format
.Format
) + This
->format
.Format
.cbSize
;
385 hr
= DSERR_INVALIDPARAM
;
387 memcpy(wfx
, &This
->format
.Format
, size
);
395 static HRESULT WINAPI
DSCBuffer_GetStatus(IDirectSoundCaptureBuffer8
*iface
, DWORD
*status
)
397 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
399 TRACE("(%p)->(%p)\n", iface
, status
);
402 return DSERR_INVALIDPARAM
;
403 EnterCriticalSection(&This
->parent
->crst
);
407 *status
|= DSCBSTATUS_CAPTURING
;
409 *status
|= DSCBSTATUS_LOOPING
;
411 LeaveCriticalSection(&This
->parent
->crst
);
416 static HRESULT WINAPI
DSCBuffer_Initialize(IDirectSoundCaptureBuffer8
*iface
, IDirectSoundCapture
*parent
, const DSCBUFFERDESC
*desc
)
418 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
419 WAVEFORMATEX
*format
;
420 ALenum buf_format
= -1;
422 TRACE("(%p)->(%p, %p)\n", iface
, parent
, desc
);
425 return DSERR_ALREADYINITIALIZED
;
427 if (!desc
->lpwfxFormat
)
428 return DSERR_INVALIDPARAM
;
430 format
= desc
->lpwfxFormat
;
431 if(format
->nChannels
> 2)
433 WARN("nChannels > 2 not supported for recording\n");
434 return DSERR_INVALIDPARAM
;
437 if(format
->wFormatTag
== WAVE_FORMAT_PCM
)
439 if(format
->nChannels
== 1)
441 switch(format
->wBitsPerSample
)
443 case 8: buf_format
= AL_FORMAT_MONO8
; break;
444 case 16: buf_format
= AL_FORMAT_MONO16
; break;
446 WARN("Unsupported bpp %u\n", format
->wBitsPerSample
);
447 return DSERR_BADFORMAT
;
450 else if(format
->nChannels
== 2)
452 switch(format
->wBitsPerSample
)
454 case 8: buf_format
= AL_FORMAT_STEREO8
; break;
455 case 16: buf_format
= AL_FORMAT_STEREO16
; break;
457 WARN("Unsupported bpp %u\n", format
->wBitsPerSample
);
458 return DSERR_BADFORMAT
;
462 WARN("Unsupported channels: %d\n", format
->nChannels
);
464 memcpy(&This
->format
.Format
, format
, sizeof(This
->format
.Format
));
465 This
->format
.Format
.nBlockAlign
= This
->format
.Format
.wBitsPerSample
* This
->format
.Format
.nChannels
/ 8;
466 This
->format
.Format
.nAvgBytesPerSec
= This
->format
.Format
.nSamplesPerSec
* This
->format
.Format
.nBlockAlign
;
467 This
->format
.Format
.cbSize
= 0;
469 else if(format
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
471 WAVEFORMATEXTENSIBLE
*wfe
;
473 if(format
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
))
474 return DSERR_INVALIDPARAM
;
475 else if(format
->cbSize
> sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
) &&
476 format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
))
477 return DSERR_CONTROLUNAVAIL
;
479 wfe
= CONTAINING_RECORD(format
, WAVEFORMATEXTENSIBLE
, Format
);
480 if(!IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))
481 return DSERR_BADFORMAT
;
482 if(wfe
->Samples
.wValidBitsPerSample
&&
483 wfe
->Samples
.wValidBitsPerSample
!= wfe
->Format
.wBitsPerSample
)
484 return DSERR_BADFORMAT
;
486 if(wfe
->Format
.nChannels
== 1 && wfe
->dwChannelMask
== SPEAKER_FRONT_CENTER
)
488 switch(wfe
->Format
.wBitsPerSample
)
490 case 8: buf_format
= AL_FORMAT_MONO8
; break;
491 case 16: buf_format
= AL_FORMAT_MONO16
; break;
493 WARN("Unsupported bpp %u\n", wfe
->Format
.wBitsPerSample
);
494 return DSERR_BADFORMAT
;
497 else if(wfe
->Format
.nChannels
== 2 && wfe
->dwChannelMask
== (SPEAKER_FRONT_LEFT
|SPEAKER_FRONT_RIGHT
))
499 switch(wfe
->Format
.wBitsPerSample
)
501 case 8: buf_format
= AL_FORMAT_STEREO8
; break;
502 case 16: buf_format
= AL_FORMAT_STEREO16
; break;
504 WARN("Unsupported bpp %u\n", wfe
->Format
.wBitsPerSample
);
505 return DSERR_BADFORMAT
;
509 WARN("Unsupported channels: %d -- 0x%08"LONGFMT
"u\n", wfe
->Format
.nChannels
, wfe
->dwChannelMask
);
511 memcpy(&This
->format
, wfe
, sizeof(This
->format
));
512 This
->format
.Format
.cbSize
= sizeof(This
->format
) - sizeof(This
->format
.Format
);
513 This
->format
.Format
.nBlockAlign
= This
->format
.Format
.wBitsPerSample
* This
->format
.Format
.nChannels
/ 8;
514 This
->format
.Format
.nAvgBytesPerSec
= This
->format
.Format
.nSamplesPerSec
* This
->format
.Format
.nBlockAlign
;
517 WARN("Unhandled formattag %x\n", format
->wFormatTag
);
521 WARN("Could not get OpenAL format\n");
522 return DSERR_INVALIDPARAM
;
525 This
->buf_size
= desc
->dwBufferBytes
;
526 This
->buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->buf_size
);
529 WARN("Out of memory\n");
530 return DSERR_INVALIDPARAM
;
533 This
->dev
= alcCaptureOpenDevice(This
->parent
->device
, This
->format
.Format
.nSamplesPerSec
, buf_format
, This
->buf_size
/ This
->format
.Format
.nBlockAlign
);
536 ERR("Couldn't open device %s 0x%x@%"LONGFMT
"u, reason: %04x\n", This
->parent
->device
, buf_format
, This
->format
.Format
.nSamplesPerSec
, alcGetError(NULL
));
537 return DSERR_INVALIDPARAM
;
543 static HRESULT WINAPI
DSCBuffer_Lock(IDirectSoundCaptureBuffer8
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
545 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
549 TRACE("(%p)->(%"LONGFMT
"u, %"LONGFMT
"u, %p, %p, %p, %p, %#"LONGFMT
"x)\n", iface
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
551 EnterCriticalSection(&This
->parent
->crst
);
552 hr
= DSERR_INVALIDPARAM
;
554 if(ptr1
) *ptr1
= NULL
;
556 if(ptr2
) *ptr2
= NULL
;
559 if (ofs
>= This
->buf_size
)
561 WARN("Invalid ofs %"LONGFMT
"u\n", ofs
);
566 WARN("Invalid pointer/len %p %p\n", ptr1
, len1
);
569 if((flags
&DSCBLOCK_ENTIREBUFFER
))
570 bytes
= This
->buf_size
;
571 else if(bytes
> This
->buf_size
)
573 WARN("Invalid size %"LONGFMT
"u\n", bytes
);
577 if (ofs
+ bytes
>= This
->buf_size
)
579 *len1
= This
->buf_size
- ofs
;
580 remain
= bytes
- *len1
;
587 *ptr1
= This
->buf
+ ofs
;
589 if (ptr2
&& len2
&& remain
)
597 LeaveCriticalSection(&This
->parent
->crst
);
601 static HRESULT WINAPI
DSCBuffer_Start(IDirectSoundCaptureBuffer8
*iface
, DWORD flags
)
603 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
605 TRACE("(%p)->(%08"LONGFMT
"x)\n", iface
, flags
);
607 EnterCriticalSection(&This
->parent
->crst
);
610 DSCBuffer_starttimer(This
);
612 alcCaptureStart(This
->dev
);
614 This
->looping
= !!(flags
& DSCBSTART_LOOPING
);
615 LeaveCriticalSection(&This
->parent
->crst
);
619 static HRESULT WINAPI
DSCBuffer_Stop(IDirectSoundCaptureBuffer8
*iface
)
621 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
623 TRACE("(%p)->()\n", iface
);
625 EnterCriticalSection(&This
->parent
->crst
);
629 for(i
= 0;i
< This
->nnotify
;++i
)
631 if(This
->notify
[i
].dwOffset
== DSCBPN_OFFSET_STOP
)
632 SetEvent(This
->notify
[i
].hEventNotify
);
635 This
->playing
= This
->looping
= 0;
636 alcCaptureStop(This
->dev
);
638 LeaveCriticalSection(&This
->parent
->crst
);
642 static HRESULT WINAPI
DSCBuffer_Unlock(IDirectSoundCaptureBuffer8
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
644 TRACE("(%p)->(%p, %"LONGFMT
"u, %p, %"LONGFMT
"u)\n", iface
, ptr1
, len1
, ptr2
, len2
);
647 return DSERR_INVALIDPARAM
;
651 static HRESULT WINAPI
DSCBuffer_GetObjectInPath(IDirectSoundCaptureBuffer8
*iface
, REFGUID guid
, DWORD num
, REFGUID riid
, void **ppv
)
653 FIXME("(%p)->(%s, %"LONGFMT
"u, %s, %p) stub\n", iface
, debugstr_guid(guid
), num
, debugstr_guid(riid
), ppv
);
657 static HRESULT WINAPI
DSCBuffer_GetFXStatus(IDirectSoundCaptureBuffer8
*iface
, DWORD count
, DWORD
*status
)
659 FIXME("(%p)->(%"LONGFMT
"u, %p) stub\n", iface
, count
, status
);
663 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl
=
665 DSCBuffer_QueryInterface
,
669 DSCBuffer_GetCurrentPosition
,
672 DSCBuffer_Initialize
,
677 DSCBuffer_GetObjectInPath
,
678 DSCBuffer_GetFXStatus
681 static inline DSCBuffer
*impl_from_IDirectSoundNotify(IDirectSoundNotify
*iface
)
683 return CONTAINING_RECORD(iface
, DSCBuffer
, IDirectSoundNotify_iface
);
686 static HRESULT WINAPI
DSCBufferNot_QueryInterface(IDirectSoundNotify
*iface
, REFIID riid
, void **ppv
)
688 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
689 return IDirectSoundCaptureBuffer_QueryInterface((IDirectSoundCaptureBuffer
*)This
, riid
, ppv
);
692 static ULONG WINAPI
DSCBufferNot_AddRef(IDirectSoundNotify
*iface
)
694 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
697 InterlockedIncrement(&This
->all_ref
);
698 ret
= InterlockedIncrement(&This
->not_ref
);
699 TRACE("new refcount %"LONGFMT
"d\n", ret
);
703 static ULONG WINAPI
DSCBufferNot_Release(IDirectSoundNotify
*iface
)
705 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
708 ret
= InterlockedDecrement(&This
->not_ref
);
709 TRACE("new refcount %"LONGFMT
"d\n", ret
);
710 if(InterlockedDecrement(&This
->all_ref
) == 0)
711 DSCBuffer_Destroy(This
);
716 static HRESULT WINAPI
DSCBufferNot_SetNotificationPositions(IDirectSoundNotify
*iface
, DWORD count
, const DSBPOSITIONNOTIFY
*notifications
)
718 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
719 DSBPOSITIONNOTIFY
*nots
;
723 TRACE("(%p)->(%"LONGFMT
"u, %p))\n", iface
, count
, notifications
);
725 EnterCriticalSection(&This
->parent
->crst
);
726 hr
= DSERR_INVALIDPARAM
;
727 if (count
&& !notifications
)
730 hr
= DSCBuffer_GetStatus(&This
->IDirectSoundCaptureBuffer8_iface
, &state
);
734 hr
= DSERR_INVALIDCALL
;
735 if (state
& DSCBSTATUS_CAPTURING
)
740 HeapFree(GetProcessHeap(), 0, This
->notify
);
747 hr
= DSERR_INVALIDPARAM
;
748 for (i
= 0; i
< count
; ++i
)
750 if (notifications
[i
].dwOffset
>= This
->buf_size
751 && notifications
[i
].dwOffset
!= DSCBPN_OFFSET_STOP
)
755 nots
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(*nots
));
758 memcpy(nots
, notifications
, count
*sizeof(*nots
));
759 HeapFree(GetProcessHeap(), 0, This
->notify
);
761 This
->nnotify
= count
;
766 LeaveCriticalSection(&This
->parent
->crst
);
770 static const IDirectSoundNotifyVtbl DSCNot_Vtbl
=
772 DSCBufferNot_QueryInterface
,
774 DSCBufferNot_Release
,
775 DSCBufferNot_SetNotificationPositions
779 static inline DSCImpl
*impl_from_IDirectSoundCapture(IDirectSoundCapture
*iface
)
781 return CONTAINING_RECORD(iface
, DSCImpl
, IDirectSoundCapture_iface
);
784 HRESULT
DSOUND_CaptureCreate(REFIID riid
, void **cap
)
790 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
791 if(!This
) return DSERR_OUTOFMEMORY
;
793 This
->IDirectSoundCapture_iface
.lpVtbl
= (IDirectSoundCaptureVtbl
*)&DSC_Vtbl
;
795 InitializeCriticalSection(&This
->crst
);
796 This
->crst
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DSCImpl.crst");
798 if(FAILED(IDirectSoundCapture_QueryInterface(&This
->IDirectSoundCapture_iface
, riid
, cap
)))
800 DSCImpl_Destroy(This
);
801 return E_NOINTERFACE
;
806 static void DSCImpl_Destroy(DSCImpl
*This
)
808 EnterCriticalSection(&This
->crst
);
810 DSCBuffer_Destroy(This
->buf
);
811 LeaveCriticalSection(&This
->crst
);
813 HeapFree(GetProcessHeap(), 0, This
->device
);
815 This
->crst
.DebugInfo
->Spare
[0] = 0;
816 DeleteCriticalSection(&This
->crst
);
818 HeapFree(GetProcessHeap(), 0, This
);
821 static HRESULT WINAPI
DSCImpl_QueryInterface(IDirectSoundCapture
*iface
, REFIID riid
, void **ppv
)
823 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
825 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
828 if(IsEqualIID(riid
, &IID_IUnknown
) ||
829 IsEqualIID(riid
, &IID_IDirectSoundCapture
))
830 *ppv
= &This
->IDirectSoundCapture_iface
;
832 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
836 IUnknown_AddRef((IUnknown
*)*ppv
);
840 return E_NOINTERFACE
;
843 static ULONG WINAPI
DSCImpl_AddRef(IDirectSoundCapture
*iface
)
845 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
848 ref
= InterlockedIncrement(&This
->ref
);
849 TRACE("Reference count incremented to %"LONGFMT
"i\n", ref
);
854 static ULONG WINAPI
DSCImpl_Release(IDirectSoundCapture
*iface
)
856 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
859 ref
= InterlockedDecrement(&This
->ref
);
860 TRACE("Reference count decremented to %"LONGFMT
"i\n", ref
);
862 DSCImpl_Destroy(This
);
867 static HRESULT WINAPI
DSCImpl_CreateCaptureBuffer(IDirectSoundCapture
*iface
, const DSCBUFFERDESC
*desc
, IDirectSoundCaptureBuffer
**ppv
, IUnknown
*unk
)
869 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
872 TRACE("(%p)->(%p, %p, %p)\n", iface
, desc
, ppv
, unk
);
876 WARN("Aggregation isn't supported\n");
877 return DSERR_NOAGGREGATION
;
880 if(!desc
|| desc
->dwSize
< sizeof(DSCBUFFERDESC1
))
882 WARN("Passed invalid description %p %"LONGFMT
"u\n", desc
, desc
?desc
->dwSize
:0);
883 return DSERR_INVALIDPARAM
;
887 WARN("Passed null pointer\n");
888 return DSERR_INVALIDPARAM
;
892 EnterCriticalSection(&This
->crst
);
895 hr
= DSERR_UNINITIALIZED
;
896 WARN("Not initialized\n");
901 hr
= DSERR_ALLOCATED
;
902 WARN("Capture buffer already allocated\n");
906 hr
= DSCBuffer_Create(&This
->buf
, This
);
909 hr
= IDirectSoundCaptureBuffer8_Initialize(&This
->buf
->IDirectSoundCaptureBuffer8_iface
, iface
, desc
);
911 *ppv
= (IDirectSoundCaptureBuffer
*)&This
->buf
->IDirectSoundCaptureBuffer8_iface
;
914 DSCBuffer_Destroy(This
->buf
);
920 LeaveCriticalSection(&This
->crst
);
924 static HRESULT WINAPI
DSCImpl_GetCaps(IDirectSoundCapture
*iface
, DSCCAPS
*caps
)
926 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
928 TRACE("(%p)->(%p)\n", iface
, caps
);
931 WARN("Not initialized\n");
932 return DSERR_UNINITIALIZED
;
936 WARN("Caps is null\n");
937 return DSERR_INVALIDPARAM
;
939 if(caps
->dwSize
< sizeof(*caps
)) {
940 WARN("Invalid size %"LONGFMT
"d\n", caps
->dwSize
);
941 return DSERR_INVALIDPARAM
;
945 /* Support all WAVE_FORMAT formats specified in mmsystem.h */
946 caps
->dwFormats
= 0x000fffff;
947 caps
->dwChannels
= 2;
952 static HRESULT WINAPI
DSCImpl_Initialize(IDirectSoundCapture
*iface
, const GUID
*devguid
)
954 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
956 const ALCchar
*devs
, *drv_name
;
960 TRACE("(%p)->(%p)\n", iface
, devguid
);
964 ERR("OpenAL not loaded!\n");
965 return DSERR_NODRIVER
;
969 WARN("Already initialized\n");
970 return DSERR_ALREADYINITIALIZED
;
973 if(!devguid
|| IsEqualGUID(devguid
, &GUID_NULL
))
974 devguid
= &DSDEVID_DefaultCapture
;
976 hr
= GetDeviceID(devguid
, &guid
);
978 return DSERR_INVALIDPARAM
;
981 EnterCriticalSection(&This
->crst
);
982 EnterCriticalSection(&openal_crst
);
983 devs
= DSOUND_getcapturedevicestrings();
987 if(memcmp(devguid
, &DSOUND_capture_guid
, sizeof(GUID
)-1) ||
990 WARN("No driver found\n");
996 const ALCchar
*str
= devs
;
999 str
+= strlen(str
) + 1;
1002 WARN("No driver string found\n");
1011 This
->device
= HeapAlloc(GetProcessHeap(), 0, strlen(drv_name
)+1);
1014 WARN("Out of memory to allocate %s\n", drv_name
);
1017 strcpy(This
->device
, drv_name
);
1021 LeaveCriticalSection(&openal_crst
);
1022 LeaveCriticalSection(&This
->crst
);
1026 static const IDirectSoundCaptureVtbl DSC_Vtbl
=
1028 DSCImpl_QueryInterface
,
1031 DSCImpl_CreateCaptureBuffer
,