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
32 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM
, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
35 typedef struct DSCImpl DSCImpl
;
36 typedef struct DSCBuffer DSCBuffer
;
39 /* IDirectSoundCapture and IDirectSoundCapture8 are aliases */
40 IDirectSoundCapture IDirectSoundCapture_iface
;
41 IUnknown IUnknown_iface
;
42 LONG allref
, dscref
, unkref
;
49 CRITICAL_SECTION crst
;
53 IDirectSoundCaptureBuffer8 IDirectSoundCaptureBuffer8_iface
;
54 IDirectSoundNotify IDirectSoundNotify_iface
;
66 WAVEFORMATEXTENSIBLE format
;
68 DSBPOSITIONNOTIFY
*notify
;
76 volatile LONG quit_now
;
79 BOOL playing
, looping
;
82 static const IDirectSoundCaptureVtbl DSC_Vtbl
;
83 static const IUnknownVtbl DSC_Unknown_Vtbl
;
84 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl
;
85 static const IDirectSoundNotifyVtbl DSCNot_Vtbl
;
87 static void DSCImpl_Destroy(DSCImpl
*This
);
89 static void trigger_notifies(DSCBuffer
*buf
, DWORD lastpos
, DWORD curpos
)
96 for(i
= 0;i
< buf
->nnotify
;++i
)
98 DSBPOSITIONNOTIFY
*not = &buf
->notify
[i
];
99 HANDLE event
= not->hEventNotify
;
100 DWORD ofs
= not->dwOffset
;
102 if (ofs
== DSCBPN_OFFSET_STOP
)
105 /* Wraparound case */
108 if(ofs
< curpos
|| ofs
>= lastpos
)
110 TRACE("Triggering notification %lu (%lu) from buffer %p\n", i
, ofs
, buf
);
117 if(ofs
>= lastpos
&& ofs
< curpos
)
119 TRACE("Triggering notification %lu (%lu) from buffer %p\n", i
, ofs
, buf
);
125 static DWORD CALLBACK
DSCBuffer_thread(void *param
)
127 DSCBuffer
*This
= param
;
128 CRITICAL_SECTION
*crst
= &This
->parent
->crst
;
130 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL
);
132 while(WaitForSingleObject(This
->timer_evt
, INFINITE
) == WAIT_OBJECT_0
&& !This
->quit_now
)
136 alcGetIntegerv(This
->dev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
137 if(avail
== 0 || !This
->playing
) continue;
139 EnterCriticalSection(crst
);
142 LeaveCriticalSection(crst
);
146 avail
*= This
->format
.Format
.nBlockAlign
;
147 if((DWORD
)avail
> This
->buf_size
- This
->pos
)
148 avail
= This
->buf_size
- This
->pos
;
150 alcCaptureSamples(This
->dev
, This
->buf
+This
->pos
, avail
/This
->format
.Format
.nBlockAlign
);
151 trigger_notifies(This
, This
->pos
, This
->pos
+ avail
);
154 if(This
->pos
== This
->buf_size
)
160 for(i
= 0;i
< This
->nnotify
;++i
)
162 if(This
->notify
[i
].dwOffset
== DSCBPN_OFFSET_STOP
)
163 SetEvent(This
->notify
[i
].hEventNotify
);
167 alcCaptureStop(This
->dev
);
171 alcGetIntegerv(This
->dev
, ALC_CAPTURE_SAMPLES
, 1, &avail
);
172 if(avail
) goto more_samples
;
176 LeaveCriticalSection(crst
);
183 static void CALLBACK
DSCBuffer_timer(void *arg
, BOOLEAN unused
)
186 SetEvent((HANDLE
)arg
);
189 static void DSCBuffer_starttimer(DSCBuffer
*This
)
191 ALint refresh
= FAKE_REFRESH_COUNT
;
194 if(This
->queue_timer
)
197 triggertime
= 1000 / refresh
* 2 / 3;
198 TRACE("Calling timer every %lu ms for %i refreshes per second\n", triggertime
, refresh
);
200 CreateTimerQueueTimer(&This
->queue_timer
, NULL
, DSCBuffer_timer
, This
->timer_evt
,
201 triggertime
, triggertime
, WT_EXECUTEINTIMERTHREAD
);
204 static HRESULT
DSCBuffer_Create(DSCBuffer
**buf
, DSCImpl
*parent
)
206 DSCBuffer
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
207 if(!This
) return E_OUTOFMEMORY
;
209 This
->IDirectSoundCaptureBuffer8_iface
.lpVtbl
= &DSCBuffer_Vtbl
;
210 This
->IDirectSoundNotify_iface
.lpVtbl
= &DSCNot_Vtbl
;
212 This
->all_ref
= This
->ref
= 1;
214 This
->parent
= parent
;
216 This
->quit_now
= FALSE
;
217 This
->timer_evt
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
218 if(!This
->timer_evt
) goto fail
;
220 This
->queue_timer
= NULL
;
222 This
->thread_hdl
= CreateThread(NULL
, 0, DSCBuffer_thread
, This
, 0, &This
->thread_id
);
223 if(!This
->thread_hdl
) goto fail
;
230 CloseHandle(This
->timer_evt
);
231 This
->timer_evt
= NULL
;
233 HeapFree(GetProcessHeap(), 0, This
);
237 static void DSCBuffer_Destroy(DSCBuffer
*This
)
239 if(This
->queue_timer
)
240 DeleteTimerQueueTimer(NULL
, This
->queue_timer
, INVALID_HANDLE_VALUE
);
241 This
->queue_timer
= NULL
;
245 InterlockedExchange(&This
->quit_now
, TRUE
);
246 SetEvent(This
->timer_evt
);
248 if(WaitForSingleObject(This
->thread_hdl
, 1000) != WAIT_OBJECT_0
)
249 ERR("Thread wait timed out\n");
251 CloseHandle(This
->thread_hdl
);
252 This
->thread_hdl
= NULL
;
256 CloseHandle(This
->timer_evt
);
257 This
->timer_evt
= NULL
;
262 alcCaptureStop(This
->dev
);
263 alcCaptureCloseDevice(This
->dev
);
265 This
->parent
->buf
= NULL
;
267 HeapFree(GetProcessHeap(), 0, This
->notify
);
268 HeapFree(GetProcessHeap(), 0, This
->buf
);
269 HeapFree(GetProcessHeap(), 0, This
);
272 static inline DSCBuffer
*impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8
*iface
)
274 return CONTAINING_RECORD(iface
, DSCBuffer
, IDirectSoundCaptureBuffer8_iface
);
277 static HRESULT WINAPI
DSCBuffer_QueryInterface(IDirectSoundCaptureBuffer8
*iface
, REFIID riid
, void **ppv
)
279 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
281 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
287 if(IsEqualIID(riid
, &IID_IUnknown
) ||
288 IsEqualIID(riid
, &IID_IDirectSoundCaptureBuffer
))
289 *ppv
= &This
->IDirectSoundCaptureBuffer8_iface
;
290 else if(IsEqualIID(riid
, &IID_IDirectSoundCaptureBuffer8
))
292 if(This
->parent
->is_8
)
293 *ppv
= &This
->IDirectSoundCaptureBuffer8_iface
;
295 else if(IsEqualIID(riid
, &IID_IDirectSoundNotify
))
296 *ppv
= &This
->IDirectSoundNotify_iface
;
298 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
301 return E_NOINTERFACE
;
302 IUnknown_AddRef((IUnknown
*)*ppv
);
306 static ULONG WINAPI
DSCBuffer_AddRef(IDirectSoundCaptureBuffer8
*iface
)
308 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
311 InterlockedIncrement(&This
->all_ref
);
312 ref
= InterlockedIncrement(&This
->ref
);
313 TRACE("Reference count incremented to %li\n", ref
);
318 static ULONG WINAPI
DSCBuffer_Release(IDirectSoundCaptureBuffer8
*iface
)
320 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
323 ref
= InterlockedDecrement(&This
->ref
);
324 TRACE("Reference count decremented to %li\n", ref
);
325 if(InterlockedDecrement(&This
->all_ref
) == 0)
326 DSCBuffer_Destroy(This
);
331 static HRESULT WINAPI
DSCBuffer_GetCaps(IDirectSoundCaptureBuffer8
*iface
, DSCBCAPS
*caps
)
333 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
335 if (!caps
|| caps
->dwSize
< sizeof(*caps
))
336 return DSERR_INVALIDPARAM
;
337 caps
->dwSize
= sizeof(*caps
);
339 caps
->dwBufferBytes
= This
->buf_size
;
343 static HRESULT WINAPI
DSCBuffer_GetCurrentPosition(IDirectSoundCaptureBuffer8
*iface
, DWORD
*cappos
, DWORD
*readpos
)
345 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
348 EnterCriticalSection(&This
->parent
->crst
);
352 pos2
= This
->format
.Format
.nSamplesPerSec
/ 100;
353 pos2
*= This
->format
.Format
.nBlockAlign
;
355 if (!This
->looping
&& pos2
>= This
->buf_size
)
358 pos2
%= This
->buf_size
;
362 LeaveCriticalSection(&This
->parent
->crst
);
364 if(cappos
) *cappos
= pos1
;
365 if(readpos
) *readpos
= pos2
;
370 static HRESULT WINAPI
DSCBuffer_GetFormat(IDirectSoundCaptureBuffer8
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
372 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
376 TRACE("(%p)->(%p, %lu, %p)\n", iface
, wfx
, allocated
, written
);
380 WARN("Cannot report format or format size\n");
381 return DSERR_INVALIDPARAM
;
384 size
= sizeof(This
->format
.Format
) + This
->format
.Format
.cbSize
;
388 hr
= DSERR_INVALIDPARAM
;
390 memcpy(wfx
, &This
->format
.Format
, size
);
398 static HRESULT WINAPI
DSCBuffer_GetStatus(IDirectSoundCaptureBuffer8
*iface
, DWORD
*status
)
400 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
402 TRACE("(%p)->(%p)\n", iface
, status
);
405 return DSERR_INVALIDPARAM
;
406 EnterCriticalSection(&This
->parent
->crst
);
410 *status
|= DSCBSTATUS_CAPTURING
;
412 *status
|= DSCBSTATUS_LOOPING
;
414 LeaveCriticalSection(&This
->parent
->crst
);
419 static HRESULT WINAPI
DSCBuffer_Initialize(IDirectSoundCaptureBuffer8
*iface
, IDirectSoundCapture
*parent
, const DSCBUFFERDESC
*desc
)
421 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
422 WAVEFORMATEX
*format
;
423 ALenum buf_format
= -1;
425 TRACE("(%p)->(%p, %p)\n", iface
, parent
, desc
);
428 return DSERR_ALREADYINITIALIZED
;
430 if (!desc
->lpwfxFormat
)
431 return DSERR_INVALIDPARAM
;
433 format
= desc
->lpwfxFormat
;
434 if(format
->nChannels
<= 0 || format
->nChannels
> 2)
436 WARN("Invalid Channels %d\n", format
->nChannels
);
437 return DSERR_INVALIDPARAM
;
439 if(format
->wBitsPerSample
<= 0 || (format
->wBitsPerSample
%8) != 0)
441 WARN("Invalid BitsPerSample %d\n", format
->wBitsPerSample
);
442 return DSERR_INVALIDPARAM
;
444 if(format
->nBlockAlign
!= format
->nChannels
*format
->wBitsPerSample
/8)
446 WARN("Invalid BlockAlign %d (expected %u = %u*%u/8)\n",
447 format
->nBlockAlign
, format
->nChannels
*format
->wBitsPerSample
/8,
448 format
->nChannels
, format
->wBitsPerSample
);
449 return DSERR_INVALIDPARAM
;
451 if(format
->nSamplesPerSec
< DSBFREQUENCY_MIN
|| format
->nSamplesPerSec
> DSBFREQUENCY_MAX
)
453 WARN("Invalid sample rate %lu\n", format
->nSamplesPerSec
);
454 return DSERR_INVALIDPARAM
;
456 if(format
->nAvgBytesPerSec
!= format
->nSamplesPerSec
*format
->nBlockAlign
)
458 WARN("Invalid AvgBytesPerSec %lu (expected %lu = %lu*%u)\n",
459 format
->nAvgBytesPerSec
, format
->nSamplesPerSec
*format
->nBlockAlign
,
460 format
->nSamplesPerSec
, format
->nBlockAlign
);
461 return DSERR_INVALIDPARAM
;
464 if(format
->wFormatTag
== WAVE_FORMAT_PCM
)
466 if(format
->nChannels
== 1)
468 switch(format
->wBitsPerSample
)
470 case 8: buf_format
= AL_FORMAT_MONO8
; break;
471 case 16: buf_format
= AL_FORMAT_MONO16
; break;
473 WARN("Unsupported bpp %u\n", format
->wBitsPerSample
);
474 return DSERR_BADFORMAT
;
477 else if(format
->nChannels
== 2)
479 switch(format
->wBitsPerSample
)
481 case 8: buf_format
= AL_FORMAT_STEREO8
; break;
482 case 16: buf_format
= AL_FORMAT_STEREO16
; break;
484 WARN("Unsupported bpp %u\n", format
->wBitsPerSample
);
485 return DSERR_BADFORMAT
;
489 WARN("Unsupported channels: %d\n", format
->nChannels
);
491 This
->format
.Format
= *format
;
492 This
->format
.Format
.cbSize
= 0;
494 else if(format
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
496 WAVEFORMATEXTENSIBLE
*wfe
;
498 if(format
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
))
499 return DSERR_INVALIDPARAM
;
500 else if(format
->cbSize
> sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
) &&
501 format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
))
502 return DSERR_CONTROLUNAVAIL
;
504 wfe
= CONTAINING_RECORD(format
, WAVEFORMATEXTENSIBLE
, Format
);
505 if(!IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))
506 return DSERR_BADFORMAT
;
507 if(wfe
->Samples
.wValidBitsPerSample
&&
508 wfe
->Samples
.wValidBitsPerSample
!= wfe
->Format
.wBitsPerSample
)
509 return DSERR_BADFORMAT
;
511 if(wfe
->Format
.nChannels
== 1 && wfe
->dwChannelMask
== SPEAKER_FRONT_CENTER
)
513 switch(wfe
->Format
.wBitsPerSample
)
515 case 8: buf_format
= AL_FORMAT_MONO8
; break;
516 case 16: buf_format
= AL_FORMAT_MONO16
; break;
518 WARN("Unsupported bpp %u\n", wfe
->Format
.wBitsPerSample
);
519 return DSERR_BADFORMAT
;
522 else if(wfe
->Format
.nChannels
== 2 && wfe
->dwChannelMask
== (SPEAKER_FRONT_LEFT
|SPEAKER_FRONT_RIGHT
))
524 switch(wfe
->Format
.wBitsPerSample
)
526 case 8: buf_format
= AL_FORMAT_STEREO8
; break;
527 case 16: buf_format
= AL_FORMAT_STEREO16
; break;
529 WARN("Unsupported bpp %u\n", wfe
->Format
.wBitsPerSample
);
530 return DSERR_BADFORMAT
;
534 WARN("Unsupported channels: %d -- 0x%08lu\n", wfe
->Format
.nChannels
, wfe
->dwChannelMask
);
537 This
->format
.Format
.cbSize
= sizeof(This
->format
) - sizeof(This
->format
.Format
);
538 This
->format
.Samples
.wValidBitsPerSample
= This
->format
.Format
.wBitsPerSample
;
541 WARN("Unhandled formattag %x\n", format
->wFormatTag
);
545 WARN("Could not get OpenAL format\n");
546 return DSERR_INVALIDPARAM
;
549 if(desc
->dwBufferBytes
< This
->format
.Format
.nBlockAlign
||
550 (desc
->dwBufferBytes
%This
->format
.Format
.nBlockAlign
) != 0)
552 WARN("Invalid BufferBytes (%lu %% %d)\n", desc
->dwBufferBytes
,
553 This
->format
.Format
.nBlockAlign
);
554 return DSERR_INVALIDPARAM
;
558 This
->buf_size
= desc
->dwBufferBytes
;
559 This
->buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->buf_size
);
562 WARN("Out of memory\n");
563 return DSERR_INVALIDPARAM
;
566 This
->dev
= alcCaptureOpenDevice(This
->parent
->device
, This
->format
.Format
.nSamplesPerSec
, buf_format
, This
->format
.Format
.nSamplesPerSec
/ FAKE_REFRESH_COUNT
* 2);
569 ERR("Couldn't open device %s 0x%x@%lu, reason: %04x\n", This
->parent
->device
, buf_format
, This
->format
.Format
.nSamplesPerSec
, alcGetError(NULL
));
570 return DSERR_INVALIDPARAM
;
576 static HRESULT WINAPI
DSCBuffer_Lock(IDirectSoundCaptureBuffer8
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
578 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
581 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, %#lx)\n", iface
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
585 WARN("Invalid pointer/len %p %p\n", ptr1
, len1
);
586 return DSERR_INVALIDPARAM
;
591 if(ptr2
) *ptr2
= NULL
;
594 if(ofs
>= This
->buf_size
)
596 WARN("Invalid ofs %lu\n", ofs
);
597 return DSERR_INVALIDPARAM
;
600 if((flags
&DSCBLOCK_ENTIREBUFFER
))
601 bytes
= This
->buf_size
;
602 else if(bytes
> This
->buf_size
)
604 WARN("Invalid size %lu\n", bytes
);
605 return DSERR_INVALIDPARAM
;
608 if(InterlockedExchange(&This
->locked
, TRUE
) == TRUE
)
610 WARN("Already locked\n");
611 return DSERR_INVALIDPARAM
;
614 if(ofs
+ bytes
>= This
->buf_size
)
616 *len1
= This
->buf_size
- ofs
;
617 remain
= bytes
- *len1
;
624 *ptr1
= This
->buf
+ ofs
;
626 if(ptr2
&& len2
&& remain
)
635 static HRESULT WINAPI
DSCBuffer_Start(IDirectSoundCaptureBuffer8
*iface
, DWORD flags
)
637 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
639 TRACE("(%p)->(%08lx)\n", iface
, flags
);
641 EnterCriticalSection(&This
->parent
->crst
);
644 DSCBuffer_starttimer(This
);
646 alcCaptureStart(This
->dev
);
648 This
->looping
|= !!(flags
& DSCBSTART_LOOPING
);
649 LeaveCriticalSection(&This
->parent
->crst
);
653 static HRESULT WINAPI
DSCBuffer_Stop(IDirectSoundCaptureBuffer8
*iface
)
655 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
657 TRACE("(%p)->()\n", iface
);
659 EnterCriticalSection(&This
->parent
->crst
);
663 for(i
= 0;i
< This
->nnotify
;++i
)
665 if(This
->notify
[i
].dwOffset
== DSCBPN_OFFSET_STOP
)
666 SetEvent(This
->notify
[i
].hEventNotify
);
669 This
->playing
= This
->looping
= 0;
670 alcCaptureStop(This
->dev
);
672 LeaveCriticalSection(&This
->parent
->crst
);
676 static HRESULT WINAPI
DSCBuffer_Unlock(IDirectSoundCaptureBuffer8
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
678 DSCBuffer
*This
= impl_from_IDirectSoundCaptureBuffer8(iface
);
679 DWORD_PTR ofs1
, ofs2
;
680 DWORD_PTR boundary
= (DWORD_PTR
)This
->buf
;
682 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface
, ptr1
, len1
, ptr2
, len2
);
684 if(InterlockedExchange(&This
->locked
, FALSE
) == FALSE
)
686 WARN("Not locked\n");
687 return DSERR_INVALIDPARAM
;
690 /* Make sure offset is between boundary and boundary + bufsize */
691 ofs1
= (DWORD_PTR
)ptr1
;
692 ofs2
= (DWORD_PTR
)ptr2
;
694 return DSERR_INVALIDPARAM
;
695 if(ofs2
&& ofs2
!= boundary
)
696 return DSERR_INVALIDPARAM
;
700 if(This
->buf_size
-ofs1
< len1
|| len2
> ofs1
)
701 return DSERR_INVALIDPARAM
;
706 static HRESULT WINAPI
DSCBuffer_GetObjectInPath(IDirectSoundCaptureBuffer8
*iface
, REFGUID guid
, DWORD num
, REFGUID riid
, void **ppv
)
708 FIXME("(%p)->(%s, %lu, %s, %p) stub\n", iface
, debugstr_guid(guid
), num
, debugstr_guid(riid
), ppv
);
712 static HRESULT WINAPI
DSCBuffer_GetFXStatus(IDirectSoundCaptureBuffer8
*iface
, DWORD count
, DWORD
*status
)
714 FIXME("(%p)->(%lu, %p) stub\n", iface
, count
, status
);
718 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl
=
720 DSCBuffer_QueryInterface
,
724 DSCBuffer_GetCurrentPosition
,
727 DSCBuffer_Initialize
,
732 DSCBuffer_GetObjectInPath
,
733 DSCBuffer_GetFXStatus
736 static inline DSCBuffer
*impl_from_IDirectSoundNotify(IDirectSoundNotify
*iface
)
738 return CONTAINING_RECORD(iface
, DSCBuffer
, IDirectSoundNotify_iface
);
741 static HRESULT WINAPI
DSCBufferNot_QueryInterface(IDirectSoundNotify
*iface
, REFIID riid
, void **ppv
)
743 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
744 return IDirectSoundCaptureBuffer_QueryInterface((IDirectSoundCaptureBuffer
*)This
, riid
, ppv
);
747 static ULONG WINAPI
DSCBufferNot_AddRef(IDirectSoundNotify
*iface
)
749 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
752 InterlockedIncrement(&This
->all_ref
);
753 ret
= InterlockedIncrement(&This
->not_ref
);
754 TRACE("new refcount %ld\n", ret
);
758 static ULONG WINAPI
DSCBufferNot_Release(IDirectSoundNotify
*iface
)
760 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
763 ret
= InterlockedDecrement(&This
->not_ref
);
764 TRACE("new refcount %ld\n", ret
);
765 if(InterlockedDecrement(&This
->all_ref
) == 0)
766 DSCBuffer_Destroy(This
);
771 static HRESULT WINAPI
DSCBufferNot_SetNotificationPositions(IDirectSoundNotify
*iface
, DWORD count
, const DSBPOSITIONNOTIFY
*notifications
)
773 DSCBuffer
*This
= impl_from_IDirectSoundNotify(iface
);
774 DSBPOSITIONNOTIFY
*nots
;
778 TRACE("(%p)->(%lu, %p))\n", iface
, count
, notifications
);
780 EnterCriticalSection(&This
->parent
->crst
);
781 hr
= DSERR_INVALIDPARAM
;
782 if (count
&& !notifications
)
785 hr
= DSCBuffer_GetStatus(&This
->IDirectSoundCaptureBuffer8_iface
, &state
);
789 hr
= DSERR_INVALIDCALL
;
790 if (state
& DSCBSTATUS_CAPTURING
)
795 HeapFree(GetProcessHeap(), 0, This
->notify
);
802 hr
= DSERR_INVALIDPARAM
;
803 for (i
= 0; i
< count
; ++i
)
805 if (notifications
[i
].dwOffset
>= This
->buf_size
806 && notifications
[i
].dwOffset
!= DSCBPN_OFFSET_STOP
)
810 nots
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(*nots
));
813 memcpy(nots
, notifications
, count
*sizeof(*nots
));
814 HeapFree(GetProcessHeap(), 0, This
->notify
);
816 This
->nnotify
= count
;
821 LeaveCriticalSection(&This
->parent
->crst
);
825 static const IDirectSoundNotifyVtbl DSCNot_Vtbl
=
827 DSCBufferNot_QueryInterface
,
829 DSCBufferNot_Release
,
830 DSCBufferNot_SetNotificationPositions
834 static inline DSCImpl
*impl_from_IDirectSoundCapture(IDirectSoundCapture
*iface
)
836 return CONTAINING_RECORD(iface
, DSCImpl
, IDirectSoundCapture_iface
);
839 static inline DSCImpl
*impl_from_IUnknown(IUnknown
*iface
)
841 return CONTAINING_RECORD(iface
, DSCImpl
, IUnknown_iface
);
844 static HRESULT WINAPI
DSCImpl_QueryInterface(IDirectSoundCapture
*iface
, REFIID riid
, void **ppv
);
845 static ULONG WINAPI
DSCImpl_AddRef(IDirectSoundCapture
*iface
);
846 static ULONG WINAPI
DSCImpl_Release(IDirectSoundCapture
*iface
);
848 HRESULT
DSOUND_CaptureCreate(REFIID riid
, void **cap
)
852 hr
= DSOUND_CaptureCreate8(&IID_IDirectSoundCapture
, cap
);
855 DSCImpl
*impl
= impl_from_IDirectSoundCapture(*cap
);
858 if(!IsEqualIID(riid
, &IID_IDirectSoundCapture
))
860 hr
= DSCImpl_QueryInterface(&impl
->IDirectSoundCapture_iface
, riid
, cap
);
861 DSCImpl_Release(&impl
->IDirectSoundCapture_iface
);
867 HRESULT
DSOUND_CaptureCreate8(REFIID riid
, void **cap
)
873 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
874 if(!This
) return DSERR_OUTOFMEMORY
;
876 This
->IDirectSoundCapture_iface
.lpVtbl
= &DSC_Vtbl
;
877 This
->IUnknown_iface
.lpVtbl
= &DSC_Unknown_Vtbl
;
881 InitializeCriticalSection(&This
->crst
);
883 if(FAILED(DSCImpl_QueryInterface(&This
->IDirectSoundCapture_iface
, riid
, cap
)))
885 DSCImpl_Destroy(This
);
886 return E_NOINTERFACE
;
891 static void DSCImpl_Destroy(DSCImpl
*This
)
893 EnterCriticalSection(&This
->crst
);
895 DSCBuffer_Destroy(This
->buf
);
896 LeaveCriticalSection(&This
->crst
);
898 HeapFree(GetProcessHeap(), 0, This
->device
);
900 DeleteCriticalSection(&This
->crst
);
902 HeapFree(GetProcessHeap(), 0, This
);
906 static HRESULT WINAPI
DSCImpl_IUnknown_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppobj
)
908 DSCImpl
*This
= impl_from_IUnknown(iface
);
909 return DSCImpl_QueryInterface(&This
->IDirectSoundCapture_iface
, riid
, ppobj
);
912 static ULONG WINAPI
DSCImpl_IUnknown_AddRef(IUnknown
*iface
)
914 DSCImpl
*This
= impl_from_IUnknown(iface
);
917 InterlockedIncrement(&(This
->allref
));
918 ref
= InterlockedIncrement(&(This
->unkref
));
919 TRACE("(%p) ref was %lu\n", This
, ref
- 1);
924 static ULONG WINAPI
DSCImpl_IUnknown_Release(IUnknown
*iface
)
926 DSCImpl
*This
= impl_from_IUnknown(iface
);
927 ULONG ref
= InterlockedDecrement(&(This
->unkref
));
928 TRACE("(%p) ref was %lu\n", This
, ref
+ 1);
929 if(InterlockedDecrement(&(This
->allref
)) == 0)
930 DSCImpl_Destroy(This
);
934 static const IUnknownVtbl DSC_Unknown_Vtbl
= {
935 DSCImpl_IUnknown_QueryInterface
,
936 DSCImpl_IUnknown_AddRef
,
937 DSCImpl_IUnknown_Release
941 static HRESULT WINAPI
DSCImpl_QueryInterface(IDirectSoundCapture
*iface
, REFIID riid
, void **ppv
)
943 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
945 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
948 if(IsEqualIID(riid
, &IID_IDirectSoundCapture
))
949 *ppv
= &This
->IDirectSoundCapture_iface
;
950 else if(IsEqualIID(riid
, &IID_IUnknown
))
951 *ppv
= &This
->IUnknown_iface
;
953 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
957 IUnknown_AddRef((IUnknown
*)*ppv
);
961 return E_NOINTERFACE
;
964 static ULONG WINAPI
DSCImpl_AddRef(IDirectSoundCapture
*iface
)
966 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
969 InterlockedIncrement(&(This
->allref
));
970 ref
= InterlockedIncrement(&This
->dscref
);
971 TRACE("Reference count incremented to %li\n", ref
);
976 static ULONG WINAPI
DSCImpl_Release(IDirectSoundCapture
*iface
)
978 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
981 ref
= InterlockedDecrement(&This
->dscref
);
982 TRACE("Reference count decremented to %li\n", ref
);
983 if(InterlockedDecrement(&This
->allref
) == 0)
984 DSCImpl_Destroy(This
);
989 static HRESULT WINAPI
DSCImpl_CreateCaptureBuffer(IDirectSoundCapture
*iface
, const DSCBUFFERDESC
*desc
, IDirectSoundCaptureBuffer
**ppv
, IUnknown
*unk
)
991 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
994 TRACE("(%p)->(%p, %p, %p)\n", iface
, desc
, ppv
, unk
);
998 WARN("Aggregation isn't supported\n");
999 return DSERR_NOAGGREGATION
;
1002 if(!desc
|| desc
->dwSize
< sizeof(DSCBUFFERDESC1
))
1004 WARN("Passed invalid description %p %lu\n", desc
, desc
?desc
->dwSize
:0);
1005 return DSERR_INVALIDPARAM
;
1009 WARN("Passed null pointer\n");
1010 return DSERR_INVALIDPARAM
;
1014 EnterCriticalSection(&This
->crst
);
1017 hr
= DSERR_UNINITIALIZED
;
1018 WARN("Not initialized\n");
1023 hr
= DSERR_ALLOCATED
;
1024 WARN("Capture buffer already allocated\n");
1028 hr
= DSCBuffer_Create(&This
->buf
, This
);
1031 hr
= DSCBuffer_Initialize(&This
->buf
->IDirectSoundCaptureBuffer8_iface
, iface
, desc
);
1033 *ppv
= (IDirectSoundCaptureBuffer
*)&This
->buf
->IDirectSoundCaptureBuffer8_iface
;
1036 DSCBuffer_Destroy(This
->buf
);
1042 LeaveCriticalSection(&This
->crst
);
1046 static HRESULT WINAPI
DSCImpl_GetCaps(IDirectSoundCapture
*iface
, DSCCAPS
*caps
)
1048 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
1050 TRACE("(%p)->(%p)\n", iface
, caps
);
1053 WARN("Not initialized\n");
1054 return DSERR_UNINITIALIZED
;
1058 WARN("Caps is null\n");
1059 return DSERR_INVALIDPARAM
;
1061 if(caps
->dwSize
< sizeof(*caps
)) {
1062 WARN("Invalid size %ld\n", caps
->dwSize
);
1063 return DSERR_INVALIDPARAM
;
1067 /* Support all WAVE_FORMAT formats specified in mmsystem.h */
1068 caps
->dwFormats
= 0x000fffff;
1069 caps
->dwChannels
= 2;
1074 static HRESULT WINAPI
DSCImpl_Initialize(IDirectSoundCapture
*iface
, const GUID
*devguid
)
1076 DSCImpl
*This
= impl_from_IDirectSoundCapture(iface
);
1077 OLECHAR
*guid_str
= NULL
;
1082 TRACE("(%p)->(%p)\n", iface
, devguid
);
1086 ERR("OpenAL not loaded!\n");
1087 return DSERR_NODRIVER
;
1092 WARN("Already initialized\n");
1093 return DSERR_ALREADYINITIALIZED
;
1096 if(!devguid
|| IsEqualGUID(devguid
, &GUID_NULL
))
1097 devguid
= &DSDEVID_DefaultCapture
;
1098 else if(IsEqualGUID(devguid
, &DSDEVID_DefaultPlayback
) ||
1099 IsEqualGUID(devguid
, &DSDEVID_DefaultVoicePlayback
))
1100 return DSERR_NODRIVER
;
1102 hr
= GetDeviceID(devguid
, &guid
);
1103 if(FAILED(hr
)) return hr
;
1107 hr
= StringFromCLSID(devguid
, &guid_str
);
1110 ERR("Failed to convert GUID to string\n");
1114 EnterCriticalSection(&This
->crst
);
1115 EnterCriticalSection(&openal_crst
);
1118 len
= WideCharToMultiByte(CP_UTF8
, 0, guid_str
, -1, NULL
, 0, NULL
, NULL
);
1121 ERR("Failed to convert GUID to string\n");
1125 This
->device
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
+1);
1128 WARN("Out of memory to allocate %ls\n", guid_str
);
1131 WideCharToMultiByte(CP_UTF8
, 0, guid_str
, -1, This
->device
, len
, NULL
, NULL
);
1135 LeaveCriticalSection(&openal_crst
);
1136 LeaveCriticalSection(&This
->crst
);
1138 CoTaskMemFree(guid_str
);
1143 static const IDirectSoundCaptureVtbl DSC_Vtbl
=
1145 DSCImpl_QueryInterface
,
1148 DSCImpl_CreateCaptureBuffer
,