/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Configuration of network devices * FILE: dll/directx/dsound_new/capturebuffer.c * PURPOSE: IDirectSoundCaptureBuffer8 implementation * * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org) */ #include "precomp.h" const GUID KSINTERFACESETID_Standard = {0x1A8766A0L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; const GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; const GUID KSDATAFORMAT_TYPE_AUDIO = {0x73647561L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX = {0x05589f81L, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}}; const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}}; const GUID KSEVENTSETID_LoopedStreaming = {0x4682B940L, 0xC6EF, 0x11D0, {0x96, 0xD8, 0x00, 0xAA, 0x00, 0x51, 0xE5, 0x1D}}; typedef struct { IDirectSoundCaptureBuffer8Vtbl *lpVtbl; LONG ref; LPFILTERINFO Filter; HANDLE hPin; PUCHAR Buffer; DWORD BufferSize; LPWAVEFORMATEX Format; WAVEFORMATEX MixFormat; BOOL bMix; BOOL bLoop; KSSTATE State; PUCHAR MixBuffer; ULONG MixBufferSize; HANDLE hStopEvent; volatile LONG StopMixerThread; volatile LONG CurrentMixPosition; LPDIRECTSOUNDNOTIFY Notify; }CDirectSoundCaptureBufferImpl, *LPCDirectSoundCaptureBufferImpl; DWORD WINAPI MixerThreadRoutine( LPVOID lpParameter) { KSPROPERTY Request; KSAUDIO_POSITION Position; DWORD Result, MixPosition, BufferPosition, BytesWritten, BytesRead, MixLength, BufferLength; LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)lpParameter; /* setup audio position property request */ Request.Id = KSPROPERTY_AUDIO_POSITION; Request.Set = KSPROPSETID_Audio; Request.Flags = KSPROPERTY_TYPE_GET; MixPosition = 0; BufferPosition = 0; do { /* query current position */ Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSPROPERTY), (PVOID)&Position, sizeof(KSAUDIO_POSITION), NULL); /* sanity check */ ASSERT(Result == ERROR_SUCCESS); /* FIXME implement samplerate conversion */ ASSERT(This->MixFormat.nSamplesPerSec == This->Format->nSamplesPerSec); /* FIXME implement bitrate conversion */ ASSERT(This->MixFormat.wBitsPerSample == This->Format->wBitsPerSample); /* sanity check */ ASSERT(BufferPosition <= This->BufferSize); ASSERT(MixPosition <= This->MixBufferSize); if (BufferPosition == This->BufferSize) { /* restart from front */ BufferPosition = 0; } if (MixPosition == This->MixBufferSize) { /* restart from front */ MixPosition = 0; } if (This->MixFormat.nChannels != This->Format->nChannels) { if ((DWORD)Position.PlayOffset >= MixPosition) { /* calculate buffer position difference */ MixLength = Position.PlayOffset - MixPosition; } else { /* buffer overlap */ MixLength = This->MixBufferSize - MixPosition; } BufferLength = This->BufferSize - BufferPosition; /* convert the format */ PerformChannelConversion(&This->MixBuffer[MixPosition], MixLength, &BytesRead, This->MixFormat.nChannels, This->Format->nChannels, This->Format->wBitsPerSample, &This->Buffer[BufferPosition], BufferLength, &BytesWritten); /* update buffer offsets */ MixPosition += BytesRead; BufferPosition += BytesWritten; DPRINT("MixPosition %u BufferPosition %u BytesRead %u BytesWritten %u MixLength %u BufferLength %u\n", MixPosition, BufferPosition, BytesRead, BytesWritten, MixLength, BufferLength); } /* Notify Events */ if (This->Notify) { DoNotifyPositionEvents(This->Notify, This->CurrentMixPosition, BufferPosition); } /* update offset */ InterlockedExchange(&This->CurrentMixPosition, (LONG)BufferPosition); /* FIXME use timer */ Sleep(10); }while(InterlockedCompareExchange(&This->StopMixerThread, 0, 0) == 0); /* signal stop event */ SetEvent(This->hStopEvent); /* done */ return 0; } HRESULT WINAPI IDirectSoundCaptureBufferImpl_QueryInterface( LPDIRECTSOUNDCAPTUREBUFFER8 iface, IN REFIID riid, LPVOID* ppobj) { LPOLESTR pStr; LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); /* check if requested interface is supported */ if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer) || IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer8)) { *ppobj = (LPVOID)&This->lpVtbl; InterlockedIncrement(&This->ref); return S_OK; } /* check if the interface is supported */ if (IsEqualIID(riid, &IID_IDirectSoundNotify)) { if (!This->Notify) { HRESULT hr = NewDirectSoundNotify(&This->Notify, This->bLoop, This->bMix, This->hPin, This->BufferSize); if (FAILED(hr)) return hr; *ppobj = (LPVOID)This->Notify; return S_OK; } /* increment reference count on existing notify object */ IDirectSoundNotify_AddRef(This->Notify); *ppobj = (LPVOID)This->Notify; return S_OK; } /* interface not supported */ if (SUCCEEDED(StringFromIID(riid, &pStr))) { DPRINT("No Interface for class %s\n", pStr); CoTaskMemFree(pStr); } return E_NOINTERFACE; } ULONG WINAPI IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface) { ULONG ref; LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); /* increment reference count */ ref = InterlockedIncrement(&This->ref); return ref; } ULONG WINAPI IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface) { ULONG ref; LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); /* release reference count */ ref = InterlockedDecrement(&(This->ref)); if (!ref) { if (This->hPin) { /* close pin handle */ CloseHandle(This->hPin); } if (This->hStopEvent) { /* close stop event handle */ CloseHandle(This->hStopEvent); } if (This->MixBuffer) { /* free mix buffer */ HeapFree(GetProcessHeap(), 0, This->MixBuffer); } /* free capture buffer */ HeapFree(GetProcessHeap(), 0, This->Buffer); /* free wave format */ HeapFree(GetProcessHeap(), 0, This->Format); /* free capture buffer */ HeapFree(GetProcessHeap(), 0, This); } return ref; } HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCaps( LPDIRECTSOUNDCAPTUREBUFFER8 iface, LPDSCBCAPS lpDSCBCaps ) { LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); if (!lpDSCBCaps) { /* invalid parameter */ return DSERR_INVALIDPARAM; } if (lpDSCBCaps->dwSize != sizeof(DSCBCAPS)) { /* invalid parameter */ return DSERR_INVALIDPARAM; } lpDSCBCaps->dwBufferBytes = This->BufferSize; lpDSCBCaps->dwReserved = 0; //lpDSCBCaps->dwFlags = DSCBCAPS_WAVEMAPPED; return DS_OK; } HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCurrentPosition( LPDIRECTSOUNDCAPTUREBUFFER8 iface, LPDWORD lpdwCapturePosition, LPDWORD lpdwReadPosition) { KSAUDIO_POSITION Position; KSPROPERTY Request; DWORD Result; DWORD Value; LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); if (!This->hPin) { if (lpdwCapturePosition) *lpdwCapturePosition = 0; if (lpdwReadPosition) *lpdwReadPosition = 0; DPRINT("No Audio Pin\n"); return DS_OK; } if (This->bMix) { /* read current position */ Value = InterlockedCompareExchange(&This->CurrentMixPosition, 0, 0); if (lpdwCapturePosition) *lpdwCapturePosition = (DWORD)Value; if (lpdwReadPosition) *lpdwReadPosition = (DWORD)Value; return DS_OK; } /* setup audio position property request */ Request.Id = KSPROPERTY_AUDIO_POSITION; Request.Set = KSPROPSETID_Audio; Request.Flags = KSPROPERTY_TYPE_GET; Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSPROPERTY), (PVOID)&Position, sizeof(KSAUDIO_POSITION), NULL); if (Result != ERROR_SUCCESS) { DPRINT("GetPosition failed with %x\n", Result); return DSERR_UNSUPPORTED; } //DPRINT("Play %I64u Write %I64u \n", Position.PlayOffset, Position.WriteOffset); if (lpdwCapturePosition) *lpdwCapturePosition = (DWORD)Position.PlayOffset; if (lpdwReadPosition) *lpdwReadPosition = (DWORD)Position.WriteOffset; return DS_OK; } HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFormat( LPDIRECTSOUNDCAPTUREBUFFER8 iface, LPWAVEFORMATEX lpwfxFormat, DWORD dwSizeAllocated, LPDWORD lpdwSizeWritten) { DWORD FormatSize; LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); FormatSize = sizeof(WAVEFORMATEX) + This->Format->cbSize; if (!lpwfxFormat && !lpdwSizeWritten) { /* invalid parameter */ return DSERR_INVALIDPARAM; } if (!lpwfxFormat) { /* return required format size */ *lpdwSizeWritten = FormatSize; return DS_OK; } else { if (dwSizeAllocated >= FormatSize) { /* copy format */ CopyMemory(lpwfxFormat, This->Format, FormatSize); if (lpdwSizeWritten) *lpdwSizeWritten = FormatSize; return DS_OK; } /* buffer too small */ if (lpdwSizeWritten) *lpdwSizeWritten = 0; return DSERR_INVALIDPARAM; } } HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetStatus( LPDIRECTSOUNDCAPTUREBUFFER8 iface, LPDWORD lpdwStatus ) { LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); if (!lpdwStatus) { /* invalid parameter */ return DSERR_INVALIDPARAM; } /* reset flags */ *lpdwStatus = 0; /* check if pin is running */ if (This->State == KSSTATE_RUN) *lpdwStatus |= DSCBSTATUS_CAPTURING; /* check if a looped buffer is used */ if (This->bLoop) *lpdwStatus |= DSCBSTATUS_LOOPING; /* done */ return DS_OK; } HRESULT WINAPI IDirectSoundCaptureBufferImpl_Initialize( LPDIRECTSOUNDCAPTUREBUFFER8 iface, LPDIRECTSOUNDCAPTURE lpDSC, LPCDSCBUFFERDESC lpcDSCBDesc) { /* capture buffer is already initialized */ return DSERR_ALREADYINITIALIZED; } HRESULT WINAPI IDirectSoundCaptureBufferImpl_Lock( LPDIRECTSOUNDCAPTUREBUFFER8 iface, DWORD dwOffset, DWORD dwBytes, LPVOID* ppvAudioPtr1, LPDWORD pdwAudioBytes1, LPVOID* ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags ) { LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); DPRINT("This %p dwOffset %u dwBytes %u ppvAudioPtr1 %p pdwAudioBytes1 %p ppvAudioPtr2 %p pdwAudioBytes2 %p dwFlags %x This->BufferSize %u\n", This, dwOffset, dwBytes, ppvAudioPtr1, pdwAudioBytes1, ppvAudioPtr2, pdwAudioBytes2, dwFlags, This->BufferSize); if (dwFlags == DSBLOCK_ENTIREBUFFER) { *ppvAudioPtr1 = (LPVOID)This->Buffer; *pdwAudioBytes1 = This->BufferSize; if (ppvAudioPtr2) *ppvAudioPtr2 = NULL; if (pdwAudioBytes2) *pdwAudioBytes2 = 0; return DS_OK; } else { ASSERT(dwOffset < This->BufferSize); ASSERT(dwBytes < This->BufferSize); ASSERT(dwBytes + dwOffset <= This->BufferSize); *ppvAudioPtr1 = This->Buffer + dwOffset; *pdwAudioBytes1 = dwBytes; if (ppvAudioPtr2) *ppvAudioPtr2 = NULL; if (pdwAudioBytes2) *pdwAudioBytes2 = 0; return DS_OK; } } HRESULT WINAPI IDirectSoundCaptureBufferImpl_Start( LPDIRECTSOUNDCAPTUREBUFFER8 iface, DWORD dwFlags ) { KSPROPERTY Property; KSSTREAM_HEADER Header; DWORD Result, BytesTransferred; OVERLAPPED Overlapped; KSSTATE State; HANDLE hThread; LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); DPRINT("IDirectSoundCaptureBufferImpl_Start Flags %x\n", dwFlags); ASSERT(dwFlags == DSCBSTART_LOOPING); /* check if pin is already running */ if (This->State == KSSTATE_RUN) return DS_OK; /* check if there is a pin instance */ if (!This->hPin) return DSERR_GENERIC; /* setup request */ Property.Set = KSPROPSETID_Connection; Property.Id = KSPROPERTY_CONNECTION_STATE; Property.Flags = KSPROPERTY_TYPE_SET; State = KSSTATE_RUN; /* set pin to run */ Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesTransferred); ASSERT(Result == ERROR_SUCCESS); if (Result == ERROR_SUCCESS) { /* store result */ This->State = State; } /* initialize overlapped struct */ ZeroMemory(&Overlapped, sizeof(OVERLAPPED)); Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); /* clear stream header */ ZeroMemory(&Header, sizeof(KSSTREAM_HEADER)); /* initialize stream header */ Header.FrameExtent = This->BufferSize; Header.DataUsed = 0; Header.Data = (This->bMix ? This->MixBuffer : This->Buffer); Header.Size = sizeof(KSSTREAM_HEADER); Header.PresentationTime.Numerator = 1; Header.PresentationTime.Denominator = 1; Result = DeviceIoControl(This->hPin, IOCTL_KS_WRITE_STREAM, NULL, 0, &Header, sizeof(KSSTREAM_HEADER), &BytesTransferred, &Overlapped); if (Result != ERROR_SUCCESS) { DPRINT("Failed submit buffer with %lx\n", Result); return DSERR_GENERIC; } if (This->bMix) { if (!This->hStopEvent) { /* create stop event */ This->hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!This->hStopEvent) { DPRINT1("Failed to create event object with %x\n", GetLastError()); return DSERR_GENERIC; } } /* set state to stop false */ This->StopMixerThread = FALSE; hThread = CreateThread(NULL, 0, MixerThreadRoutine, (PVOID)This, 0, NULL); if (!hThread) { DPRINT1("Failed to create thread with %x\n", GetLastError()); return DSERR_GENERIC; } /* close thread handle */ CloseHandle(hThread); } return DS_OK; } HRESULT WINAPI IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface ) { KSPROPERTY Property; DWORD Result; KSSTATE State; LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl); if (This->State == KSSTATE_STOP) { /* stream has already been stopped */ return DS_OK; } if (!This->hPin) return DSERR_GENERIC; /* setup request */ Property.Set = KSPROPSETID_Connection; Property.Id = KSPROPERTY_CONNECTION_STATE; Property.Flags = KSPROPERTY_TYPE_SET; State = KSSTATE_STOP; /* set pin to stop */ Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), NULL); ASSERT(Result == ERROR_SUCCESS); if (This->bMix) { /* sanity check */ ASSERT(This->hStopEvent); /* reset event */ ResetEvent(This->hStopEvent); /* signal event to stop */ This->StopMixerThread = TRUE; /* Wait for the event to stop */ WaitForSingleObject(This->hStopEvent, INFINITE); } if (Result == ERROR_SUCCESS) { /* store result */ This->State = State; return DS_OK; } DPRINT("Failed to stop pin\n"); return DSERR_GENERIC; } HRESULT WINAPI IDirectSoundCaptureBufferImpl_Unlock( LPDIRECTSOUNDCAPTUREBUFFER8 iface, LPVOID lpvAudioPtr1, DWORD dwAudioBytes1, LPVOID lpvAudioPtr2, DWORD dwAudioBytes2 ) { return DS_OK; } HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetObjectInPath( LPDIRECTSOUNDCAPTUREBUFFER8 iface, REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, LPVOID* ppObject ) { UNIMPLEMENTED; return DSERR_INVALIDPARAM; } HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFXStatus( LPDIRECTSOUNDCAPTUREBUFFER8 iface, DWORD dwFXCount, LPDWORD pdwFXStatus ) { UNIMPLEMENTED; return DSERR_INVALIDPARAM; } static IDirectSoundCaptureBuffer8Vtbl vt_DirectSoundCaptureBuffer8 = { /* IUnknown methods */ IDirectSoundCaptureBufferImpl_QueryInterface, IDirectSoundCaptureBufferImpl_AddRef, IDirectSoundCaptureBufferImpl_Release, /* IDirectSoundCaptureBuffer methods */ IDirectSoundCaptureBufferImpl_GetCaps, IDirectSoundCaptureBufferImpl_GetCurrentPosition, IDirectSoundCaptureBufferImpl_GetFormat, IDirectSoundCaptureBufferImpl_GetStatus, IDirectSoundCaptureBufferImpl_Initialize, IDirectSoundCaptureBufferImpl_Lock, IDirectSoundCaptureBufferImpl_Start, IDirectSoundCaptureBufferImpl_Stop, IDirectSoundCaptureBufferImpl_Unlock, /* IDirectSoundCaptureBuffer methods */ IDirectSoundCaptureBufferImpl_GetObjectInPath, IDirectSoundCaptureBufferImpl_GetFXStatus }; HRESULT NewDirectSoundCaptureBuffer( LPDIRECTSOUNDCAPTUREBUFFER8 *OutBuffer, LPFILTERINFO Filter, LPCDSCBUFFERDESC lpcDSBufferDesc) { DWORD FormatSize, MixBufferSize; ULONG DeviceId = 0, PinId; DWORD Result = ERROR_SUCCESS; WAVEFORMATEX MixFormat; LPCDirectSoundCaptureBufferImpl This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundCaptureBufferImpl)); if (!This) { /* not enough memory */ return DSERR_OUTOFMEMORY; } /* calculate format size */ FormatSize = sizeof(WAVEFORMATEX) + lpcDSBufferDesc->lpwfxFormat->cbSize; /* allocate format struct */ This->Format = HeapAlloc(GetProcessHeap(), 0, FormatSize); if (!This->Format) { /* not enough memory */ HeapFree(GetProcessHeap(), 0, This); return DSERR_OUTOFMEMORY; } /* sanity check */ ASSERT(lpcDSBufferDesc->dwBufferBytes); /* allocate capture buffer */ This->Buffer = HeapAlloc(GetProcessHeap(), 0, lpcDSBufferDesc->dwBufferBytes); if (!This->Buffer) { /* not enough memory */ HeapFree(GetProcessHeap(), 0, This->Format); HeapFree(GetProcessHeap(), 0, This); return DSERR_OUTOFMEMORY; } /* store buffer size */ This->BufferSize = lpcDSBufferDesc->dwBufferBytes; ASSERT(lpcDSBufferDesc->lpwfxFormat->cbSize == 0); do { /* try all available recording pins on that filter */ PinId = GetPinIdFromFilter(Filter, TRUE, DeviceId); if (PinId == ULONG_MAX) break; Result = OpenPin(Filter->hFilter, PinId, lpcDSBufferDesc->lpwfxFormat, &This->hPin, TRUE); if (Result == ERROR_SUCCESS) break; DeviceId++; }while(TRUE); if (Result != ERROR_SUCCESS) { /* failed to instantiate the capture pin with the native format * try to compute a compatible format and use that * we could use the mixer api for this purpose but... the kmixer isnt working very good atm */ DeviceId = 0; do { /* try all available recording pins on that filter */ PinId = GetPinIdFromFilter(Filter, TRUE, DeviceId); DPRINT("PinId %u DeviceId %u\n", PinId, DeviceId); if (PinId == ULONG_MAX) break; if (CreateCompatiblePin(Filter->hFilter, PinId, TRUE, lpcDSBufferDesc->lpwfxFormat, &MixFormat, &This->hPin)) { This->bMix = TRUE; CopyMemory(&This->MixFormat, &MixFormat, sizeof(WAVEFORMATEX)); break; } DeviceId++; }while(TRUE); if (!This->bMix) { /* FIXME should not happen */ DPRINT("failed to compute a compatible format\n"); HeapFree(GetProcessHeap(), 0, This->MixBuffer); HeapFree(GetProcessHeap(), 0, This->Buffer); HeapFree(GetProcessHeap(), 0, This->Format); HeapFree(GetProcessHeap(), 0, This); return DSERR_GENERIC; } MixBufferSize = lpcDSBufferDesc->dwBufferBytes; MixBufferSize /= lpcDSBufferDesc->lpwfxFormat->nChannels; MixBufferSize /= (lpcDSBufferDesc->lpwfxFormat->wBitsPerSample/8); MixBufferSize *= This->MixFormat.nChannels; MixBufferSize *= (This->MixFormat.wBitsPerSample/8); /* allocate buffer for mixing */ This->MixBuffer = HeapAlloc(GetProcessHeap(), 0, MixBufferSize); if (!This->Buffer) { /* not enough memory */ CloseHandle(This->hPin); HeapFree(GetProcessHeap(), 0, This->Buffer); HeapFree(GetProcessHeap(), 0, This->Format); HeapFree(GetProcessHeap(), 0, This); return DSERR_OUTOFMEMORY; } This->MixBufferSize = MixBufferSize; DPRINT1("MixBufferSize %u BufferSize %u\n", MixBufferSize, This->BufferSize); } /* initialize capture buffer */ This->ref = 1; This->lpVtbl = &vt_DirectSoundCaptureBuffer8; This->Filter = Filter; This->State = KSSTATE_STOP; This->bLoop = TRUE; RtlMoveMemory(This->Format, lpcDSBufferDesc->lpwfxFormat, FormatSize); *OutBuffer = (LPDIRECTSOUNDCAPTUREBUFFER8)&This->lpVtbl; return DS_OK; }