mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
820 lines
23 KiB
C
820 lines
23 KiB
C
/*
|
|
* 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;
|
|
}
|