1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Configuration of network devices 4 * FILE: dll/directx/dsound_new/capturebuffer.c 5 * PURPOSE: IDirectSoundCaptureBuffer8 implementation 6 * 7 * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org) 8 */ 9 10 11 #include "precomp.h" 12 13 const GUID KSINTERFACESETID_Standard = {0x1A8766A0L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; 14 const GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; 15 const GUID KSDATAFORMAT_TYPE_AUDIO = {0x73647561L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; 16 const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX = {0x05589f81L, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}}; 17 const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; 18 const GUID KSEVENTSETID_LoopedStreaming = {0x4682B940L, 0xC6EF, 0x11D0, {0x96, 0xD8, 0x00, 0xAA, 0x00, 0x51, 0xE5, 0x1D}}; 19 20 21 22 typedef struct 23 { 24 IDirectSoundCaptureBuffer8Vtbl *lpVtbl; 25 26 LONG ref; 27 LPFILTERINFO Filter; 28 HANDLE hPin; 29 PUCHAR Buffer; 30 DWORD BufferSize; 31 LPWAVEFORMATEX Format; 32 WAVEFORMATEX MixFormat; 33 BOOL bMix; 34 BOOL bLoop; 35 KSSTATE State; 36 PUCHAR MixBuffer; 37 ULONG MixBufferSize; 38 HANDLE hStopEvent; 39 volatile LONG StopMixerThread; 40 volatile LONG CurrentMixPosition; 41 42 LPDIRECTSOUNDNOTIFY Notify; 43 44 }CDirectSoundCaptureBufferImpl, *LPCDirectSoundCaptureBufferImpl; 45 46 DWORD 47 WINAPI 48 MixerThreadRoutine( 49 LPVOID lpParameter) 50 { 51 KSPROPERTY Request; 52 KSAUDIO_POSITION Position; 53 DWORD Result, MixPosition, BufferPosition, BytesWritten, BytesRead, MixLength, BufferLength; 54 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)lpParameter; 55 56 /* setup audio position property request */ 57 Request.Id = KSPROPERTY_AUDIO_POSITION; 58 Request.Set = KSPROPSETID_Audio; 59 Request.Flags = KSPROPERTY_TYPE_GET; 60 61 MixPosition = 0; 62 BufferPosition = 0; 63 do 64 { 65 /* query current position */ 66 Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSPROPERTY), (PVOID)&Position, sizeof(KSAUDIO_POSITION), NULL); 67 68 /* sanity check */ 69 ASSERT(Result == ERROR_SUCCESS); 70 71 /* FIXME implement samplerate conversion */ 72 ASSERT(This->MixFormat.nSamplesPerSec == This->Format->nSamplesPerSec); 73 74 /* FIXME implement bitrate conversion */ 75 ASSERT(This->MixFormat.wBitsPerSample == This->Format->wBitsPerSample); 76 77 /* sanity check */ 78 ASSERT(BufferPosition <= This->BufferSize); 79 ASSERT(MixPosition <= This->MixBufferSize); 80 81 if (BufferPosition == This->BufferSize) 82 { 83 /* restart from front */ 84 BufferPosition = 0; 85 } 86 87 if (MixPosition == This->MixBufferSize) 88 { 89 /* restart from front */ 90 MixPosition = 0; 91 } 92 93 if (This->MixFormat.nChannels != This->Format->nChannels) 94 { 95 if ((DWORD)Position.PlayOffset >= MixPosition) 96 { 97 /* calculate buffer position difference */ 98 MixLength = Position.PlayOffset - MixPosition; 99 } 100 else 101 { 102 /* buffer overlap */ 103 MixLength = This->MixBufferSize - MixPosition; 104 } 105 106 BufferLength = This->BufferSize - BufferPosition; 107 108 /* convert the format */ 109 PerformChannelConversion(&This->MixBuffer[MixPosition], MixLength, &BytesRead, This->MixFormat.nChannels, This->Format->nChannels, This->Format->wBitsPerSample, &This->Buffer[BufferPosition], BufferLength, &BytesWritten); 110 111 /* update buffer offsets */ 112 MixPosition += BytesRead; 113 BufferPosition += BytesWritten; 114 DPRINT("MixPosition %u BufferPosition %u BytesRead %u BytesWritten %u MixLength %u BufferLength %u\n", MixPosition, BufferPosition, BytesRead, BytesWritten, MixLength, BufferLength); 115 } 116 117 /* Notify Events */ 118 if (This->Notify) 119 { 120 DoNotifyPositionEvents(This->Notify, This->CurrentMixPosition, BufferPosition); 121 } 122 123 /* update offset */ 124 InterlockedExchange(&This->CurrentMixPosition, (LONG)BufferPosition); 125 126 /* FIXME use timer */ 127 Sleep(10); 128 129 }while(InterlockedCompareExchange(&This->StopMixerThread, 0, 0) == 0); 130 131 132 /* signal stop event */ 133 SetEvent(This->hStopEvent); 134 135 /* done */ 136 return 0; 137 } 138 139 140 141 HRESULT 142 WINAPI 143 IDirectSoundCaptureBufferImpl_QueryInterface( 144 LPDIRECTSOUNDCAPTUREBUFFER8 iface, 145 IN REFIID riid, 146 LPVOID* ppobj) 147 { 148 LPOLESTR pStr; 149 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); 150 151 /* check if requested interface is supported */ 152 if (IsEqualIID(riid, &IID_IUnknown) || 153 IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer) || 154 IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer8)) 155 { 156 *ppobj = (LPVOID)&This->lpVtbl; 157 InterlockedIncrement(&This->ref); 158 return S_OK; 159 } 160 161 /* check if the interface is supported */ 162 if (IsEqualIID(riid, &IID_IDirectSoundNotify)) 163 { 164 if (!This->Notify) 165 { 166 HRESULT hr = NewDirectSoundNotify(&This->Notify, This->bLoop, This->bMix, This->hPin, This->BufferSize); 167 if (FAILED(hr)) 168 return hr; 169 170 *ppobj = (LPVOID)This->Notify; 171 return S_OK; 172 } 173 174 /* increment reference count on existing notify object */ 175 IDirectSoundNotify_AddRef(This->Notify); 176 *ppobj = (LPVOID)This->Notify; 177 return S_OK; 178 } 179 180 /* interface not supported */ 181 if (SUCCEEDED(StringFromIID(riid, &pStr))) 182 { 183 DPRINT("No Interface for class %s\n", pStr); 184 CoTaskMemFree(pStr); 185 } 186 return E_NOINTERFACE; 187 } 188 189 ULONG 190 WINAPI 191 IDirectSoundCaptureBufferImpl_AddRef( 192 LPDIRECTSOUNDCAPTUREBUFFER8 iface) 193 { 194 ULONG ref; 195 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); 196 197 /* increment reference count */ 198 ref = InterlockedIncrement(&This->ref); 199 200 return ref; 201 202 } 203 204 ULONG 205 WINAPI 206 IDirectSoundCaptureBufferImpl_Release( 207 LPDIRECTSOUNDCAPTUREBUFFER8 iface) 208 { 209 ULONG ref; 210 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); 211 212 /* release reference count */ 213 ref = InterlockedDecrement(&(This->ref)); 214 215 if (!ref) 216 { 217 if (This->hPin) 218 { 219 /* close pin handle */ 220 CloseHandle(This->hPin); 221 } 222 223 if (This->hStopEvent) 224 { 225 /* close stop event handle */ 226 CloseHandle(This->hStopEvent); 227 } 228 229 if (This->MixBuffer) 230 { 231 /* free mix buffer */ 232 HeapFree(GetProcessHeap(), 0, This->MixBuffer); 233 } 234 235 /* free capture buffer */ 236 HeapFree(GetProcessHeap(), 0, This->Buffer); 237 /* free wave format */ 238 HeapFree(GetProcessHeap(), 0, This->Format); 239 /* free capture buffer */ 240 HeapFree(GetProcessHeap(), 0, This); 241 } 242 243 return ref; 244 } 245 246 247 HRESULT 248 WINAPI 249 IDirectSoundCaptureBufferImpl_GetCaps( 250 LPDIRECTSOUNDCAPTUREBUFFER8 iface, 251 LPDSCBCAPS lpDSCBCaps ) 252 { 253 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); 254 255 if (!lpDSCBCaps) 256 { 257 /* invalid parameter */ 258 return DSERR_INVALIDPARAM; 259 } 260 261 if (lpDSCBCaps->dwSize != sizeof(DSCBCAPS)) 262 { 263 /* invalid parameter */ 264 return DSERR_INVALIDPARAM; 265 } 266 267 lpDSCBCaps->dwBufferBytes = This->BufferSize; 268 lpDSCBCaps->dwReserved = 0; 269 //lpDSCBCaps->dwFlags = DSCBCAPS_WAVEMAPPED; 270 271 return DS_OK; 272 } 273 274 HRESULT 275 WINAPI 276 IDirectSoundCaptureBufferImpl_GetCurrentPosition( 277 LPDIRECTSOUNDCAPTUREBUFFER8 iface, 278 LPDWORD lpdwCapturePosition, 279 LPDWORD lpdwReadPosition) 280 { 281 KSAUDIO_POSITION Position; 282 KSPROPERTY Request; 283 DWORD Result; 284 DWORD Value; 285 286 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); 287 288 if (!This->hPin) 289 { 290 if (lpdwCapturePosition) 291 *lpdwCapturePosition = 0; 292 293 if (lpdwReadPosition) 294 *lpdwReadPosition = 0; 295 296 DPRINT("No Audio Pin\n"); 297 return DS_OK; 298 } 299 300 if (This->bMix) 301 { 302 /* read current position */ 303 Value = InterlockedCompareExchange(&This->CurrentMixPosition, 0, 0); 304 305 if (lpdwCapturePosition) 306 *lpdwCapturePosition = (DWORD)Value; 307 308 if (lpdwReadPosition) 309 *lpdwReadPosition = (DWORD)Value; 310 311 return DS_OK; 312 } 313 314 /* setup audio position property request */ 315 Request.Id = KSPROPERTY_AUDIO_POSITION; 316 Request.Set = KSPROPSETID_Audio; 317 Request.Flags = KSPROPERTY_TYPE_GET; 318 319 320 Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSPROPERTY), (PVOID)&Position, sizeof(KSAUDIO_POSITION), NULL); 321 322 if (Result != ERROR_SUCCESS) 323 { 324 DPRINT("GetPosition failed with %x\n", Result); 325 return DSERR_UNSUPPORTED; 326 } 327 328 //DPRINT("Play %I64u Write %I64u \n", Position.PlayOffset, Position.WriteOffset); 329 330 if (lpdwCapturePosition) 331 *lpdwCapturePosition = (DWORD)Position.PlayOffset; 332 333 if (lpdwReadPosition) 334 *lpdwReadPosition = (DWORD)Position.WriteOffset; 335 336 return DS_OK; 337 } 338 339 340 HRESULT 341 WINAPI 342 IDirectSoundCaptureBufferImpl_GetFormat( 343 LPDIRECTSOUNDCAPTUREBUFFER8 iface, 344 LPWAVEFORMATEX lpwfxFormat, 345 DWORD dwSizeAllocated, 346 LPDWORD lpdwSizeWritten) 347 { 348 DWORD FormatSize; 349 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); 350 351 FormatSize = sizeof(WAVEFORMATEX) + This->Format->cbSize; 352 353 if (!lpwfxFormat && !lpdwSizeWritten) 354 { 355 /* invalid parameter */ 356 return DSERR_INVALIDPARAM; 357 } 358 359 if (!lpwfxFormat) 360 { 361 /* return required format size */ 362 *lpdwSizeWritten = FormatSize; 363 return DS_OK; 364 } 365 else 366 { 367 if (dwSizeAllocated >= FormatSize) 368 { 369 /* copy format */ 370 CopyMemory(lpwfxFormat, This->Format, FormatSize); 371 372 if (lpdwSizeWritten) 373 *lpdwSizeWritten = FormatSize; 374 375 return DS_OK; 376 } 377 /* buffer too small */ 378 if (lpdwSizeWritten) 379 *lpdwSizeWritten = 0; 380 return DSERR_INVALIDPARAM; 381 } 382 } 383 384 HRESULT 385 WINAPI 386 IDirectSoundCaptureBufferImpl_GetStatus( 387 LPDIRECTSOUNDCAPTUREBUFFER8 iface, 388 LPDWORD lpdwStatus ) 389 { 390 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); 391 392 if (!lpdwStatus) 393 { 394 /* invalid parameter */ 395 return DSERR_INVALIDPARAM; 396 } 397 398 /* reset flags */ 399 *lpdwStatus = 0; 400 401 /* check if pin is running */ 402 if (This->State == KSSTATE_RUN) 403 *lpdwStatus |= DSCBSTATUS_CAPTURING; 404 405 /* check if a looped buffer is used */ 406 if (This->bLoop) 407 *lpdwStatus |= DSCBSTATUS_LOOPING; 408 409 /* done */ 410 return DS_OK; 411 } 412 413 HRESULT 414 WINAPI 415 IDirectSoundCaptureBufferImpl_Initialize( 416 LPDIRECTSOUNDCAPTUREBUFFER8 iface, 417 LPDIRECTSOUNDCAPTURE lpDSC, 418 LPCDSCBUFFERDESC lpcDSCBDesc) 419 { 420 /* capture buffer is already initialized */ 421 return DSERR_ALREADYINITIALIZED; 422 } 423 424 HRESULT 425 WINAPI 426 IDirectSoundCaptureBufferImpl_Lock( 427 LPDIRECTSOUNDCAPTUREBUFFER8 iface, 428 DWORD dwOffset, 429 DWORD dwBytes, 430 LPVOID* ppvAudioPtr1, 431 LPDWORD pdwAudioBytes1, 432 LPVOID* ppvAudioPtr2, 433 LPDWORD pdwAudioBytes2, 434 DWORD dwFlags ) 435 { 436 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); 437 438 DPRINT("This %p dwOffset %u dwBytes %u ppvAudioPtr1 %p pdwAudioBytes1 %p ppvAudioPtr2 %p pdwAudioBytes2 %p dwFlags %x This->BufferSize %u\n", 439 This, dwOffset, dwBytes, ppvAudioPtr1, pdwAudioBytes1, ppvAudioPtr2, pdwAudioBytes2, dwFlags, This->BufferSize); 440 441 if (dwFlags == DSBLOCK_ENTIREBUFFER) 442 { 443 *ppvAudioPtr1 = (LPVOID)This->Buffer; 444 *pdwAudioBytes1 = This->BufferSize; 445 if (ppvAudioPtr2) 446 *ppvAudioPtr2 = NULL; 447 if (pdwAudioBytes2) 448 *pdwAudioBytes2 = 0; 449 450 return DS_OK; 451 } 452 else 453 { 454 ASSERT(dwOffset < This->BufferSize); 455 ASSERT(dwBytes < This->BufferSize); 456 ASSERT(dwBytes + dwOffset <= This->BufferSize); 457 458 *ppvAudioPtr1 = This->Buffer + dwOffset; 459 *pdwAudioBytes1 = dwBytes; 460 if (ppvAudioPtr2) 461 *ppvAudioPtr2 = NULL; 462 if (pdwAudioBytes2) 463 *pdwAudioBytes2 = 0; 464 465 return DS_OK; 466 } 467 } 468 469 HRESULT 470 WINAPI 471 IDirectSoundCaptureBufferImpl_Start( 472 LPDIRECTSOUNDCAPTUREBUFFER8 iface, 473 DWORD dwFlags ) 474 { 475 KSPROPERTY Property; 476 KSSTREAM_HEADER Header; 477 DWORD Result, BytesTransferred; 478 OVERLAPPED Overlapped; 479 KSSTATE State; 480 HANDLE hThread; 481 482 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); 483 484 DPRINT("IDirectSoundCaptureBufferImpl_Start Flags %x\n", dwFlags); 485 ASSERT(dwFlags == DSCBSTART_LOOPING); 486 487 /* check if pin is already running */ 488 if (This->State == KSSTATE_RUN) 489 return DS_OK; 490 491 492 /* check if there is a pin instance */ 493 if (!This->hPin) 494 return DSERR_GENERIC; 495 496 /* setup request */ 497 Property.Set = KSPROPSETID_Connection; 498 Property.Id = KSPROPERTY_CONNECTION_STATE; 499 Property.Flags = KSPROPERTY_TYPE_SET; 500 State = KSSTATE_RUN; 501 502 /* set pin to run */ 503 Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesTransferred); 504 505 ASSERT(Result == ERROR_SUCCESS); 506 507 if (Result == ERROR_SUCCESS) 508 { 509 /* store result */ 510 This->State = State; 511 } 512 513 /* initialize overlapped struct */ 514 ZeroMemory(&Overlapped, sizeof(OVERLAPPED)); 515 Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 516 517 /* clear stream header */ 518 ZeroMemory(&Header, sizeof(KSSTREAM_HEADER)); 519 520 /* initialize stream header */ 521 Header.FrameExtent = This->BufferSize; 522 Header.DataUsed = 0; 523 Header.Data = (This->bMix ? This->MixBuffer : This->Buffer); 524 Header.Size = sizeof(KSSTREAM_HEADER); 525 Header.PresentationTime.Numerator = 1; 526 Header.PresentationTime.Denominator = 1; 527 528 Result = DeviceIoControl(This->hPin, IOCTL_KS_WRITE_STREAM, NULL, 0, &Header, sizeof(KSSTREAM_HEADER), &BytesTransferred, &Overlapped); 529 530 if (Result != ERROR_SUCCESS) 531 { 532 DPRINT("Failed submit buffer with %lx\n", Result); 533 return DSERR_GENERIC; 534 } 535 536 if (This->bMix) 537 { 538 if (!This->hStopEvent) 539 { 540 /* create stop event */ 541 This->hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 542 if (!This->hStopEvent) 543 { 544 DPRINT1("Failed to create event object with %x\n", GetLastError()); 545 return DSERR_GENERIC; 546 } 547 } 548 549 /* set state to stop false */ 550 This->StopMixerThread = FALSE; 551 552 hThread = CreateThread(NULL, 0, MixerThreadRoutine, (PVOID)This, 0, NULL); 553 if (!hThread) 554 { 555 DPRINT1("Failed to create thread with %x\n", GetLastError()); 556 return DSERR_GENERIC; 557 } 558 559 /* close thread handle */ 560 CloseHandle(hThread); 561 } 562 563 564 return DS_OK; 565 } 566 567 HRESULT 568 WINAPI 569 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface ) 570 { 571 KSPROPERTY Property; 572 DWORD Result; 573 KSSTATE State; 574 575 LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); 576 577 if (This->State == KSSTATE_STOP) 578 { 579 /* stream has already been stopped */ 580 return DS_OK; 581 } 582 583 if (!This->hPin) 584 return DSERR_GENERIC; 585 586 /* setup request */ 587 Property.Set = KSPROPSETID_Connection; 588 Property.Id = KSPROPERTY_CONNECTION_STATE; 589 Property.Flags = KSPROPERTY_TYPE_SET; 590 State = KSSTATE_STOP; 591 592 593 /* set pin to stop */ 594 Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), NULL); 595 596 ASSERT(Result == ERROR_SUCCESS); 597 598 599 if (This->bMix) 600 { 601 /* sanity check */ 602 ASSERT(This->hStopEvent); 603 /* reset event */ 604 ResetEvent(This->hStopEvent); 605 /* signal event to stop */ 606 This->StopMixerThread = TRUE; 607 /* Wait for the event to stop */ 608 WaitForSingleObject(This->hStopEvent, INFINITE); 609 } 610 611 612 if (Result == ERROR_SUCCESS) 613 { 614 /* store result */ 615 This->State = State; 616 return DS_OK; 617 } 618 619 DPRINT("Failed to stop pin\n"); 620 return DSERR_GENERIC; 621 } 622 623 HRESULT 624 WINAPI 625 IDirectSoundCaptureBufferImpl_Unlock( 626 LPDIRECTSOUNDCAPTUREBUFFER8 iface, 627 LPVOID lpvAudioPtr1, 628 DWORD dwAudioBytes1, 629 LPVOID lpvAudioPtr2, 630 DWORD dwAudioBytes2 ) 631 { 632 return DS_OK; 633 } 634 635 HRESULT 636 WINAPI 637 IDirectSoundCaptureBufferImpl_GetObjectInPath( 638 LPDIRECTSOUNDCAPTUREBUFFER8 iface, 639 REFGUID rguidObject, 640 DWORD dwIndex, 641 REFGUID rguidInterface, 642 LPVOID* ppObject ) 643 { 644 UNIMPLEMENTED; 645 return DSERR_INVALIDPARAM; 646 } 647 648 HRESULT 649 WINAPI 650 IDirectSoundCaptureBufferImpl_GetFXStatus( 651 LPDIRECTSOUNDCAPTUREBUFFER8 iface, 652 DWORD dwFXCount, 653 LPDWORD pdwFXStatus ) 654 { 655 UNIMPLEMENTED; 656 return DSERR_INVALIDPARAM; 657 } 658 659 660 static IDirectSoundCaptureBuffer8Vtbl vt_DirectSoundCaptureBuffer8 = 661 { 662 /* IUnknown methods */ 663 IDirectSoundCaptureBufferImpl_QueryInterface, 664 IDirectSoundCaptureBufferImpl_AddRef, 665 IDirectSoundCaptureBufferImpl_Release, 666 667 /* IDirectSoundCaptureBuffer methods */ 668 IDirectSoundCaptureBufferImpl_GetCaps, 669 IDirectSoundCaptureBufferImpl_GetCurrentPosition, 670 IDirectSoundCaptureBufferImpl_GetFormat, 671 IDirectSoundCaptureBufferImpl_GetStatus, 672 IDirectSoundCaptureBufferImpl_Initialize, 673 IDirectSoundCaptureBufferImpl_Lock, 674 IDirectSoundCaptureBufferImpl_Start, 675 IDirectSoundCaptureBufferImpl_Stop, 676 IDirectSoundCaptureBufferImpl_Unlock, 677 678 /* IDirectSoundCaptureBuffer methods */ 679 IDirectSoundCaptureBufferImpl_GetObjectInPath, 680 IDirectSoundCaptureBufferImpl_GetFXStatus 681 }; 682 683 684 685 686 HRESULT 687 NewDirectSoundCaptureBuffer( 688 LPDIRECTSOUNDCAPTUREBUFFER8 *OutBuffer, 689 LPFILTERINFO Filter, 690 LPCDSCBUFFERDESC lpcDSBufferDesc) 691 { 692 DWORD FormatSize, MixBufferSize; 693 ULONG DeviceId = 0, PinId; 694 DWORD Result = ERROR_SUCCESS; 695 WAVEFORMATEX MixFormat; 696 697 LPCDirectSoundCaptureBufferImpl This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundCaptureBufferImpl)); 698 699 if (!This) 700 { 701 /* not enough memory */ 702 return DSERR_OUTOFMEMORY; 703 } 704 705 /* calculate format size */ 706 FormatSize = sizeof(WAVEFORMATEX) + lpcDSBufferDesc->lpwfxFormat->cbSize; 707 /* allocate format struct */ 708 This->Format = HeapAlloc(GetProcessHeap(), 0, FormatSize); 709 if (!This->Format) 710 { 711 /* not enough memory */ 712 HeapFree(GetProcessHeap(), 0, This); 713 return DSERR_OUTOFMEMORY; 714 } 715 716 /* sanity check */ 717 ASSERT(lpcDSBufferDesc->dwBufferBytes); 718 719 /* allocate capture buffer */ 720 This->Buffer = HeapAlloc(GetProcessHeap(), 0, lpcDSBufferDesc->dwBufferBytes); 721 if (!This->Buffer) 722 { 723 /* not enough memory */ 724 HeapFree(GetProcessHeap(), 0, This->Format); 725 HeapFree(GetProcessHeap(), 0, This); 726 return DSERR_OUTOFMEMORY; 727 } 728 729 /* store buffer size */ 730 This->BufferSize = lpcDSBufferDesc->dwBufferBytes; 731 ASSERT(lpcDSBufferDesc->lpwfxFormat->cbSize == 0); 732 733 do 734 { 735 /* try all available recording pins on that filter */ 736 PinId = GetPinIdFromFilter(Filter, TRUE, DeviceId); 737 738 if (PinId == ULONG_MAX) 739 break; 740 741 Result = OpenPin(Filter->hFilter, PinId, lpcDSBufferDesc->lpwfxFormat, &This->hPin, TRUE); 742 if (Result == ERROR_SUCCESS) 743 break; 744 745 DeviceId++; 746 }while(TRUE); 747 748 if (Result != ERROR_SUCCESS) 749 { 750 /* failed to instantiate the capture pin with the native format 751 * try to compute a compatible format and use that 752 * we could use the mixer api for this purpose but... the kmixer isnt working very good atm 753 */ 754 755 DeviceId = 0; 756 do 757 { 758 /* try all available recording pins on that filter */ 759 PinId = GetPinIdFromFilter(Filter, TRUE, DeviceId); 760 DPRINT("PinId %u DeviceId %u\n", PinId, DeviceId); 761 762 if (PinId == ULONG_MAX) 763 break; 764 765 if (CreateCompatiblePin(Filter->hFilter, PinId, TRUE, lpcDSBufferDesc->lpwfxFormat, &MixFormat, &This->hPin)) 766 { 767 This->bMix = TRUE; 768 CopyMemory(&This->MixFormat, &MixFormat, sizeof(WAVEFORMATEX)); 769 break; 770 } 771 772 DeviceId++; 773 }while(TRUE); 774 775 776 if (!This->bMix) 777 { 778 /* FIXME should not happen */ 779 DPRINT("failed to compute a compatible format\n"); 780 HeapFree(GetProcessHeap(), 0, This->MixBuffer); 781 HeapFree(GetProcessHeap(), 0, This->Buffer); 782 HeapFree(GetProcessHeap(), 0, This->Format); 783 HeapFree(GetProcessHeap(), 0, This); 784 return DSERR_GENERIC; 785 } 786 787 MixBufferSize = lpcDSBufferDesc->dwBufferBytes; 788 MixBufferSize /= lpcDSBufferDesc->lpwfxFormat->nChannels; 789 MixBufferSize /= (lpcDSBufferDesc->lpwfxFormat->wBitsPerSample/8); 790 791 MixBufferSize *= This->MixFormat.nChannels; 792 MixBufferSize *= (This->MixFormat.wBitsPerSample/8); 793 794 /* allocate buffer for mixing */ 795 This->MixBuffer = HeapAlloc(GetProcessHeap(), 0, MixBufferSize); 796 if (!This->Buffer) 797 { 798 /* not enough memory */ 799 CloseHandle(This->hPin); 800 HeapFree(GetProcessHeap(), 0, This->Buffer); 801 HeapFree(GetProcessHeap(), 0, This->Format); 802 HeapFree(GetProcessHeap(), 0, This); 803 return DSERR_OUTOFMEMORY; 804 } 805 This->MixBufferSize = MixBufferSize; 806 DPRINT1("MixBufferSize %u BufferSize %u\n", MixBufferSize, This->BufferSize); 807 } 808 809 /* initialize capture buffer */ 810 This->ref = 1; 811 This->lpVtbl = &vt_DirectSoundCaptureBuffer8; 812 This->Filter = Filter; 813 This->State = KSSTATE_STOP; 814 This->bLoop = TRUE; 815 816 RtlMoveMemory(This->Format, lpcDSBufferDesc->lpwfxFormat, FormatSize); 817 818 *OutBuffer = (LPDIRECTSOUNDCAPTUREBUFFER8)&This->lpVtbl; 819 return DS_OK; 820 } 821