Fix some unused parameter warnings
[dsound-openal.git] / capture.c
blobf9842cc955b4d8276a3cfbc6330fce779ebc85ec
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
20 #include <stdarg.h>
22 #ifdef __WINESRC__
24 #define COBJMACROS
25 #define NONAMELESSSTRUCT
26 #define NONAMELESSUNION
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "winreg.h"
32 #include "mmsystem.h"
33 #include "winternl.h"
34 #include "mmddk.h"
35 #include "wine/debug.h"
36 #include "dsound.h"
38 #include "dsound_private.h"
40 #include "ks.h"
41 #include "ksmedia.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
45 #else
47 #define WINVER 0x0600
48 #include <windows.h>
49 #include <dsound.h>
51 #include "dsound_private.h"
53 #ifndef DSCBPN_OFFSET_STOP
54 #define DSCBPN_OFFSET_STOP 0xffffffff
55 #endif
57 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
59 #endif
61 /* IDirectSoundCapture and IDirectSoundCapture8 are aliases */
62 HRESULT DSOUND_CaptureCreate(REFIID riid, IDirectSoundCapture **cap)
64 return DSOUND_CaptureCreate8(riid, cap);
67 typedef struct DSCBuffer DSCBuffer;
69 typedef struct DSCImpl
71 const IDirectSoundCaptureVtbl *lpVtbl;
72 LONG ref;
74 ALCchar *device;
75 DSCBuffer *buf;
76 UINT timer_id;
77 DWORD timer_res;
78 CRITICAL_SECTION crst;
79 } DSCImpl;
81 struct DSCBuffer
83 const IDirectSoundCaptureBuffer8Vtbl *lpVtbl;
84 const IDirectSoundNotifyVtbl *lpNotVtbl;
85 LONG ref, not_ref;
86 DSCImpl *parent;
87 ALCdevice *dev;
88 DWORD buf_size;
89 BYTE *buf;
90 WAVEFORMATEX *format;
91 DSBPOSITIONNOTIFY *notify;
92 DWORD nnotify;
94 DWORD pos;
95 BOOL playing, looping;
98 static const IDirectSoundCaptureVtbl DSC_Vtbl;
99 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl;
100 static const IDirectSoundNotifyVtbl DSCNot_Vtbl;
102 static void DSCImpl_Destroy(DSCImpl *This);
104 static HRESULT DSCBuffer_Create(DSCBuffer **buf)
106 DSCBuffer *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
107 if (!This)
108 return E_OUTOFMEMORY;
109 This->lpVtbl = &DSCBuffer_Vtbl;
110 This->lpNotVtbl = &DSCNot_Vtbl;
111 This->ref = 1;
112 *buf = This;
113 return S_OK;
116 static void trigger_notifies(DSCBuffer *buf, DWORD lastpos, DWORD curpos)
118 DWORD i;
119 if (lastpos == curpos)
120 return;
121 for (i = 0; i < buf->nnotify; ++i)
123 DSBPOSITIONNOTIFY *not = &buf->notify[i];
124 HANDLE event = not->hEventNotify;
125 DWORD ofs = not->dwOffset;
127 if (ofs == DSCBPN_OFFSET_STOP)
128 continue;
130 /* Wraparound case */
131 if (curpos < lastpos)
133 if (ofs < curpos
134 || ofs >= lastpos)
135 SetEvent(event);
136 continue;
139 /* Normal case */
140 if (ofs >= lastpos
141 && ofs < curpos)
142 SetEvent(event);
146 static void CALLBACK DSCBuffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
147 DWORD_PTR dw1, DWORD_PTR dw2)
149 DSCImpl *This = (DSCImpl*)dwUser;
150 ALCint avail = 0;
151 DSCBuffer *buf;
152 (void)timerID;
153 (void)msg;
154 (void)dw1;
155 (void)dw2;
157 EnterCriticalSection(&This->crst);
158 buf = This->buf;
159 if (!buf || !buf->dev || !buf->playing)
160 goto out;
162 alcGetIntegerv(buf->dev, ALC_CAPTURE_SAMPLES, 1, &avail);
163 if (avail)
165 avail *= buf->format->nBlockAlign;
166 if (avail + buf->pos > buf->buf_size)
167 avail = buf->buf_size - buf->pos;
169 alcCaptureSamples(buf->dev, buf->buf + buf->pos, avail/buf->format->nBlockAlign);
170 trigger_notifies(buf, buf->pos, buf->pos + avail);
171 buf->pos += avail;
173 if (buf->pos == buf->buf_size)
175 buf->pos = 0;
176 if (!buf->looping)
177 IDirectSoundCaptureBuffer_Stop((IDirectSoundCaptureBuffer*)buf);
178 else
180 avail = 0;
181 alcGetIntegerv(buf->dev, ALC_CAPTURE_SAMPLES, 1, &avail);
182 avail *= buf->format->nBlockAlign;
183 if ((ALCuint)avail >= buf->buf_size)
185 ERR("TOO MUCH AVAIL: %u/%u\n", avail, buf->buf_size);
186 avail = buf->buf_size;
189 if (avail)
191 alcCaptureSamples(buf->dev, buf->buf + buf->pos, avail/buf->format->nBlockAlign);
192 trigger_notifies(buf, buf->pos, buf->pos + avail);
193 buf->pos += avail;
199 out:
200 LeaveCriticalSection(&This->crst);
201 return;
204 static void DSCBuffer_starttimer(DSCImpl *prim)
206 TIMECAPS time;
207 ALint refresh = FAKE_REFRESH_COUNT;
208 DWORD triggertime, res = DS_TIME_RES;
210 if (prim->timer_id)
211 return;
213 timeGetDevCaps(&time, sizeof(TIMECAPS));
214 triggertime = 1000 / refresh;
215 if (triggertime < time.wPeriodMin)
216 triggertime = time.wPeriodMin;
217 TRACE("Calling timer every %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 prim->timer_res = res;
223 prim->timer_id = timeSetEvent(triggertime, res, DSCBuffer_timer, (DWORD_PTR)prim, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
226 static void DSCBuffer_Destroy(DSCBuffer *This)
228 if (This->dev)
230 if (This->playing)
231 alcCaptureStop(This->dev);
232 alcCaptureCloseDevice(This->dev);
234 if (This->parent)
235 This->parent->buf = NULL;
236 HeapFree(GetProcessHeap(), 0, This->notify);
237 HeapFree(GetProcessHeap(), 0, This->format);
238 HeapFree(GetProcessHeap(), 0, This->buf);
239 HeapFree(GetProcessHeap(), 0, This);
242 static HRESULT WINAPI DSCBuffer_QueryInterface(IDirectSoundCaptureBuffer8 *iface, REFIID riid, void **ppv)
244 DSCBuffer *This = (DSCBuffer*)iface;
245 if (!ppv)
246 return E_POINTER;
247 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
248 *ppv = NULL;
249 if (IsEqualIID(riid, &IID_IDirectSoundNotify))
250 *ppv = &This->lpNotVtbl;
251 else if (IsEqualIID(riid, &IID_IUnknown)
252 || IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer)
253 || IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer8))
254 *ppv = This;
255 if (!*ppv)
256 return E_NOINTERFACE;
257 IUnknown_AddRef((IUnknown*)*ppv);
258 return S_OK;
261 static ULONG WINAPI DSCBuffer_AddRef(IDirectSoundCaptureBuffer8 *iface)
263 DSCBuffer *This = (DSCBuffer*)iface;
264 LONG ref;
265 ref = InterlockedIncrement(&This->ref);
266 TRACE("Reference count incremented to %i\n", ref);
267 return ref;
270 static ULONG WINAPI DSCBuffer_Release(IDirectSoundCaptureBuffer8 *iface)
272 DSCBuffer *This = (DSCBuffer*)iface;
273 CRITICAL_SECTION *crst = &This->parent->crst;
274 LONG ref;
275 EnterCriticalSection(crst);
276 ref = InterlockedDecrement(&This->ref);
277 TRACE("Reference count decremented to %i\n", ref);
278 if (!ref && !This->not_ref)
279 DSCBuffer_Destroy(This);
280 LeaveCriticalSection(crst);
281 return ref;
284 static HRESULT WINAPI DSCBuffer_GetCaps(IDirectSoundCaptureBuffer8 *iface, DSCBCAPS *caps)
286 DSCBuffer *This = (DSCBuffer*)iface;
288 if (!caps || caps->dwSize < sizeof(*caps))
289 return DSERR_INVALIDPARAM;
290 caps->dwSize = sizeof(*caps);
291 caps->dwFlags = 0;
292 caps->dwBufferBytes = This->buf_size;
293 return S_OK;
296 static HRESULT WINAPI DSCBuffer_GetCurrentPosition(IDirectSoundCaptureBuffer8 *iface, DWORD *cappos, DWORD *readpos)
298 DSCBuffer *This = (DSCBuffer*)iface;
299 DWORD pos1, pos2;
301 EnterCriticalSection(&This->parent->crst);
302 pos1 = This->pos;
303 if (This->playing)
305 pos2 = This->format->nSamplesPerSec / 100;
306 pos2 *= This->format->nBlockAlign;
307 pos2 += pos1;
308 if (!This->looping && pos2 >= This->buf_size)
309 pos2 = 0;
310 else
311 pos2 %= This->buf_size;
313 else
314 pos2 = pos1;
315 LeaveCriticalSection(&This->parent->crst);
317 if(cappos) *cappos = pos1;
318 if(readpos) *readpos = pos2;
320 return S_OK;
323 static HRESULT WINAPI DSCBuffer_GetFormat(IDirectSoundCaptureBuffer8 *iface, WAVEFORMATEX *wfx, DWORD size, DWORD *written)
325 DSCBuffer *This = (DSCBuffer*)iface;
326 TRACE("(%p,%p,%u,%p)\n", This, wfx, size, written);
328 if (size > sizeof(WAVEFORMATEX) + This->format->cbSize)
329 size = sizeof(WAVEFORMATEX) + This->format->cbSize;
331 if (wfx)
333 CopyMemory(wfx, This->format, size);
334 if (written)
335 *written = size;
336 } else if (written)
337 *written = sizeof(WAVEFORMATEX) + This->format->cbSize;
338 else
339 return DSERR_INVALIDPARAM;
341 return S_OK;
344 static HRESULT WINAPI DSCBuffer_GetStatus(IDirectSoundCaptureBuffer8 *iface, DWORD *status)
346 DSCBuffer *This = (DSCBuffer*)iface;
347 TRACE("(%p)->(%p)\n", This, status);
349 if (!status)
350 return DSERR_INVALIDPARAM;
351 EnterCriticalSection(&This->parent->crst);
352 *status = 0;
353 if (This->playing)
355 *status |= DSCBSTATUS_CAPTURING;
356 if (This->looping)
357 *status |= DSCBSTATUS_LOOPING;
359 LeaveCriticalSection(&This->parent->crst);
361 return S_OK;
364 static HRESULT WINAPI DSCBuffer_Initialize(IDirectSoundCaptureBuffer8 *iface, IDirectSoundCapture *parent, const DSCBUFFERDESC *desc)
366 DSCBuffer *This = (DSCBuffer*)iface;
367 WAVEFORMATEX *format;
368 ALenum buf_format = -1;
370 if (This->parent)
371 return DSERR_ALREADYINITIALIZED;
372 This->parent = (DSCImpl*)parent;
373 if (!desc->lpwfxFormat)
374 return DSERR_INVALIDPARAM;
376 format = desc->lpwfxFormat;
377 if (format->nChannels > 2)
379 WARN("nChannels > 2 not supported for recording\n");
380 return DSERR_INVALIDPARAM;
383 if (!This->format)
384 This->format = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
385 if (!This->format)
386 return DSERR_OUTOFMEMORY;
388 if (format->wFormatTag == WAVE_FORMAT_PCM
389 || format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
391 if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
393 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)format;
394 if (format->cbSize < sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX))
395 return DSERR_INVALIDPARAM;
396 else if (format->cbSize > sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)
397 && format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
398 return DSERR_CONTROLUNAVAIL;
399 else if (!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
400 return DSERR_BADFORMAT;
403 if (format->nChannels == 1)
405 switch (format->wBitsPerSample)
407 case 8: buf_format = AL_FORMAT_MONO8; break;
408 case 16: buf_format = AL_FORMAT_MONO16; break;
409 default:
410 WARN("Unsupported bpp %u\n", format->wBitsPerSample);
411 return DSERR_BADFORMAT;
414 else if (format->nChannels == 2)
416 switch (format->wBitsPerSample)
418 case 8: buf_format = AL_FORMAT_STEREO8; break;
419 case 16: buf_format = AL_FORMAT_STEREO16; break;
420 default:
421 WARN("Unsupported bpp %u\n", format->wBitsPerSample);
422 return DSERR_BADFORMAT;
425 memcpy(This->format, format, sizeof(*format) + format->cbSize);
426 if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
427 This->format->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
428 else
429 This->format->cbSize = 0;
430 This->format->nBlockAlign = This->format->wBitsPerSample * This->format->nChannels / 8;
431 This->format->nAvgBytesPerSec = This->format->nSamplesPerSec * This->format->nBlockAlign;
433 else if (format->wFormatTag)
434 WARN("Unhandled formattag %x\n", format->wFormatTag);
436 This->buf_size = desc->dwBufferBytes;
437 if(buf_format <= 0)
439 WARN("Could not get OpenAL format\n");
440 return DSERR_INVALIDPARAM;
442 This->dev = alcCaptureOpenDevice(This->parent->device, This->format->nSamplesPerSec, buf_format, This->buf_size / This->format->nBlockAlign);
443 if (!This->dev)
445 ERR("couldn't open device %s %x@%u, reason: %04x\n", This->parent->device, buf_format, This->format->nSamplesPerSec, alcGetError(NULL));
446 return DSERR_INVALIDPARAM;
448 This->buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->buf_size);
449 if (!This->buf)
451 alcCaptureCloseDevice(This->dev);
452 WARN("Out of memory\n");
453 return DSERR_INVALIDPARAM;
456 return S_OK;
459 static HRESULT WINAPI DSCBuffer_Lock(IDirectSoundCaptureBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
461 DSCBuffer *This = (DSCBuffer*)iface;
462 HRESULT hr;
463 DWORD remain;
464 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, %#x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
466 EnterCriticalSection(&This->parent->crst);
467 hr = DSERR_INVALIDPARAM;
468 if (ptr1)
469 *ptr1 = NULL;
470 if (len1)
471 *len1 = 0;
472 if (ptr2)
473 *ptr2 = NULL;
474 if (len2)
475 *len2 = 0;
476 if (ofs >= This->buf_size)
478 WARN("Invalid ofs %u\n", ofs);
479 goto out;
481 if (!ptr1 || !len1)
483 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
484 goto out;
486 if (flags & DSCBLOCK_ENTIREBUFFER)
487 bytes = This->buf_size;
488 if (bytes > This->buf_size)
490 WARN("Invalid size %u\n", bytes);
491 goto out;
494 if (ofs + bytes >= This->buf_size)
496 *len1 = This->buf_size - ofs;
497 remain = bytes - *len1;
499 else
501 *len1 = bytes;
502 remain = 0;
504 *ptr1 = This->buf + ofs;
506 if (ptr2 && len2 && remain)
508 *ptr2 = This->buf;
509 *len2 = remain;
511 hr = S_OK;
513 out:
514 LeaveCriticalSection(&This->parent->crst);
515 return hr;
518 static HRESULT WINAPI DSCBuffer_Start(IDirectSoundCaptureBuffer8 *iface, DWORD flags)
520 DSCBuffer *This = (DSCBuffer*)iface;
521 TRACE("(%p)->(%08x)\n", This, flags);
523 EnterCriticalSection(&This->parent->crst);
524 if (!This->playing)
526 DSCBuffer_starttimer(This->parent);
527 This->playing = 1;
528 alcCaptureStart(This->dev);
530 This->looping = !!(flags & DSCBSTART_LOOPING);
531 LeaveCriticalSection(&This->parent->crst);
532 return S_OK;
535 static HRESULT WINAPI DSCBuffer_Stop(IDirectSoundCaptureBuffer8 *iface)
537 DSCBuffer *This = (DSCBuffer*)iface;
538 TRACE("(%p)\n", This);
540 EnterCriticalSection(&This->parent->crst);
541 if (This->playing)
543 DWORD i;
545 for (i = 0; i < This->nnotify; ++i)
546 if (This->notify[i].dwOffset == DSCBPN_OFFSET_STOP)
548 SetEvent(This->notify[i].hEventNotify);
549 break;
551 This->playing = This->looping = 0;
552 alcCaptureStop(This->dev);
554 LeaveCriticalSection(&This->parent->crst);
555 return S_OK;
558 static HRESULT WINAPI DSCBuffer_Unlock(IDirectSoundCaptureBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
560 DSCBuffer *This = (DSCBuffer*)iface;
561 TRACE("(%p)->(%p,%u,%p,%u)\n", This, ptr1, len1, ptr2, len2);
563 if (!ptr1)
564 return DSERR_INVALIDPARAM;
565 return S_OK;
568 static HRESULT WINAPI DSCBuffer_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface, REFGUID guid, DWORD num, REFGUID riid, void **ppv)
570 DSCBuffer *This = (DSCBuffer*)iface;
571 FIXME("(%p)->(%s %u %s %p) stub\n", This, debugstr_guid(guid), num, debugstr_guid(riid), ppv);
572 return E_NOTIMPL;
575 static HRESULT WINAPI DSCBuffer_GetFXStatus(IDirectSoundCaptureBuffer8 *iface, DWORD count, DWORD *status)
577 DSCBuffer *This = (DSCBuffer*)iface;
578 FIXME("(%p)->(%u %p) stub\n", This, count, status);
579 return E_NOTIMPL;
582 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl =
584 DSCBuffer_QueryInterface,
585 DSCBuffer_AddRef,
586 DSCBuffer_Release,
587 DSCBuffer_GetCaps,
588 DSCBuffer_GetCurrentPosition,
589 DSCBuffer_GetFormat,
590 DSCBuffer_GetStatus,
591 DSCBuffer_Initialize,
592 DSCBuffer_Lock,
593 DSCBuffer_Start,
594 DSCBuffer_Stop,
595 DSCBuffer_Unlock,
596 DSCBuffer_GetObjectInPath,
597 DSCBuffer_GetFXStatus
600 static DSCBuffer *get_this_from_not(IDirectSoundNotify *iface)
602 return (DSCBuffer*)((char*)iface - offsetof(DSCBuffer,lpNotVtbl));
605 static HRESULT WINAPI DSCBufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
607 DSCBuffer *This = get_this_from_not(iface);
608 return IDirectSoundCaptureBuffer_QueryInterface((IDirectSoundCaptureBuffer*)This, riid, ppv);
611 static ULONG WINAPI DSCBufferNot_AddRef(IDirectSoundNotify *iface)
613 DSCBuffer *This = get_this_from_not(iface);
614 LONG ret;
616 ret = InterlockedIncrement(&This->not_ref);
617 TRACE("new refcount %d\n", ret);
618 return ret;
621 static ULONG WINAPI DSCBufferNot_Release(IDirectSoundNotify *iface)
623 DSCBuffer *This = get_this_from_not(iface);
624 CRITICAL_SECTION *crst = &This->parent->crst;
625 LONG ret;
627 EnterCriticalSection(crst);
628 ret = InterlockedDecrement(&This->not_ref);
629 TRACE("new refcount %d\n", ret);
630 if (!ret && !This->ref)
631 DSCBuffer_Destroy(This);
632 LeaveCriticalSection(crst);
633 return ret;
636 static HRESULT WINAPI DSCBufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
638 DSCBuffer *This = get_this_from_not(iface);
639 DSBPOSITIONNOTIFY *nots;
640 HRESULT hr;
641 DWORD state;
643 EnterCriticalSection(&This->parent->crst);
644 hr = DSERR_INVALIDPARAM;
645 if (count && !notifications)
646 goto out;
648 hr = DSCBuffer_GetStatus((IDirectSoundCaptureBuffer8*)This, &state);
649 if (FAILED(hr))
650 goto out;
652 hr = DSERR_INVALIDCALL;
653 if (state & DSCBSTATUS_CAPTURING)
654 goto out;
656 if (!count)
658 HeapFree(GetProcessHeap(), 0, This->notify);
659 This->notify = 0;
660 This->nnotify = 0;
662 else
664 DWORD i;
665 hr = DSERR_INVALIDPARAM;
666 for (i = 0; i < count; ++i)
668 if (notifications[i].dwOffset >= This->buf_size
669 && notifications[i].dwOffset != DSCBPN_OFFSET_STOP)
670 goto out;
672 hr = E_OUTOFMEMORY;
673 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
674 if (!nots)
675 goto out;
676 memcpy(nots, notifications, count*sizeof(*nots));
677 HeapFree(GetProcessHeap(), 0, This->notify);
678 This->notify = nots;
679 This->nnotify = count;
680 hr = S_OK;
683 out:
684 LeaveCriticalSection(&This->parent->crst);
685 return hr;
688 static const IDirectSoundNotifyVtbl DSCNot_Vtbl =
690 DSCBufferNot_QueryInterface,
691 DSCBufferNot_AddRef,
692 DSCBufferNot_Release,
693 DSCBufferNot_SetNotificationPositions
696 HRESULT DSOUND_CaptureCreate8(REFIID riid, IDirectSoundCapture8 **cap)
698 DSCImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
699 *cap = NULL;
700 if (!This)
701 return DSERR_OUTOFMEMORY;
702 This->lpVtbl = &DSC_Vtbl;
704 InitializeCriticalSection(&This->crst);
705 This->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DSCImpl.crst");
706 if (FAILED(IUnknown_QueryInterface((IUnknown*)This, riid, (void**)cap)))
708 DSCImpl_Destroy(This);
709 return E_NOINTERFACE;
711 return S_OK;
714 static void DSCImpl_Destroy(DSCImpl *This)
716 if (This->timer_id)
718 timeKillEvent(This->timer_id);
719 timeEndPeriod(This->timer_res);
721 EnterCriticalSection(&This->crst);
722 if (This->buf)
723 DSCBuffer_Destroy(This->buf);
724 LeaveCriticalSection(&This->crst);
725 HeapFree(GetProcessHeap(), 0, This->device);
726 This->crst.DebugInfo->Spare[0] = 0;
727 DeleteCriticalSection(&This->crst);
728 HeapFree(GetProcessHeap(), 0, This);
731 static HRESULT WINAPI DSCImpl_QueryInterface(IDirectSoundCapture *iface, REFIID riid, void **ppv)
733 *ppv = NULL;
734 if (IsEqualIID(riid, &IID_IUnknown)
735 || IsEqualIID(riid, &IID_IDirectSoundCapture))
737 *ppv = iface;
739 if (!*ppv)
740 return E_NOINTERFACE;
741 IUnknown_AddRef((IUnknown*)*ppv);
742 return S_OK;
745 static ULONG WINAPI DSCImpl_AddRef(IDirectSoundCapture8 *iface)
747 DSCImpl *This = (DSCImpl*)iface;
748 LONG ref;
749 ref = InterlockedIncrement(&This->ref);
750 TRACE("Reference count incremented to %i\n", ref);
751 return ref;
754 static ULONG WINAPI DSCImpl_Release(IDirectSoundCapture8 *iface)
756 DSCImpl *This = (DSCImpl*)iface;
757 LONG ref;
758 ref = InterlockedDecrement(&This->ref);
759 TRACE("Reference count decremented to %i\n", ref);
760 if (!ref)
761 DSCImpl_Destroy(This);
762 return ref;
765 static HRESULT WINAPI DSCImpl_CreateCaptureBuffer(IDirectSoundCapture8 *iface, const DSCBUFFERDESC *desc, IDirectSoundCaptureBuffer **ppv, IUnknown *unk)
767 DSCImpl *This = (DSCImpl*)iface;
768 HRESULT hr;
769 TRACE("(%p)->(%p,%p,%p)\n", This, desc, ppv, unk);
771 if (unk)
773 WARN("Aggregation isn't supported\n");
774 return DSERR_NOAGGREGATION;
777 if (!desc || desc->dwSize < sizeof(DSCBUFFERDESC1))
779 WARN("Passed invalid description %p %u\n", desc, desc?desc->dwSize:0);
780 return DSERR_INVALIDPARAM;
782 if (!ppv)
784 WARN("Passed null pointer\n");
785 return DSERR_INVALIDPARAM;
787 *ppv = NULL;
789 EnterCriticalSection(&This->crst);
790 if (!This->device)
792 hr = DSERR_UNINITIALIZED;
793 WARN("Not initialized\n");
794 goto out;
796 if (This->buf)
798 hr = DSERR_ALLOCATED;
799 WARN("Capture buffer already allocated\n");
800 goto out;
803 hr = DSCBuffer_Create(&This->buf);
804 if (SUCCEEDED(hr))
806 hr = IDirectSoundCaptureBuffer_Initialize((IDirectSoundCaptureBuffer*)This->buf, iface, desc);
807 if (FAILED(hr))
809 DSCBuffer_Destroy(This->buf);
810 This->buf = NULL;
813 *ppv = (IDirectSoundCaptureBuffer*)This->buf;
814 out:
815 LeaveCriticalSection(&This->crst);
816 return hr;
819 static HRESULT WINAPI DSCImpl_GetCaps(IDirectSoundCapture8 *iface, DSCCAPS *caps)
821 DSCImpl *This = (DSCImpl*)iface;
822 TRACE("(%p,%p)\n", This, caps);
824 if (!This->device) {
825 WARN("Not initialized\n");
826 return DSERR_UNINITIALIZED;
829 if (!caps) {
830 WARN("Caps is null\n");
831 return DSERR_INVALIDPARAM;
834 if (caps->dwSize < sizeof(*caps)) {
835 WARN("Invalid size %d\n", caps->dwSize);
836 return DSERR_INVALIDPARAM;
839 caps->dwFlags = 0;
840 /* Support all WAVE_FORMAT formats specified in mmsystem.h */
841 caps->dwFormats = 0x000fffff;
842 caps->dwChannels = 2;
844 return DS_OK;
847 static HRESULT WINAPI DSCImpl_Initialize(IDirectSoundCapture8 *iface, const GUID *devguid)
849 DSCImpl *This = (DSCImpl*)iface;
850 HRESULT hr;
851 const ALCchar *devs, *drv_name;
852 GUID guid;
853 UINT n;
854 TRACE("(%p,%p)\n", This, devguid);
856 if (!openal_loaded)
858 ERR("OpenAL not loaded!\n");
859 return DSERR_NODRIVER;
862 if (This->device) {
863 WARN("Already initialized\n");
864 return DSERR_ALREADYINITIALIZED;
867 if (!devguid)
868 devguid = &DSDEVID_DefaultCapture;
870 hr = GetDeviceID(devguid, &guid);
871 if (FAILED(hr))
872 return DSERR_INVALIDPARAM;
873 devguid = &guid;
875 EnterCriticalSection(&This->crst);
876 EnterCriticalSection(&openal_crst);
877 devs = DSOUND_getcapturedevicestrings();
878 n = guid.Data4[7];
880 hr = DSERR_NODRIVER;
881 if (memcmp(devguid, &DSOUND_capture_guid, sizeof(GUID)-1)
882 || !devs || !*devs)
884 WARN("No driver found\n");
885 goto out;
888 if (n)
890 const ALCchar *str = devs;
891 while (n--)
893 str += strlen(str) + 1;
894 if (!*str)
896 WARN("No driver string found\n");
897 goto out;
900 drv_name = str;
902 else
903 drv_name = devs;
905 This->device = HeapAlloc(GetProcessHeap(), 0, strlen(drv_name)+1);
906 if (!This->device)
908 WARN("Out of memory to allocate %s\n", drv_name);
909 goto out;
911 strcpy(This->device, drv_name);
913 hr = S_OK;
914 out:
915 LeaveCriticalSection(&openal_crst);
916 LeaveCriticalSection(&This->crst);
917 return hr;
920 static const IDirectSoundCaptureVtbl DSC_Vtbl =
922 DSCImpl_QueryInterface,
923 DSCImpl_AddRef,
924 DSCImpl_Release,
925 DSCImpl_CreateCaptureBuffer,
926 DSCImpl_GetCaps,
927 DSCImpl_Initialize