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 WAVEFORMATEXTENSIBLE format
;
91 DSBPOSITIONNOTIFY
*notify
;
100 BOOL playing
, looping
;
103 static const IDirectSoundCaptureVtbl DSC_Vtbl
;
104 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl
;
105 static const IDirectSoundNotifyVtbl DSCNot_Vtbl
;
107 static void DSCImpl_Destroy(DSCImpl
*This
);
109 static void trigger_notifies(DSCBuffer
*buf
, DWORD lastpos
, DWORD curpos
)
113 if(lastpos
== curpos
)
116 for(i
= 0;i
< buf
->nnotify
;++i
)
118 DSBPOSITIONNOTIFY
*not = &buf
->notify
[i
];
119 HANDLE event
= not->hEventNotify
;
120 DWORD ofs
= not->dwOffset
;
122 if (ofs
== DSCBPN_OFFSET_STOP
)
125 /* Wraparound case */
128 if(ofs
< curpos
|| ofs
>= lastpos
)
130 TRACE("Triggering notification %"LONGFMT
"u (%"LONGFMT
"u) from buffer %p\n", i
, ofs
, buf
);
137 if(ofs
>= lastpos
&& ofs
< curpos
)
139 TRACE("Triggering notification %"LONGFMT
"u (%"LONGFMT
"u) from buffer %p\n", i
, ofs
, buf
);
145 static DWORD CALLBACK
DSCBuffer_thread(void *param
)
147 DSCImpl
*This
= param
;
152 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL
);
154 while(GetMessageA(&msg
, NULL
, 0, 0))
156 if(msg
.message
!= WM_USER
)
161 alcGetIntegerv(buf
->dev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
165 EnterCriticalSection(&This
->crst
);
167 avail
*= buf
->format
.Format
.nBlockAlign
;
168 if(avail
+ buf
->pos
> buf
->buf_size
)
169 avail
= buf
->buf_size
- buf
->pos
;
171 alcCaptureSamples(buf
->dev
, buf
->buf
+ buf
->pos
, avail
/buf
->format
.Format
.nBlockAlign
);
172 trigger_notifies(buf
, buf
->pos
, buf
->pos
+ avail
);
175 if(buf
->pos
== buf
->buf_size
)
179 IDirectSoundCaptureBuffer8_Stop(&buf
->IDirectSoundCaptureBuffer8_iface
);
182 alcGetIntegerv(buf
->dev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
183 if(avail
) goto more_samples
;
187 LeaveCriticalSection(&This
->crst
);
194 static void CALLBACK
DSCBuffer_timer(UINT timerID
, UINT msg
, DWORD_PTR dwUser
,
195 DWORD_PTR dw1
, DWORD_PTR dw2
)
201 PostThreadMessageA(dwUser
, WM_USER
, 0, 0);
204 static void DSCBuffer_starttimer(DSCBuffer
*This
)
207 ALint refresh
= FAKE_REFRESH_COUNT
;
208 DWORD triggertime
, res
= DS_TIME_RES
;
213 timeGetDevCaps(&time
, sizeof(TIMECAPS
));
214 triggertime
= 1000 / refresh
;
215 if (triggertime
< time
.wPeriodMin
)
216 triggertime
= time
.wPeriodMin
;
217 TRACE("Calling timer every %"LONGFMT
"u ms for %i refreshes per second\n", triggertime
, refresh
);
218 if (res
< time
.wPeriodMin
)
219 res
= time
.wPeriodMin
;
220 if (timeBeginPeriod(res
) == TIMERR_NOCANDO
)
221 WARN("Could not set minimum resolution, don't expect sound\n");
222 This
->timer_res
= res
;
223 This
->timer_id
= timeSetEvent(triggertime
, res
, DSCBuffer_timer
, This
->thread_id
, TIME_PERIODIC
|TIME_KILL_SYNCHRONOUS
);
226 static HRESULT
DSCBuffer_Create(DSCBuffer
**buf
, DSCImpl
*parent
)
228 DSCBuffer
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
229 if(!This
) return E_OUTOFMEMORY
;
231 This
->IDirectSoundCaptureBuffer8_iface
.lpVtbl
= (IDirectSoundCaptureBuffer8Vtbl
*)&DSCBuffer_Vtbl
;
232 This
->IDirectSoundNotify_iface
.lpVtbl
= (IDirectSoundNotifyVtbl
*)&DSCNot_Vtbl
;
234 This
->all_ref
= This
->ref
= 1;
236 This
->parent
= parent
;
238 This
->thread_hdl
= CreateThread(NULL
, 0, DSCBuffer_thread
, This
->parent
, 0, &This
->thread_id
);
239 if(This
->thread_hdl
== NULL
)
241 HeapFree(GetProcessHeap(), 0, This
);
242 return DSERR_OUTOFMEMORY
;
249 static void DSCBuffer_Destroy(DSCBuffer
*This
)
253 timeKillEvent(This
->timer_id
);
254 timeEndPeriod(This
->timer_res
);
258 PostThreadMessageA(This
->thread_id
, WM_QUIT
, 0, 0);
259 if(WaitForSingleObject(This
->thread_hdl
, 1000) != WAIT_OBJECT_0
)
260 ERR("Thread wait timed out");
261 CloseHandle(This
->thread_hdl
);
267 alcCaptureStop(This
->dev
);
268 alcCaptureCloseDevice(This
->dev
);
270 This
->parent
->buf
= NULL
;
272 HeapFree(GetProcessHeap(), 0, This
->notify
);
273 HeapFree(GetProcessHeap(), 0, This
->buf
);
274 HeapFree(GetProcessHeap(), 0, This
);
277 static inline DSCBuffer
*impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8
*iface
)
279 return CONTAINING_RECORD(iface
, DSCBuffer
, IDirectSoundCaptureBuffer8_iface
);
282 static HRESULT WINAPI
DSCBuffer_QueryInterface(IDirectSoundCaptureBuffer8
*iface
, REFIID riid
, void **ppv
)
284 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
286 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
292 if (IsEqualIID(riid
, &IID_IDirectSoundNotify
))
293 *ppv
= &This
->IDirectSoundNotify_iface
;
294 else if (IsEqualIID(riid
, &IID_IUnknown
) ||
295 IsEqualIID(riid
, &IID_IDirectSoundCaptureBuffer
) ||
296 IsEqualIID(riid
, &IID_IDirectSoundCaptureBuffer8
))
297 *ppv
= &This
->IDirectSoundCaptureBuffer8_iface
;
300 return E_NOINTERFACE
;
301 IUnknown_AddRef((IUnknown
*)*ppv
);
305 static ULONG WINAPI
DSCBuffer_AddRef(IDirectSoundCaptureBuffer8
*iface
)
307 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
310 InterlockedIncrement(&This
->all_ref
);
311 ref
= InterlockedIncrement(&This
->ref
);
312 TRACE("Reference count incremented to %"LONGFMT
"i\n", ref
);
317 static ULONG WINAPI
DSCBuffer_Release(IDirectSoundCaptureBuffer8
*iface
)
319 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
322 ref
= InterlockedDecrement(&This
->ref
);
323 TRACE("Reference count decremented to %"LONGFMT
"i\n", ref
);
324 if(InterlockedDecrement(&This
->all_ref
) == 0)
325 DSCBuffer_Destroy(This
);
330 static HRESULT WINAPI
DSCBuffer_GetCaps(IDirectSoundCaptureBuffer8
*iface
, DSCBCAPS
*caps
)
332 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
334 if (!caps
|| caps
->dwSize
< sizeof(*caps
))
335 return DSERR_INVALIDPARAM
;
336 caps
->dwSize
= sizeof(*caps
);
338 caps
->dwBufferBytes
= This
->buf_size
;
342 static HRESULT WINAPI
DSCBuffer_GetCurrentPosition(IDirectSoundCaptureBuffer8
*iface
, DWORD
*cappos
, DWORD
*readpos
)
344 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
347 EnterCriticalSection(&This
->parent
->crst
);
351 pos2
= This
->format
.Format
.nSamplesPerSec
/ 100;
352 pos2
*= This
->format
.Format
.nBlockAlign
;
354 if (!This
->looping
&& pos2
>= This
->buf_size
)
357 pos2
%= This
->buf_size
;
361 LeaveCriticalSection(&This
->parent
->crst
);
363 if(cappos
) *cappos
= pos1
;
364 if(readpos
) *readpos
= pos2
;
369 static HRESULT WINAPI
DSCBuffer_GetFormat(IDirectSoundCaptureBuffer8
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
371 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
375 TRACE("(%p)->(%p, %"LONGFMT
"u, %p)\n", iface
, wfx
, allocated
, written
);
379 WARN("Cannot report format or format size\n");
380 return DSERR_INVALIDPARAM
;
383 size
= sizeof(This
->format
.Format
) + This
->format
.Format
.cbSize
;
387 hr
= DSERR_INVALIDPARAM
;
389 memcpy(wfx
, &This
->format
.Format
, size
);
397 static HRESULT WINAPI
DSCBuffer_GetStatus(IDirectSoundCaptureBuffer8
*iface
, DWORD
*status
)
399 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
401 TRACE("(%p)->(%p)\n", iface
, status
);
404 return DSERR_INVALIDPARAM
;
405 EnterCriticalSection(&This
->parent
->crst
);
409 *status
|= DSCBSTATUS_CAPTURING
;
411 *status
|= DSCBSTATUS_LOOPING
;
413 LeaveCriticalSection(&This
->parent
->crst
);
418 static HRESULT WINAPI
DSCBuffer_Initialize(IDirectSoundCaptureBuffer8
*iface
, IDirectSoundCapture
*parent
, const DSCBUFFERDESC
*desc
)
420 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
421 WAVEFORMATEX
*format
;
422 ALenum buf_format
= -1;
424 TRACE("(%p)->(%p, %p)\n", iface
, parent
, desc
);
427 return DSERR_ALREADYINITIALIZED
;
429 if (!desc
->lpwfxFormat
)
430 return DSERR_INVALIDPARAM
;
432 format
= desc
->lpwfxFormat
;
433 if(format
->nChannels
> 2)
435 WARN("nChannels > 2 not supported for recording\n");
436 return DSERR_INVALIDPARAM
;
439 if(format
->wFormatTag
== WAVE_FORMAT_PCM
)
441 if(format
->nChannels
== 1)
443 switch(format
->wBitsPerSample
)
445 case 8: buf_format
= AL_FORMAT_MONO8
; break;
446 case 16: buf_format
= AL_FORMAT_MONO16
; break;
448 WARN("Unsupported bpp %u\n", format
->wBitsPerSample
);
449 return DSERR_BADFORMAT
;
452 else if(format
->nChannels
== 2)
454 switch(format
->wBitsPerSample
)
456 case 8: buf_format
= AL_FORMAT_STEREO8
; break;
457 case 16: buf_format
= AL_FORMAT_STEREO16
; break;
459 WARN("Unsupported bpp %u\n", format
->wBitsPerSample
);
460 return DSERR_BADFORMAT
;
464 WARN("Unsupported channels: %d\n", format
->nChannels
);
466 memcpy(&This
->format
.Format
, format
, sizeof(This
->format
.Format
));
467 This
->format
.Format
.nBlockAlign
= This
->format
.Format
.wBitsPerSample
* This
->format
.Format
.nChannels
/ 8;
468 This
->format
.Format
.nAvgBytesPerSec
= This
->format
.Format
.nSamplesPerSec
* This
->format
.Format
.nBlockAlign
;
469 This
->format
.Format
.cbSize
= 0;
471 else if(format
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
473 WAVEFORMATEXTENSIBLE
*wfe
;
475 if(format
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
))
476 return DSERR_INVALIDPARAM
;
477 else if(format
->cbSize
> sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
) &&
478 format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
))
479 return DSERR_CONTROLUNAVAIL
;
481 wfe
= CONTAINING_RECORD(format
, WAVEFORMATEXTENSIBLE
, Format
);
482 if(!IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))
483 return DSERR_BADFORMAT
;
484 if(wfe
->Samples
.wValidBitsPerSample
&&
485 wfe
->Samples
.wValidBitsPerSample
!= wfe
->Format
.wBitsPerSample
)
486 return DSERR_BADFORMAT
;
488 if(wfe
->Format
.nChannels
== 1 && wfe
->dwChannelMask
== SPEAKER_FRONT_CENTER
)
490 switch(wfe
->Format
.wBitsPerSample
)
492 case 8: buf_format
= AL_FORMAT_MONO8
; break;
493 case 16: buf_format
= AL_FORMAT_MONO16
; break;
495 WARN("Unsupported bpp %u\n", wfe
->Format
.wBitsPerSample
);
496 return DSERR_BADFORMAT
;
499 else if(wfe
->Format
.nChannels
== 2 && wfe
->dwChannelMask
== (SPEAKER_FRONT_LEFT
|SPEAKER_FRONT_RIGHT
))
501 switch(wfe
->Format
.wBitsPerSample
)
503 case 8: buf_format
= AL_FORMAT_STEREO8
; break;
504 case 16: buf_format
= AL_FORMAT_STEREO16
; break;
506 WARN("Unsupported bpp %u\n", wfe
->Format
.wBitsPerSample
);
507 return DSERR_BADFORMAT
;
511 WARN("Unsupported channels: %d -- 0x%08"LONGFMT
"u\n", wfe
->Format
.nChannels
, wfe
->dwChannelMask
);
513 memcpy(&This
->format
, wfe
, sizeof(This
->format
));
514 This
->format
.Format
.cbSize
= sizeof(This
->format
) - sizeof(This
->format
.Format
);
515 This
->format
.Format
.nBlockAlign
= This
->format
.Format
.wBitsPerSample
* This
->format
.Format
.nChannels
/ 8;
516 This
->format
.Format
.nAvgBytesPerSec
= This
->format
.Format
.nSamplesPerSec
* This
->format
.Format
.nBlockAlign
;
519 WARN("Unhandled formattag %x\n", format
->wFormatTag
);
523 WARN("Could not get OpenAL format\n");
524 return DSERR_INVALIDPARAM
;
527 This
->buf_size
= desc
->dwBufferBytes
;
528 This
->buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->buf_size
);
531 WARN("Out of memory\n");
532 return DSERR_INVALIDPARAM
;
535 This
->dev
= alcCaptureOpenDevice(This
->parent
->device
, This
->format
.Format
.nSamplesPerSec
, buf_format
, This
->format
.Format
.nSamplesPerSec
/ FAKE_REFRESH_COUNT
* 2);
538 ERR("Couldn't open device %s 0x%x@%"LONGFMT
"u, reason: %04x\n", This
->parent
->device
, buf_format
, This
->format
.Format
.nSamplesPerSec
, alcGetError(NULL
));
539 return DSERR_INVALIDPARAM
;
545 static HRESULT WINAPI
DSCBuffer_Lock(IDirectSoundCaptureBuffer8
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
547 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
550 TRACE("(%p)->(%"LONGFMT
"u, %"LONGFMT
"u, %p, %p, %p, %p, %#"LONGFMT
"x)\n", iface
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
554 WARN("Invalid pointer/len %p %p\n", ptr1
, len1
);
555 return DSERR_INVALIDPARAM
;
560 if(ptr2
) *ptr2
= NULL
;
563 if(ofs
>= This
->buf_size
)
565 WARN("Invalid ofs %"LONGFMT
"u\n", ofs
);
566 return DSERR_INVALIDPARAM
;
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
);
574 return DSERR_INVALIDPARAM
;
577 if(InterlockedExchange(&This
->locked
, TRUE
) == TRUE
)
579 WARN("Already locked\n");
580 return DSERR_INVALIDPARAM
;
583 if(ofs
+ bytes
>= This
->buf_size
)
585 *len1
= This
->buf_size
- ofs
;
586 remain
= bytes
- *len1
;
593 *ptr1
= This
->buf
+ ofs
;
595 if(ptr2
&& len2
&& remain
)
604 static HRESULT WINAPI
DSCBuffer_Start(IDirectSoundCaptureBuffer8
*iface
, DWORD flags
)
606 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
608 TRACE("(%p)->(%08"LONGFMT
"x)\n", iface
, flags
);
610 EnterCriticalSection(&This
->parent
->crst
);
613 DSCBuffer_starttimer(This
);
615 alcCaptureStart(This
->dev
);
617 This
->looping
= !!(flags
& DSCBSTART_LOOPING
);
618 LeaveCriticalSection(&This
->parent
->crst
);
622 static HRESULT WINAPI
DSCBuffer_Stop(IDirectSoundCaptureBuffer8
*iface
)
624 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
626 TRACE("(%p)->()\n", iface
);
628 EnterCriticalSection(&This
->parent
->crst
);
632 for(i
= 0;i
< This
->nnotify
;++i
)
634 if(This
->notify
[i
].dwOffset
== DSCBPN_OFFSET_STOP
)
635 SetEvent(This
->notify
[i
].hEventNotify
);
638 This
->playing
= This
->looping
= 0;
639 alcCaptureStop(This
->dev
);
641 LeaveCriticalSection(&This
->parent
->crst
);
645 static HRESULT WINAPI
DSCBuffer_Unlock(IDirectSoundCaptureBuffer8
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
647 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
648 DWORD_PTR ofs1
, ofs2
;
649 DWORD_PTR boundary
= (DWORD_PTR
)This
->buf
;
651 TRACE("(%p)->(%p, %"LONGFMT
"u, %p, %"LONGFMT
"u)\n", iface
, ptr1
, len1
, ptr2
, len2
);
653 if(InterlockedExchange(&This
->locked
, FALSE
) == FALSE
)
655 WARN("Not locked\n");
656 return DSERR_INVALIDPARAM
;
659 /* Make sure offset is between boundary and boundary + bufsize */
660 ofs1
= (DWORD_PTR
)ptr1
;
661 ofs2
= (DWORD_PTR
)ptr2
;
663 return DSERR_INVALIDPARAM
;
664 if(ofs2
&& ofs2
!= boundary
)
665 return DSERR_INVALIDPARAM
;
669 if(This
->buf_size
-ofs1
< len1
|| len2
> ofs1
)
670 return DSERR_INVALIDPARAM
;
675 static HRESULT WINAPI
DSCBuffer_GetObjectInPath(IDirectSoundCaptureBuffer8
*iface
, REFGUID guid
, DWORD num
, REFGUID riid
, void **ppv
)
677 FIXME("(%p)->(%s, %"LONGFMT
"u, %s, %p) stub\n", iface
, debugstr_guid(guid
), num
, debugstr_guid(riid
), ppv
);
681 static HRESULT WINAPI
DSCBuffer_GetFXStatus(IDirectSoundCaptureBuffer8
*iface
, DWORD count
, DWORD
*status
)
683 FIXME("(%p)->(%"LONGFMT
"u, %p) stub\n", iface
, count
, status
);
687 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl
=
689 DSCBuffer_QueryInterface
,
693 DSCBuffer_GetCurrentPosition
,
696 DSCBuffer_Initialize
,
701 DSCBuffer_GetObjectInPath
,
702 DSCBuffer_GetFXStatus
705 static inline DSCBuffer
*impl_from_IDirectSoundNotify(IDirectSoundNotify
*iface
)
707 return CONTAINING_RECORD(iface
, DSCBuffer
, IDirectSoundNotify_iface
);
710 static HRESULT WINAPI
DSCBufferNot_QueryInterface(IDirectSoundNotify
*iface
, REFIID riid
, void **ppv
)
712 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
713 return IDirectSoundCaptureBuffer_QueryInterface((IDirectSoundCaptureBuffer
*)This
, riid
, ppv
);
716 static ULONG WINAPI
DSCBufferNot_AddRef(IDirectSoundNotify
*iface
)
718 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
721 InterlockedIncrement(&This
->all_ref
);
722 ret
= InterlockedIncrement(&This
->not_ref
);
723 TRACE("new refcount %"LONGFMT
"d\n", ret
);
727 static ULONG WINAPI
DSCBufferNot_Release(IDirectSoundNotify
*iface
)
729 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
732 ret
= InterlockedDecrement(&This
->not_ref
);
733 TRACE("new refcount %"LONGFMT
"d\n", ret
);
734 if(InterlockedDecrement(&This
->all_ref
) == 0)
735 DSCBuffer_Destroy(This
);
740 static HRESULT WINAPI
DSCBufferNot_SetNotificationPositions(IDirectSoundNotify
*iface
, DWORD count
, const DSBPOSITIONNOTIFY
*notifications
)
742 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
743 DSBPOSITIONNOTIFY
*nots
;
747 TRACE("(%p)->(%"LONGFMT
"u, %p))\n", iface
, count
, notifications
);
749 EnterCriticalSection(&This
->parent
->crst
);
750 hr
= DSERR_INVALIDPARAM
;
751 if (count
&& !notifications
)
754 hr
= DSCBuffer_GetStatus(&This
->IDirectSoundCaptureBuffer8_iface
, &state
);
758 hr
= DSERR_INVALIDCALL
;
759 if (state
& DSCBSTATUS_CAPTURING
)
764 HeapFree(GetProcessHeap(), 0, This
->notify
);
771 hr
= DSERR_INVALIDPARAM
;
772 for (i
= 0; i
< count
; ++i
)
774 if (notifications
[i
].dwOffset
>= This
->buf_size
775 && notifications
[i
].dwOffset
!= DSCBPN_OFFSET_STOP
)
779 nots
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(*nots
));
782 memcpy(nots
, notifications
, count
*sizeof(*nots
));
783 HeapFree(GetProcessHeap(), 0, This
->notify
);
785 This
->nnotify
= count
;
790 LeaveCriticalSection(&This
->parent
->crst
);
794 static const IDirectSoundNotifyVtbl DSCNot_Vtbl
=
796 DSCBufferNot_QueryInterface
,
798 DSCBufferNot_Release
,
799 DSCBufferNot_SetNotificationPositions
803 static inline DSCImpl
*impl_from_IDirectSoundCapture(IDirectSoundCapture
*iface
)
805 return CONTAINING_RECORD(iface
, DSCImpl
, IDirectSoundCapture_iface
);
808 HRESULT
DSOUND_CaptureCreate(REFIID riid
, void **cap
)
814 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
815 if(!This
) return DSERR_OUTOFMEMORY
;
817 This
->IDirectSoundCapture_iface
.lpVtbl
= (IDirectSoundCaptureVtbl
*)&DSC_Vtbl
;
819 InitializeCriticalSection(&This
->crst
);
820 This
->crst
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DSCImpl.crst");
822 if(FAILED(IDirectSoundCapture_QueryInterface(&This
->IDirectSoundCapture_iface
, riid
, cap
)))
824 DSCImpl_Destroy(This
);
825 return E_NOINTERFACE
;
830 static void DSCImpl_Destroy(DSCImpl
*This
)
832 EnterCriticalSection(&This
->crst
);
834 DSCBuffer_Destroy(This
->buf
);
835 LeaveCriticalSection(&This
->crst
);
837 HeapFree(GetProcessHeap(), 0, This
->device
);
839 This
->crst
.DebugInfo
->Spare
[0] = 0;
840 DeleteCriticalSection(&This
->crst
);
842 HeapFree(GetProcessHeap(), 0, This
);
845 static HRESULT WINAPI
DSCImpl_QueryInterface(IDirectSoundCapture
*iface
, REFIID riid
, void **ppv
)
847 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
849 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
852 if(IsEqualIID(riid
, &IID_IUnknown
) ||
853 IsEqualIID(riid
, &IID_IDirectSoundCapture
))
854 *ppv
= &This
->IDirectSoundCapture_iface
;
856 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
860 IUnknown_AddRef((IUnknown
*)*ppv
);
864 return E_NOINTERFACE
;
867 static ULONG WINAPI
DSCImpl_AddRef(IDirectSoundCapture
*iface
)
869 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
872 ref
= InterlockedIncrement(&This
->ref
);
873 TRACE("Reference count incremented to %"LONGFMT
"i\n", ref
);
878 static ULONG WINAPI
DSCImpl_Release(IDirectSoundCapture
*iface
)
880 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
883 ref
= InterlockedDecrement(&This
->ref
);
884 TRACE("Reference count decremented to %"LONGFMT
"i\n", ref
);
886 DSCImpl_Destroy(This
);
891 static HRESULT WINAPI
DSCImpl_CreateCaptureBuffer(IDirectSoundCapture
*iface
, const DSCBUFFERDESC
*desc
, IDirectSoundCaptureBuffer
**ppv
, IUnknown
*unk
)
893 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
896 TRACE("(%p)->(%p, %p, %p)\n", iface
, desc
, ppv
, unk
);
900 WARN("Aggregation isn't supported\n");
901 return DSERR_NOAGGREGATION
;
904 if(!desc
|| desc
->dwSize
< sizeof(DSCBUFFERDESC1
))
906 WARN("Passed invalid description %p %"LONGFMT
"u\n", desc
, desc
?desc
->dwSize
:0);
907 return DSERR_INVALIDPARAM
;
911 WARN("Passed null pointer\n");
912 return DSERR_INVALIDPARAM
;
916 EnterCriticalSection(&This
->crst
);
919 hr
= DSERR_UNINITIALIZED
;
920 WARN("Not initialized\n");
925 hr
= DSERR_ALLOCATED
;
926 WARN("Capture buffer already allocated\n");
930 hr
= DSCBuffer_Create(&This
->buf
, This
);
933 hr
= IDirectSoundCaptureBuffer8_Initialize(&This
->buf
->IDirectSoundCaptureBuffer8_iface
, iface
, desc
);
935 *ppv
= (IDirectSoundCaptureBuffer
*)&This
->buf
->IDirectSoundCaptureBuffer8_iface
;
938 DSCBuffer_Destroy(This
->buf
);
944 LeaveCriticalSection(&This
->crst
);
948 static HRESULT WINAPI
DSCImpl_GetCaps(IDirectSoundCapture
*iface
, DSCCAPS
*caps
)
950 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
952 TRACE("(%p)->(%p)\n", iface
, caps
);
955 WARN("Not initialized\n");
956 return DSERR_UNINITIALIZED
;
960 WARN("Caps is null\n");
961 return DSERR_INVALIDPARAM
;
963 if(caps
->dwSize
< sizeof(*caps
)) {
964 WARN("Invalid size %"LONGFMT
"d\n", caps
->dwSize
);
965 return DSERR_INVALIDPARAM
;
969 /* Support all WAVE_FORMAT formats specified in mmsystem.h */
970 caps
->dwFormats
= 0x000fffff;
971 caps
->dwChannels
= 2;
976 static HRESULT WINAPI
DSCImpl_Initialize(IDirectSoundCapture
*iface
, const GUID
*devguid
)
978 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
980 const ALCchar
*devs
, *drv_name
;
984 TRACE("(%p)->(%p)\n", iface
, devguid
);
988 ERR("OpenAL not loaded!\n");
989 return DSERR_NODRIVER
;
993 WARN("Already initialized\n");
994 return DSERR_ALREADYINITIALIZED
;
997 if(!devguid
|| IsEqualGUID(devguid
, &GUID_NULL
))
998 devguid
= &DSDEVID_DefaultCapture
;
1000 hr
= GetDeviceID(devguid
, &guid
);
1002 return DSERR_INVALIDPARAM
;
1005 EnterCriticalSection(&This
->crst
);
1006 EnterCriticalSection(&openal_crst
);
1007 devs
= DSOUND_getcapturedevicestrings();
1010 hr
= DSERR_NODRIVER
;
1011 if(memcmp(devguid
, &DSOUND_capture_guid
, sizeof(GUID
)-1) ||
1014 WARN("No driver found\n");
1020 const ALCchar
*str
= devs
;
1023 str
+= strlen(str
) + 1;
1026 WARN("No driver string found\n");
1035 This
->device
= HeapAlloc(GetProcessHeap(), 0, strlen(drv_name
)+1);
1038 WARN("Out of memory to allocate %s\n", drv_name
);
1041 strcpy(This
->device
, drv_name
);
1045 LeaveCriticalSection(&openal_crst
);
1046 LeaveCriticalSection(&This
->crst
);
1050 static const IDirectSoundCaptureVtbl DSC_Vtbl
=
1052 DSCImpl_QueryInterface
,
1055 DSCImpl_CreateCaptureBuffer
,