Wrap the wide-char enumerating functions instead of the ASCII
[dsound-openal.git] / capture.c
blob294dc7a5e1f64b49157e876f292d9cb6acf59504
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, void **cap)
64 return DSOUND_CaptureCreate8(riid, cap);
67 typedef struct DSCImpl DSCImpl;
68 typedef struct DSCBuffer DSCBuffer;
70 struct DSCImpl {
71 IDirectSoundCapture IDirectSoundCapture_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 = (IDirectSoundCaptureBuffer8Vtbl*)&DSCBuffer_Vtbl;
111 This->IDirectSoundNotify_iface.lpVtbl = (IDirectSoundNotifyVtbl*)&DSCNot_Vtbl;
113 This->all_ref = This->ref = 1;
115 *buf = This;
116 return S_OK;
119 static void trigger_notifies(DSCBuffer *buf, DWORD lastpos, DWORD curpos)
121 DWORD i;
123 if (lastpos == curpos)
124 return;
126 for (i = 0; i < buf->nnotify; ++i)
128 DSBPOSITIONNOTIFY *not = &buf->notify[i];
129 HANDLE event = not->hEventNotify;
130 DWORD ofs = not->dwOffset;
132 if (ofs == DSCBPN_OFFSET_STOP)
133 continue;
135 /* Wraparound case */
136 if (curpos < lastpos)
138 if (ofs < curpos || ofs >= lastpos)
139 SetEvent(event);
140 continue;
143 /* Normal case */
144 if (ofs >= lastpos && ofs < curpos)
145 SetEvent(event);
149 static void CALLBACK DSCBuffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
150 DWORD_PTR dw1, DWORD_PTR dw2)
152 DSCImpl *This = (DSCImpl*)dwUser;
153 ALCint avail = 0;
154 DSCBuffer *buf;
155 (void)timerID;
156 (void)msg;
157 (void)dw1;
158 (void)dw2;
160 EnterCriticalSection(&This->crst);
161 buf = This->buf;
162 if (!buf || !buf->dev || !buf->playing)
163 goto out;
165 alcGetIntegerv(buf->dev, ALC_CAPTURE_SAMPLES, 1, &avail);
166 if (avail)
168 avail *= buf->format->nBlockAlign;
169 if (avail + buf->pos > buf->buf_size)
170 avail = buf->buf_size - buf->pos;
172 alcCaptureSamples(buf->dev, buf->buf + buf->pos, avail/buf->format->nBlockAlign);
173 trigger_notifies(buf, buf->pos, buf->pos + avail);
174 buf->pos += avail;
176 if (buf->pos == buf->buf_size)
178 buf->pos = 0;
179 if (!buf->looping)
180 IDirectSoundCaptureBuffer_Stop((IDirectSoundCaptureBuffer*)buf);
181 else
183 avail = 0;
184 alcGetIntegerv(buf->dev, ALC_CAPTURE_SAMPLES, 1, &avail);
185 avail *= buf->format->nBlockAlign;
186 if ((ALCuint)avail >= buf->buf_size)
188 ERR("TOO MUCH AVAIL: %u/%u\n", avail, buf->buf_size);
189 avail = buf->buf_size;
192 if (avail)
194 alcCaptureSamples(buf->dev, buf->buf + buf->pos, avail/buf->format->nBlockAlign);
195 trigger_notifies(buf, buf->pos, buf->pos + avail);
196 buf->pos += avail;
202 out:
203 LeaveCriticalSection(&This->crst);
204 return;
207 static void DSCBuffer_starttimer(DSCImpl *prim)
209 TIMECAPS time;
210 ALint refresh = FAKE_REFRESH_COUNT;
211 DWORD triggertime, res = DS_TIME_RES;
213 if (prim->timer_id)
214 return;
216 timeGetDevCaps(&time, sizeof(TIMECAPS));
217 triggertime = 1000 / refresh;
218 if (triggertime < time.wPeriodMin)
219 triggertime = time.wPeriodMin;
220 TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime, refresh);
221 if (res < time.wPeriodMin)
222 res = time.wPeriodMin;
223 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
224 WARN("Could not set minimum resolution, don't expect sound\n");
225 prim->timer_res = res;
226 prim->timer_id = timeSetEvent(triggertime, res, DSCBuffer_timer, (DWORD_PTR)prim, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
229 static void DSCBuffer_Destroy(DSCBuffer *This)
231 if(This->dev)
233 if(This->playing)
234 alcCaptureStop(This->dev);
235 alcCaptureCloseDevice(This->dev);
237 if(This->parent)
238 This->parent->buf = NULL;
239 HeapFree(GetProcessHeap(), 0, This->notify);
240 HeapFree(GetProcessHeap(), 0, This->format);
241 HeapFree(GetProcessHeap(), 0, This->buf);
242 HeapFree(GetProcessHeap(), 0, This);
245 static inline DSCBuffer *impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8 *iface)
247 return CONTAINING_RECORD(iface, DSCBuffer, IDirectSoundCaptureBuffer8_iface);
250 static HRESULT WINAPI DSCBuffer_QueryInterface(IDirectSoundCaptureBuffer8 *iface, REFIID riid, void **ppv)
252 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
254 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
256 if(!ppv)
257 return E_POINTER;
258 *ppv = NULL;
260 if (IsEqualIID(riid, &IID_IDirectSoundNotify))
261 *ppv = &This->IDirectSoundNotify_iface;
262 else if (IsEqualIID(riid, &IID_IUnknown) ||
263 IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer) ||
264 IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer8))
265 *ppv = &This->IDirectSoundCaptureBuffer8_iface;
267 if (!*ppv)
268 return E_NOINTERFACE;
269 IUnknown_AddRef((IUnknown*)*ppv);
270 return S_OK;
273 static ULONG WINAPI DSCBuffer_AddRef(IDirectSoundCaptureBuffer8 *iface)
275 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
276 LONG ref;
278 InterlockedIncrement(&This->all_ref);
279 ref = InterlockedIncrement(&This->ref);
280 TRACE("Reference count incremented to %i\n", ref);
282 return ref;
285 static ULONG WINAPI DSCBuffer_Release(IDirectSoundCaptureBuffer8 *iface)
287 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
288 LONG ref;
290 ref = InterlockedDecrement(&This->ref);
291 TRACE("Reference count decremented to %i\n", ref);
292 if(InterlockedDecrement(&This->all_ref) == 0)
293 DSCBuffer_Destroy(This);
295 return ref;
298 static HRESULT WINAPI DSCBuffer_GetCaps(IDirectSoundCaptureBuffer8 *iface, DSCBCAPS *caps)
300 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
302 if (!caps || caps->dwSize < sizeof(*caps))
303 return DSERR_INVALIDPARAM;
304 caps->dwSize = sizeof(*caps);
305 caps->dwFlags = 0;
306 caps->dwBufferBytes = This->buf_size;
307 return S_OK;
310 static HRESULT WINAPI DSCBuffer_GetCurrentPosition(IDirectSoundCaptureBuffer8 *iface, DWORD *cappos, DWORD *readpos)
312 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
313 DWORD pos1, pos2;
315 EnterCriticalSection(&This->parent->crst);
316 pos1 = This->pos;
317 if (This->playing)
319 pos2 = This->format->nSamplesPerSec / 100;
320 pos2 *= This->format->nBlockAlign;
321 pos2 += pos1;
322 if (!This->looping && pos2 >= This->buf_size)
323 pos2 = 0;
324 else
325 pos2 %= This->buf_size;
327 else
328 pos2 = pos1;
329 LeaveCriticalSection(&This->parent->crst);
331 if(cappos) *cappos = pos1;
332 if(readpos) *readpos = pos2;
334 return S_OK;
337 static HRESULT WINAPI DSCBuffer_GetFormat(IDirectSoundCaptureBuffer8 *iface, WAVEFORMATEX *wfx, DWORD size, DWORD *written)
339 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
340 TRACE("(%p,%p,%u,%p)\n", This, wfx, size, written);
342 if (size > sizeof(WAVEFORMATEX) + This->format->cbSize)
343 size = sizeof(WAVEFORMATEX) + This->format->cbSize;
345 if (wfx)
347 CopyMemory(wfx, This->format, size);
348 if (written)
349 *written = size;
351 else if (written)
352 *written = sizeof(WAVEFORMATEX) + This->format->cbSize;
353 else
354 return DSERR_INVALIDPARAM;
356 return S_OK;
359 static HRESULT WINAPI DSCBuffer_GetStatus(IDirectSoundCaptureBuffer8 *iface, DWORD *status)
361 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
362 TRACE("(%p)->(%p)\n", This, status);
364 if (!status)
365 return DSERR_INVALIDPARAM;
366 EnterCriticalSection(&This->parent->crst);
367 *status = 0;
368 if (This->playing)
370 *status |= DSCBSTATUS_CAPTURING;
371 if (This->looping)
372 *status |= DSCBSTATUS_LOOPING;
374 LeaveCriticalSection(&This->parent->crst);
376 return S_OK;
379 static HRESULT WINAPI DSCBuffer_Initialize(IDirectSoundCaptureBuffer8 *iface, IDirectSoundCapture *parent, const DSCBUFFERDESC *desc)
381 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
382 WAVEFORMATEX *format;
383 ALenum buf_format = -1;
385 if (This->parent)
386 return DSERR_ALREADYINITIALIZED;
387 This->parent = (DSCImpl*)parent;
389 if (!desc->lpwfxFormat)
390 return DSERR_INVALIDPARAM;
392 format = desc->lpwfxFormat;
393 if (format->nChannels > 2)
395 WARN("nChannels > 2 not supported for recording\n");
396 return DSERR_INVALIDPARAM;
399 if (!This->format)
400 This->format = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
401 if (!This->format)
402 return DSERR_OUTOFMEMORY;
404 if (format->wFormatTag == WAVE_FORMAT_PCM ||
405 format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
407 if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
409 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)format;
410 if (format->cbSize < sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX))
411 return DSERR_INVALIDPARAM;
412 else if (format->cbSize > sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)
413 && format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
414 return DSERR_CONTROLUNAVAIL;
415 else if (!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
416 return DSERR_BADFORMAT;
419 if (format->nChannels == 1)
421 switch (format->wBitsPerSample)
423 case 8: buf_format = AL_FORMAT_MONO8; break;
424 case 16: buf_format = AL_FORMAT_MONO16; break;
425 default:
426 WARN("Unsupported bpp %u\n", format->wBitsPerSample);
427 return DSERR_BADFORMAT;
430 else if (format->nChannels == 2)
432 switch (format->wBitsPerSample)
434 case 8: buf_format = AL_FORMAT_STEREO8; break;
435 case 16: buf_format = AL_FORMAT_STEREO16; break;
436 default:
437 WARN("Unsupported bpp %u\n", format->wBitsPerSample);
438 return DSERR_BADFORMAT;
441 memcpy(This->format, format, sizeof(*format) + format->cbSize);
442 if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
443 This->format->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
444 else
445 This->format->cbSize = 0;
446 This->format->nBlockAlign = This->format->wBitsPerSample * This->format->nChannels / 8;
447 This->format->nAvgBytesPerSec = This->format->nSamplesPerSec * This->format->nBlockAlign;
449 else if (format->wFormatTag)
450 WARN("Unhandled formattag %x\n", format->wFormatTag);
452 This->buf_size = desc->dwBufferBytes;
453 if(buf_format <= 0)
455 WARN("Could not get OpenAL format\n");
456 return DSERR_INVALIDPARAM;
459 This->dev = alcCaptureOpenDevice(This->parent->device, This->format->nSamplesPerSec, buf_format, This->buf_size / This->format->nBlockAlign);
460 if (!This->dev)
462 ERR("couldn't open device %s %x@%u, reason: %04x\n", This->parent->device, buf_format, This->format->nSamplesPerSec, alcGetError(NULL));
463 return DSERR_INVALIDPARAM;
466 This->buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->buf_size);
467 if (!This->buf)
469 alcCaptureCloseDevice(This->dev);
470 WARN("Out of memory\n");
471 return DSERR_INVALIDPARAM;
474 return S_OK;
477 static HRESULT WINAPI DSCBuffer_Lock(IDirectSoundCaptureBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
479 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
480 HRESULT hr;
481 DWORD remain;
482 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, %#x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
484 EnterCriticalSection(&This->parent->crst);
485 hr = DSERR_INVALIDPARAM;
487 if(ptr1) *ptr1 = NULL;
488 if(len1) *len1 = 0;
489 if(ptr2) *ptr2 = NULL;
490 if(len2) *len2 = 0;
492 if (ofs >= This->buf_size)
494 WARN("Invalid ofs %u\n", ofs);
495 goto out;
497 if (!ptr1 || !len1)
499 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
500 goto out;
502 if((flags&DSCBLOCK_ENTIREBUFFER))
503 bytes = This->buf_size;
504 else if(bytes > This->buf_size)
506 WARN("Invalid size %u\n", bytes);
507 goto out;
510 if (ofs + bytes >= This->buf_size)
512 *len1 = This->buf_size - ofs;
513 remain = bytes - *len1;
515 else
517 *len1 = bytes;
518 remain = 0;
520 *ptr1 = This->buf + ofs;
522 if (ptr2 && len2 && remain)
524 *ptr2 = This->buf;
525 *len2 = remain;
527 hr = S_OK;
529 out:
530 LeaveCriticalSection(&This->parent->crst);
531 return hr;
534 static HRESULT WINAPI DSCBuffer_Start(IDirectSoundCaptureBuffer8 *iface, DWORD flags)
536 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
537 TRACE("(%p)->(%08x)\n", This, flags);
539 EnterCriticalSection(&This->parent->crst);
540 if (!This->playing)
542 DSCBuffer_starttimer(This->parent);
543 This->playing = 1;
544 alcCaptureStart(This->dev);
546 This->looping = !!(flags & DSCBSTART_LOOPING);
547 LeaveCriticalSection(&This->parent->crst);
548 return S_OK;
551 static HRESULT WINAPI DSCBuffer_Stop(IDirectSoundCaptureBuffer8 *iface)
553 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
554 TRACE("(%p)\n", This);
556 EnterCriticalSection(&This->parent->crst);
557 if (This->playing)
559 DWORD i;
561 for (i = 0; i < This->nnotify; ++i)
562 if (This->notify[i].dwOffset == DSCBPN_OFFSET_STOP)
564 SetEvent(This->notify[i].hEventNotify);
565 break;
567 This->playing = This->looping = 0;
568 alcCaptureStop(This->dev);
570 LeaveCriticalSection(&This->parent->crst);
571 return S_OK;
574 static HRESULT WINAPI DSCBuffer_Unlock(IDirectSoundCaptureBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
576 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
577 TRACE("(%p)->(%p,%u,%p,%u)\n", This, ptr1, len1, ptr2, len2);
579 if (!ptr1)
580 return DSERR_INVALIDPARAM;
581 return S_OK;
584 static HRESULT WINAPI DSCBuffer_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface, REFGUID guid, DWORD num, REFGUID riid, void **ppv)
586 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
587 FIXME("(%p)->(%s %u %s %p) stub\n", This, debugstr_guid(guid), num, debugstr_guid(riid), ppv);
588 return E_NOTIMPL;
591 static HRESULT WINAPI DSCBuffer_GetFXStatus(IDirectSoundCaptureBuffer8 *iface, DWORD count, DWORD *status)
593 DSCBuffer *This = impl_from_IDirectSoundCaptureBuffer8(iface);
594 FIXME("(%p)->(%u %p) stub\n", This, count, status);
595 return E_NOTIMPL;
598 static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl =
600 DSCBuffer_QueryInterface,
601 DSCBuffer_AddRef,
602 DSCBuffer_Release,
603 DSCBuffer_GetCaps,
604 DSCBuffer_GetCurrentPosition,
605 DSCBuffer_GetFormat,
606 DSCBuffer_GetStatus,
607 DSCBuffer_Initialize,
608 DSCBuffer_Lock,
609 DSCBuffer_Start,
610 DSCBuffer_Stop,
611 DSCBuffer_Unlock,
612 DSCBuffer_GetObjectInPath,
613 DSCBuffer_GetFXStatus
616 static inline DSCBuffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
618 return CONTAINING_RECORD(iface, DSCBuffer, IDirectSoundNotify_iface);
621 static HRESULT WINAPI DSCBufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
623 DSCBuffer *This = impl_from_IDirectSoundNotify(iface);
624 return IDirectSoundCaptureBuffer_QueryInterface((IDirectSoundCaptureBuffer*)This, riid, ppv);
627 static ULONG WINAPI DSCBufferNot_AddRef(IDirectSoundNotify *iface)
629 DSCBuffer *This = impl_from_IDirectSoundNotify(iface);
630 LONG ret;
632 InterlockedIncrement(&This->all_ref);
633 ret = InterlockedIncrement(&This->not_ref);
634 TRACE("new refcount %d\n", ret);
635 return ret;
638 static ULONG WINAPI DSCBufferNot_Release(IDirectSoundNotify *iface)
640 DSCBuffer *This = impl_from_IDirectSoundNotify(iface);
641 LONG ret;
643 ret = InterlockedDecrement(&This->not_ref);
644 TRACE("new refcount %d\n", ret);
645 if(InterlockedDecrement(&This->all_ref) == 0)
646 DSCBuffer_Destroy(This);
648 return ret;
651 static HRESULT WINAPI DSCBufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
653 DSCBuffer *This = impl_from_IDirectSoundNotify(iface);
654 DSBPOSITIONNOTIFY *nots;
655 HRESULT hr;
656 DWORD state;
658 EnterCriticalSection(&This->parent->crst);
659 hr = DSERR_INVALIDPARAM;
660 if (count && !notifications)
661 goto out;
663 hr = DSCBuffer_GetStatus(&This->IDirectSoundCaptureBuffer8_iface, &state);
664 if (FAILED(hr))
665 goto out;
667 hr = DSERR_INVALIDCALL;
668 if (state & DSCBSTATUS_CAPTURING)
669 goto out;
671 if (!count)
673 HeapFree(GetProcessHeap(), 0, This->notify);
674 This->notify = 0;
675 This->nnotify = 0;
677 else
679 DWORD i;
680 hr = DSERR_INVALIDPARAM;
681 for (i = 0; i < count; ++i)
683 if (notifications[i].dwOffset >= This->buf_size
684 && notifications[i].dwOffset != DSCBPN_OFFSET_STOP)
685 goto out;
687 hr = E_OUTOFMEMORY;
688 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
689 if (!nots)
690 goto out;
691 memcpy(nots, notifications, count*sizeof(*nots));
692 HeapFree(GetProcessHeap(), 0, This->notify);
693 This->notify = nots;
694 This->nnotify = count;
695 hr = S_OK;
698 out:
699 LeaveCriticalSection(&This->parent->crst);
700 return hr;
703 static const IDirectSoundNotifyVtbl DSCNot_Vtbl =
705 DSCBufferNot_QueryInterface,
706 DSCBufferNot_AddRef,
707 DSCBufferNot_Release,
708 DSCBufferNot_SetNotificationPositions
711 HRESULT DSOUND_CaptureCreate8(REFIID riid, void **cap)
713 DSCImpl *This;
715 *cap = NULL;
717 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
718 if(!This) return DSERR_OUTOFMEMORY;
720 This->IDirectSoundCapture_iface.lpVtbl = (IDirectSoundCaptureVtbl*)&DSC_Vtbl;
722 InitializeCriticalSection(&This->crst);
723 This->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DSCImpl.crst");
725 if(FAILED(IDirectSoundCapture_QueryInterface(&This->IDirectSoundCapture_iface, riid, cap)))
727 DSCImpl_Destroy(This);
728 return E_NOINTERFACE;
730 return S_OK;
733 static void DSCImpl_Destroy(DSCImpl *This)
735 if (This->timer_id)
737 timeKillEvent(This->timer_id);
738 timeEndPeriod(This->timer_res);
741 EnterCriticalSection(&This->crst);
742 if (This->buf)
743 DSCBuffer_Destroy(This->buf);
744 LeaveCriticalSection(&This->crst);
746 HeapFree(GetProcessHeap(), 0, This->device);
748 This->crst.DebugInfo->Spare[0] = 0;
749 DeleteCriticalSection(&This->crst);
751 HeapFree(GetProcessHeap(), 0, This);
754 static HRESULT WINAPI DSCImpl_QueryInterface(IDirectSoundCapture *iface, REFIID riid, void **ppv)
756 *ppv = NULL;
757 if(IsEqualIID(riid, &IID_IUnknown) ||
758 IsEqualIID(riid, &IID_IDirectSoundCapture))
759 *ppv = iface;
761 if(!*ppv)
762 return E_NOINTERFACE;
763 IUnknown_AddRef((IUnknown*)*ppv);
764 return S_OK;
767 static ULONG WINAPI DSCImpl_AddRef(IDirectSoundCapture8 *iface)
769 DSCImpl *This = (DSCImpl*)iface;
770 LONG ref;
772 ref = InterlockedIncrement(&This->ref);
773 TRACE("Reference count incremented to %i\n", ref);
775 return ref;
778 static ULONG WINAPI DSCImpl_Release(IDirectSoundCapture8 *iface)
780 DSCImpl *This = (DSCImpl*)iface;
781 LONG ref;
783 ref = InterlockedDecrement(&This->ref);
784 TRACE("Reference count decremented to %i\n", ref);
785 if(!ref)
786 DSCImpl_Destroy(This);
788 return ref;
791 static HRESULT WINAPI DSCImpl_CreateCaptureBuffer(IDirectSoundCapture8 *iface, const DSCBUFFERDESC *desc, IDirectSoundCaptureBuffer **ppv, IUnknown *unk)
793 DSCImpl *This = (DSCImpl*)iface;
794 HRESULT hr;
795 TRACE("(%p)->(%p,%p,%p)\n", This, desc, ppv, unk);
797 if (unk)
799 WARN("Aggregation isn't supported\n");
800 return DSERR_NOAGGREGATION;
803 if (!desc || desc->dwSize < sizeof(DSCBUFFERDESC1))
805 WARN("Passed invalid description %p %u\n", desc, desc?desc->dwSize:0);
806 return DSERR_INVALIDPARAM;
808 if (!ppv)
810 WARN("Passed null pointer\n");
811 return DSERR_INVALIDPARAM;
813 *ppv = NULL;
815 EnterCriticalSection(&This->crst);
816 if (!This->device)
818 hr = DSERR_UNINITIALIZED;
819 WARN("Not initialized\n");
820 goto out;
822 if (This->buf)
824 hr = DSERR_ALLOCATED;
825 WARN("Capture buffer already allocated\n");
826 goto out;
829 hr = DSCBuffer_Create(&This->buf);
830 if (SUCCEEDED(hr))
832 hr = IDirectSoundCaptureBuffer_Initialize((IDirectSoundCaptureBuffer*)This->buf, iface, desc);
833 if (FAILED(hr))
835 DSCBuffer_Destroy(This->buf);
836 This->buf = NULL;
839 *ppv = (IDirectSoundCaptureBuffer*)This->buf;
840 out:
841 LeaveCriticalSection(&This->crst);
842 return hr;
845 static HRESULT WINAPI DSCImpl_GetCaps(IDirectSoundCapture8 *iface, DSCCAPS *caps)
847 DSCImpl *This = (DSCImpl*)iface;
848 TRACE("(%p,%p)\n", This, caps);
850 if (!This->device) {
851 WARN("Not initialized\n");
852 return DSERR_UNINITIALIZED;
855 if (!caps) {
856 WARN("Caps is null\n");
857 return DSERR_INVALIDPARAM;
860 if (caps->dwSize < sizeof(*caps)) {
861 WARN("Invalid size %d\n", caps->dwSize);
862 return DSERR_INVALIDPARAM;
865 caps->dwFlags = 0;
866 /* Support all WAVE_FORMAT formats specified in mmsystem.h */
867 caps->dwFormats = 0x000fffff;
868 caps->dwChannels = 2;
870 return DS_OK;
873 static HRESULT WINAPI DSCImpl_Initialize(IDirectSoundCapture8 *iface, const GUID *devguid)
875 DSCImpl *This = (DSCImpl*)iface;
876 HRESULT hr;
877 const ALCchar *devs, *drv_name;
878 GUID guid;
879 UINT n;
880 TRACE("(%p,%p)\n", This, devguid);
882 if (!openal_loaded)
884 ERR("OpenAL not loaded!\n");
885 return DSERR_NODRIVER;
888 if (This->device) {
889 WARN("Already initialized\n");
890 return DSERR_ALREADYINITIALIZED;
893 if (!devguid)
894 devguid = &DSDEVID_DefaultCapture;
896 hr = GetDeviceID(devguid, &guid);
897 if (FAILED(hr))
898 return DSERR_INVALIDPARAM;
899 devguid = &guid;
901 EnterCriticalSection(&This->crst);
902 EnterCriticalSection(&openal_crst);
903 devs = DSOUND_getcapturedevicestrings();
904 n = guid.Data4[7];
906 hr = DSERR_NODRIVER;
907 if(memcmp(devguid, &DSOUND_capture_guid, sizeof(GUID)-1) ||
908 !devs || !*devs)
910 WARN("No driver found\n");
911 goto out;
914 if(n)
916 const ALCchar *str = devs;
917 while (n--)
919 str += strlen(str) + 1;
920 if (!*str)
922 WARN("No driver string found\n");
923 goto out;
926 drv_name = str;
928 else
929 drv_name = devs;
931 This->device = HeapAlloc(GetProcessHeap(), 0, strlen(drv_name)+1);
932 if (!This->device)
934 WARN("Out of memory to allocate %s\n", drv_name);
935 goto out;
937 strcpy(This->device, drv_name);
939 hr = S_OK;
940 out:
941 LeaveCriticalSection(&openal_crst);
942 LeaveCriticalSection(&This->crst);
943 return hr;
946 static const IDirectSoundCaptureVtbl DSC_Vtbl =
948 DSCImpl_QueryInterface,
949 DSCImpl_AddRef,
950 DSCImpl_Release,
951 DSCImpl_CreateCaptureBuffer,
952 DSCImpl_GetCaps,
953 DSCImpl_Initialize