[DSOUND]
[reactos.git] / reactos / dll / directx / dsound_new / capturebuffer.c
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 (janderwald@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 }