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
;
74 CRITICAL_SECTION crst
;
78 IDirectSoundCaptureBuffer8 IDirectSoundCaptureBuffer8_iface
;
79 IDirectSoundNotify IDirectSoundNotify_iface
;
91 WAVEFORMATEXTENSIBLE format
;
93 DSBPOSITIONNOTIFY
*notify
;
102 BOOL playing
, looping
;
105 static const IDirectSoundCaptureVtbl DSC_Vtbl
;
106 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl
;
107 static const IDirectSoundNotifyVtbl DSCNot_Vtbl
;
109 static void DSCImpl_Destroy(DSCImpl
*This
);
111 static void trigger_notifies(DSCBuffer
*buf
, DWORD lastpos
, DWORD curpos
)
115 if(lastpos
== curpos
)
118 for(i
= 0;i
< buf
->nnotify
;++i
)
120 DSBPOSITIONNOTIFY
*not = &buf
->notify
[i
];
121 HANDLE event
= not->hEventNotify
;
122 DWORD ofs
= not->dwOffset
;
124 if (ofs
== DSCBPN_OFFSET_STOP
)
127 /* Wraparound case */
130 if(ofs
< curpos
|| ofs
>= lastpos
)
132 TRACE("Triggering notification %"LONGFMT
"u (%"LONGFMT
"u) from buffer %p\n", i
, ofs
, buf
);
139 if(ofs
>= lastpos
&& ofs
< curpos
)
141 TRACE("Triggering notification %"LONGFMT
"u (%"LONGFMT
"u) from buffer %p\n", i
, ofs
, buf
);
147 static DWORD CALLBACK
DSCBuffer_thread(void *param
)
149 DSCImpl
*This
= param
;
154 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL
);
156 while(GetMessageA(&msg
, NULL
, 0, 0))
158 if(msg
.message
!= WM_USER
)
163 alcGetIntegerv(buf
->dev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
164 if(avail
== 0 || !buf
->playing
)
167 EnterCriticalSection(&This
->crst
);
169 avail
*= buf
->format
.Format
.nBlockAlign
;
170 if(avail
+ buf
->pos
> buf
->buf_size
)
171 avail
= buf
->buf_size
- buf
->pos
;
173 alcCaptureSamples(buf
->dev
, buf
->buf
+ buf
->pos
, avail
/buf
->format
.Format
.nBlockAlign
);
174 trigger_notifies(buf
, buf
->pos
, buf
->pos
+ avail
);
177 if(buf
->pos
== buf
->buf_size
)
181 IDirectSoundCaptureBuffer8_Stop(&buf
->IDirectSoundCaptureBuffer8_iface
);
184 alcGetIntegerv(buf
->dev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
185 if(avail
) goto more_samples
;
189 LeaveCriticalSection(&This
->crst
);
196 static void CALLBACK
DSCBuffer_timer(UINT timerID
, UINT msg
, DWORD_PTR dwUser
,
197 DWORD_PTR dw1
, DWORD_PTR dw2
)
203 PostThreadMessageA(dwUser
, WM_USER
, 0, 0);
206 static void DSCBuffer_starttimer(DSCBuffer
*This
)
209 ALint refresh
= FAKE_REFRESH_COUNT
;
210 DWORD triggertime
, res
= DS_TIME_RES
;
215 timeGetDevCaps(&time
, sizeof(TIMECAPS
));
216 triggertime
= 1000 / refresh
;
217 if (triggertime
< time
.wPeriodMin
)
218 triggertime
= time
.wPeriodMin
;
219 TRACE("Calling timer every %"LONGFMT
"u ms for %i refreshes per second\n", triggertime
, refresh
);
220 if (res
< time
.wPeriodMin
)
221 res
= time
.wPeriodMin
;
222 if (timeBeginPeriod(res
) == TIMERR_NOCANDO
)
223 WARN("Could not set minimum resolution, don't expect sound\n");
224 This
->timer_res
= res
;
225 This
->timer_id
= timeSetEvent(triggertime
, res
, DSCBuffer_timer
, This
->thread_id
, TIME_PERIODIC
|TIME_KILL_SYNCHRONOUS
);
228 static HRESULT
DSCBuffer_Create(DSCBuffer
**buf
, DSCImpl
*parent
)
230 DSCBuffer
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
231 if(!This
) return E_OUTOFMEMORY
;
233 This
->IDirectSoundCaptureBuffer8_iface
.lpVtbl
= (IDirectSoundCaptureBuffer8Vtbl
*)&DSCBuffer_Vtbl
;
234 This
->IDirectSoundNotify_iface
.lpVtbl
= (IDirectSoundNotifyVtbl
*)&DSCNot_Vtbl
;
236 This
->all_ref
= This
->ref
= 1;
238 This
->parent
= parent
;
240 This
->thread_hdl
= CreateThread(NULL
, 0, DSCBuffer_thread
, This
->parent
, 0, &This
->thread_id
);
241 if(This
->thread_hdl
== NULL
)
243 HeapFree(GetProcessHeap(), 0, This
);
244 return DSERR_OUTOFMEMORY
;
251 static void DSCBuffer_Destroy(DSCBuffer
*This
)
255 timeKillEvent(This
->timer_id
);
256 timeEndPeriod(This
->timer_res
);
260 PostThreadMessageA(This
->thread_id
, WM_QUIT
, 0, 0);
261 if(WaitForSingleObject(This
->thread_hdl
, 1000) != WAIT_OBJECT_0
)
262 ERR("Thread wait timed out");
263 CloseHandle(This
->thread_hdl
);
269 alcCaptureStop(This
->dev
);
270 alcCaptureCloseDevice(This
->dev
);
272 This
->parent
->buf
= NULL
;
274 HeapFree(GetProcessHeap(), 0, This
->notify
);
275 HeapFree(GetProcessHeap(), 0, This
->buf
);
276 HeapFree(GetProcessHeap(), 0, This
);
279 static inline DSCBuffer
*impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8
*iface
)
281 return CONTAINING_RECORD(iface
, DSCBuffer
, IDirectSoundCaptureBuffer8_iface
);
284 static HRESULT WINAPI
DSCBuffer_QueryInterface(IDirectSoundCaptureBuffer8
*iface
, REFIID riid
, void **ppv
)
286 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
288 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
294 if(IsEqualIID(riid
, &IID_IUnknown
) ||
295 IsEqualIID(riid
, &IID_IDirectSoundCaptureBuffer
))
296 *ppv
= &This
->IDirectSoundCaptureBuffer8_iface
;
297 else if(IsEqualIID(riid
, &IID_IDirectSoundCaptureBuffer8
))
299 if(This
->parent
->is_8
)
300 *ppv
= &This
->IDirectSoundCaptureBuffer8_iface
;
302 else if(IsEqualIID(riid
, &IID_IDirectSoundNotify
))
303 *ppv
= &This
->IDirectSoundNotify_iface
;
305 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
308 return E_NOINTERFACE
;
309 IUnknown_AddRef((IUnknown
*)*ppv
);
313 static ULONG WINAPI
DSCBuffer_AddRef(IDirectSoundCaptureBuffer8
*iface
)
315 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
318 InterlockedIncrement(&This
->all_ref
);
319 ref
= InterlockedIncrement(&This
->ref
);
320 TRACE("Reference count incremented to %"LONGFMT
"i\n", ref
);
325 static ULONG WINAPI
DSCBuffer_Release(IDirectSoundCaptureBuffer8
*iface
)
327 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
330 ref
= InterlockedDecrement(&This
->ref
);
331 TRACE("Reference count decremented to %"LONGFMT
"i\n", ref
);
332 if(InterlockedDecrement(&This
->all_ref
) == 0)
333 DSCBuffer_Destroy(This
);
338 static HRESULT WINAPI
DSCBuffer_GetCaps(IDirectSoundCaptureBuffer8
*iface
, DSCBCAPS
*caps
)
340 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
342 if (!caps
|| caps
->dwSize
< sizeof(*caps
))
343 return DSERR_INVALIDPARAM
;
344 caps
->dwSize
= sizeof(*caps
);
346 caps
->dwBufferBytes
= This
->buf_size
;
350 static HRESULT WINAPI
DSCBuffer_GetCurrentPosition(IDirectSoundCaptureBuffer8
*iface
, DWORD
*cappos
, DWORD
*readpos
)
352 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
355 EnterCriticalSection(&This
->parent
->crst
);
359 pos2
= This
->format
.Format
.nSamplesPerSec
/ 100;
360 pos2
*= This
->format
.Format
.nBlockAlign
;
362 if (!This
->looping
&& pos2
>= This
->buf_size
)
365 pos2
%= This
->buf_size
;
369 LeaveCriticalSection(&This
->parent
->crst
);
371 if(cappos
) *cappos
= pos1
;
372 if(readpos
) *readpos
= pos2
;
377 static HRESULT WINAPI
DSCBuffer_GetFormat(IDirectSoundCaptureBuffer8
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
379 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
383 TRACE("(%p)->(%p, %"LONGFMT
"u, %p)\n", iface
, wfx
, allocated
, written
);
387 WARN("Cannot report format or format size\n");
388 return DSERR_INVALIDPARAM
;
391 size
= sizeof(This
->format
.Format
) + This
->format
.Format
.cbSize
;
395 hr
= DSERR_INVALIDPARAM
;
397 memcpy(wfx
, &This
->format
.Format
, size
);
405 static HRESULT WINAPI
DSCBuffer_GetStatus(IDirectSoundCaptureBuffer8
*iface
, DWORD
*status
)
407 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
409 TRACE("(%p)->(%p)\n", iface
, status
);
412 return DSERR_INVALIDPARAM
;
413 EnterCriticalSection(&This
->parent
->crst
);
417 *status
|= DSCBSTATUS_CAPTURING
;
419 *status
|= DSCBSTATUS_LOOPING
;
421 LeaveCriticalSection(&This
->parent
->crst
);
426 static HRESULT WINAPI
DSCBuffer_Initialize(IDirectSoundCaptureBuffer8
*iface
, IDirectSoundCapture
*parent
, const DSCBUFFERDESC
*desc
)
428 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
429 WAVEFORMATEX
*format
;
430 ALenum buf_format
= -1;
432 TRACE("(%p)->(%p, %p)\n", iface
, parent
, desc
);
435 return DSERR_ALREADYINITIALIZED
;
437 if (!desc
->lpwfxFormat
)
438 return DSERR_INVALIDPARAM
;
440 format
= desc
->lpwfxFormat
;
441 if(format
->nChannels
> 2)
443 WARN("nChannels > 2 not supported for recording\n");
444 return DSERR_INVALIDPARAM
;
447 if(format
->wFormatTag
== WAVE_FORMAT_PCM
)
449 if(format
->nChannels
== 1)
451 switch(format
->wBitsPerSample
)
453 case 8: buf_format
= AL_FORMAT_MONO8
; break;
454 case 16: buf_format
= AL_FORMAT_MONO16
; break;
456 WARN("Unsupported bpp %u\n", format
->wBitsPerSample
);
457 return DSERR_BADFORMAT
;
460 else if(format
->nChannels
== 2)
462 switch(format
->wBitsPerSample
)
464 case 8: buf_format
= AL_FORMAT_STEREO8
; break;
465 case 16: buf_format
= AL_FORMAT_STEREO16
; break;
467 WARN("Unsupported bpp %u\n", format
->wBitsPerSample
);
468 return DSERR_BADFORMAT
;
472 WARN("Unsupported channels: %d\n", format
->nChannels
);
474 memcpy(&This
->format
.Format
, format
, sizeof(This
->format
.Format
));
475 This
->format
.Format
.nBlockAlign
= This
->format
.Format
.wBitsPerSample
* This
->format
.Format
.nChannels
/ 8;
476 This
->format
.Format
.nAvgBytesPerSec
= This
->format
.Format
.nSamplesPerSec
* This
->format
.Format
.nBlockAlign
;
477 This
->format
.Format
.cbSize
= 0;
479 else if(format
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
481 WAVEFORMATEXTENSIBLE
*wfe
;
483 if(format
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
))
484 return DSERR_INVALIDPARAM
;
485 else if(format
->cbSize
> sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
) &&
486 format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
))
487 return DSERR_CONTROLUNAVAIL
;
489 wfe
= CONTAINING_RECORD(format
, WAVEFORMATEXTENSIBLE
, Format
);
490 if(!IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))
491 return DSERR_BADFORMAT
;
492 if(wfe
->Samples
.wValidBitsPerSample
&&
493 wfe
->Samples
.wValidBitsPerSample
!= wfe
->Format
.wBitsPerSample
)
494 return DSERR_BADFORMAT
;
496 if(wfe
->Format
.nChannels
== 1 && wfe
->dwChannelMask
== SPEAKER_FRONT_CENTER
)
498 switch(wfe
->Format
.wBitsPerSample
)
500 case 8: buf_format
= AL_FORMAT_MONO8
; break;
501 case 16: buf_format
= AL_FORMAT_MONO16
; break;
503 WARN("Unsupported bpp %u\n", wfe
->Format
.wBitsPerSample
);
504 return DSERR_BADFORMAT
;
507 else if(wfe
->Format
.nChannels
== 2 && wfe
->dwChannelMask
== (SPEAKER_FRONT_LEFT
|SPEAKER_FRONT_RIGHT
))
509 switch(wfe
->Format
.wBitsPerSample
)
511 case 8: buf_format
= AL_FORMAT_STEREO8
; break;
512 case 16: buf_format
= AL_FORMAT_STEREO16
; break;
514 WARN("Unsupported bpp %u\n", wfe
->Format
.wBitsPerSample
);
515 return DSERR_BADFORMAT
;
519 WARN("Unsupported channels: %d -- 0x%08"LONGFMT
"u\n", wfe
->Format
.nChannels
, wfe
->dwChannelMask
);
521 memcpy(&This
->format
, wfe
, sizeof(This
->format
));
522 This
->format
.Format
.cbSize
= sizeof(This
->format
) - sizeof(This
->format
.Format
);
523 This
->format
.Format
.nBlockAlign
= This
->format
.Format
.wBitsPerSample
* This
->format
.Format
.nChannels
/ 8;
524 This
->format
.Format
.nAvgBytesPerSec
= This
->format
.Format
.nSamplesPerSec
* This
->format
.Format
.nBlockAlign
;
527 WARN("Unhandled formattag %x\n", format
->wFormatTag
);
531 WARN("Could not get OpenAL format\n");
532 return DSERR_INVALIDPARAM
;
535 This
->buf_size
= desc
->dwBufferBytes
;
536 This
->buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->buf_size
);
539 WARN("Out of memory\n");
540 return DSERR_INVALIDPARAM
;
543 This
->dev
= alcCaptureOpenDevice(This
->parent
->device
, This
->format
.Format
.nSamplesPerSec
, buf_format
, This
->format
.Format
.nSamplesPerSec
/ FAKE_REFRESH_COUNT
* 2);
546 ERR("Couldn't open device %s 0x%x@%"LONGFMT
"u, reason: %04x\n", This
->parent
->device
, buf_format
, This
->format
.Format
.nSamplesPerSec
, alcGetError(NULL
));
547 return DSERR_INVALIDPARAM
;
553 static HRESULT WINAPI
DSCBuffer_Lock(IDirectSoundCaptureBuffer8
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
555 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
558 TRACE("(%p)->(%"LONGFMT
"u, %"LONGFMT
"u, %p, %p, %p, %p, %#"LONGFMT
"x)\n", iface
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
562 WARN("Invalid pointer/len %p %p\n", ptr1
, len1
);
563 return DSERR_INVALIDPARAM
;
568 if(ptr2
) *ptr2
= NULL
;
571 if(ofs
>= This
->buf_size
)
573 WARN("Invalid ofs %"LONGFMT
"u\n", ofs
);
574 return DSERR_INVALIDPARAM
;
577 if((flags
&DSCBLOCK_ENTIREBUFFER
))
578 bytes
= This
->buf_size
;
579 else if(bytes
> This
->buf_size
)
581 WARN("Invalid size %"LONGFMT
"u\n", bytes
);
582 return DSERR_INVALIDPARAM
;
585 if(InterlockedExchange(&This
->locked
, TRUE
) == TRUE
)
587 WARN("Already locked\n");
588 return DSERR_INVALIDPARAM
;
591 if(ofs
+ bytes
>= This
->buf_size
)
593 *len1
= This
->buf_size
- ofs
;
594 remain
= bytes
- *len1
;
601 *ptr1
= This
->buf
+ ofs
;
603 if(ptr2
&& len2
&& remain
)
612 static HRESULT WINAPI
DSCBuffer_Start(IDirectSoundCaptureBuffer8
*iface
, DWORD flags
)
614 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
616 TRACE("(%p)->(%08"LONGFMT
"x)\n", iface
, flags
);
618 EnterCriticalSection(&This
->parent
->crst
);
621 DSCBuffer_starttimer(This
);
623 alcCaptureStart(This
->dev
);
625 This
->looping
= !!(flags
& DSCBSTART_LOOPING
);
626 LeaveCriticalSection(&This
->parent
->crst
);
630 static HRESULT WINAPI
DSCBuffer_Stop(IDirectSoundCaptureBuffer8
*iface
)
632 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
634 TRACE("(%p)->()\n", iface
);
636 EnterCriticalSection(&This
->parent
->crst
);
640 for(i
= 0;i
< This
->nnotify
;++i
)
642 if(This
->notify
[i
].dwOffset
== DSCBPN_OFFSET_STOP
)
643 SetEvent(This
->notify
[i
].hEventNotify
);
646 This
->playing
= This
->looping
= 0;
647 alcCaptureStop(This
->dev
);
649 LeaveCriticalSection(&This
->parent
->crst
);
653 static HRESULT WINAPI
DSCBuffer_Unlock(IDirectSoundCaptureBuffer8
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
655 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
656 DWORD_PTR ofs1
, ofs2
;
657 DWORD_PTR boundary
= (DWORD_PTR
)This
->buf
;
659 TRACE("(%p)->(%p, %"LONGFMT
"u, %p, %"LONGFMT
"u)\n", iface
, ptr1
, len1
, ptr2
, len2
);
661 if(InterlockedExchange(&This
->locked
, FALSE
) == FALSE
)
663 WARN("Not locked\n");
664 return DSERR_INVALIDPARAM
;
667 /* Make sure offset is between boundary and boundary + bufsize */
668 ofs1
= (DWORD_PTR
)ptr1
;
669 ofs2
= (DWORD_PTR
)ptr2
;
671 return DSERR_INVALIDPARAM
;
672 if(ofs2
&& ofs2
!= boundary
)
673 return DSERR_INVALIDPARAM
;
677 if(This
->buf_size
-ofs1
< len1
|| len2
> ofs1
)
678 return DSERR_INVALIDPARAM
;
683 static HRESULT WINAPI
DSCBuffer_GetObjectInPath(IDirectSoundCaptureBuffer8
*iface
, REFGUID guid
, DWORD num
, REFGUID riid
, void **ppv
)
685 FIXME("(%p)->(%s, %"LONGFMT
"u, %s, %p) stub\n", iface
, debugstr_guid(guid
), num
, debugstr_guid(riid
), ppv
);
689 static HRESULT WINAPI
DSCBuffer_GetFXStatus(IDirectSoundCaptureBuffer8
*iface
, DWORD count
, DWORD
*status
)
691 FIXME("(%p)->(%"LONGFMT
"u, %p) stub\n", iface
, count
, status
);
695 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl
=
697 DSCBuffer_QueryInterface
,
701 DSCBuffer_GetCurrentPosition
,
704 DSCBuffer_Initialize
,
709 DSCBuffer_GetObjectInPath
,
710 DSCBuffer_GetFXStatus
713 static inline DSCBuffer
*impl_from_IDirectSoundNotify(IDirectSoundNotify
*iface
)
715 return CONTAINING_RECORD(iface
, DSCBuffer
, IDirectSoundNotify_iface
);
718 static HRESULT WINAPI
DSCBufferNot_QueryInterface(IDirectSoundNotify
*iface
, REFIID riid
, void **ppv
)
720 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
721 return IDirectSoundCaptureBuffer_QueryInterface((IDirectSoundCaptureBuffer
*)This
, riid
, ppv
);
724 static ULONG WINAPI
DSCBufferNot_AddRef(IDirectSoundNotify
*iface
)
726 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
729 InterlockedIncrement(&This
->all_ref
);
730 ret
= InterlockedIncrement(&This
->not_ref
);
731 TRACE("new refcount %"LONGFMT
"d\n", ret
);
735 static ULONG WINAPI
DSCBufferNot_Release(IDirectSoundNotify
*iface
)
737 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
740 ret
= InterlockedDecrement(&This
->not_ref
);
741 TRACE("new refcount %"LONGFMT
"d\n", ret
);
742 if(InterlockedDecrement(&This
->all_ref
) == 0)
743 DSCBuffer_Destroy(This
);
748 static HRESULT WINAPI
DSCBufferNot_SetNotificationPositions(IDirectSoundNotify
*iface
, DWORD count
, const DSBPOSITIONNOTIFY
*notifications
)
750 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
751 DSBPOSITIONNOTIFY
*nots
;
755 TRACE("(%p)->(%"LONGFMT
"u, %p))\n", iface
, count
, notifications
);
757 EnterCriticalSection(&This
->parent
->crst
);
758 hr
= DSERR_INVALIDPARAM
;
759 if (count
&& !notifications
)
762 hr
= DSCBuffer_GetStatus(&This
->IDirectSoundCaptureBuffer8_iface
, &state
);
766 hr
= DSERR_INVALIDCALL
;
767 if (state
& DSCBSTATUS_CAPTURING
)
772 HeapFree(GetProcessHeap(), 0, This
->notify
);
779 hr
= DSERR_INVALIDPARAM
;
780 for (i
= 0; i
< count
; ++i
)
782 if (notifications
[i
].dwOffset
>= This
->buf_size
783 && notifications
[i
].dwOffset
!= DSCBPN_OFFSET_STOP
)
787 nots
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(*nots
));
790 memcpy(nots
, notifications
, count
*sizeof(*nots
));
791 HeapFree(GetProcessHeap(), 0, This
->notify
);
793 This
->nnotify
= count
;
798 LeaveCriticalSection(&This
->parent
->crst
);
802 static const IDirectSoundNotifyVtbl DSCNot_Vtbl
=
804 DSCBufferNot_QueryInterface
,
806 DSCBufferNot_Release
,
807 DSCBufferNot_SetNotificationPositions
811 static inline DSCImpl
*impl_from_IDirectSoundCapture(IDirectSoundCapture
*iface
)
813 return CONTAINING_RECORD(iface
, DSCImpl
, IDirectSoundCapture_iface
);
816 HRESULT
DSOUND_CaptureCreate(REFIID riid
, void **cap
)
820 hr
= DSOUND_CaptureCreate8(&IID_IDirectSoundCapture
, cap
);
823 DSCImpl
*impl
= impl_from_IDirectSoundCapture(*cap
);
826 if(!IsEqualIID(riid
, &IID_IDirectSoundCapture
))
828 hr
= IDirectSoundCapture_QueryInterface(&impl
->IDirectSoundCapture_iface
, riid
, cap
);
829 IDirectSoundCapture_Release(&impl
->IDirectSoundCapture_iface
);
835 HRESULT
DSOUND_CaptureCreate8(REFIID riid
, void **cap
)
841 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
842 if(!This
) return DSERR_OUTOFMEMORY
;
844 This
->IDirectSoundCapture_iface
.lpVtbl
= (IDirectSoundCaptureVtbl
*)&DSC_Vtbl
;
848 InitializeCriticalSection(&This
->crst
);
849 This
->crst
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DSCImpl.crst");
851 if(FAILED(IDirectSoundCapture_QueryInterface(&This
->IDirectSoundCapture_iface
, riid
, cap
)))
853 DSCImpl_Destroy(This
);
854 return E_NOINTERFACE
;
859 static void DSCImpl_Destroy(DSCImpl
*This
)
861 EnterCriticalSection(&This
->crst
);
863 DSCBuffer_Destroy(This
->buf
);
864 LeaveCriticalSection(&This
->crst
);
866 HeapFree(GetProcessHeap(), 0, This
->device
);
868 This
->crst
.DebugInfo
->Spare
[0] = 0;
869 DeleteCriticalSection(&This
->crst
);
871 HeapFree(GetProcessHeap(), 0, This
);
874 static HRESULT WINAPI
DSCImpl_QueryInterface(IDirectSoundCapture
*iface
, REFIID riid
, void **ppv
)
876 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
878 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
881 if(IsEqualIID(riid
, &IID_IUnknown
) ||
882 IsEqualIID(riid
, &IID_IDirectSoundCapture
))
883 *ppv
= &This
->IDirectSoundCapture_iface
;
885 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
889 IUnknown_AddRef((IUnknown
*)*ppv
);
893 return E_NOINTERFACE
;
896 static ULONG WINAPI
DSCImpl_AddRef(IDirectSoundCapture
*iface
)
898 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
901 ref
= InterlockedIncrement(&This
->ref
);
902 TRACE("Reference count incremented to %"LONGFMT
"i\n", ref
);
907 static ULONG WINAPI
DSCImpl_Release(IDirectSoundCapture
*iface
)
909 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
912 ref
= InterlockedDecrement(&This
->ref
);
913 TRACE("Reference count decremented to %"LONGFMT
"i\n", ref
);
915 DSCImpl_Destroy(This
);
920 static HRESULT WINAPI
DSCImpl_CreateCaptureBuffer(IDirectSoundCapture
*iface
, const DSCBUFFERDESC
*desc
, IDirectSoundCaptureBuffer
**ppv
, IUnknown
*unk
)
922 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
925 TRACE("(%p)->(%p, %p, %p)\n", iface
, desc
, ppv
, unk
);
929 WARN("Aggregation isn't supported\n");
930 return DSERR_NOAGGREGATION
;
933 if(!desc
|| desc
->dwSize
< sizeof(DSCBUFFERDESC1
))
935 WARN("Passed invalid description %p %"LONGFMT
"u\n", desc
, desc
?desc
->dwSize
:0);
936 return DSERR_INVALIDPARAM
;
940 WARN("Passed null pointer\n");
941 return DSERR_INVALIDPARAM
;
945 EnterCriticalSection(&This
->crst
);
948 hr
= DSERR_UNINITIALIZED
;
949 WARN("Not initialized\n");
954 hr
= DSERR_ALLOCATED
;
955 WARN("Capture buffer already allocated\n");
959 hr
= DSCBuffer_Create(&This
->buf
, This
);
962 hr
= IDirectSoundCaptureBuffer8_Initialize(&This
->buf
->IDirectSoundCaptureBuffer8_iface
, iface
, desc
);
964 *ppv
= (IDirectSoundCaptureBuffer
*)&This
->buf
->IDirectSoundCaptureBuffer8_iface
;
967 DSCBuffer_Destroy(This
->buf
);
973 LeaveCriticalSection(&This
->crst
);
977 static HRESULT WINAPI
DSCImpl_GetCaps(IDirectSoundCapture
*iface
, DSCCAPS
*caps
)
979 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
981 TRACE("(%p)->(%p)\n", iface
, caps
);
984 WARN("Not initialized\n");
985 return DSERR_UNINITIALIZED
;
989 WARN("Caps is null\n");
990 return DSERR_INVALIDPARAM
;
992 if(caps
->dwSize
< sizeof(*caps
)) {
993 WARN("Invalid size %"LONGFMT
"d\n", caps
->dwSize
);
994 return DSERR_INVALIDPARAM
;
998 /* Support all WAVE_FORMAT formats specified in mmsystem.h */
999 caps
->dwFormats
= 0x000fffff;
1000 caps
->dwChannels
= 2;
1005 static HRESULT WINAPI
DSCImpl_Initialize(IDirectSoundCapture
*iface
, const GUID
*devguid
)
1007 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
1009 const ALCchar
*devs
, *drv_name
;
1013 TRACE("(%p)->(%p)\n", iface
, devguid
);
1017 ERR("OpenAL not loaded!\n");
1018 return DSERR_NODRIVER
;
1022 WARN("Already initialized\n");
1023 return DSERR_ALREADYINITIALIZED
;
1026 if(!devguid
|| IsEqualGUID(devguid
, &GUID_NULL
))
1027 devguid
= &DSDEVID_DefaultCapture
;
1029 hr
= GetDeviceID(devguid
, &guid
);
1031 return DSERR_INVALIDPARAM
;
1034 EnterCriticalSection(&This
->crst
);
1035 EnterCriticalSection(&openal_crst
);
1036 devs
= DSOUND_getcapturedevicestrings();
1039 hr
= DSERR_NODRIVER
;
1040 if(memcmp(devguid
, &DSOUND_capture_guid
, sizeof(GUID
)-1) ||
1043 WARN("No driver found\n");
1049 const ALCchar
*str
= devs
;
1052 str
+= strlen(str
) + 1;
1055 WARN("No driver string found\n");
1064 This
->device
= HeapAlloc(GetProcessHeap(), 0, strlen(drv_name
)+1);
1067 WARN("Out of memory to allocate %s\n", drv_name
);
1070 strcpy(This
->device
, drv_name
);
1074 LeaveCriticalSection(&openal_crst
);
1075 LeaveCriticalSection(&This
->crst
);
1079 static const IDirectSoundCaptureVtbl DSC_Vtbl
=
1081 DSCImpl_QueryInterface
,
1084 DSCImpl_CreateCaptureBuffer
,