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