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
26 #include "dsound_private.h"
28 #ifndef DSCBPN_OFFSET_STOP
29 #define DSCBPN_OFFSET_STOP 0xffffffff
33 typedef struct DSCImpl DSCImpl
;
34 typedef struct DSCBuffer DSCBuffer
;
37 /* IDirectSoundCapture and IDirectSoundCapture8 are aliases */
38 IDirectSoundCapture IDirectSoundCapture_iface
;
39 IUnknown IUnknown_iface
;
40 LONG allref
, dscref
, unkref
;
47 CRITICAL_SECTION crst
;
51 IDirectSoundCaptureBuffer8 IDirectSoundCaptureBuffer8_iface
;
52 IDirectSoundNotify IDirectSoundNotify_iface
;
64 WAVEFORMATEXTENSIBLE format
;
66 DSBPOSITIONNOTIFY
*notify
;
74 volatile LONG quit_now
;
77 BOOL playing
, looping
;
80 static const IDirectSoundCaptureVtbl DSC_Vtbl
;
81 static const IUnknownVtbl DSC_Unknown_Vtbl
;
82 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl
;
83 static const IDirectSoundNotifyVtbl DSCNot_Vtbl
;
85 static void DSCImpl_Destroy(DSCImpl
*This
);
87 static void trigger_notifies(DSCBuffer
*buf
, DWORD lastpos
, DWORD curpos
)
94 for(i
= 0;i
< buf
->nnotify
;++i
)
96 DSBPOSITIONNOTIFY
*not = &buf
->notify
[i
];
97 HANDLE event
= not->hEventNotify
;
98 DWORD ofs
= not->dwOffset
;
100 if (ofs
== DSCBPN_OFFSET_STOP
)
103 /* Wraparound case */
106 if(ofs
< curpos
|| ofs
>= lastpos
)
108 TRACE("Triggering notification %lu (%lu) from buffer %p\n", i
, ofs
, buf
);
115 if(ofs
>= lastpos
&& ofs
< curpos
)
117 TRACE("Triggering notification %lu (%lu) from buffer %p\n", i
, ofs
, buf
);
123 static DWORD CALLBACK
DSCBuffer_thread(void *param
)
125 DSCBuffer
*This
= param
;
126 CRITICAL_SECTION
*crst
= &This
->parent
->crst
;
128 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL
);
130 while(WaitForSingleObject(This
->timer_evt
, INFINITE
) == WAIT_OBJECT_0
&& !This
->quit_now
)
134 alcGetIntegerv(This
->device
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
135 if(avail
== 0 || !This
->playing
) continue;
137 EnterCriticalSection(crst
);
140 LeaveCriticalSection(crst
);
144 avail
*= This
->format
.Format
.nBlockAlign
;
145 if((DWORD
)avail
> This
->buf_size
- This
->pos
)
146 avail
= This
->buf_size
- This
->pos
;
148 alcCaptureSamples(This
->device
, This
->buf
+This
->pos
,
149 avail
/This
->format
.Format
.nBlockAlign
);
150 trigger_notifies(This
, This
->pos
, This
->pos
+ avail
);
153 if(This
->pos
== This
->buf_size
)
159 for(i
= 0;i
< This
->nnotify
;++i
)
161 if(This
->notify
[i
].dwOffset
== DSCBPN_OFFSET_STOP
)
162 SetEvent(This
->notify
[i
].hEventNotify
);
166 alcCaptureStop(This
->device
);
170 alcGetIntegerv(This
->device
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
171 if(avail
) goto more_samples
;
175 LeaveCriticalSection(crst
);
182 static void CALLBACK
DSCBuffer_timer(void *arg
, BOOLEAN unused
)
185 SetEvent((HANDLE
)arg
);
188 static void DSCBuffer_starttimer(DSCBuffer
*This
)
190 ALint refresh
= FAKE_REFRESH_COUNT
;
193 if(This
->queue_timer
)
196 triggertime
= 1000 / refresh
* 2 / 3;
197 TRACE("Calling timer every %lu ms for %i refreshes per second\n", triggertime
, refresh
);
199 CreateTimerQueueTimer(&This
->queue_timer
, NULL
, DSCBuffer_timer
, This
->timer_evt
,
200 triggertime
, triggertime
, WT_EXECUTEINTIMERTHREAD
);
203 static HRESULT
DSCBuffer_Create(DSCBuffer
**buf
, DSCImpl
*parent
)
205 DSCBuffer
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
206 if(!This
) return E_OUTOFMEMORY
;
208 This
->IDirectSoundCaptureBuffer8_iface
.lpVtbl
= &DSCBuffer_Vtbl
;
209 This
->IDirectSoundNotify_iface
.lpVtbl
= &DSCNot_Vtbl
;
211 This
->all_ref
= This
->ref
= 1;
213 This
->parent
= parent
;
215 This
->quit_now
= FALSE
;
216 This
->timer_evt
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
217 if(!This
->timer_evt
) goto fail
;
219 This
->queue_timer
= NULL
;
221 This
->thread_hdl
= CreateThread(NULL
, 0, DSCBuffer_thread
, This
, 0, &This
->thread_id
);
222 if(!This
->thread_hdl
) goto fail
;
229 CloseHandle(This
->timer_evt
);
230 This
->timer_evt
= NULL
;
232 HeapFree(GetProcessHeap(), 0, This
);
236 static void DSCBuffer_Destroy(DSCBuffer
*This
)
238 if(This
->queue_timer
)
239 DeleteTimerQueueTimer(NULL
, This
->queue_timer
, INVALID_HANDLE_VALUE
);
240 This
->queue_timer
= NULL
;
244 InterlockedExchange(&This
->quit_now
, TRUE
);
245 SetEvent(This
->timer_evt
);
247 if(WaitForSingleObject(This
->thread_hdl
, 1000) != WAIT_OBJECT_0
)
248 ERR("Thread wait timed out\n");
250 CloseHandle(This
->thread_hdl
);
251 This
->thread_hdl
= NULL
;
255 CloseHandle(This
->timer_evt
);
256 This
->timer_evt
= NULL
;
261 alcCaptureStop(This
->device
);
262 alcCaptureCloseDevice(This
->device
);
264 This
->parent
->buf
= NULL
;
266 HeapFree(GetProcessHeap(), 0, This
->notify
);
267 HeapFree(GetProcessHeap(), 0, This
->buf
);
268 HeapFree(GetProcessHeap(), 0, This
);
271 static inline DSCBuffer
*impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8
*iface
)
273 return CONTAINING_RECORD(iface
, DSCBuffer
, IDirectSoundCaptureBuffer8_iface
);
276 static HRESULT WINAPI
DSCBuffer_QueryInterface(IDirectSoundCaptureBuffer8
*iface
, REFIID riid
, void **ppv
)
278 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
280 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
286 if(IsEqualIID(riid
, &IID_IUnknown
) ||
287 IsEqualIID(riid
, &IID_IDirectSoundCaptureBuffer
))
288 *ppv
= &This
->IDirectSoundCaptureBuffer8_iface
;
289 else if(IsEqualIID(riid
, &IID_IDirectSoundCaptureBuffer8
))
291 if(This
->parent
->is_8
)
292 *ppv
= &This
->IDirectSoundCaptureBuffer8_iface
;
294 else if(IsEqualIID(riid
, &IID_IDirectSoundNotify
))
295 *ppv
= &This
->IDirectSoundNotify_iface
;
297 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
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 %li\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 %li\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, %lu, %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
<= 0 || format
->nChannels
> 2)
435 WARN("Invalid Channels %d\n", format
->nChannels
);
436 return DSERR_INVALIDPARAM
;
438 if(format
->wBitsPerSample
<= 0 || (format
->wBitsPerSample
%8) != 0)
440 WARN("Invalid BitsPerSample %d\n", format
->wBitsPerSample
);
441 return DSERR_INVALIDPARAM
;
443 if(format
->nBlockAlign
!= format
->nChannels
*format
->wBitsPerSample
/8)
445 WARN("Invalid BlockAlign %d (expected %u = %u*%u/8)\n",
446 format
->nBlockAlign
, format
->nChannels
*format
->wBitsPerSample
/8,
447 format
->nChannels
, format
->wBitsPerSample
);
448 return DSERR_INVALIDPARAM
;
450 if(format
->nSamplesPerSec
< DSBFREQUENCY_MIN
|| format
->nSamplesPerSec
> DSBFREQUENCY_MAX
)
452 WARN("Invalid sample rate %lu\n", format
->nSamplesPerSec
);
453 return DSERR_INVALIDPARAM
;
455 if(format
->nAvgBytesPerSec
!= format
->nSamplesPerSec
*format
->nBlockAlign
)
457 WARN("Invalid AvgBytesPerSec %lu (expected %lu = %lu*%u)\n",
458 format
->nAvgBytesPerSec
, format
->nSamplesPerSec
*format
->nBlockAlign
,
459 format
->nSamplesPerSec
, format
->nBlockAlign
);
460 return DSERR_INVALIDPARAM
;
463 if(format
->wFormatTag
== WAVE_FORMAT_PCM
)
465 if(format
->nChannels
== 1)
467 switch(format
->wBitsPerSample
)
469 case 8: buf_format
= AL_FORMAT_MONO8
; break;
470 case 16: buf_format
= AL_FORMAT_MONO16
; break;
472 WARN("Unsupported bpp %u\n", format
->wBitsPerSample
);
473 return DSERR_BADFORMAT
;
476 else if(format
->nChannels
== 2)
478 switch(format
->wBitsPerSample
)
480 case 8: buf_format
= AL_FORMAT_STEREO8
; break;
481 case 16: buf_format
= AL_FORMAT_STEREO16
; break;
483 WARN("Unsupported bpp %u\n", format
->wBitsPerSample
);
484 return DSERR_BADFORMAT
;
488 WARN("Unsupported channels: %d\n", format
->nChannels
);
490 This
->format
.Format
= *format
;
491 This
->format
.Format
.cbSize
= 0;
493 else if(format
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
495 WAVEFORMATEXTENSIBLE
*wfe
;
497 if(format
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
))
498 return DSERR_INVALIDPARAM
;
499 else if(format
->cbSize
> sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
) &&
500 format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
))
501 return DSERR_CONTROLUNAVAIL
;
503 wfe
= CONTAINING_RECORD(format
, WAVEFORMATEXTENSIBLE
, Format
);
504 if(!IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))
505 return DSERR_BADFORMAT
;
506 if(wfe
->Samples
.wValidBitsPerSample
&&
507 wfe
->Samples
.wValidBitsPerSample
!= wfe
->Format
.wBitsPerSample
)
508 return DSERR_BADFORMAT
;
510 if(wfe
->Format
.nChannels
== 1 && wfe
->dwChannelMask
== SPEAKER_FRONT_CENTER
)
512 switch(wfe
->Format
.wBitsPerSample
)
514 case 8: buf_format
= AL_FORMAT_MONO8
; break;
515 case 16: buf_format
= AL_FORMAT_MONO16
; break;
517 WARN("Unsupported bpp %u\n", wfe
->Format
.wBitsPerSample
);
518 return DSERR_BADFORMAT
;
521 else if(wfe
->Format
.nChannels
== 2 && wfe
->dwChannelMask
== (SPEAKER_FRONT_LEFT
|SPEAKER_FRONT_RIGHT
))
523 switch(wfe
->Format
.wBitsPerSample
)
525 case 8: buf_format
= AL_FORMAT_STEREO8
; break;
526 case 16: buf_format
= AL_FORMAT_STEREO16
; break;
528 WARN("Unsupported bpp %u\n", wfe
->Format
.wBitsPerSample
);
529 return DSERR_BADFORMAT
;
533 WARN("Unsupported channels: %d -- 0x%08lu\n", wfe
->Format
.nChannels
, wfe
->dwChannelMask
);
536 This
->format
.Format
.cbSize
= sizeof(This
->format
) - sizeof(This
->format
.Format
);
537 This
->format
.Samples
.wValidBitsPerSample
= This
->format
.Format
.wBitsPerSample
;
540 WARN("Unhandled formattag %x\n", format
->wFormatTag
);
544 WARN("Could not get OpenAL format\n");
545 return DSERR_INVALIDPARAM
;
548 if(desc
->dwBufferBytes
< This
->format
.Format
.nBlockAlign
||
549 (desc
->dwBufferBytes
%This
->format
.Format
.nBlockAlign
) != 0)
551 WARN("Invalid BufferBytes (%lu %% %d)\n", desc
->dwBufferBytes
,
552 This
->format
.Format
.nBlockAlign
);
553 return DSERR_INVALIDPARAM
;
557 This
->buf_size
= desc
->dwBufferBytes
;
558 This
->buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->buf_size
);
561 WARN("Out of memory\n");
562 return DSERR_INVALIDPARAM
;
565 This
->device
= alcCaptureOpenDevice(This
->parent
->device_name
,
566 This
->format
.Format
.nSamplesPerSec
, buf_format
,
567 This
->format
.Format
.nSamplesPerSec
/ FAKE_REFRESH_COUNT
* 2
571 ERR("Couldn't open device %s 0x%x@%lu, reason: %04x\n", This
->parent
->device_name
,
572 buf_format
, This
->format
.Format
.nSamplesPerSec
, alcGetError(NULL
));
573 return DSERR_INVALIDPARAM
;
579 static HRESULT WINAPI
DSCBuffer_Lock(IDirectSoundCaptureBuffer8
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
581 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
584 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, %#lx)\n", iface
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
588 WARN("Invalid pointer/len %p %p\n", ptr1
, len1
);
589 return DSERR_INVALIDPARAM
;
594 if(ptr2
) *ptr2
= NULL
;
597 if(ofs
>= This
->buf_size
)
599 WARN("Invalid ofs %lu\n", ofs
);
600 return DSERR_INVALIDPARAM
;
603 if((flags
&DSCBLOCK_ENTIREBUFFER
))
604 bytes
= This
->buf_size
;
605 else if(bytes
> This
->buf_size
)
607 WARN("Invalid size %lu\n", bytes
);
608 return DSERR_INVALIDPARAM
;
611 if(InterlockedExchange(&This
->locked
, TRUE
) == TRUE
)
613 WARN("Already locked\n");
614 return DSERR_INVALIDPARAM
;
617 if(ofs
+ bytes
>= This
->buf_size
)
619 *len1
= This
->buf_size
- ofs
;
620 remain
= bytes
- *len1
;
627 *ptr1
= This
->buf
+ ofs
;
629 if(ptr2
&& len2
&& remain
)
638 static HRESULT WINAPI
DSCBuffer_Start(IDirectSoundCaptureBuffer8
*iface
, DWORD flags
)
640 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
642 TRACE("(%p)->(%08lx)\n", iface
, flags
);
644 EnterCriticalSection(&This
->parent
->crst
);
647 DSCBuffer_starttimer(This
);
649 alcCaptureStart(This
->device
);
651 This
->looping
|= !!(flags
& DSCBSTART_LOOPING
);
652 LeaveCriticalSection(&This
->parent
->crst
);
656 static HRESULT WINAPI
DSCBuffer_Stop(IDirectSoundCaptureBuffer8
*iface
)
658 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
660 TRACE("(%p)->()\n", iface
);
662 EnterCriticalSection(&This
->parent
->crst
);
666 for(i
= 0;i
< This
->nnotify
;++i
)
668 if(This
->notify
[i
].dwOffset
== DSCBPN_OFFSET_STOP
)
669 SetEvent(This
->notify
[i
].hEventNotify
);
672 This
->playing
= This
->looping
= 0;
673 alcCaptureStop(This
->device
);
675 LeaveCriticalSection(&This
->parent
->crst
);
679 static HRESULT WINAPI
DSCBuffer_Unlock(IDirectSoundCaptureBuffer8
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
681 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
682 DWORD_PTR ofs1
, ofs2
;
683 DWORD_PTR boundary
= (DWORD_PTR
)This
->buf
;
685 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface
, ptr1
, len1
, ptr2
, len2
);
687 if(InterlockedExchange(&This
->locked
, FALSE
) == FALSE
)
689 WARN("Not locked\n");
690 return DSERR_INVALIDPARAM
;
693 /* Make sure offset is between boundary and boundary + bufsize */
694 ofs1
= (DWORD_PTR
)ptr1
;
695 ofs2
= (DWORD_PTR
)ptr2
;
697 return DSERR_INVALIDPARAM
;
698 if(ofs2
&& ofs2
!= boundary
)
699 return DSERR_INVALIDPARAM
;
703 if(This
->buf_size
-ofs1
< len1
|| len2
> ofs1
)
704 return DSERR_INVALIDPARAM
;
709 static HRESULT WINAPI
DSCBuffer_GetObjectInPath(IDirectSoundCaptureBuffer8
*iface
, REFGUID guid
, DWORD num
, REFGUID riid
, void **ppv
)
711 FIXME("(%p)->(%s, %lu, %s, %p) stub\n", iface
, debugstr_guid(guid
), num
, debugstr_guid(riid
), ppv
);
715 static HRESULT WINAPI
DSCBuffer_GetFXStatus(IDirectSoundCaptureBuffer8
*iface
, DWORD count
, DWORD
*status
)
717 FIXME("(%p)->(%lu, %p) stub\n", iface
, count
, status
);
721 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl
=
723 DSCBuffer_QueryInterface
,
727 DSCBuffer_GetCurrentPosition
,
730 DSCBuffer_Initialize
,
735 DSCBuffer_GetObjectInPath
,
736 DSCBuffer_GetFXStatus
739 static inline DSCBuffer
*impl_from_IDirectSoundNotify(IDirectSoundNotify
*iface
)
741 return CONTAINING_RECORD(iface
, DSCBuffer
, IDirectSoundNotify_iface
);
744 static HRESULT WINAPI
DSCBufferNot_QueryInterface(IDirectSoundNotify
*iface
, REFIID riid
, void **ppv
)
746 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
747 return IDirectSoundCaptureBuffer_QueryInterface(&This
->IDirectSoundCaptureBuffer8_iface
, riid
, ppv
);
750 static ULONG WINAPI
DSCBufferNot_AddRef(IDirectSoundNotify
*iface
)
752 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
755 InterlockedIncrement(&This
->all_ref
);
756 ret
= InterlockedIncrement(&This
->not_ref
);
757 TRACE("new refcount %ld\n", ret
);
761 static ULONG WINAPI
DSCBufferNot_Release(IDirectSoundNotify
*iface
)
763 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
766 ret
= InterlockedDecrement(&This
->not_ref
);
767 TRACE("new refcount %ld\n", ret
);
768 if(InterlockedDecrement(&This
->all_ref
) == 0)
769 DSCBuffer_Destroy(This
);
774 static HRESULT WINAPI
DSCBufferNot_SetNotificationPositions(IDirectSoundNotify
*iface
, DWORD count
, const DSBPOSITIONNOTIFY
*notifications
)
776 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
777 DSBPOSITIONNOTIFY
*nots
;
781 TRACE("(%p)->(%lu, %p))\n", iface
, count
, notifications
);
783 EnterCriticalSection(&This
->parent
->crst
);
784 hr
= DSERR_INVALIDPARAM
;
785 if (count
&& !notifications
)
788 hr
= DSCBuffer_GetStatus(&This
->IDirectSoundCaptureBuffer8_iface
, &state
);
789 if(FAILED(hr
)) goto out
;
791 hr
= DSERR_INVALIDCALL
;
792 if (state
& DSCBSTATUS_CAPTURING
)
797 HeapFree(GetProcessHeap(), 0, This
->notify
);
804 hr
= DSERR_INVALIDPARAM
;
805 for (i
= 0; i
< count
; ++i
)
807 if (notifications
[i
].dwOffset
>= This
->buf_size
808 && notifications
[i
].dwOffset
!= DSCBPN_OFFSET_STOP
)
812 nots
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(*nots
));
815 memcpy(nots
, notifications
, count
*sizeof(*nots
));
816 HeapFree(GetProcessHeap(), 0, This
->notify
);
818 This
->nnotify
= count
;
823 LeaveCriticalSection(&This
->parent
->crst
);
827 static const IDirectSoundNotifyVtbl DSCNot_Vtbl
=
829 DSCBufferNot_QueryInterface
,
831 DSCBufferNot_Release
,
832 DSCBufferNot_SetNotificationPositions
836 static inline DSCImpl
*impl_from_IDirectSoundCapture(IDirectSoundCapture
*iface
)
838 return CONTAINING_RECORD(iface
, DSCImpl
, IDirectSoundCapture_iface
);
841 static inline DSCImpl
*impl_from_IUnknown(IUnknown
*iface
)
843 return CONTAINING_RECORD(iface
, DSCImpl
, IUnknown_iface
);
846 static HRESULT WINAPI
DSCImpl_QueryInterface(IDirectSoundCapture
*iface
, REFIID riid
, void **ppv
);
847 static ULONG WINAPI
DSCImpl_AddRef(IDirectSoundCapture
*iface
);
848 static ULONG WINAPI
DSCImpl_Release(IDirectSoundCapture
*iface
);
850 HRESULT
DSOUND_CaptureCreate(REFIID riid
, void **cap
)
854 hr
= DSOUND_CaptureCreate8(&IID_IDirectSoundCapture
, cap
);
857 DSCImpl
*impl
= impl_from_IDirectSoundCapture(*cap
);
860 if(!IsEqualIID(riid
, &IID_IDirectSoundCapture
))
862 hr
= DSCImpl_QueryInterface(&impl
->IDirectSoundCapture_iface
, riid
, cap
);
863 DSCImpl_Release(&impl
->IDirectSoundCapture_iface
);
869 HRESULT
DSOUND_CaptureCreate8(REFIID riid
, void **cap
)
875 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
876 if(!This
) return DSERR_OUTOFMEMORY
;
878 This
->IDirectSoundCapture_iface
.lpVtbl
= &DSC_Vtbl
;
879 This
->IUnknown_iface
.lpVtbl
= &DSC_Unknown_Vtbl
;
883 InitializeCriticalSection(&This
->crst
);
885 if(FAILED(DSCImpl_QueryInterface(&This
->IDirectSoundCapture_iface
, riid
, cap
)))
887 DSCImpl_Destroy(This
);
888 return E_NOINTERFACE
;
893 static void DSCImpl_Destroy(DSCImpl
*This
)
895 EnterCriticalSection(&This
->crst
);
897 DSCBuffer_Destroy(This
->buf
);
898 LeaveCriticalSection(&This
->crst
);
900 HeapFree(GetProcessHeap(), 0, This
->device_name
);
902 DeleteCriticalSection(&This
->crst
);
904 HeapFree(GetProcessHeap(), 0, This
);
908 static HRESULT WINAPI
DSCImpl_IUnknown_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppobj
)
910 DSCImpl
*This
= impl_from_IUnknown(iface
);
911 return DSCImpl_QueryInterface(&This
->IDirectSoundCapture_iface
, riid
, ppobj
);
914 static ULONG WINAPI
DSCImpl_IUnknown_AddRef(IUnknown
*iface
)
916 DSCImpl
*This
= impl_from_IUnknown(iface
);
919 InterlockedIncrement(&(This
->allref
));
920 ref
= InterlockedIncrement(&(This
->unkref
));
921 TRACE("(%p) ref was %lu\n", This
, ref
- 1);
926 static ULONG WINAPI
DSCImpl_IUnknown_Release(IUnknown
*iface
)
928 DSCImpl
*This
= impl_from_IUnknown(iface
);
929 ULONG ref
= InterlockedDecrement(&(This
->unkref
));
930 TRACE("(%p) ref was %lu\n", This
, ref
+ 1);
931 if(InterlockedDecrement(&(This
->allref
)) == 0)
932 DSCImpl_Destroy(This
);
936 static const IUnknownVtbl DSC_Unknown_Vtbl
= {
937 DSCImpl_IUnknown_QueryInterface
,
938 DSCImpl_IUnknown_AddRef
,
939 DSCImpl_IUnknown_Release
943 static HRESULT WINAPI
DSCImpl_QueryInterface(IDirectSoundCapture
*iface
, REFIID riid
, void **ppv
)
945 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
947 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
950 if(IsEqualIID(riid
, &IID_IDirectSoundCapture
))
951 *ppv
= &This
->IDirectSoundCapture_iface
;
952 else if(IsEqualIID(riid
, &IID_IUnknown
))
953 *ppv
= &This
->IUnknown_iface
;
955 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
959 IUnknown_AddRef((IUnknown
*)*ppv
);
963 return E_NOINTERFACE
;
966 static ULONG WINAPI
DSCImpl_AddRef(IDirectSoundCapture
*iface
)
968 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
971 InterlockedIncrement(&(This
->allref
));
972 ref
= InterlockedIncrement(&This
->dscref
);
973 TRACE("Reference count incremented to %li\n", ref
);
978 static ULONG WINAPI
DSCImpl_Release(IDirectSoundCapture
*iface
)
980 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
983 ref
= InterlockedDecrement(&This
->dscref
);
984 TRACE("Reference count decremented to %li\n", ref
);
985 if(InterlockedDecrement(&This
->allref
) == 0)
986 DSCImpl_Destroy(This
);
991 static HRESULT WINAPI
DSCImpl_CreateCaptureBuffer(IDirectSoundCapture
*iface
, const DSCBUFFERDESC
*desc
, IDirectSoundCaptureBuffer
**ppv
, IUnknown
*unk
)
993 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
997 TRACE("(%p)->(%p, %p, %p)\n", iface
, desc
, ppv
, unk
);
1001 WARN("Aggregation isn't supported\n");
1002 return DSERR_NOAGGREGATION
;
1005 if(!desc
|| desc
->dwSize
< sizeof(DSCBUFFERDESC1
))
1007 WARN("Passed invalid description %p %lu\n", desc
, desc
?desc
->dwSize
:0);
1008 return DSERR_INVALIDPARAM
;
1012 WARN("Passed null pointer\n");
1013 return DSERR_INVALIDPARAM
;
1017 EnterCriticalSection(&This
->crst
);
1018 if(!This
->device_name
)
1020 hr
= DSERR_UNINITIALIZED
;
1021 WARN("Not initialized\n");
1026 hr
= DSERR_ALLOCATED
;
1027 WARN("Capture buffer already allocated\n");
1031 hr
= DSCBuffer_Create(&buffer
, This
);
1034 hr
= DSCBuffer_Initialize(&buffer
->IDirectSoundCaptureBuffer8_iface
, iface
, desc
);
1036 DSCBuffer_Release(&buffer
->IDirectSoundCaptureBuffer8_iface
);
1040 *ppv
= (IDirectSoundCaptureBuffer
*)&buffer
->IDirectSoundCaptureBuffer8_iface
;
1045 LeaveCriticalSection(&This
->crst
);
1049 static HRESULT WINAPI
DSCImpl_GetCaps(IDirectSoundCapture
*iface
, DSCCAPS
*caps
)
1051 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
1053 TRACE("(%p)->(%p)\n", iface
, caps
);
1055 if(!This
->device_name
)
1057 WARN("Not initialized\n");
1058 return DSERR_UNINITIALIZED
;
1062 WARN("Caps is null\n");
1063 return DSERR_INVALIDPARAM
;
1065 if(caps
->dwSize
< sizeof(*caps
)) {
1066 WARN("Invalid size %ld\n", caps
->dwSize
);
1067 return DSERR_INVALIDPARAM
;
1071 /* Support all WAVE_FORMAT formats specified in mmsystem.h */
1072 caps
->dwFormats
= 0x000fffff;
1073 caps
->dwChannels
= 2;
1078 static HRESULT WINAPI
DSCImpl_Initialize(IDirectSoundCapture
*iface
, const GUID
*devguid
)
1080 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
1081 OLECHAR
*guid_str
= NULL
;
1086 TRACE("(%p)->(%p)\n", iface
, devguid
);
1090 ERR("OpenAL not loaded!\n");
1091 return DSERR_NODRIVER
;
1094 if(This
->device_name
)
1096 WARN("Already initialized\n");
1097 return DSERR_ALREADYINITIALIZED
;
1100 if(!devguid
|| IsEqualGUID(devguid
, &GUID_NULL
))
1101 devguid
= &DSDEVID_DefaultCapture
;
1102 else if(IsEqualGUID(devguid
, &DSDEVID_DefaultPlayback
) ||
1103 IsEqualGUID(devguid
, &DSDEVID_DefaultVoicePlayback
))
1104 return DSERR_NODRIVER
;
1106 hr
= GetDeviceID(devguid
, &guid
);
1107 if(FAILED(hr
)) return hr
;
1111 hr
= StringFromCLSID(devguid
, &guid_str
);
1114 ERR("Failed to convert GUID to string\n");
1118 EnterCriticalSection(&This
->crst
);
1119 EnterCriticalSection(&openal_crst
);
1122 len
= WideCharToMultiByte(CP_UTF8
, 0, guid_str
, -1, NULL
, 0, NULL
, NULL
);
1125 ERR("Failed to convert GUID to string\n");
1129 This
->device_name
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
+1);
1130 if(!This
->device_name
)
1132 WARN("Out of memory to duplicate string \"%ls\"\n", guid_str
);
1135 WideCharToMultiByte(CP_UTF8
, 0, guid_str
, -1, This
->device_name
, len
, NULL
, NULL
);
1139 LeaveCriticalSection(&openal_crst
);
1140 LeaveCriticalSection(&This
->crst
);
1142 CoTaskMemFree(guid_str
);
1147 static const IDirectSoundCaptureVtbl DSC_Vtbl
=
1149 DSCImpl_QueryInterface
,
1152 DSCImpl_CreateCaptureBuffer
,