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