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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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