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