dsound: Implement capture buffer based on mmdevapi v2
[wine/multimedia.git] / dlls / dsound / capture.c
bloba0d20d9b289979561550b19c085cb016fc1aa9d2
1 /* DirectSoundCapture
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2001 TransGaming Technologies, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * TODO:
23 * Implement FX support.
26 #include <stdarg.h>
28 #define COBJMACROS
29 #define NONAMELESSSTRUCT
30 #define NONAMELESSUNION
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winuser.h"
34 #include "wingdi.h"
35 #include "mmsystem.h"
36 #include "mmddk.h"
37 #include "winternl.h"
38 #include "winnls.h"
39 #include "wine/debug.h"
40 #include "dsound.h"
41 #include "dsound_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
46 typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl;
48 typedef struct IDirectSoundCaptureImpl
50 IDirectSoundCapture IDirectSoundCapture_iface;
51 LONG ref;
52 GUID device;
53 IDirectSoundCaptureBufferImpl *buf;
54 CRITICAL_SECTION crst;
55 BOOL is_8, voice;
56 UINT timer_id;
57 DWORD timer_res;
58 } IDirectSoundCaptureImpl;
60 static void IDirectSoundCaptureImpl_Destroy(IDirectSoundCaptureImpl *This);
62 struct IDirectSoundCaptureBufferImpl
64 IDirectSoundCaptureBuffer8 IDirectSoundCaptureBuffer8_iface;
65 LONG ref;
66 IDirectSoundCaptureImpl *parent;
67 IAudioClient *dev;
68 IAudioCaptureClient *cap_dev;
69 DWORD buf_size;
70 BYTE *buf;
71 WAVEFORMATEX *format;
72 DSBPOSITIONNOTIFY *notify;
73 DWORD nnotify;
75 DWORD pos;
76 BOOL playing, looping;
79 static void IDirectSoundCaptureBufferImpl_Destroy(IDirectSoundCaptureBufferImpl *This);
81 static IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8 *iface)
83 return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundCaptureBuffer8_iface);
86 static IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
88 return CONTAINING_RECORD(iface, IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
91 static void trigger_notifies(IDirectSoundCaptureBufferImpl *buf, DWORD lastpos, DWORD curpos)
93 TRACE("stub\n");
96 static void CALLBACK IDirectSoundCaptureBufferImpl_timer(UINT timerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
98 IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl*)dwUser;
99 IDirectSoundCaptureBufferImpl *buf;
100 UINT32 avail = 0;
102 EnterCriticalSection(&This->crst);
103 buf = This->buf;
104 if (!buf || !buf->dev || !buf->playing)
105 goto out;
107 IAudioCaptureClient_GetNextPacketSize(buf->cap_dev, &avail);
108 if (avail)
110 BYTE *data = 0;
111 UINT32 read = 0;
112 DWORD flags = 0;
113 UINT64 pos = 0;
114 DWORD block = buf->format->nBlockAlign;
116 IAudioCaptureClient_GetBuffer(buf->cap_dev, &data, &read, &flags, &pos, 0);
117 if (read * block + buf->pos >= buf->buf_size)
119 if (!buf->looping)
121 trigger_notifies(buf, buf->pos, 0);
122 memcpy(buf->buf + buf->pos, data, buf->buf_size - buf->pos);
123 buf->pos = 0;
124 IAudioCaptureClient_ReleaseBuffer(buf->cap_dev, read);
125 IDirectSoundCaptureBuffer8_Stop(&buf->IDirectSoundCaptureBuffer8_iface);
127 else
129 DWORD firstpart = buf->buf_size - buf->pos, oldpos = buf->pos;
130 memcpy(buf->buf + buf->pos, data, firstpart);
131 buf->pos = read * block - firstpart;
132 memcpy(buf->buf, data + firstpart, buf->pos);
133 trigger_notifies(buf, oldpos, buf->pos);
134 IAudioCaptureClient_ReleaseBuffer(buf->cap_dev, read);
136 } else {
137 memcpy(buf->buf + buf->pos, data, read * block);
138 trigger_notifies(buf, buf->pos, buf->pos + read * block);
139 buf->pos += read * block;
140 IAudioCaptureClient_ReleaseBuffer(buf->cap_dev, read);
144 out:
145 LeaveCriticalSection(&This->crst);
146 return;
149 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_QueryInterface(IDirectSoundCaptureBuffer8 *iface, REFIID riid, void **ppv)
151 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
152 if (!ppv)
153 return E_POINTER;
154 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
155 *ppv = NULL;
156 if (IsEqualIID(riid, &IID_IUnknown) ||
157 IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer) ||
158 (This->parent->is_8 && IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer8)))
159 *ppv = &This->IDirectSoundCaptureBuffer8_iface;
160 if (!*ppv)
161 return E_NOINTERFACE;
162 IUnknown_AddRef((IUnknown*)*ppv);
163 return S_OK;
166 static ULONG WINAPI IDirectSoundCaptureBufferImpl_AddRef(IDirectSoundCaptureBuffer8 *iface)
168 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
169 LONG ref;
170 ref = InterlockedIncrement(&This->ref);
171 TRACE("Reference count incremented to %i\n", ref);
172 return ref;
175 static ULONG WINAPI IDirectSoundCaptureBufferImpl_Release(IDirectSoundCaptureBuffer8 *iface)
177 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
178 LONG ref;
179 ref = InterlockedDecrement(&This->ref);
180 TRACE("Reference count decremented to %i\n", ref);
181 if (!ref)
182 IDirectSoundCaptureBufferImpl_Destroy(This);
183 return ref;
186 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCaps(IDirectSoundCaptureBuffer8 *iface, DSCBCAPS *caps)
188 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
190 if (!caps || caps->dwSize < sizeof(*caps))
191 return DSERR_INVALIDPARAM;
192 caps->dwSize = sizeof(*caps);
193 caps->dwFlags = 0;
194 caps->dwBufferBytes = This->buf_size;
195 return S_OK;
198 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCurrentPosition(IDirectSoundCaptureBuffer8 *iface, DWORD *cappos, DWORD *readpos)
200 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
201 DWORD pos1, pos2;
202 TRACE("(%p)->(%p, %p)\n", This, cappos, readpos);
203 EnterCriticalSection(&This->parent->crst);
204 pos1 = This->pos;
205 if (This->playing)
207 pos2 = This->format->nSamplesPerSec / 100;
208 pos2 *= This->format->nBlockAlign;
209 pos2 += pos1;
210 if (!This->looping && pos2 > This->buf_size)
211 pos2 = 0;
212 else
213 pos2 %= This->buf_size;
215 else
216 pos2 = pos1;
217 pos2 %= This->buf_size;
218 LeaveCriticalSection(&This->parent->crst);
219 TRACE("Reporting %u %u\n", pos1, pos2);
220 if (readpos)
221 *readpos = pos1;
222 if (cappos)
223 *cappos = pos2;
224 return S_OK;
227 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFormat(IDirectSoundCaptureBuffer8 *iface, WAVEFORMATEX *wfx, DWORD size, DWORD *written)
229 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
230 TRACE("(%p,%p,%u,%p)\n", This, wfx, size, written);
232 if (size > sizeof(WAVEFORMATEX) + This->format->cbSize)
233 size = sizeof(WAVEFORMATEX) + This->format->cbSize;
235 if (wfx)
237 CopyMemory(wfx, This->format, size);
238 if (written)
239 *written = size;
240 } else if (written)
241 *written = sizeof(WAVEFORMATEX) + This->format->cbSize;
242 else
243 return DSERR_INVALIDPARAM;
245 return S_OK;
248 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetStatus(IDirectSoundCaptureBuffer8 *iface, DWORD *status)
250 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
251 TRACE("(%p)->(%p)\n", This, status);
253 if (!status)
254 return DSERR_INVALIDPARAM;
255 EnterCriticalSection(&This->parent->crst);
256 *status = 0;
257 if (This->playing)
259 *status |= DSCBSTATUS_CAPTURING;
260 if (This->looping)
261 *status |= DSCBSTATUS_LOOPING;
263 LeaveCriticalSection(&This->parent->crst);
265 return S_OK;
268 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Initialize(IDirectSoundCaptureBuffer8 *iface, IDirectSoundCapture *parent, const DSCBUFFERDESC *desc)
270 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
271 WAVEFORMATEX *format;
272 HRESULT hr;
273 IMMDevice *dev = NULL;
275 if (This->parent)
276 return DSERR_ALREADYINITIALIZED;
277 This->parent = impl_from_IDirectSoundCapture(parent);
278 if (!desc->lpwfxFormat || !desc->dwBufferBytes)
279 return DSERR_INVALIDPARAM;
281 format = desc->lpwfxFormat;
282 if (format->nChannels > 2)
284 WARN("nChannels > 2 not supported for recording\n");
285 return DSERR_INVALIDPARAM;
288 if (!This->format)
289 This->format = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
290 if (!This->format)
291 return DSERR_OUTOFMEMORY;
293 if (format->wFormatTag == WAVE_FORMAT_PCM
294 || format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
296 if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
298 if (format->cbSize < sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX))
299 return DSERR_INVALIDPARAM;
300 else if (format->cbSize > sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)
301 && format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
302 return DSERR_CONTROLUNAVAIL;
304 memcpy(This->format, format, sizeof(WAVEFORMATEXTENSIBLE));
305 This->format->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
307 else
309 memcpy(This->format, format, sizeof(WAVEFORMATEX));
310 This->format->cbSize = 0;
313 This->format->nBlockAlign = This->format->wBitsPerSample * This->format->nChannels / 8;
314 This->format->nAvgBytesPerSec = This->format->nSamplesPerSec * This->format->nBlockAlign;
316 else if (format->wFormatTag)
317 WARN("Unhandled formattag %x\n", format->wFormatTag);
319 This->buf_size = desc->dwBufferBytes;
320 hr = get_mmdevice(eCapture, &This->parent->device, &dev);
321 if (SUCCEEDED(hr))
322 hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&This->dev);
323 if (SUCCEEDED(hr))
324 hr = IAudioClient_Initialize(This->dev, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, 0, This->format, NULL);
325 if (SUCCEEDED(hr))
326 hr = IAudioClient_GetService(This->dev, &IID_IAudioCaptureClient, (void**)&This->cap_dev);
327 if (FAILED(hr))
329 if (This->dev)
330 IUnknown_Release(This->dev);
331 This->dev = NULL;
332 if (dev)
333 IUnknown_Release(dev);
334 if (hr == AUDCLNT_E_UNSUPPORTED_FORMAT)
336 WARN("Couldn't open device: bad format\n");
337 return DSERR_BADFORMAT;
339 ERR("couldn't open device %s %i: %08x\n", debugstr_guid(&This->parent->device), This->format->nSamplesPerSec, hr);
340 return hr == DSERR_INVALIDPARAM;
342 This->buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->buf_size);
343 if (!This->buf)
345 IAudioCaptureClient_Release(This->cap_dev);
346 IAudioClient_Release(This->dev);
347 WARN("Out of memory\n");
348 return DSERR_INVALIDPARAM;
351 return S_OK;
354 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Lock(IDirectSoundCaptureBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
356 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
357 HRESULT hr;
358 DWORD remain;
359 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, %#x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
361 EnterCriticalSection(&This->parent->crst);
362 hr = DSERR_INVALIDPARAM;
363 if (ptr1)
364 *ptr1 = NULL;
365 if (len1)
366 *len1 = 0;
367 if (ptr2)
368 *ptr2 = NULL;
369 if (len2)
370 *len2 = 0;
371 if (ofs >= This->buf_size)
373 WARN("Invalid ofs %u\n", ofs);
374 goto out;
376 if (!ptr1 || !len1)
378 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
379 goto out;
381 if (flags & DSCBLOCK_ENTIREBUFFER)
382 bytes = This->buf_size;
383 if (bytes > This->buf_size)
385 WARN("Invalid size %u\n", bytes);
386 goto out;
389 if (ofs + bytes >= This->buf_size)
391 *len1 = This->buf_size - ofs;
392 remain = bytes - *len1;
394 else
396 *len1 = bytes;
397 remain = 0;
399 *ptr1 = This->buf + ofs;
401 if (ptr2 && len2 && remain)
403 *ptr2 = This->buf;
404 *len2 = remain;
406 hr = S_OK;
408 out:
409 LeaveCriticalSection(&This->parent->crst);
410 return hr;
413 static void IDirectSoundCaptureBufferImpl_starttimer(IDirectSoundCaptureBufferImpl *This)
415 TIMECAPS time;
416 REFERENCE_TIME min_period, default_period;
417 DWORD triggertime, res = DS_TIME_RES;
419 if (This->parent->timer_id)
420 return;
422 timeGetDevCaps(&time, sizeof(TIMECAPS));
423 IAudioClient_GetDevicePeriod(This->dev, &default_period, &min_period);
424 triggertime = default_period / 10000;
425 if (triggertime < time.wPeriodMin)
426 triggertime = time.wPeriodMin;
427 TRACE("Calling timer every %u ms\n", triggertime);
428 if (res < time.wPeriodMin)
429 res = time.wPeriodMin;
430 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
431 WARN("Could not set minimum resolution, don't expect sound\n");
432 This->parent->timer_res = res;
433 This->parent->timer_id = timeSetEvent(triggertime, res, IDirectSoundCaptureBufferImpl_timer, (DWORD_PTR)This->parent, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
436 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Start(IDirectSoundCaptureBuffer8 *iface, DWORD flags)
438 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
439 TRACE("(%p)->(%08x)\n", This, flags);
441 EnterCriticalSection(&This->parent->crst);
442 if (!This->playing)
444 IDirectSoundCaptureBufferImpl_starttimer(This);
445 This->playing = 1;
446 IAudioClient_Start(This->dev);
448 This->looping = !!(flags & DSCBSTART_LOOPING);
449 LeaveCriticalSection(&This->parent->crst);
450 return S_OK;
453 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Stop(IDirectSoundCaptureBuffer8 *iface)
455 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
456 TRACE("(%p)\n", This);
458 EnterCriticalSection(&This->parent->crst);
459 if (This->playing)
461 DWORD i;
463 for (i = 0; i < This->nnotify; ++i)
464 if (This->notify[i].dwOffset == DSCBPN_OFFSET_STOP)
466 SetEvent(This->notify[i].hEventNotify);
467 break;
469 This->playing = This->looping = 0;
470 IAudioClient_Stop(This->dev);
471 IAudioClient_Reset(This->dev);
473 LeaveCriticalSection(&This->parent->crst);
474 return S_OK;
477 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Unlock(IDirectSoundCaptureBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
479 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
480 TRACE("(%p)->(%p,%u,%p,%u)\n", This, ptr1, len2, ptr2, len2);
482 if (!ptr1)
483 return DSERR_INVALIDPARAM;
484 return S_OK;
487 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface, REFGUID guid, DWORD num, REFGUID riid, void **ppv)
489 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
490 FIXME("(%p)->(%s %u %s %p) stub\n", This, debugstr_guid(guid), num, debugstr_guid(riid), ppv);
491 return E_NOTIMPL;
494 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFXStatus(IDirectSoundCaptureBuffer8 *iface, DWORD count, DWORD *status)
496 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
497 FIXME("(%p)->(%u %p) stub\n", This, count, status);
498 return E_NOTIMPL;
501 static const IDirectSoundCaptureBuffer8Vtbl IDirectSoundCaptureBufferImpl_Vtbl = {
502 IDirectSoundCaptureBufferImpl_QueryInterface,
503 IDirectSoundCaptureBufferImpl_AddRef,
504 IDirectSoundCaptureBufferImpl_Release,
505 IDirectSoundCaptureBufferImpl_GetCaps,
506 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
507 IDirectSoundCaptureBufferImpl_GetFormat,
508 IDirectSoundCaptureBufferImpl_GetStatus,
509 IDirectSoundCaptureBufferImpl_Initialize,
510 IDirectSoundCaptureBufferImpl_Lock,
511 IDirectSoundCaptureBufferImpl_Start,
512 IDirectSoundCaptureBufferImpl_Stop,
513 IDirectSoundCaptureBufferImpl_Unlock,
514 IDirectSoundCaptureBufferImpl_GetObjectInPath,
515 IDirectSoundCaptureBufferImpl_GetFXStatus
518 static HRESULT IDirectSoundCaptureBufferImpl_Create(IDirectSoundCaptureBufferImpl **buf)
520 IDirectSoundCaptureBufferImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
521 if (!This)
522 return E_OUTOFMEMORY;
523 This->IDirectSoundCaptureBuffer8_iface.lpVtbl = &IDirectSoundCaptureBufferImpl_Vtbl;
524 This->ref = 1;
525 *buf = This;
526 return S_OK;
529 static void IDirectSoundCaptureBufferImpl_Destroy(IDirectSoundCaptureBufferImpl *This)
531 if (This->dev)
533 if (This->playing)
534 IAudioClient_Stop(This->dev);
535 IAudioCaptureClient_Release(This->cap_dev);
536 IAudioClient_Release(This->dev);
538 if (This->parent)
539 This->parent->buf = NULL;
540 HeapFree(GetProcessHeap(), 0, This->notify);
541 HeapFree(GetProcessHeap(), 0, This->format);
542 HeapFree(GetProcessHeap(), 0, This->buf);
543 HeapFree(GetProcessHeap(), 0, This);
547 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface, REFIID riid, void **ppobj)
549 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
550 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj);
552 if (ppobj == NULL) {
553 WARN("invalid parameter\n");
554 return E_INVALIDARG;
557 *ppobj = NULL;
559 if (IsEqualIID(riid, &IID_IUnknown)) {
560 IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This);
561 *ppobj = This;
562 return DS_OK;
563 } else if (IsEqualIID(riid, &IID_IDirectSoundCapture)) {
564 IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This);
565 *ppobj = This;
566 return DS_OK;
569 WARN("unsupported riid: %s\n", debugstr_guid(riid));
570 return E_NOINTERFACE;
573 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
575 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
576 ULONG ref = InterlockedIncrement(&(This->ref));
577 TRACE("(%p) ref was %d\n", This, ref - 1);
578 return ref;
581 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
583 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
584 ULONG ref = InterlockedDecrement(&(This->ref));
585 TRACE("(%p) ref was %d\n", This, ref + 1);
587 if (!ref) {
588 IDirectSoundCaptureImpl_Destroy(This);
589 TRACE("(%p) released\n", This);
591 return ref;
594 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface, const DSCBUFFERDESC *desc, IDirectSoundCaptureBuffer **ppv, IUnknown *unk)
596 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
597 HRESULT hr;
598 TRACE("(%p)->(%p,%p,%p)\n", This, desc, ppv, unk);
600 if (unk)
602 WARN("Aggregation isn't supported\n");
603 return DSERR_NOAGGREGATION;
606 if (!desc || desc->dwSize < sizeof(DSCBUFFERDESC1))
608 WARN("Passed invalid description %p %u\n", desc, desc?desc->dwSize:0);
609 return DSERR_INVALIDPARAM;
611 if (!ppv)
613 WARN("Passed null pointer\n");
614 return DSERR_INVALIDPARAM;
616 *ppv = NULL;
618 EnterCriticalSection(&This->crst);
619 if (IsEqualIID(&This->device, &GUID_NULL))
621 hr = DSERR_UNINITIALIZED;
622 WARN("Not initialized\n");
623 goto out;
626 hr = IDirectSoundCaptureBufferImpl_Create(&This->buf);
627 if (SUCCEEDED(hr))
629 hr = IDirectSoundCaptureBuffer_Initialize((IDirectSoundCaptureBuffer*)This->buf, iface, desc);
630 if (FAILED(hr))
632 IDirectSoundCaptureBufferImpl_Destroy(This->buf);
633 This->buf = NULL;
636 *ppv = (IDirectSoundCaptureBuffer*)&This->buf->IDirectSoundCaptureBuffer8_iface;
637 out:
638 LeaveCriticalSection(&This->crst);
639 return hr;
642 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface, DSCCAPS *caps)
644 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
645 TRACE("(%p,%p)\n", This, caps);
647 if (IsEqualIID(&This->device, &GUID_NULL)) {
648 WARN("Not initialized\n");
649 return DSERR_UNINITIALIZED;
652 if (!caps) {
653 WARN("Caps is null\n");
654 return DSERR_INVALIDPARAM;
657 if (caps->dwSize < sizeof(*caps)) {
658 WARN("Invalid size %d\n", caps->dwSize);
659 return DSERR_INVALIDPARAM;
662 caps->dwFlags = 0;
663 /* Support all WAVE_FORMAT formats specified in mmsystem.h */
664 caps->dwFormats = 0x000fffff;
665 caps->dwChannels = 2;
667 return DS_OK;
670 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface, const GUID *devguid)
672 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
673 HRESULT hr;
674 GUID guid;
675 BOOL voice = devguid && IsEqualIID(devguid, &DSDEVID_DefaultVoiceCapture);
676 IMMDevice *dev;
678 TRACE("(%p,%p)\n", This, devguid);
680 if (!IsEqualIID(&This->device, &GUID_NULL)) {
681 WARN("Already initialized\n");
682 return DSERR_ALREADYINITIALIZED;
685 if (!devguid)
686 devguid = &DSDEVID_DefaultCapture;
687 guid = *devguid;
689 EnterCriticalSection(&This->crst);
690 hr = get_mmdevice(eCapture, &guid, &dev);
691 if (FAILED(hr))
693 WARN("Failed to create device for %s: %08x\n", debugstr_guid(&guid), hr);
694 hr = DSERR_NODRIVER;
695 goto out;
697 IMMDevice_Release(dev);
698 This->device = guid;
699 This->voice = voice;
700 hr = S_OK;
701 out:
702 LeaveCriticalSection(&This->crst);
703 return hr;
706 static const IDirectSoundCaptureVtbl dscvt =
708 IDirectSoundCaptureImpl_QueryInterface,
709 IDirectSoundCaptureImpl_AddRef,
710 IDirectSoundCaptureImpl_Release,
711 IDirectSoundCaptureImpl_CreateCaptureBuffer,
712 IDirectSoundCaptureImpl_GetCaps,
713 IDirectSoundCaptureImpl_Initialize
716 HRESULT DSOUND_CaptureCreate(REFIID riid, LPDIRECTSOUNDCAPTURE *ppDSC)
718 HRESULT hr;
719 hr = DSOUND_CaptureCreate8(riid, ppDSC);
720 if (SUCCEEDED(hr))
721 impl_from_IDirectSoundCapture(*ppDSC)->is_8 = 0;
722 return hr;
725 HRESULT DSOUND_CaptureCreate8(REFIID riid, LPDIRECTSOUNDCAPTURE8 *cap)
727 IDirectSoundCaptureImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
728 *cap = NULL;
729 if (!This)
730 return DSERR_OUTOFMEMORY;
731 This->IDirectSoundCapture_iface.lpVtbl = &dscvt;
732 This->is_8 = 1;
734 InitializeCriticalSection(&This->crst);
735 This->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DSCImpl.crst");
736 if (FAILED(IUnknown_QueryInterface((IUnknown*)This, riid, (void**)cap)))
738 IDirectSoundCaptureImpl_Destroy(This);
739 return E_NOINTERFACE;
741 return S_OK;
744 static void IDirectSoundCaptureImpl_Destroy(IDirectSoundCaptureImpl *This)
746 if (This->timer_id)
748 timeKillEvent(This->timer_id);
749 timeEndPeriod(This->timer_res);
751 EnterCriticalSection(&This->crst);
752 if (This->buf)
753 IDirectSoundCaptureBufferImpl_Destroy(This->buf);
754 LeaveCriticalSection(&This->crst);
755 This->crst.DebugInfo->Spare[0] = 0;
756 DeleteCriticalSection(&This->crst);
757 HeapFree(GetProcessHeap(), 0, This);
760 /***************************************************************************
761 * DirectSoundCaptureCreate [DSOUND.6]
763 * Create and initialize a DirectSoundCapture interface.
765 * PARAMS
766 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
767 * lplpDSC [O] Address of a variable to receive the interface pointer.
768 * pUnkOuter [I] Must be NULL.
770 * RETURNS
771 * Success: DS_OK
772 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
773 * DSERR_OUTOFMEMORY
775 * NOTES
776 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
777 * or NULL for the default device or DSDEVID_DefaultCapture or
778 * DSDEVID_DefaultVoiceCapture.
780 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
782 HRESULT WINAPI DirectSoundCaptureCreate(
783 LPCGUID lpcGUID,
784 LPDIRECTSOUNDCAPTURE *ppDSC,
785 LPUNKNOWN pUnkOuter)
787 HRESULT hr;
788 LPDIRECTSOUNDCAPTURE pDSC;
789 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
791 if (ppDSC == NULL) {
792 WARN("invalid parameter: ppDSC == NULL\n");
793 return DSERR_INVALIDPARAM;
796 if (pUnkOuter) {
797 WARN("invalid parameter: pUnkOuter != NULL\n");
798 *ppDSC = NULL;
799 return DSERR_NOAGGREGATION;
802 hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, &pDSC);
803 if (hr == DS_OK) {
804 hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
805 if (hr != DS_OK) {
806 IDirectSoundCapture_Release(pDSC);
807 pDSC = 0;
811 *ppDSC = pDSC;
813 return hr;
816 /***************************************************************************
817 * DirectSoundCaptureCreate8 [DSOUND.12]
819 * Create and initialize a DirectSoundCapture interface.
821 * PARAMS
822 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
823 * lplpDSC [O] Address of a variable to receive the interface pointer.
824 * pUnkOuter [I] Must be NULL.
826 * RETURNS
827 * Success: DS_OK
828 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
829 * DSERR_OUTOFMEMORY
831 * NOTES
832 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
833 * or NULL for the default device or DSDEVID_DefaultCapture or
834 * DSDEVID_DefaultVoiceCapture.
836 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
838 HRESULT WINAPI DirectSoundCaptureCreate8(
839 LPCGUID lpcGUID,
840 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
841 LPUNKNOWN pUnkOuter)
843 HRESULT hr;
844 LPDIRECTSOUNDCAPTURE8 pDSC8;
845 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
847 if (ppDSC8 == NULL) {
848 WARN("invalid parameter: ppDSC8 == NULL\n");
849 return DSERR_INVALIDPARAM;
852 if (pUnkOuter) {
853 WARN("invalid parameter: pUnkOuter != NULL\n");
854 *ppDSC8 = NULL;
855 return DSERR_NOAGGREGATION;
858 hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture, &pDSC8);
859 if (hr == DS_OK) {
860 hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
861 if (hr != DS_OK) {
862 IDirectSoundCapture_Release(pDSC8);
863 pDSC8 = 0;
867 *ppDSC8 = pDSC8;
869 return hr;