Author: janderwald
Date: Sat Nov 7 04:43:56 2009
New Revision: 43994
URL:
http://svn.reactos.org/svn/reactos?rev=43994&view=rev
Log:
[DSOUND_NEW]
- Implement stereo to mono channel conversion
- Create a thread which performs the mixing
- Fixes messed up voice recording in Skype 3.6
Modified:
trunk/reactos/dll/directx/dsound_new/capturebuffer.c
trunk/reactos/dll/directx/dsound_new/misc.c
trunk/reactos/dll/directx/dsound_new/precomp.h
Modified: trunk/reactos/dll/directx/dsound_new/capturebuffer.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/directx/dsound_new/cap…
==============================================================================
--- trunk/reactos/dll/directx/dsound_new/capturebuffer.c [iso-8859-1] (original)
+++ trunk/reactos/dll/directx/dsound_new/capturebuffer.c [iso-8859-1] Sat Nov 7 04:43:56
2009
@@ -30,8 +30,101 @@
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
@@ -94,6 +187,18 @@
{
/* 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 */
@@ -145,6 +250,7 @@
KSAUDIO_POSITION Position;
KSPROPERTY Request;
DWORD Result;
+ DWORD Value;
LPCDirectSoundCaptureBufferImpl This =
(LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl,
lpVtbl);
@@ -157,6 +263,20 @@
*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;
}
@@ -326,6 +446,8 @@
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 @@
/* 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;
@@ -379,6 +501,34 @@
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;
}
@@ -413,6 +563,20 @@
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)
{
@@ -492,7 +656,7 @@
LPFILTERINFO Filter,
LPCDSCBUFFERDESC lpcDSBufferDesc)
{
- DWORD FormatSize;
+ DWORD FormatSize, MixBufferSize;
ULONG DeviceId = 0, PinId;
DWORD Result = ERROR_SUCCESS;
WAVEFORMATEX MixFormat;
@@ -580,11 +744,33 @@
{
/* 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 */
Modified: trunk/reactos/dll/directx/dsound_new/misc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/directx/dsound_new/mis…
==============================================================================
--- trunk/reactos/dll/directx/dsound_new/misc.c [iso-8859-1] (original)
+++ trunk/reactos/dll/directx/dsound_new/misc.c [iso-8859-1] Sat Nov 7 04:43:56 2009
@@ -12,6 +12,69 @@
const GUID KSPROPSETID_Pin = {0x8C134960L, 0x51AD, 0x11CF, {0x87,
0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
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(
@@ -498,20 +561,21 @@
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;
Modified: trunk/reactos/dll/directx/dsound_new/precomp.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/directx/dsound_new/pre…
==============================================================================
--- trunk/reactos/dll/directx/dsound_new/precomp.h [iso-8859-1] (original)
+++ trunk/reactos/dll/directx/dsound_new/precomp.h [iso-8859-1] Sat Nov 7 04:43:56 2009
@@ -110,6 +110,18 @@
/* 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,