Fix some missing initializer warnings
[wine/multimedia.git] / capture.c
blobe2632fe8d5f95d879b8627155f78bcd94927a02a
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 DSCImpl DSCImpl;
68 typedef struct DSCBuffer DSCBuffer;
70 struct DSCImpl {
71 IDirectSoundCapture8 IDirectSoundCapture8_iface;
72 LONG ref;
74 ALCchar *device;
75 DSCBuffer *buf;
76 UINT timer_id;
77 DWORD timer_res;
78 CRITICAL_SECTION crst;
81 struct DSCBuffer {
82 IDirectSoundCaptureBuffer8 IDirectSoundCaptureBuffer8_iface;
83 IDirectSoundNotify IDirectSoundNotify_iface;
84 LONG ref, not_ref;
85 LONG all_ref;
87 DSCImpl *parent;
88 ALCdevice *dev;
89 DWORD buf_size;
90 BYTE *buf;
91 WAVEFORMATEX *format;
92 DSBPOSITIONNOTIFY *notify;
93 DWORD nnotify;
95 DWORD pos;
96 BOOL playing, looping;
99 static const IDirectSoundCaptureVtbl DSC_Vtbl;
100 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl;
101 static const IDirectSoundNotifyVtbl DSCNot_Vtbl;
103 static void DSCImpl_Destroy(DSCImpl *This);
105 static HRESULT DSCBuffer_Create(DSCBuffer **buf)
107 DSCBuffer *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
108 if (!This) return E_OUTOFMEMORY;
110 This->IDirectSoundCaptureBuffer8_iface.lpVtbl = &DSCBuffer_Vtbl;
111 This->IDirectSoundNotify_iface.lpVtbl = &DSCNot_Vtbl;
112 This->all_ref = This->ref = 1;
114 *buf = This;
115 return S_OK;
118 static void trigger_notifies(DSCBuffer *buf, DWORD lastpos, DWORD curpos)
120 DWORD i;
122 if (lastpos == curpos)
123 return;
125 for (i = 0; i < buf->nnotify; ++i)
127 DSBPOSITIONNOTIFY *not = &buf->notify[i];
128 HANDLE event = not->hEventNotify;
129 DWORD ofs = not->dwOffset;
131 if (ofs == DSCBPN_OFFSET_STOP)
132 continue;
134 /* Wraparound case */
135 if (curpos < lastpos)
137 if (ofs < curpos || ofs >= lastpos)
138 SetEvent(event);
139 continue;
142 /* Normal case */
143 if (ofs >= lastpos && ofs < curpos)
144 SetEvent(event);
148 static void CALLBACK DSCBuffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
149 DWORD_PTR dw1, DWORD_PTR dw2)
151 DSCImpl *This = (DSCImpl*)dwUser;
152 ALCint avail = 0;
153 DSCBuffer *buf;
154 (void)timerID;
155 (void)msg;
156 (void)dw1;
157 (void)dw2;
159 EnterCriticalSection(&This->crst);
160 buf = This->buf;
161 if (!buf || !buf->dev || !buf->playing)
162 goto out;
164 alcGetIntegerv(buf->dev, ALC_CAPTURE_SAMPLES, 1, &avail);
165 if (avail)
167 avail *= buf->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->nBlockAlign);
172 trigger_notifies(buf, buf->pos, buf->pos + avail);
173 buf->pos += avail;
175 if (buf->pos == buf->buf_size)
177 buf->pos = 0;
178 if (!buf->looping)
179 IDirectSoundCaptureBuffer_Stop((IDirectSoundCaptureBuffer*)buf);
180 else
182 avail = 0;
183 alcGetIntegerv(buf->dev, ALC_CAPTURE_SAMPLES, 1, &avail);
184 avail *= buf->format->nBlockAlign;
185 if ((ALCuint)avail >= buf->buf_size)
187 ERR("TOO MUCH AVAIL: %u/%u\n", avail, buf->buf_size);
188 avail = buf->buf_size;
191 if (avail)
193 alcCaptureSamples(buf->dev, buf->buf + buf->pos, avail/buf->format->nBlockAlign);
194 trigger_notifies(buf, buf->pos, buf->pos + avail);
195 buf->pos += avail;
201 out:
202 LeaveCriticalSection(&This->crst);
203 return;
206 static void DSCBuffer_starttimer(DSCImpl *prim)
208 TIMECAPS time;
209 ALint refresh = FAKE_REFRESH_COUNT;
210 DWORD triggertime, res = DS_TIME_RES;
212 if (prim->timer_id)
213 return;
215 timeGetDevCaps(&time, sizeof(TIMECAPS));
216 triggertime = 1000 / refresh;
217 if (triggertime < time.wPeriodMin)
218 triggertime = time.wPeriodMin;
219 TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime, refresh);
220 if (res < time.wPeriodMin)
221 res = time.wPeriodMin;
222 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
223 WARN("Could not set minimum resolution, don't expect sound\n");
224 prim->timer_res = res;
225 prim->timer_id = timeSetEvent(triggertime, res, DSCBuffer_timer, (DWORD_PTR)prim, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
228 static void DSCBuffer_Destroy(DSCBuffer *This)
230 if(This->dev)
232 if(This->playing)
233 alcCaptureStop(This->dev);
234 alcCaptureCloseDevice(This->dev);
236 if(This->parent)
237 This->parent->buf = NULL;
238 HeapFree(GetProcessHeap(), 0, This->notify);
239 HeapFree(GetProcessHeap(), 0, This->format);
240 HeapFree(GetProcessHeap(), 0, This->buf);
241 HeapFree(GetProcessHeap(), 0, This);
244 static inline DSCBuffer *impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8 *iface)
246 return CONTAINING_RECORD(iface, DSCBuffer, IDirectSoundCaptureBuffer8_iface);
249 static HRESULT WINAPI DSCBuffer_QueryInterface(IDirectSoundCaptureBuffer8 *iface, REFIID riid, void **ppv)
251 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
253 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
255 if(!ppv)
256 return E_POINTER;
257 *ppv = NULL;
259 if (IsEqualIID(riid, &IID_IDirectSoundNotify))
260 *ppv = &This->IDirectSoundNotify_iface;
261 else if (IsEqualIID(riid, &IID_IUnknown) ||
262 IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer) ||
263 IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer8))
264 *ppv = &This->IDirectSoundCaptureBuffer8_iface;
266 if (!*ppv)
267 return E_NOINTERFACE;
268 IUnknown_AddRef((IUnknown*)*ppv);
269 return S_OK;
272 static ULONG WINAPI DSCBuffer_AddRef(IDirectSoundCaptureBuffer8 *iface)
274 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
275 LONG ref;
277 InterlockedIncrement(&This->all_ref);
278 ref = InterlockedIncrement(&This->ref);
279 TRACE("Reference count incremented to %i\n", ref);
281 return ref;
284 static ULONG WINAPI DSCBuffer_Release(IDirectSoundCaptureBuffer8 *iface)
286 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
287 LONG ref;
289 ref = InterlockedDecrement(&This->ref);
290 TRACE("Reference count decremented to %i\n", ref);
291 if(InterlockedDecrement(&This->all_ref) == 0)
292 DSCBuffer_Destroy(This);
294 return ref;
297 static HRESULT WINAPI DSCBuffer_GetCaps(IDirectSoundCaptureBuffer8 *iface, DSCBCAPS *caps)
299 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
301 if (!caps || caps->dwSize < sizeof(*caps))
302 return DSERR_INVALIDPARAM;
303 caps->dwSize = sizeof(*caps);
304 caps->dwFlags = 0;
305 caps->dwBufferBytes = This->buf_size;
306 return S_OK;
309 static HRESULT WINAPI DSCBuffer_GetCurrentPosition(IDirectSoundCaptureBuffer8 *iface, DWORD *cappos, DWORD *readpos)
311 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
312 DWORD pos1, pos2;
314 EnterCriticalSection(&This->parent->crst);
315 pos1 = This->pos;
316 if (This->playing)
318 pos2 = This->format->nSamplesPerSec / 100;
319 pos2 *= This->format->nBlockAlign;
320 pos2 += pos1;
321 if (!This->looping && pos2 >= This->buf_size)
322 pos2 = 0;
323 else
324 pos2 %= This->buf_size;
326 else
327 pos2 = pos1;
328 LeaveCriticalSection(&This->parent->crst);
330 if(cappos) *cappos = pos1;
331 if(readpos) *readpos = pos2;
333 return S_OK;
336 static HRESULT WINAPI DSCBuffer_GetFormat(IDirectSoundCaptureBuffer8 *iface, WAVEFORMATEX *wfx, DWORD size, DWORD *written)
338 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
339 TRACE("(%p,%p,%u,%p)\n", This, wfx, size, written);
341 if (size > sizeof(WAVEFORMATEX) + This->format->cbSize)
342 size = sizeof(WAVEFORMATEX) + This->format->cbSize;
344 if (wfx)
346 CopyMemory(wfx, This->format, size);
347 if (written)
348 *written = size;
350 else if (written)
351 *written = sizeof(WAVEFORMATEX) + This->format->cbSize;
352 else
353 return DSERR_INVALIDPARAM;
355 return S_OK;
358 static HRESULT WINAPI DSCBuffer_GetStatus(IDirectSoundCaptureBuffer8 *iface, DWORD *status)
360 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
361 TRACE("(%p)->(%p)\n", This, status);
363 if (!status)
364 return DSERR_INVALIDPARAM;
365 EnterCriticalSection(&This->parent->crst);
366 *status = 0;
367 if (This->playing)
369 *status |= DSCBSTATUS_CAPTURING;
370 if (This->looping)
371 *status |= DSCBSTATUS_LOOPING;
373 LeaveCriticalSection(&This->parent->crst);
375 return S_OK;
378 static HRESULT WINAPI DSCBuffer_Initialize(IDirectSoundCaptureBuffer8 *iface, IDirectSoundCapture *parent, const DSCBUFFERDESC *desc)
380 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
381 WAVEFORMATEX *format;
382 ALenum buf_format = -1;
384 if (This->parent)
385 return DSERR_ALREADYINITIALIZED;
386 This->parent = (DSCImpl*)parent;
388 if (!desc->lpwfxFormat)
389 return DSERR_INVALIDPARAM;
391 format = desc->lpwfxFormat;
392 if (format->nChannels > 2)
394 WARN("nChannels > 2 not supported for recording\n");
395 return DSERR_INVALIDPARAM;
398 if (!This->format)
399 This->format = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
400 if (!This->format)
401 return DSERR_OUTOFMEMORY;
403 if (format->wFormatTag == WAVE_FORMAT_PCM ||
404 format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
406 if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
408 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)format;
409 if (format->cbSize < sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX))
410 return DSERR_INVALIDPARAM;
411 else if (format->cbSize > sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)
412 && format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
413 return DSERR_CONTROLUNAVAIL;
414 else if (!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
415 return DSERR_BADFORMAT;
418 if (format->nChannels == 1)
420 switch (format->wBitsPerSample)
422 case 8: buf_format = AL_FORMAT_MONO8; break;
423 case 16: buf_format = AL_FORMAT_MONO16; break;
424 default:
425 WARN("Unsupported bpp %u\n", format->wBitsPerSample);
426 return DSERR_BADFORMAT;
429 else if (format->nChannels == 2)
431 switch (format->wBitsPerSample)
433 case 8: buf_format = AL_FORMAT_STEREO8; break;
434 case 16: buf_format = AL_FORMAT_STEREO16; break;
435 default:
436 WARN("Unsupported bpp %u\n", format->wBitsPerSample);
437 return DSERR_BADFORMAT;
440 memcpy(This->format, format, sizeof(*format) + format->cbSize);
441 if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
442 This->format->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
443 else
444 This->format->cbSize = 0;
445 This->format->nBlockAlign = This->format->wBitsPerSample * This->format->nChannels / 8;
446 This->format->nAvgBytesPerSec = This->format->nSamplesPerSec * This->format->nBlockAlign;
448 else if (format->wFormatTag)
449 WARN("Unhandled formattag %x\n", format->wFormatTag);
451 This->buf_size = desc->dwBufferBytes;
452 if(buf_format <= 0)
454 WARN("Could not get OpenAL format\n");
455 return DSERR_INVALIDPARAM;
458 This->dev = alcCaptureOpenDevice(This->parent->device, This->format->nSamplesPerSec, buf_format, This->buf_size / This->format->nBlockAlign);
459 if (!This->dev)
461 ERR("couldn't open device %s %x@%u, reason: %04x\n", This->parent->device, buf_format, This->format->nSamplesPerSec, alcGetError(NULL));
462 return DSERR_INVALIDPARAM;
465 This->buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->buf_size);
466 if (!This->buf)
468 alcCaptureCloseDevice(This->dev);
469 WARN("Out of memory\n");
470 return DSERR_INVALIDPARAM;
473 return S_OK;
476 static HRESULT WINAPI DSCBuffer_Lock(IDirectSoundCaptureBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
478 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
479 HRESULT hr;
480 DWORD remain;
481 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, %#x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
483 EnterCriticalSection(&This->parent->crst);
484 hr = DSERR_INVALIDPARAM;
486 if(ptr1) *ptr1 = NULL;
487 if(len1) *len1 = 0;
488 if(ptr2) *ptr2 = NULL;
489 if(len2) *len2 = 0;
491 if (ofs >= This->buf_size)
493 WARN("Invalid ofs %u\n", ofs);
494 goto out;
496 if (!ptr1 || !len1)
498 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
499 goto out;
501 if((flags&DSCBLOCK_ENTIREBUFFER))
502 bytes = This->buf_size;
503 else if(bytes > This->buf_size)
505 WARN("Invalid size %u\n", bytes);
506 goto out;
509 if (ofs + bytes >= This->buf_size)
511 *len1 = This->buf_size - ofs;
512 remain = bytes - *len1;
514 else
516 *len1 = bytes;
517 remain = 0;
519 *ptr1 = This->buf + ofs;
521 if (ptr2 && len2 && remain)
523 *ptr2 = This->buf;
524 *len2 = remain;
526 hr = S_OK;
528 out:
529 LeaveCriticalSection(&This->parent->crst);
530 return hr;
533 static HRESULT WINAPI DSCBuffer_Start(IDirectSoundCaptureBuffer8 *iface, DWORD flags)
535 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
536 TRACE("(%p)->(%08x)\n", This, flags);
538 EnterCriticalSection(&This->parent->crst);
539 if (!This->playing)
541 DSCBuffer_starttimer(This->parent);
542 This->playing = 1;
543 alcCaptureStart(This->dev);
545 This->looping = !!(flags & DSCBSTART_LOOPING);
546 LeaveCriticalSection(&This->parent->crst);
547 return S_OK;
550 static HRESULT WINAPI DSCBuffer_Stop(IDirectSoundCaptureBuffer8 *iface)
552 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
553 TRACE("(%p)\n", This);
555 EnterCriticalSection(&This->parent->crst);
556 if (This->playing)
558 DWORD i;
560 for (i = 0; i < This->nnotify; ++i)
561 if (This->notify[i].dwOffset == DSCBPN_OFFSET_STOP)
563 SetEvent(This->notify[i].hEventNotify);
564 break;
566 This->playing = This->looping = 0;
567 alcCaptureStop(This->dev);
569 LeaveCriticalSection(&This->parent->crst);
570 return S_OK;
573 static HRESULT WINAPI DSCBuffer_Unlock(IDirectSoundCaptureBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
575 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
576 TRACE("(%p)->(%p,%u,%p,%u)\n", This, ptr1, len1, ptr2, len2);
578 if (!ptr1)
579 return DSERR_INVALIDPARAM;
580 return S_OK;
583 static HRESULT WINAPI DSCBuffer_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface, REFGUID guid, DWORD num, REFGUID riid, void **ppv)
585 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
586 FIXME("(%p)->(%s %u %s %p) stub\n", This, debugstr_guid(guid), num, debugstr_guid(riid), ppv);
587 return E_NOTIMPL;
590 static HRESULT WINAPI DSCBuffer_GetFXStatus(IDirectSoundCaptureBuffer8 *iface, DWORD count, DWORD *status)
592 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
593 FIXME("(%p)->(%u %p) stub\n", This, count, status);
594 return E_NOTIMPL;
597 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl =
599 DSCBuffer_QueryInterface,
600 DSCBuffer_AddRef,
601 DSCBuffer_Release,
602 DSCBuffer_GetCaps,
603 DSCBuffer_GetCurrentPosition,
604 DSCBuffer_GetFormat,
605 DSCBuffer_GetStatus,
606 DSCBuffer_Initialize,
607 DSCBuffer_Lock,
608 DSCBuffer_Start,
609 DSCBuffer_Stop,
610 DSCBuffer_Unlock,
611 DSCBuffer_GetObjectInPath,
612 DSCBuffer_GetFXStatus
615 static inline DSCBuffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
617 return CONTAINING_RECORD(iface, DSCBuffer, IDirectSoundNotify_iface);
620 static HRESULT WINAPI DSCBufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
622 DSCBuffer *This = impl_from_IDirectSoundNotify(iface);
623 return IDirectSoundCaptureBuffer_QueryInterface((IDirectSoundCaptureBuffer*)This, riid, ppv);
626 static ULONG WINAPI DSCBufferNot_AddRef(IDirectSoundNotify *iface)
628 DSCBuffer *This = impl_from_IDirectSoundNotify(iface);
629 LONG ret;
631 InterlockedIncrement(&This->all_ref);
632 ret = InterlockedIncrement(&This->not_ref);
633 TRACE("new refcount %d\n", ret);
634 return ret;
637 static ULONG WINAPI DSCBufferNot_Release(IDirectSoundNotify *iface)
639 DSCBuffer *This = impl_from_IDirectSoundNotify(iface);
640 LONG ret;
642 ret = InterlockedDecrement(&This->not_ref);
643 TRACE("new refcount %d\n", ret);
644 if(InterlockedDecrement(&This->all_ref) == 0)
645 DSCBuffer_Destroy(This);
647 return ret;
650 static HRESULT WINAPI DSCBufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
652 DSCBuffer *This = impl_from_IDirectSoundNotify(iface);
653 DSBPOSITIONNOTIFY *nots;
654 HRESULT hr;
655 DWORD state;
657 EnterCriticalSection(&This->parent->crst);
658 hr = DSERR_INVALIDPARAM;
659 if (count && !notifications)
660 goto out;
662 hr = DSCBuffer_GetStatus(&This->IDirectSoundCaptureBuffer8_iface, &state);
663 if (FAILED(hr))
664 goto out;
666 hr = DSERR_INVALIDCALL;
667 if (state & DSCBSTATUS_CAPTURING)
668 goto out;
670 if (!count)
672 HeapFree(GetProcessHeap(), 0, This->notify);
673 This->notify = 0;
674 This->nnotify = 0;
676 else
678 DWORD i;
679 hr = DSERR_INVALIDPARAM;
680 for (i = 0; i < count; ++i)
682 if (notifications[i].dwOffset >= This->buf_size
683 && notifications[i].dwOffset != DSCBPN_OFFSET_STOP)
684 goto out;
686 hr = E_OUTOFMEMORY;
687 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
688 if (!nots)
689 goto out;
690 memcpy(nots, notifications, count*sizeof(*nots));
691 HeapFree(GetProcessHeap(), 0, This->notify);
692 This->notify = nots;
693 This->nnotify = count;
694 hr = S_OK;
697 out:
698 LeaveCriticalSection(&This->parent->crst);
699 return hr;
702 static const IDirectSoundNotifyVtbl DSCNot_Vtbl =
704 DSCBufferNot_QueryInterface,
705 DSCBufferNot_AddRef,
706 DSCBufferNot_Release,
707 DSCBufferNot_SetNotificationPositions
710 HRESULT DSOUND_CaptureCreate8(REFIID riid, IDirectSoundCapture8 **cap)
712 DSCImpl *This;
714 *cap = NULL;
716 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
717 if(!This) return DSERR_OUTOFMEMORY;
719 This->IDirectSoundCapture8_iface.lpVtbl = &DSC_Vtbl;
721 InitializeCriticalSection(&This->crst);
722 This->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DSCImpl.crst");
724 if(FAILED(IDirectSoundCapture_QueryInterface(&This->IDirectSoundCapture8_iface, riid, (void**)cap)))
726 DSCImpl_Destroy(This);
727 return E_NOINTERFACE;
729 return S_OK;
732 static void DSCImpl_Destroy(DSCImpl *This)
734 if (This->timer_id)
736 timeKillEvent(This->timer_id);
737 timeEndPeriod(This->timer_res);
740 EnterCriticalSection(&This->crst);
741 if (This->buf)
742 DSCBuffer_Destroy(This->buf);
743 LeaveCriticalSection(&This->crst);
745 HeapFree(GetProcessHeap(), 0, This->device);
747 This->crst.DebugInfo->Spare[0] = 0;
748 DeleteCriticalSection(&This->crst);
750 HeapFree(GetProcessHeap(), 0, This);
753 static HRESULT WINAPI DSCImpl_QueryInterface(IDirectSoundCapture *iface, REFIID riid, void **ppv)
755 *ppv = NULL;
756 if(IsEqualIID(riid, &IID_IUnknown) ||
757 IsEqualIID(riid, &IID_IDirectSoundCapture))
758 *ppv = iface;
760 if(!*ppv)
761 return E_NOINTERFACE;
762 IUnknown_AddRef((IUnknown*)*ppv);
763 return S_OK;
766 static ULONG WINAPI DSCImpl_AddRef(IDirectSoundCapture8 *iface)
768 DSCImpl *This = (DSCImpl*)iface;
769 LONG ref;
771 ref = InterlockedIncrement(&This->ref);
772 TRACE("Reference count incremented to %i\n", ref);
774 return ref;
777 static ULONG WINAPI DSCImpl_Release(IDirectSoundCapture8 *iface)
779 DSCImpl *This = (DSCImpl*)iface;
780 LONG ref;
782 ref = InterlockedDecrement(&This->ref);
783 TRACE("Reference count decremented to %i\n", ref);
784 if(!ref)
785 DSCImpl_Destroy(This);
787 return ref;
790 static HRESULT WINAPI DSCImpl_CreateCaptureBuffer(IDirectSoundCapture8 *iface, const DSCBUFFERDESC *desc, IDirectSoundCaptureBuffer **ppv, IUnknown *unk)
792 DSCImpl *This = (DSCImpl*)iface;
793 HRESULT hr;
794 TRACE("(%p)->(%p,%p,%p)\n", This, desc, ppv, unk);
796 if (unk)
798 WARN("Aggregation isn't supported\n");
799 return DSERR_NOAGGREGATION;
802 if (!desc || desc->dwSize < sizeof(DSCBUFFERDESC1))
804 WARN("Passed invalid description %p %u\n", desc, desc?desc->dwSize:0);
805 return DSERR_INVALIDPARAM;
807 if (!ppv)
809 WARN("Passed null pointer\n");
810 return DSERR_INVALIDPARAM;
812 *ppv = NULL;
814 EnterCriticalSection(&This->crst);
815 if (!This->device)
817 hr = DSERR_UNINITIALIZED;
818 WARN("Not initialized\n");
819 goto out;
821 if (This->buf)
823 hr = DSERR_ALLOCATED;
824 WARN("Capture buffer already allocated\n");
825 goto out;
828 hr = DSCBuffer_Create(&This->buf);
829 if (SUCCEEDED(hr))
831 hr = IDirectSoundCaptureBuffer_Initialize((IDirectSoundCaptureBuffer*)This->buf, iface, desc);
832 if (FAILED(hr))
834 DSCBuffer_Destroy(This->buf);
835 This->buf = NULL;
838 *ppv = (IDirectSoundCaptureBuffer*)This->buf;
839 out:
840 LeaveCriticalSection(&This->crst);
841 return hr;
844 static HRESULT WINAPI DSCImpl_GetCaps(IDirectSoundCapture8 *iface, DSCCAPS *caps)
846 DSCImpl *This = (DSCImpl*)iface;
847 TRACE("(%p,%p)\n", This, caps);
849 if (!This->device) {
850 WARN("Not initialized\n");
851 return DSERR_UNINITIALIZED;
854 if (!caps) {
855 WARN("Caps is null\n");
856 return DSERR_INVALIDPARAM;
859 if (caps->dwSize < sizeof(*caps)) {
860 WARN("Invalid size %d\n", caps->dwSize);
861 return DSERR_INVALIDPARAM;
864 caps->dwFlags = 0;
865 /* Support all WAVE_FORMAT formats specified in mmsystem.h */
866 caps->dwFormats = 0x000fffff;
867 caps->dwChannels = 2;
869 return DS_OK;
872 static HRESULT WINAPI DSCImpl_Initialize(IDirectSoundCapture8 *iface, const GUID *devguid)
874 DSCImpl *This = (DSCImpl*)iface;
875 HRESULT hr;
876 const ALCchar *devs, *drv_name;
877 GUID guid;
878 UINT n;
879 TRACE("(%p,%p)\n", This, devguid);
881 if (!openal_loaded)
883 ERR("OpenAL not loaded!\n");
884 return DSERR_NODRIVER;
887 if (This->device) {
888 WARN("Already initialized\n");
889 return DSERR_ALREADYINITIALIZED;
892 if (!devguid)
893 devguid = &DSDEVID_DefaultCapture;
895 hr = GetDeviceID(devguid, &guid);
896 if (FAILED(hr))
897 return DSERR_INVALIDPARAM;
898 devguid = &guid;
900 EnterCriticalSection(&This->crst);
901 EnterCriticalSection(&openal_crst);
902 devs = DSOUND_getcapturedevicestrings();
903 n = guid.Data4[7];
905 hr = DSERR_NODRIVER;
906 if(memcmp(devguid, &DSOUND_capture_guid, sizeof(GUID)-1) ||
907 !devs || !*devs)
909 WARN("No driver found\n");
910 goto out;
913 if(n)
915 const ALCchar *str = devs;
916 while (n--)
918 str += strlen(str) + 1;
919 if (!*str)
921 WARN("No driver string found\n");
922 goto out;
925 drv_name = str;
927 else
928 drv_name = devs;
930 This->device = HeapAlloc(GetProcessHeap(), 0, strlen(drv_name)+1);
931 if (!This->device)
933 WARN("Out of memory to allocate %s\n", drv_name);
934 goto out;
936 strcpy(This->device, drv_name);
938 hr = S_OK;
939 out:
940 LeaveCriticalSection(&openal_crst);
941 LeaveCriticalSection(&This->crst);
942 return hr;
945 static const IDirectSoundCaptureVtbl DSC_Vtbl =
947 DSCImpl_QueryInterface,
948 DSCImpl_AddRef,
949 DSCImpl_Release,
950 DSCImpl_CreateCaptureBuffer,
951 DSCImpl_GetCaps,
952 DSCImpl_Initialize