fd7539ac645767d456b556aeecf08e58013b2762
[reactos.git] / reactos / dll / directx / wine / dsound / capture.c
1 /* DirectSoundCapture
2 *
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2001 TransGaming Technologies, Inc.
6 *
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.
11 *
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.
16 *
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
20 */
21 /*
22 * TODO:
23 * Implement FX support.
24 * Implement both IDirectSoundCaptureBuffer and IDirectSoundCaptureBuffer8
25 * Make DirectSoundCaptureCreate and DirectSoundCaptureCreate8 behave differently
26 */
27
28 #include "dsound_private.h"
29
30 typedef struct DirectSoundCaptureDevice DirectSoundCaptureDevice;
31
32 /* IDirectSoundCaptureBuffer implementation structure */
33 typedef struct IDirectSoundCaptureBufferImpl
34 {
35 IDirectSoundCaptureBuffer8 IDirectSoundCaptureBuffer8_iface;
36 IDirectSoundNotify IDirectSoundNotify_iface;
37 LONG numIfaces; /* "in use interfaces" refcount */
38 LONG ref, refn;
39 /* IDirectSoundCaptureBuffer fields */
40 DirectSoundCaptureDevice *device;
41 DSCBUFFERDESC *pdscbd;
42 DWORD flags;
43 /* IDirectSoundNotify fields */
44 DSBPOSITIONNOTIFY *notifies;
45 int nrofnotifies;
46 HANDLE thread;
47 HANDLE sleepev;
48 } IDirectSoundCaptureBufferImpl;
49
50 /* DirectSoundCaptureDevice implementation structure */
51 struct DirectSoundCaptureDevice
52 {
53 GUID guid;
54 LONG ref;
55 DSCCAPS drvcaps;
56 BYTE *buffer;
57 DWORD buflen, write_pos_bytes;
58 WAVEFORMATEX *pwfx;
59 IDirectSoundCaptureBufferImpl *capture_buffer;
60 DWORD state;
61 CRITICAL_SECTION lock;
62 IMMDevice *mmdevice;
63 IAudioClient *client;
64 IAudioCaptureClient *capture;
65 struct list entry;
66 };
67
68 static DWORD WINAPI DSOUND_capture_thread(void *user);
69
70 static void capturebuffer_destroy(IDirectSoundCaptureBufferImpl *This)
71 {
72 if (This->device->state == STATE_CAPTURING)
73 This->device->state = STATE_STOPPING;
74
75 if(This->thread){
76 SetEvent(This->sleepev);
77 WaitForSingleObject(This->thread, INFINITE);
78 CloseHandle(This->thread);
79 }
80 CloseHandle(This->sleepev);
81
82 HeapFree(GetProcessHeap(),0, This->pdscbd);
83
84 if (This->device->client) {
85 IAudioClient_Release(This->device->client);
86 This->device->client = NULL;
87 }
88
89 if (This->device->capture) {
90 IAudioCaptureClient_Release(This->device->capture);
91 This->device->capture = NULL;
92 }
93
94 /* remove from DirectSoundCaptureDevice */
95 This->device->capture_buffer = NULL;
96
97 HeapFree(GetProcessHeap(), 0, This->notifies);
98 HeapFree(GetProcessHeap(), 0, This);
99 TRACE("(%p) released\n", This);
100 }
101
102 /*******************************************************************************
103 * IDirectSoundNotify
104 */
105 static inline struct IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
106 {
107 return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundNotify_iface);
108 }
109
110 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(IDirectSoundNotify *iface, REFIID riid,
111 void **ppobj)
112 {
113 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
114
115 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj);
116
117 return IDirectSoundCaptureBuffer_QueryInterface(&This->IDirectSoundCaptureBuffer8_iface, riid, ppobj);
118 }
119
120 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(IDirectSoundNotify *iface)
121 {
122 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
123 ULONG ref = InterlockedIncrement(&This->refn);
124
125 TRACE("(%p) ref was %d\n", This, ref - 1);
126
127 if(ref == 1)
128 InterlockedIncrement(&This->numIfaces);
129
130 return ref;
131 }
132
133 static ULONG WINAPI IDirectSoundNotifyImpl_Release(IDirectSoundNotify *iface)
134 {
135 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
136 ULONG ref = InterlockedDecrement(&This->refn);
137
138 TRACE("(%p) ref was %d\n", This, ref + 1);
139
140 if (!ref && !InterlockedDecrement(&This->numIfaces))
141 capturebuffer_destroy(This);
142
143 return ref;
144 }
145
146 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSoundNotify *iface,
147 DWORD howmuch, const DSBPOSITIONNOTIFY *notify)
148 {
149 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
150 TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
151
152 if (howmuch > 0 && notify == NULL) {
153 WARN("invalid parameter: notify == NULL\n");
154 return DSERR_INVALIDPARAM;
155 }
156
157 if (TRACE_ON(dsound)) {
158 unsigned int i;
159 for (i=0;i<howmuch;i++)
160 TRACE("notify at %d to %p\n",
161 notify[i].dwOffset,notify[i].hEventNotify);
162 }
163
164 if (howmuch > 0) {
165 /* Make an internal copy of the caller-supplied array.
166 * Replace the existing copy if one is already present. */
167 if (This->notifies)
168 This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->notifies,
169 howmuch * sizeof(DSBPOSITIONNOTIFY));
170 else
171 This->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
172 howmuch * sizeof(DSBPOSITIONNOTIFY));
173
174 if (!This->notifies) {
175 WARN("out of memory\n");
176 return DSERR_OUTOFMEMORY;
177 }
178 CopyMemory(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
179 This->nrofnotifies = howmuch;
180 } else {
181 HeapFree(GetProcessHeap(), 0, This->notifies);
182 This->notifies = NULL;
183 This->nrofnotifies = 0;
184 }
185
186 return S_OK;
187 }
188
189 static const IDirectSoundNotifyVtbl dscnvt =
190 {
191 IDirectSoundNotifyImpl_QueryInterface,
192 IDirectSoundNotifyImpl_AddRef,
193 IDirectSoundNotifyImpl_Release,
194 IDirectSoundNotifyImpl_SetNotificationPositions
195 };
196
197
198 static const char * const captureStateString[] = {
199 "STATE_STOPPED",
200 "STATE_STARTING",
201 "STATE_CAPTURING",
202 "STATE_STOPPING"
203 };
204
205
206 /*******************************************************************************
207 * IDirectSoundCaptureBuffer
208 */
209 static inline IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8 *iface)
210 {
211 return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundCaptureBuffer8_iface);
212 }
213
214 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_QueryInterface(IDirectSoundCaptureBuffer8 *iface,
215 REFIID riid, void **ppobj)
216 {
217 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
218
219 TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
220
221 if (ppobj == NULL) {
222 WARN("invalid parameter\n");
223 return E_INVALIDARG;
224 }
225
226 *ppobj = NULL;
227
228 if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
229 IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
230 IDirectSoundCaptureBuffer8_AddRef(iface);
231 *ppobj = iface;
232 return S_OK;
233 }
234
235 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
236 IDirectSoundNotify_AddRef(&This->IDirectSoundNotify_iface);
237 *ppobj = &This->IDirectSoundNotify_iface;
238 return S_OK;
239 }
240
241 FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
242 return E_NOINTERFACE;
243 }
244
245 static ULONG WINAPI IDirectSoundCaptureBufferImpl_AddRef(IDirectSoundCaptureBuffer8 *iface)
246 {
247 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
248 ULONG ref = InterlockedIncrement(&This->ref);
249
250 TRACE("(%p) ref was %d\n", This, ref - 1);
251
252 if(ref == 1)
253 InterlockedIncrement(&This->numIfaces);
254
255 return ref;
256 }
257
258 static ULONG WINAPI IDirectSoundCaptureBufferImpl_Release(IDirectSoundCaptureBuffer8 *iface)
259 {
260 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
261 ULONG ref = InterlockedDecrement(&This->ref);
262
263 TRACE("(%p) ref was %d\n", This, ref + 1);
264
265 if (!ref && !InterlockedDecrement(&This->numIfaces))
266 capturebuffer_destroy(This);
267
268 return ref;
269 }
270
271 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCaps(IDirectSoundCaptureBuffer8 *iface,
272 DSCBCAPS *lpDSCBCaps)
273 {
274 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
275 TRACE( "(%p,%p)\n", This, lpDSCBCaps );
276
277 if (lpDSCBCaps == NULL) {
278 WARN("invalid parameter: lpDSCBCaps == NULL\n");
279 return DSERR_INVALIDPARAM;
280 }
281
282 if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
283 WARN("invalid parameter: lpDSCBCaps->dwSize = %d\n", lpDSCBCaps->dwSize);
284 return DSERR_INVALIDPARAM;
285 }
286
287 if (This->device == NULL) {
288 WARN("invalid parameter: This->device == NULL\n");
289 return DSERR_INVALIDPARAM;
290 }
291
292 lpDSCBCaps->dwSize = sizeof(DSCBCAPS);
293 lpDSCBCaps->dwFlags = This->flags;
294 lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes;
295 lpDSCBCaps->dwReserved = 0;
296
297 TRACE("returning DS_OK\n");
298 return DS_OK;
299 }
300
301 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCurrentPosition(IDirectSoundCaptureBuffer8 *iface,
302 DWORD *lpdwCapturePosition, DWORD *lpdwReadPosition)
303 {
304 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
305
306 TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
307
308 if (This->device == NULL) {
309 WARN("invalid parameter: This->device == NULL\n");
310 return DSERR_INVALIDPARAM;
311 }
312
313 EnterCriticalSection(&This->device->lock);
314
315 if (!This->device->client) {
316 LeaveCriticalSection(&This->device->lock);
317 WARN("no driver\n");
318 return DSERR_NODRIVER;
319 }
320
321 if(lpdwCapturePosition)
322 *lpdwCapturePosition = This->device->write_pos_bytes;
323
324 if(lpdwReadPosition)
325 *lpdwReadPosition = This->device->write_pos_bytes;
326
327 LeaveCriticalSection(&This->device->lock);
328
329 TRACE("cappos=%d readpos=%d\n", (lpdwCapturePosition?*lpdwCapturePosition:-1), (lpdwReadPosition?*lpdwReadPosition:-1));
330 TRACE("returning DS_OK\n");
331
332 return DS_OK;
333 }
334
335 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFormat(IDirectSoundCaptureBuffer8 *iface,
336 WAVEFORMATEX *lpwfxFormat, DWORD dwSizeAllocated, DWORD *lpdwSizeWritten)
337 {
338 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
339 HRESULT hres = DS_OK;
340
341 TRACE("(%p,%p,0x%08x,%p)\n", This, lpwfxFormat, dwSizeAllocated, lpdwSizeWritten);
342
343 if (This->device == NULL) {
344 WARN("invalid parameter: This->device == NULL\n");
345 return DSERR_INVALIDPARAM;
346 }
347
348 if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize))
349 dwSizeAllocated = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
350
351 if (lpwfxFormat) { /* NULL is valid (just want size) */
352 CopyMemory(lpwfxFormat, This->device->pwfx, dwSizeAllocated);
353 if (lpdwSizeWritten)
354 *lpdwSizeWritten = dwSizeAllocated;
355 } else {
356 if (lpdwSizeWritten)
357 *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
358 else {
359 TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
360 hres = DSERR_INVALIDPARAM;
361 }
362 }
363
364 TRACE("returning %08x\n", hres);
365 return hres;
366 }
367
368 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetStatus(IDirectSoundCaptureBuffer8 *iface,
369 DWORD *lpdwStatus)
370 {
371 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
372
373 TRACE( "(%p, %p), thread is %04x\n", This, lpdwStatus, GetCurrentThreadId() );
374
375 if (This->device == NULL) {
376 WARN("invalid parameter: This->device == NULL\n");
377 return DSERR_INVALIDPARAM;
378 }
379
380 if (lpdwStatus == NULL) {
381 WARN("invalid parameter: lpdwStatus == NULL\n");
382 return DSERR_INVALIDPARAM;
383 }
384
385 *lpdwStatus = 0;
386 EnterCriticalSection(&(This->device->lock));
387
388 TRACE("old This->device->state=%s, old lpdwStatus=%08x\n",
389 captureStateString[This->device->state],*lpdwStatus);
390 if ((This->device->state == STATE_STARTING) ||
391 (This->device->state == STATE_CAPTURING)) {
392 *lpdwStatus |= DSCBSTATUS_CAPTURING;
393 if (This->flags & DSCBSTART_LOOPING)
394 *lpdwStatus |= DSCBSTATUS_LOOPING;
395 }
396 TRACE("new This->device->state=%s, new lpdwStatus=%08x\n",
397 captureStateString[This->device->state],*lpdwStatus);
398 LeaveCriticalSection(&(This->device->lock));
399
400 TRACE("status=%x\n", *lpdwStatus);
401 TRACE("returning DS_OK\n");
402 return DS_OK;
403 }
404
405 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Initialize(IDirectSoundCaptureBuffer8 *iface,
406 IDirectSoundCapture *lpDSC, const DSCBUFFERDESC *lpcDSCBDesc)
407 {
408 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
409
410 FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
411
412 return DS_OK;
413 }
414
415 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Lock(IDirectSoundCaptureBuffer8 *iface,
416 DWORD dwReadCusor, DWORD dwReadBytes, void **lplpvAudioPtr1, DWORD *lpdwAudioBytes1,
417 void **lplpvAudioPtr2, DWORD *lpdwAudioBytes2, DWORD dwFlags)
418 {
419 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
420 HRESULT hres = DS_OK;
421
422 TRACE( "(%p,%08u,%08u,%p,%p,%p,%p,0x%08x) at %d\n", This, dwReadCusor,
423 dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
424 lpdwAudioBytes2, dwFlags, GetTickCount() );
425
426 if (This->device == NULL) {
427 WARN("invalid parameter: This->device == NULL\n");
428 return DSERR_INVALIDPARAM;
429 }
430
431 if (lplpvAudioPtr1 == NULL) {
432 WARN("invalid parameter: lplpvAudioPtr1 == NULL\n");
433 return DSERR_INVALIDPARAM;
434 }
435
436 if (lpdwAudioBytes1 == NULL) {
437 WARN("invalid parameter: lpdwAudioBytes1 == NULL\n");
438 return DSERR_INVALIDPARAM;
439 }
440
441 EnterCriticalSection(&(This->device->lock));
442
443 if (This->device->client) {
444 *lplpvAudioPtr1 = This->device->buffer + dwReadCusor;
445 if ( (dwReadCusor + dwReadBytes) > This->device->buflen) {
446 *lpdwAudioBytes1 = This->device->buflen - dwReadCusor;
447 if (lplpvAudioPtr2)
448 *lplpvAudioPtr2 = This->device->buffer;
449 if (lpdwAudioBytes2)
450 *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
451 } else {
452 *lpdwAudioBytes1 = dwReadBytes;
453 if (lplpvAudioPtr2)
454 *lplpvAudioPtr2 = 0;
455 if (lpdwAudioBytes2)
456 *lpdwAudioBytes2 = 0;
457 }
458 } else {
459 TRACE("invalid call\n");
460 hres = DSERR_INVALIDCALL; /* DSERR_NODRIVER ? */
461 }
462
463 LeaveCriticalSection(&(This->device->lock));
464
465 TRACE("returning %08x\n", hres);
466 return hres;
467 }
468
469 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Start(IDirectSoundCaptureBuffer8 *iface,
470 DWORD dwFlags)
471 {
472 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
473 HRESULT hres;
474
475 TRACE( "(%p,0x%08x)\n", This, dwFlags );
476
477 if (This->device == NULL) {
478 WARN("invalid parameter: This->device == NULL\n");
479 return DSERR_INVALIDPARAM;
480 }
481
482 if ( !This->device->client ) {
483 WARN("no driver\n");
484 return DSERR_NODRIVER;
485 }
486
487 EnterCriticalSection(&(This->device->lock));
488
489 if (This->device->state == STATE_STOPPED)
490 This->device->state = STATE_STARTING;
491 else if (This->device->state == STATE_STOPPING)
492 This->device->state = STATE_CAPTURING;
493 else
494 goto out;
495 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
496 This->flags = dwFlags;
497
498 if (This->device->buffer)
499 FillMemory(This->device->buffer, This->device->buflen, (This->device->pwfx->wBitsPerSample == 8) ? 128 : 0);
500
501 hres = IAudioClient_Start(This->device->client);
502 if(FAILED(hres)){
503 WARN("Start failed: %08x\n", hres);
504 LeaveCriticalSection(&This->device->lock);
505 return hres;
506 }
507
508 out:
509 LeaveCriticalSection(&This->device->lock);
510
511 TRACE("returning DS_OK\n");
512 return DS_OK;
513 }
514
515 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Stop(IDirectSoundCaptureBuffer8 *iface)
516 {
517 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
518 HRESULT hres;
519
520 TRACE("(%p)\n", This);
521
522 if (This->device == NULL) {
523 WARN("invalid parameter: This->device == NULL\n");
524 return DSERR_INVALIDPARAM;
525 }
526
527 EnterCriticalSection(&(This->device->lock));
528
529 TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
530 if (This->device->state == STATE_CAPTURING)
531 This->device->state = STATE_STOPPING;
532 else if (This->device->state == STATE_STARTING)
533 This->device->state = STATE_STOPPED;
534 TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
535
536 if(This->device->client){
537 hres = IAudioClient_Stop(This->device->client);
538 if(FAILED(hres)){
539 LeaveCriticalSection(&This->device->lock);
540 return hres;
541 }
542 }
543
544 LeaveCriticalSection(&(This->device->lock));
545
546 TRACE("returning DS_OK\n");
547 return DS_OK;
548 }
549
550 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Unlock(IDirectSoundCaptureBuffer8 *iface,
551 void *lpvAudioPtr1, DWORD dwAudioBytes1, void *lpvAudioPtr2, DWORD dwAudioBytes2)
552 {
553 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
554 HRESULT hres = DS_OK;
555
556 TRACE( "(%p,%p,%08u,%p,%08u)\n", This, lpvAudioPtr1, dwAudioBytes1,
557 lpvAudioPtr2, dwAudioBytes2 );
558
559 if (lpvAudioPtr1 == NULL) {
560 WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
561 return DSERR_INVALIDPARAM;
562 }
563
564 if (!This->device->client) {
565 WARN("invalid call\n");
566 hres = DSERR_INVALIDCALL;
567 }
568
569 TRACE("returning %08x\n", hres);
570 return hres;
571 }
572
573 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface,
574 REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
575 {
576 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
577
578 FIXME( "(%p,%s,%u,%s,%p): stub\n", This, debugstr_guid(rguidObject),
579 dwIndex, debugstr_guid(rguidInterface), ppObject );
580
581 if (!ppObject)
582 return DSERR_INVALIDPARAM;
583
584 *ppObject = NULL;
585 return DSERR_CONTROLUNAVAIL;
586 }
587
588 static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFXStatus(IDirectSoundCaptureBuffer8 *iface,
589 DWORD dwFXCount, DWORD *pdwFXStatus)
590 {
591 IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
592
593 FIXME( "(%p,%u,%p): stub\n", This, dwFXCount, pdwFXStatus );
594
595 return DS_OK;
596 }
597
598 static const IDirectSoundCaptureBuffer8Vtbl dscbvt =
599 {
600 /* IUnknown methods */
601 IDirectSoundCaptureBufferImpl_QueryInterface,
602 IDirectSoundCaptureBufferImpl_AddRef,
603 IDirectSoundCaptureBufferImpl_Release,
604
605 /* IDirectSoundCaptureBuffer methods */
606 IDirectSoundCaptureBufferImpl_GetCaps,
607 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
608 IDirectSoundCaptureBufferImpl_GetFormat,
609 IDirectSoundCaptureBufferImpl_GetStatus,
610 IDirectSoundCaptureBufferImpl_Initialize,
611 IDirectSoundCaptureBufferImpl_Lock,
612 IDirectSoundCaptureBufferImpl_Start,
613 IDirectSoundCaptureBufferImpl_Stop,
614 IDirectSoundCaptureBufferImpl_Unlock,
615
616 /* IDirectSoundCaptureBuffer methods */
617 IDirectSoundCaptureBufferImpl_GetObjectInPath,
618 IDirectSoundCaptureBufferImpl_GetFXStatus
619 };
620
621 static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len)
622 {
623 int i;
624 for (i = 0; i < This->nrofnotifies; ++i) {
625 LPDSBPOSITIONNOTIFY event = This->notifies + i;
626 DWORD offset = event->dwOffset;
627 TRACE("checking %d, position %d, event = %p\n", i, offset, event->hEventNotify);
628
629 if (offset == DSBPN_OFFSETSTOP) {
630 if (!from && !len) {
631 SetEvent(event->hEventNotify);
632 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
633 return;
634 }
635 else return;
636 }
637
638 if (offset >= from && offset < (from + len))
639 {
640 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
641 SetEvent(event->hEventNotify);
642 }
643 }
644 }
645
646 static HRESULT IDirectSoundCaptureBufferImpl_Create(
647 DirectSoundCaptureDevice *device,
648 IDirectSoundCaptureBufferImpl ** ppobj,
649 LPCDSCBUFFERDESC lpcDSCBufferDesc)
650 {
651 LPWAVEFORMATEX wfex;
652 IDirectSoundCaptureBufferImpl *This;
653 TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
654
655 if (ppobj == NULL) {
656 WARN("invalid parameter: ppobj == NULL\n");
657 return DSERR_INVALIDPARAM;
658 }
659
660 *ppobj = NULL;
661
662 if (!device) {
663 WARN("not initialized\n");
664 return DSERR_UNINITIALIZED;
665 }
666
667 if (lpcDSCBufferDesc == NULL) {
668 WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
669 return DSERR_INVALIDPARAM;
670 }
671
672 if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
673 (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
674 (lpcDSCBufferDesc->dwBufferBytes == 0) ||
675 (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { /* FIXME: DSERR_BADFORMAT ? */
676 WARN("invalid lpcDSCBufferDesc\n");
677 return DSERR_INVALIDPARAM;
678 }
679
680 wfex = lpcDSCBufferDesc->lpwfxFormat;
681
682 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
683 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
684 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
685 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
686 wfex->wBitsPerSample, wfex->cbSize);
687
688 device->pwfx = DSOUND_CopyFormat(wfex);
689 if ( device->pwfx == NULL )
690 return DSERR_OUTOFMEMORY;
691
692 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
693 sizeof(IDirectSoundCaptureBufferImpl));
694
695 if ( This == NULL ) {
696 WARN("out of memory\n");
697 return DSERR_OUTOFMEMORY;
698 } else {
699 HRESULT err = DS_OK;
700 LPBYTE newbuf;
701 DWORD buflen;
702
703 This->numIfaces = 0;
704 This->ref = 0;
705 This->refn = 0;
706 This->device = device;
707 This->device->capture_buffer = This;
708 This->nrofnotifies = 0;
709
710 This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
711 lpcDSCBufferDesc->dwSize);
712 if (This->pdscbd)
713 CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
714 else {
715 WARN("no memory\n");
716 This->device->capture_buffer = 0;
717 HeapFree( GetProcessHeap(), 0, This );
718 return DSERR_OUTOFMEMORY;
719 }
720
721 This->IDirectSoundCaptureBuffer8_iface.lpVtbl = &dscbvt;
722 This->IDirectSoundNotify_iface.lpVtbl = &dscnvt;
723
724 err = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
725 CLSCTX_INPROC_SERVER, NULL, (void**)&device->client);
726 if(FAILED(err)){
727 WARN("Activate failed: %08x\n", err);
728 HeapFree(GetProcessHeap(), 0, This->pdscbd);
729 This->device->capture_buffer = 0;
730 HeapFree( GetProcessHeap(), 0, This );
731 return err;
732 }
733
734 err = IAudioClient_Initialize(device->client,
735 AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST | AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
736 200 * 100000, 0, device->pwfx, NULL);
737 if(FAILED(err)){
738 WARN("Initialize failed: %08x\n", err);
739 IAudioClient_Release(device->client);
740 device->client = NULL;
741 HeapFree(GetProcessHeap(), 0, This->pdscbd);
742 This->device->capture_buffer = 0;
743 HeapFree( GetProcessHeap(), 0, This );
744 if(err == AUDCLNT_E_UNSUPPORTED_FORMAT)
745 return DSERR_BADFORMAT;
746 return err;
747 }
748
749 This->sleepev = CreateEventW(NULL, 0, 0, NULL);
750
751 err = IAudioClient_SetEventHandle(device->client, This->sleepev);
752 if(FAILED(err)){
753 WARN("SetEventHandle failed: %08x\n", err);
754 IAudioClient_Release(device->client);
755 device->client = NULL;
756 CloseHandle(This->sleepev);
757 HeapFree(GetProcessHeap(), 0, This->pdscbd);
758 This->device->capture_buffer = 0;
759 HeapFree( GetProcessHeap(), 0, This );
760 return err;
761 }
762
763 err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
764 (void**)&device->capture);
765 if(FAILED(err)){
766 WARN("GetService failed: %08x\n", err);
767 IAudioClient_Release(device->client);
768 device->client = NULL;
769 CloseHandle(This->sleepev);
770 HeapFree(GetProcessHeap(), 0, This->pdscbd);
771 This->device->capture_buffer = 0;
772 HeapFree( GetProcessHeap(), 0, This );
773 return err;
774 }
775
776 buflen = lpcDSCBufferDesc->dwBufferBytes;
777 TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
778 if (device->buffer)
779 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
780 else
781 newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
782 if (newbuf == NULL) {
783 IAudioClient_Release(device->client);
784 device->client = NULL;
785 IAudioCaptureClient_Release(device->capture);
786 device->capture = NULL;
787 CloseHandle(This->sleepev);
788 HeapFree(GetProcessHeap(), 0, This->pdscbd);
789 This->device->capture_buffer = 0;
790 HeapFree( GetProcessHeap(), 0, This );
791 return DSERR_OUTOFMEMORY;
792 }
793 device->buffer = newbuf;
794 device->buflen = buflen;
795 This->thread = CreateThread(NULL, 0, DSOUND_capture_thread, This, 0, NULL);
796 }
797
798 IDirectSoundCaptureBuffer_AddRef(&This->IDirectSoundCaptureBuffer8_iface);
799 *ppobj = This;
800
801 TRACE("returning DS_OK\n");
802 return DS_OK;
803 }
804
805
806 /*******************************************************************************
807 * DirectSoundCaptureDevice
808 */
809 static HRESULT DirectSoundCaptureDevice_Create(
810 DirectSoundCaptureDevice ** ppDevice)
811 {
812 DirectSoundCaptureDevice * device;
813 TRACE("(%p)\n", ppDevice);
814
815 /* Allocate memory */
816 device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
817
818 if (device == NULL) {
819 WARN("out of memory\n");
820 return DSERR_OUTOFMEMORY;
821 }
822
823 device->ref = 1;
824 device->state = STATE_STOPPED;
825
826 InitializeCriticalSection( &(device->lock) );
827 device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
828
829 *ppDevice = device;
830
831 return DS_OK;
832 }
833
834 static ULONG DirectSoundCaptureDevice_Release(
835 DirectSoundCaptureDevice * device)
836 {
837 ULONG ref = InterlockedDecrement(&(device->ref));
838 TRACE("(%p) ref was %d\n", device, ref + 1);
839
840 if (!ref) {
841 TRACE("deleting object\n");
842
843 EnterCriticalSection(&DSOUND_capturers_lock);
844 list_remove(&device->entry);
845 LeaveCriticalSection(&DSOUND_capturers_lock);
846
847 if (device->capture_buffer)
848 IDirectSoundCaptureBufferImpl_Release(&device->capture_buffer->IDirectSoundCaptureBuffer8_iface);
849
850 if(device->mmdevice)
851 IMMDevice_Release(device->mmdevice);
852 HeapFree(GetProcessHeap(), 0, device->pwfx);
853 device->lock.DebugInfo->Spare[0] = 0;
854 DeleteCriticalSection( &(device->lock) );
855 HeapFree(GetProcessHeap(), 0, device);
856 TRACE("(%p) released\n", device);
857 }
858 return ref;
859 }
860
861 static HRESULT DSOUND_capture_data(DirectSoundCaptureDevice *device)
862 {
863 HRESULT hr;
864 UINT32 packet_frames, packet_bytes, avail_bytes, skip_bytes = 0;
865 DWORD flags;
866 BYTE *buf;
867
868 if(!device->capture_buffer || device->state == STATE_STOPPED)
869 return S_FALSE;
870
871 if(device->state == STATE_STOPPING){
872 device->state = STATE_STOPPED;
873 return S_FALSE;
874 }
875
876 if(device->state == STATE_STARTING)
877 device->state = STATE_CAPTURING;
878
879 hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
880 &flags, NULL, NULL);
881 if(FAILED(hr)){
882 WARN("GetBuffer failed: %08x\n", hr);
883 return hr;
884 }
885
886 packet_bytes = packet_frames * device->pwfx->nBlockAlign;
887 if(packet_bytes > device->buflen){
888 TRACE("audio glitch: dsound buffer too small for data\n");
889 skip_bytes = packet_bytes - device->buflen;
890 packet_bytes = device->buflen;
891 }
892
893 avail_bytes = device->buflen - device->write_pos_bytes;
894 if(avail_bytes > packet_bytes)
895 avail_bytes = packet_bytes;
896
897 memcpy(device->buffer + device->write_pos_bytes, buf + skip_bytes, avail_bytes);
898 capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
899
900 packet_bytes -= avail_bytes;
901 if(packet_bytes > 0){
902 if(device->capture_buffer->flags & DSCBSTART_LOOPING){
903 memcpy(device->buffer, buf + skip_bytes + avail_bytes, packet_bytes);
904 capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
905 }else{
906 device->state = STATE_STOPPED;
907 capture_CheckNotify(device->capture_buffer, 0, 0);
908 }
909 }
910
911 device->write_pos_bytes += avail_bytes + packet_bytes;
912 device->write_pos_bytes %= device->buflen;
913
914 hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
915 if(FAILED(hr)){
916 WARN("ReleaseBuffer failed: %08x\n", hr);
917 return hr;
918 }
919
920 return S_OK;
921 }
922
923 static DWORD WINAPI DSOUND_capture_thread(void *user)
924 {
925 IDirectSoundCaptureBufferImpl *buffer = user;
926 HRESULT hr;
927 DWORD ret, wait_ms;
928 REFERENCE_TIME period;
929
930 hr = IAudioClient_GetDevicePeriod(buffer->device->client, &period, NULL);
931 if(FAILED(hr)){
932 WARN("GetDevicePeriod failed: %08x\n", hr);
933 wait_ms = 5;
934 }else
935 wait_ms = MulDiv(5, period, 10000);
936
937 while(buffer->ref){
938 ret = WaitForSingleObject(buffer->sleepev, wait_ms);
939
940 if(!buffer->device->ref)
941 break;
942
943 if(ret == WAIT_OBJECT_0){
944 EnterCriticalSection(&buffer->device->lock);
945
946 DSOUND_capture_data(buffer->device);
947
948 LeaveCriticalSection(&buffer->device->lock);
949 }else if(ret != WAIT_TIMEOUT)
950 WARN("WaitForSingleObject failed: %u\n", GetLastError());
951 }
952
953 return 0;
954 }
955
956 static struct _TestFormat {
957 DWORD flag;
958 DWORD rate;
959 DWORD depth;
960 WORD channels;
961 } formats_to_test[] = {
962 { WAVE_FORMAT_1M08, 11025, 8, 1 },
963 { WAVE_FORMAT_1M16, 11025, 16, 1 },
964 { WAVE_FORMAT_1S08, 11025, 8, 2 },
965 { WAVE_FORMAT_1S16, 11025, 16, 2 },
966 { WAVE_FORMAT_2M08, 22050, 8, 1 },
967 { WAVE_FORMAT_2M16, 22050, 16, 1 },
968 { WAVE_FORMAT_2S08, 22050, 8, 2 },
969 { WAVE_FORMAT_2S16, 22050, 16, 2 },
970 { WAVE_FORMAT_4M08, 44100, 8, 1 },
971 { WAVE_FORMAT_4M16, 44100, 16, 1 },
972 { WAVE_FORMAT_4S08, 44100, 8, 2 },
973 { WAVE_FORMAT_4S16, 44100, 16, 2 },
974 { WAVE_FORMAT_48M08, 48000, 8, 1 },
975 { WAVE_FORMAT_48M16, 48000, 16, 1 },
976 { WAVE_FORMAT_48S08, 48000, 8, 2 },
977 { WAVE_FORMAT_48S16, 48000, 16, 2 },
978 { WAVE_FORMAT_96M08, 96000, 8, 1 },
979 { WAVE_FORMAT_96M16, 96000, 16, 1 },
980 { WAVE_FORMAT_96S08, 96000, 8, 2 },
981 { WAVE_FORMAT_96S16, 96000, 16, 2 },
982 {0}
983 };
984
985 static HRESULT DirectSoundCaptureDevice_Initialize(
986 DirectSoundCaptureDevice ** ppDevice,
987 LPCGUID lpcGUID)
988 {
989 HRESULT hr;
990 GUID devGUID;
991 IMMDevice *mmdevice;
992 struct _TestFormat *fmt;
993 DirectSoundCaptureDevice *device;
994 IAudioClient *client;
995
996 TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
997
998 /* Default device? */
999 if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
1000 lpcGUID = &DSDEVID_DefaultCapture;
1001
1002 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
1003 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
1004 return DSERR_NODRIVER;
1005
1006 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1007 WARN("invalid parameter: lpcGUID\n");
1008 return DSERR_INVALIDPARAM;
1009 }
1010
1011 hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
1012 if(FAILED(hr))
1013 return hr;
1014
1015 EnterCriticalSection(&DSOUND_capturers_lock);
1016
1017 hr = DirectSoundCaptureDevice_Create(&device);
1018 if (hr != DS_OK) {
1019 WARN("DirectSoundCaptureDevice_Create failed\n");
1020 LeaveCriticalSection(&DSOUND_capturers_lock);
1021 return hr;
1022 }
1023
1024 device->guid = devGUID;
1025
1026 device->mmdevice = mmdevice;
1027
1028 device->drvcaps.dwFlags = 0;
1029
1030 device->drvcaps.dwFormats = 0;
1031 device->drvcaps.dwChannels = 0;
1032 hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
1033 CLSCTX_INPROC_SERVER, NULL, (void**)&client);
1034 if(FAILED(hr)){
1035 device->lock.DebugInfo->Spare[0] = 0;
1036 DeleteCriticalSection(&device->lock);
1037 HeapFree(GetProcessHeap(), 0, device);
1038 LeaveCriticalSection(&DSOUND_capturers_lock);
1039 return DSERR_NODRIVER;
1040 }
1041
1042 for(fmt = formats_to_test; fmt->flag; ++fmt){
1043 if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
1044 device->drvcaps.dwFormats |= fmt->flag;
1045 if(fmt->channels > device->drvcaps.dwChannels)
1046 device->drvcaps.dwChannels = fmt->channels;
1047 }
1048 }
1049 IAudioClient_Release(client);
1050
1051 list_add_tail(&DSOUND_capturers, &device->entry);
1052
1053 *ppDevice = device;
1054
1055 LeaveCriticalSection(&DSOUND_capturers_lock);
1056
1057 return S_OK;
1058 }
1059
1060
1061 /*****************************************************************************
1062 * IDirectSoundCapture implementation structure
1063 */
1064 typedef struct IDirectSoundCaptureImpl
1065 {
1066 IUnknown IUnknown_inner;
1067 IDirectSoundCapture IDirectSoundCapture_iface;
1068 LONG ref, refdsc, numIfaces;
1069 IUnknown *outer_unk; /* internal */
1070 DirectSoundCaptureDevice *device;
1071 BOOL has_dsc8;
1072 } IDirectSoundCaptureImpl;
1073
1074 static void capture_destroy(IDirectSoundCaptureImpl *This)
1075 {
1076 if (This->device)
1077 DirectSoundCaptureDevice_Release(This->device);
1078 HeapFree(GetProcessHeap(),0,This);
1079 TRACE("(%p) released\n", This);
1080 }
1081
1082 /*******************************************************************************
1083 * IUnknown Implementation for DirectSoundCapture
1084 */
1085 static inline IDirectSoundCaptureImpl *impl_from_IUnknown(IUnknown *iface)
1086 {
1087 return CONTAINING_RECORD(iface, IDirectSoundCaptureImpl, IUnknown_inner);
1088 }
1089
1090 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1091 {
1092 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1093
1094 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
1095
1096 if (!ppv) {
1097 WARN("invalid parameter\n");
1098 return E_INVALIDARG;
1099 }
1100 *ppv = NULL;
1101
1102 if (IsEqualIID(riid, &IID_IUnknown))
1103 *ppv = &This->IUnknown_inner;
1104 else if (IsEqualIID(riid, &IID_IDirectSoundCapture))
1105 *ppv = &This->IDirectSoundCapture_iface;
1106 else {
1107 WARN("unknown IID %s\n", debugstr_guid(riid));
1108 return E_NOINTERFACE;
1109 }
1110
1111 IUnknown_AddRef((IUnknown*)*ppv);
1112 return S_OK;
1113 }
1114
1115 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
1116 {
1117 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1118 ULONG ref = InterlockedIncrement(&This->ref);
1119
1120 TRACE("(%p) ref=%d\n", This, ref);
1121
1122 if(ref == 1)
1123 InterlockedIncrement(&This->numIfaces);
1124 return ref;
1125 }
1126
1127 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
1128 {
1129 IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
1130 ULONG ref = InterlockedDecrement(&This->ref);
1131
1132 TRACE("(%p) ref=%d\n", This, ref);
1133
1134 if (!ref && !InterlockedDecrement(&This->numIfaces))
1135 capture_destroy(This);
1136 return ref;
1137 }
1138
1139 static const IUnknownVtbl unk_vtbl =
1140 {
1141 IUnknownImpl_QueryInterface,
1142 IUnknownImpl_AddRef,
1143 IUnknownImpl_Release
1144 };
1145
1146 /***************************************************************************
1147 * IDirectSoundCaptureImpl
1148 */
1149 static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
1150 {
1151 return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
1152 }
1153
1154 static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
1155 REFIID riid, void **ppv)
1156 {
1157 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1158 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
1159 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1160 }
1161
1162 static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
1163 {
1164 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1165 ULONG ref = InterlockedIncrement(&This->refdsc);
1166
1167 TRACE("(%p) ref=%d\n", This, ref);
1168
1169 if(ref == 1)
1170 InterlockedIncrement(&This->numIfaces);
1171 return ref;
1172 }
1173
1174 static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
1175 {
1176 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1177 ULONG ref = InterlockedDecrement(&This->refdsc);
1178
1179 TRACE("(%p) ref=%d\n", This, ref);
1180
1181 if (!ref && !InterlockedDecrement(&This->numIfaces))
1182 capture_destroy(This);
1183 return ref;
1184 }
1185
1186 static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
1187 LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
1188 IUnknown *pUnk)
1189 {
1190 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1191 HRESULT hr;
1192
1193 TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
1194
1195 if (pUnk) {
1196 WARN("invalid parameter: pUnk != NULL\n");
1197 return DSERR_NOAGGREGATION;
1198 }
1199
1200 if (lpcDSCBufferDesc == NULL) {
1201 WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
1202 return DSERR_INVALIDPARAM;
1203 }
1204
1205 if (lplpDSCaptureBuffer == NULL) {
1206 WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n");
1207 return DSERR_INVALIDPARAM;
1208 }
1209
1210 if (pUnk != NULL) {
1211 WARN("invalid parameter: pUnk != NULL\n");
1212 return DSERR_INVALIDPARAM;
1213 }
1214
1215 /* FIXME: We can only have one buffer so what do we do here? */
1216 if (This->device->capture_buffer) {
1217 WARN("invalid parameter: already has buffer\n");
1218 return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */
1219 }
1220
1221 hr = IDirectSoundCaptureBufferImpl_Create(This->device,
1222 (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
1223
1224 if (hr != DS_OK)
1225 WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
1226
1227 return hr;
1228 }
1229
1230 static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
1231 LPDSCCAPS lpDSCCaps)
1232 {
1233 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1234
1235 TRACE("(%p,%p)\n",This,lpDSCCaps);
1236
1237 if (This->device == NULL) {
1238 WARN("not initialized\n");
1239 return DSERR_UNINITIALIZED;
1240 }
1241
1242 if (lpDSCCaps== NULL) {
1243 WARN("invalid parameter: lpDSCCaps== NULL\n");
1244 return DSERR_INVALIDPARAM;
1245 }
1246
1247 if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
1248 WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
1249 return DSERR_INVALIDPARAM;
1250 }
1251
1252 lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags;
1253 lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
1254 lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
1255
1256 TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
1257 lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
1258
1259 return DS_OK;
1260 }
1261
1262 static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
1263 LPCGUID lpcGUID)
1264 {
1265 IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
1266
1267 TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
1268
1269 if (This->device != NULL) {
1270 WARN("already initialized\n");
1271 return DSERR_ALREADYINITIALIZED;
1272 }
1273 return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
1274 }
1275
1276 static const IDirectSoundCaptureVtbl dscvt =
1277 {
1278 /* IUnknown methods */
1279 IDirectSoundCaptureImpl_QueryInterface,
1280 IDirectSoundCaptureImpl_AddRef,
1281 IDirectSoundCaptureImpl_Release,
1282
1283 /* IDirectSoundCapture methods */
1284 IDirectSoundCaptureImpl_CreateCaptureBuffer,
1285 IDirectSoundCaptureImpl_GetCaps,
1286 IDirectSoundCaptureImpl_Initialize
1287 };
1288
1289 HRESULT IDirectSoundCaptureImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_dsc8)
1290 {
1291 IDirectSoundCaptureImpl *obj;
1292 HRESULT hr;
1293
1294 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1295
1296 *ppv = NULL;
1297 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
1298 if (obj == NULL) {
1299 WARN("out of memory\n");
1300 return DSERR_OUTOFMEMORY;
1301 }
1302
1303 setup_dsound_options();
1304
1305 obj->IUnknown_inner.lpVtbl = &unk_vtbl;
1306 obj->IDirectSoundCapture_iface.lpVtbl = &dscvt;
1307 obj->ref = 1;
1308 obj->refdsc = 0;
1309 obj->numIfaces = 1;
1310 obj->device = NULL;
1311 obj->has_dsc8 = has_dsc8;
1312
1313 /* COM aggregation supported only internally */
1314 if (outer_unk)
1315 obj->outer_unk = outer_unk;
1316 else
1317 obj->outer_unk = &obj->IUnknown_inner;
1318
1319 hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
1320 IUnknown_Release(&obj->IUnknown_inner);
1321
1322 return hr;
1323 }
1324
1325 HRESULT DSOUND_CaptureCreate(REFIID riid, void **ppv)
1326 {
1327 return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, FALSE);
1328 }
1329
1330 HRESULT DSOUND_CaptureCreate8(REFIID riid, void **ppv)
1331 {
1332 return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, TRUE);
1333 }
1334
1335 /***************************************************************************
1336 * DirectSoundCaptureCreate [DSOUND.6]
1337 *
1338 * Create and initialize a DirectSoundCapture interface.
1339 *
1340 * PARAMS
1341 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1342 * lplpDSC [O] Address of a variable to receive the interface pointer.
1343 * pUnkOuter [I] Must be NULL.
1344 *
1345 * RETURNS
1346 * Success: DS_OK
1347 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1348 * DSERR_OUTOFMEMORY
1349 *
1350 * NOTES
1351 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1352 * or NULL for the default device or DSDEVID_DefaultCapture or
1353 * DSDEVID_DefaultVoiceCapture.
1354 *
1355 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1356 */
1357 HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
1358 IUnknown *pUnkOuter)
1359 {
1360 HRESULT hr;
1361 IDirectSoundCapture *pDSC;
1362
1363 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
1364
1365 if (ppDSC == NULL) {
1366 WARN("invalid parameter: ppDSC == NULL\n");
1367 return DSERR_INVALIDPARAM;
1368 }
1369
1370 if (pUnkOuter) {
1371 WARN("invalid parameter: pUnkOuter != NULL\n");
1372 return DSERR_NOAGGREGATION;
1373 }
1374
1375 hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, (void**)&pDSC);
1376 if (hr == DS_OK) {
1377 hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
1378 if (hr != DS_OK) {
1379 IDirectSoundCapture_Release(pDSC);
1380 pDSC = 0;
1381 }
1382 }
1383
1384 *ppDSC = pDSC;
1385
1386 return hr;
1387 }
1388
1389 /***************************************************************************
1390 * DirectSoundCaptureCreate8 [DSOUND.12]
1391 *
1392 * Create and initialize a DirectSoundCapture interface.
1393 *
1394 * PARAMS
1395 * lpcGUID [I] Address of the GUID that identifies the sound capture device.
1396 * lplpDSC [O] Address of a variable to receive the interface pointer.
1397 * pUnkOuter [I] Must be NULL.
1398 *
1399 * RETURNS
1400 * Success: DS_OK
1401 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
1402 * DSERR_OUTOFMEMORY
1403 *
1404 * NOTES
1405 * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate
1406 * or NULL for the default device or DSDEVID_DefaultCapture or
1407 * DSDEVID_DefaultVoiceCapture.
1408 *
1409 * DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
1410 */
1411 HRESULT WINAPI DirectSoundCaptureCreate8(
1412 LPCGUID lpcGUID,
1413 LPDIRECTSOUNDCAPTURE8 *ppDSC8,
1414 LPUNKNOWN pUnkOuter)
1415 {
1416 HRESULT hr;
1417 LPDIRECTSOUNDCAPTURE8 pDSC8;
1418 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter);
1419
1420 if (ppDSC8 == NULL) {
1421 WARN("invalid parameter: ppDSC8 == NULL\n");
1422 return DSERR_INVALIDPARAM;
1423 }
1424
1425 if (pUnkOuter) {
1426 WARN("invalid parameter: pUnkOuter != NULL\n");
1427 *ppDSC8 = NULL;
1428 return DSERR_NOAGGREGATION;
1429 }
1430
1431 hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, (void**)&pDSC8);
1432 if (hr == DS_OK) {
1433 hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
1434 if (hr != DS_OK) {
1435 IDirectSoundCapture_Release(pDSC8);
1436 pDSC8 = 0;
1437 }
1438 }
1439
1440 *ppDSC8 = pDSC8;
1441
1442 return hr;
1443 }