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/capt... ============================================================================== --- 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/misc... ============================================================================== --- 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/prec... ============================================================================== --- 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,