mirror of
https://github.com/reactos/reactos.git
synced 2025-01-06 06:20:13 +00:00
[DSOUND_NEW]
- Implement stereo to mono channel conversion - Create a thread which performs the mixing - Fixes messed up voice recording in Skype 3.6 svn path=/trunk/; revision=43994
This commit is contained in:
parent
c74f994e2f
commit
4bd3460f8a
3 changed files with 268 additions and 6 deletions
|
@ -30,9 +30,102 @@ typedef struct
|
|||
BOOL bMix;
|
||||
BOOL bLoop;
|
||||
KSSTATE State;
|
||||
PUCHAR MixBuffer;
|
||||
ULONG MixBufferSize;
|
||||
HANDLE hStopEvent;
|
||||
volatile LONG StopMixerThread;
|
||||
volatile LONG CurrentMixPosition;
|
||||
|
||||
}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);
|
||||
}
|
||||
/* 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(
|
||||
|
@ -96,6 +189,18 @@ IDirectSoundCaptureBufferImpl_Release(
|
|||
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 */
|
||||
|
@ -145,6 +250,7 @@ IDirectSoundCaptureBufferImpl_GetCurrentPosition(
|
|||
KSAUDIO_POSITION Position;
|
||||
KSPROPERTY Request;
|
||||
DWORD Result;
|
||||
DWORD Value;
|
||||
|
||||
LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);
|
||||
|
||||
|
@ -160,6 +266,20 @@ IDirectSoundCaptureBufferImpl_GetCurrentPosition(
|
|||
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;
|
||||
|
@ -326,6 +446,8 @@ IDirectSoundCaptureBufferImpl_Start(
|
|||
DWORD Result, BytesTransferred;
|
||||
OVERLAPPED Overlapped;
|
||||
KSSTATE State;
|
||||
HANDLE hThread;
|
||||
|
||||
LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);
|
||||
|
||||
DPRINT("IDirectSoundCaptureBufferImpl_Start Flags %x\n", dwFlags);
|
||||
|
@ -367,7 +489,7 @@ IDirectSoundCaptureBufferImpl_Start(
|
|||
/* initialize stream header */
|
||||
Header.FrameExtent = This->BufferSize;
|
||||
Header.DataUsed = 0;
|
||||
Header.Data = This->Buffer;
|
||||
Header.Data = (This->bMix ? This->MixBuffer : This->Buffer);
|
||||
Header.Size = sizeof(KSSTREAM_HEADER);
|
||||
Header.PresentationTime.Numerator = 1;
|
||||
Header.PresentationTime.Denominator = 1;
|
||||
|
@ -380,6 +502,34 @@ IDirectSoundCaptureBufferImpl_Start(
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -414,6 +564,20 @@ IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
|
|||
|
||||
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 */
|
||||
|
@ -492,7 +656,7 @@ NewDirectSoundCaptureBuffer(
|
|||
LPFILTERINFO Filter,
|
||||
LPCDSCBUFFERDESC lpcDSBufferDesc)
|
||||
{
|
||||
DWORD FormatSize;
|
||||
DWORD FormatSize, MixBufferSize;
|
||||
ULONG DeviceId = 0, PinId;
|
||||
DWORD Result = ERROR_SUCCESS;
|
||||
WAVEFORMATEX MixFormat;
|
||||
|
@ -580,11 +744,33 @@ NewDirectSoundCaptureBuffer(
|
|||
{
|
||||
/* 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 */
|
||||
|
|
|
@ -13,6 +13,69 @@ const GUID KSPROPSETID_Pin = {0x8C134960L, 0x51AD, 0x11CF, {
|
|||
const GUID KSPROPSETID_Topology = {0x720D4AC0L, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
|
||||
const GUID KSPROPSETID_Audio = {0x45FFAAA0L, 0x6E1B, 0x11D0, {0xBC, 0xF2, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
|
||||
|
||||
|
||||
VOID
|
||||
PerformChannelConversion(
|
||||
PUCHAR Buffer,
|
||||
ULONG BufferLength,
|
||||
PULONG BytesRead,
|
||||
ULONG OldChannels,
|
||||
ULONG NewChannels,
|
||||
ULONG BitsPerSample,
|
||||
PUCHAR Result,
|
||||
ULONG ResultLength,
|
||||
PULONG BytesWritten)
|
||||
{
|
||||
DWORD Samples;
|
||||
DWORD NewIndex, OldIndex;
|
||||
DWORD NewLength, Skip;
|
||||
|
||||
Samples = BufferLength / (BitsPerSample / 8) / OldChannels;
|
||||
|
||||
if (NewChannels > OldChannels)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
/* setup index */
|
||||
NewIndex = 0;
|
||||
OldIndex = 0;
|
||||
|
||||
/* calculate offsets */
|
||||
NewLength = NewChannels * (BitsPerSample/8);
|
||||
Skip = OldChannels * (BitsPerSample/8);
|
||||
|
||||
do
|
||||
{
|
||||
if (NewIndex + NewLength>= ResultLength)
|
||||
{
|
||||
NewIndex = ResultLength;
|
||||
break;
|
||||
}
|
||||
|
||||
if (OldIndex + Skip >= BufferLength)
|
||||
{
|
||||
OldIndex = BufferLength;
|
||||
break;
|
||||
}
|
||||
|
||||
/* copy first channel */
|
||||
RtlMoveMemory(&Result[NewIndex], &Buffer[OldIndex], NewLength);
|
||||
|
||||
/* skip other channels */
|
||||
OldIndex += Skip;
|
||||
|
||||
/* increment offset */
|
||||
NewIndex += NewLength;
|
||||
|
||||
}while(TRUE);
|
||||
|
||||
*BytesRead = OldIndex;
|
||||
*BytesWritten = NewIndex;
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
SetPinFormat(
|
||||
IN HANDLE hPin,
|
||||
|
@ -498,20 +561,21 @@ CreateCompatiblePin(
|
|||
else if (WaveFormatOut->wBitsPerSample > AudioRange->MaximumBitsPerSample)
|
||||
WaveFormatOut->wBitsPerSample = AudioRange->MaximumBitsPerSample;
|
||||
|
||||
DPRINT1("MinimumBitsPerSample %u MaximumBitsPerSample %u MinimumSampleFrequency %u MaximumSampleFrequency %u\n",
|
||||
DPRINT("MinimumBitsPerSample %u MaximumBitsPerSample %u MinimumSampleFrequency %u MaximumSampleFrequency %u\n",
|
||||
AudioRange->MinimumBitsPerSample, AudioRange->MaximumBitsPerSample, AudioRange->MinimumSampleFrequency, AudioRange->MaximumSampleFrequency);
|
||||
|
||||
for(nChannels = 1; nChannels <= AudioRange->MaximumChannels; nChannels++)
|
||||
{
|
||||
WaveFormatOut->nChannels = nChannels;
|
||||
|
||||
dwResult = OpenPin(hFilter, PinId, WaveFormatOut, hPin, TRUE);
|
||||
if (dwResult == ERROR_SUCCESS)
|
||||
{
|
||||
DPRINT("InFormat nChannels %u wBitsPerSample %u nSamplesPerSec %u\nOutFormat nChannels %u nBitsPerSample %u nSamplesPerSec %u\n",
|
||||
WaveFormatEx->nChannels, WaveFormatEx->wBitsPerSample, WaveFormatEx->nSamplesPerSec,
|
||||
WaveFormatOut->nChannels, WaveFormatOut->wBitsPerSample, WaveFormatOut->nSamplesPerSec);
|
||||
|
||||
dwResult = OpenPin(hFilter, PinId, WaveFormatOut, hPin, TRUE);
|
||||
if (dwResult == ERROR_SUCCESS)
|
||||
{
|
||||
|
||||
/* free buffer */
|
||||
HeapFree(GetProcessHeap(), 0, Item);
|
||||
return TRUE;
|
||||
|
|
|
@ -110,6 +110,18 @@ NewDirectSound(
|
|||
|
||||
/* misc.c */
|
||||
|
||||
VOID
|
||||
PerformChannelConversion(
|
||||
PUCHAR Buffer,
|
||||
ULONG BufferLength,
|
||||
PULONG BytesRead,
|
||||
ULONG OldChannels,
|
||||
ULONG NewChannels,
|
||||
ULONG BitsPerSample,
|
||||
PUCHAR Result,
|
||||
ULONG ResultLength,
|
||||
PULONG BytesWritten);
|
||||
|
||||
BOOL
|
||||
SetPinFormat(
|
||||
IN HANDLE hPin,
|
||||
|
|
Loading…
Reference in a new issue