Author: nyadav Date: Tue May 31 16:30:46 2011 New Revision: 52020
URL: http://svn.reactos.org/svn/reactos?rev=52020&view=rev Log: [AUDSRV] Use Double Buffering to Improve latency
Added: branches/nyadav-audio-branch/base/services/audsrv/stream.c (with props) Modified: branches/nyadav-audio-branch/base/services/audsrv/CMakeLists.txt branches/nyadav-audio-branch/base/services/audsrv/audsrv.c branches/nyadav-audio-branch/base/services/audsrv/audsrv.h branches/nyadav-audio-branch/base/services/audsrv/rpc.c branches/nyadav-audio-branch/dll/win32/audsrvapi/audsrvapi.c branches/nyadav-audio-branch/dll/win32/audsrvapi/dllmain.c branches/nyadav-audio-branch/include/reactos/idl/audsrvrpc.idl branches/nyadav-audio-branch/include/reactos/libs/audsrv/audsrvapi.h
Modified: branches/nyadav-audio-branch/base/services/audsrv/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/branches/nyadav-audio-branch/base/service... ============================================================================== --- branches/nyadav-audio-branch/base/services/audsrv/CMakeLists.txt [iso-8859-1] (original) +++ branches/nyadav-audio-branch/base/services/audsrv/CMakeLists.txt [iso-8859-1] Tue May 31 16:30:46 2011 @@ -6,7 +6,8 @@ list(APPEND SOURCE audsrv.c audsrv.rc - rpc.c) + rpc.c + stream.c)
add_executable(audsrv ${SOURCE})
Modified: branches/nyadav-audio-branch/base/services/audsrv/audsrv.c URL: http://svn.reactos.org/svn/reactos/branches/nyadav-audio-branch/base/service... ============================================================================== --- branches/nyadav-audio-branch/base/services/audsrv/audsrv.c [iso-8859-1] (original) +++ branches/nyadav-audio-branch/base/services/audsrv/audsrv.c [iso-8859-1] Tue May 31 16:30:46 2011 @@ -153,27 +153,24 @@
-void fill(MixerEngine * mixer) +void fill(MixerEngine * mixer,int buffer) { DWORD Length; UINT i = 0; - mixer->mastervolume = 1000; - mixer->masterchannels=2; - mixer->masterfreq=48000; - mixer->masterbitspersample=16; - mixer->masterchannelmask = KSAUDIO_SPEAKER_STEREO; +Sleep(100); Length = mixer->masterfreq * mixer->masterchannels * mixer->masterbitspersample / 8; - mixer->masterbuf = (PSHORT)HeapAlloc(GetProcessHeap(), 0, Length); + mixer->masterbuf[buffer] = (PSHORT)HeapAlloc(GetProcessHeap(), 0, Length); while (i < Length / 2) { - mixer->masterbuf[i] = 0x7FFF * sin(0.5 * (i - 1) * 500 * _2pi / 48000); + mixer->masterbuf[buffer][i] = 0x7FFF * sin(0.5 * (i - 1) * 500 * _2pi / 48000); i++; - mixer->masterbuf[i] = 0x7FFF * sin(0.5 * (i - 2) * 500 * _2pi / 48000); + mixer->masterbuf[buffer][i] = 0x7FFF * sin(0.5 * (i - 2) * 500 * _2pi / 48000); i++; } -} - -void initdevice(MixerEngine * mixer) + mixer->bytes_to_play = Length; +} + +void playbuffer(MixerEngine * mixer,int buffer) { SP_DEVICE_INTERFACE_DATA InterfaceData; SP_DEVINFO_DATA DeviceData; @@ -186,7 +183,8 @@ DWORD Length; BOOL Result; NTSTATUS Status; - +if(mixer->masterbuf[buffer]) +{ // // Get a handle to KS Audio Interfaces // @@ -195,7 +193,7 @@ NULL, DIGCF_DEVICEINTERFACE |DIGCF_PRESENT);
- printf("DeviceHandle %p\n", DeviceHandle); + //printf("DeviceHandle %p\n", DeviceHandle);
// // Enumerate the first interface @@ -208,7 +206,7 @@ 1, &InterfaceData);
- printf("SetupDiEnumDeviceInterfaces %u Error %ld\n", Result, GetLastError()); + //printf("SetupDiEnumDeviceInterfaces %u Error %ld\n", Result, GetLastError());
// // Get the interface details (namely the device path) @@ -227,7 +225,7 @@ NULL, &DeviceData);
- wprintf(L"SetupDiGetDeviceInterfaceDetail %u Path DetailData %s\n", Result, (LPWSTR)&DetailData->DevicePath[0]); + //wprintf(L"SetupDiGetDeviceInterfaceDetail %u Path DetailData %s\n", Result, (LPWSTR)&DetailData->DevicePath[0]);
// // Open a handle to the device @@ -240,7 +238,7 @@ FILE_ATTRIBUTE_NORMAL, NULL);
- printf("Handle %p\n", mixer->FilterHandle); + //printf("Handle %p\n", mixer->FilterHandle);
// // Close the interface handle and clean up @@ -273,7 +271,7 @@ // // Setup the KS Data Format Information // - printf("DataFormat %p %p\n", DataFormat,(PVOID)((((ULONG_PTR)DataFormat + 7)) & ~7)); + //printf("DataFormat %p %p\n", DataFormat,(PVOID)((((ULONG_PTR)DataFormat + 7)) & ~7));
DataFormat->Flags = 0; DataFormat->Reserved = 0; @@ -294,14 +292,14 @@ WaveFormat->Samples.wValidBitsPerSample = mixer->masterbitspersample; WaveFormat->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- printf("Creating pin\n"); + //printf("Creating pin\n");
// // Create the pin // Status = KsCreatePin(mixer->FilterHandle, PinConnect, GENERIC_READ|GENERIC_WRITE, &(mixer->PinHandle));
- printf("PinHandle %p Status %lx\n", mixer->PinHandle, Status); + //printf("PinHandle %p Status %lx\n", mixer->PinHandle, Status);
Length = mixer->masterfreq * mixer->masterchannels * mixer->masterbitspersample / 8; @@ -311,9 +309,9 @@ mixer->Packet = (PKSSTREAM_HEADER)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KSSTREAM_HEADER)); - mixer->Packet->Data = mixer->masterbuf; - mixer->Packet->FrameExtent = Length; - mixer->Packet->DataUsed = Length; + mixer->Packet->Data = mixer->masterbuf[buffer]; + mixer->Packet->FrameExtent = mixer->bytes_to_play; + mixer->Packet->DataUsed = mixer->bytes_to_play; mixer->Packet->Size = sizeof(KSSTREAM_HEADER); mixer->Packet->PresentationTime.Numerator = 1; mixer->Packet->PresentationTime.Denominator = 1; @@ -338,13 +336,6 @@ sizeof(State), &Length, NULL); -} -void playbuffer(MixerEngine * mixer) -{ - DWORD Length = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH * sizeof(WCHAR); - // - // Play our 1-second buffer - //
DeviceIoControl(mixer->PinHandle, IOCTL_KS_WRITE_STREAM, @@ -355,14 +346,6 @@ &Length, NULL);
-} -void closedevice(MixerEngine * mixer) -{ - KSSTATE State; - DWORD Length = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH * sizeof(WCHAR); - // - // Change the state to stop - // State = KSSTATE_STOP; DeviceIoControl(mixer->PinHandle, IOCTL_KS_PROPERTY, @@ -375,17 +358,21 @@
CloseHandle(mixer->PinHandle); CloseHandle(mixer->FilterHandle); - +} } DWORD WINAPI RunMixerThread(LPVOID param) { MixerEngine * mixer = (MixerEngine *) param; - SetEvent(mixer->EventPool[0]); + + SetEvent(mixer->played); while(1) { - while(WaitForSingleObject(mixer->EventPool[0],100)!=0){if(mixer->dead)goto DEAD;} - fill(mixer); - SetEvent(mixer->EventPool[1]); + while(WaitForSingleObject(mixer->streampresent,100)!=0){if(mixer->dead)goto DEAD;} /*Check if there is at least one stream present.*/ + + while(WaitForSingleObject(mixer->played,100)!=0){if(mixer->dead)goto DEAD;} + fill(mixer,1-mixer->playcurrent); + SetEvent(mixer->filled); + } DEAD: printf("\nMixer Thread Ended\n"); @@ -396,11 +383,11 @@ MixerEngine * mixer = (MixerEngine *) param; while(1) { - while(WaitForSingleObject(mixer->EventPool[1],100)!=0){if(mixer->dead)goto DEAD;} - initdevice(mixer); - playbuffer(mixer); - closedevice(mixer); - SetEvent(mixer->EventPool[0]); + while(WaitForSingleObject(mixer->filled,100)!=0){if(mixer->dead)goto DEAD;} + SetEvent(mixer->played); + playbuffer(mixer,mixer->playcurrent); + + mixer->playcurrent=1-mixer->playcurrent; }
DEAD: @@ -481,8 +468,12 @@ pengine->mute=FALSE;
pengine->dead=0; - pengine->EventPool[0]=CreateEvent(NULL,FALSE,FALSE,NULL); - pengine->EventPool[1]=CreateEvent(NULL,FALSE,FALSE,NULL); + pengine->playcurrent=1; + pengine->masterbuf[0] = NULL; + pengine->masterbuf[1] = NULL; + pengine->played=CreateEvent(NULL,FALSE,FALSE,NULL); + pengine->filled=CreateEvent(NULL,FALSE,FALSE,NULL); + pengine->streampresent=CreateEvent(NULL,TRUE,FALSE,NULL); SetConsoleCtrlHandler(close,TRUE); SpawnMixerThread(pengine); SpawnPlayerThread(pengine); @@ -510,8 +501,12 @@ pengine->mute=FALSE;
pengine->dead=0; - pengine->EventPool[0]=CreateEvent(NULL,FALSE,FALSE,NULL); - pengine->EventPool[1]=CreateEvent(NULL,FALSE,FALSE,NULL); + pengine->playcurrent=1; + pengine->masterbuf[0] = NULL; + pengine->masterbuf[1] = NULL; + pengine->played=CreateEvent(NULL,FALSE,FALSE,NULL); + pengine->filled=CreateEvent(NULL,FALSE,FALSE,NULL); + pengine->streampresent=CreateEvent(NULL,TRUE,FALSE,NULL); SetConsoleCtrlHandler(close,TRUE); SpawnMixerThread(pengine); SpawnPlayerThread(pengine);
Modified: branches/nyadav-audio-branch/base/services/audsrv/audsrv.h URL: http://svn.reactos.org/svn/reactos/branches/nyadav-audio-branch/base/service... ============================================================================== --- branches/nyadav-audio-branch/base/services/audsrv/audsrv.h [iso-8859-1] (original) +++ branches/nyadav-audio-branch/base/services/audsrv/audsrv.h [iso-8859-1] Tue May 31 16:30:46 2011 @@ -34,6 +34,8 @@ int bitspersample; int channels; ULONG channelmask; + HANDLE played; + HANDLE streamready; HANDLE thread; float balance; struct ServerStream * next; @@ -43,10 +45,13 @@ { /*Should be Initialized at Server Start*/ char dead; - HANDLE EventPool[2];//0=Played,1=Ready + HANDLE played; + HANDLE filled; + HANDLE streampresent; HANDLE mixerthread; HANDLE playerthread; HANDLE rpcthread; + int playcurrent; /*Should be Initialized at Server Start from configuration file,Currently there is no configuration file so initialized to a fixed value at start*/ int mastervolume; BOOL mute; @@ -55,8 +60,9 @@ int masterchannels; unsigned long masterchannelmask; int masterbitspersample; - PSHORT masterbuf; + PSHORT masterbuf[2]; /*Currently don't know the future of following variables*/ + long bytes_to_play; HANDLE FilterHandle; HANDLE PinHandle; PKSPROPERTY Property; @@ -64,10 +70,15 @@ ServerStream * serverstreamlist; } MixerEngine;
-extern MixerEngine engine; +extern MixerEngine engine,*pengine;
/* rpc.c */ DWORD WINAPI RunRPCThread(LPVOID lpParameter); +/* audsrv.c*/ +void fill(MixerEngine * mixer,int buffer); +void playbuffer(MixerEngine * mixer,int buffer); +/*stream.c*/ +HANDLE addstream(LONG frequency,int channels,int bitspersample, ULONG channelmask,int volume,int mute,float balance); /********************************/
#endif /* __AUDSRV_H__ */
Modified: branches/nyadav-audio-branch/base/services/audsrv/rpc.c URL: http://svn.reactos.org/svn/reactos/branches/nyadav-audio-branch/base/service... ============================================================================== --- branches/nyadav-audio-branch/base/services/audsrv/rpc.c [iso-8859-1] (original) +++ branches/nyadav-audio-branch/base/services/audsrv/rpc.c [iso-8859-1] Tue May 31 16:30:46 2011 @@ -45,11 +45,13 @@
/*************************RPC Functions**********************************/
-NTSTATUS AUDInitStream( IN RPC_BINDING_HANDLE hBinding) +int AUDInitStream( IN RPC_BINDING_HANDLE hBinding,LONG frequency,int channels,int bitspersample, ULONG channelmask,int volume,int mute,float balance) { - UNIMPLEMENTED;/*Coolest Macro I have ever seen*/ - printf("Client Connected and called server's procedure\n"); - return STATUS_NOT_IMPLEMENTED; + HANDLE stream; + printf("Client Connected and Initiated Stream Freq: %ld,Channle: %d,Bitspersample: %d,Mask: %ld,Volume: %d,Mute: %d,Balance: %f\n",frequency,channels,bitspersample,channelmask,volume,mute,balance); + stream = addstream(frequency,channels,bitspersample,channelmask,volume,mute,balance); + if( stream == NULL ){return 0;}else{printf("Stream added\n");} + return (int)stream; } /*************************************************************************/ void __RPC_FAR *__RPC_USER midl_user_allocate(SIZE_T len)
Added: branches/nyadav-audio-branch/base/services/audsrv/stream.c URL: http://svn.reactos.org/svn/reactos/branches/nyadav-audio-branch/base/service... ============================================================================== --- branches/nyadav-audio-branch/base/services/audsrv/stream.c (added) +++ branches/nyadav-audio-branch/base/services/audsrv/stream.c [iso-8859-1] Tue May 31 16:30:46 2011 @@ -1,0 +1,59 @@ +#include "audsrv.h" + +DWORD WINAPI RunStreamThread(LPVOID param) +{ + ServerStream * localstream = (ServerStream *) param; + + SetEvent(localstream->streamready); + printf("Signaling Mixer Thread For First Stream\n"); + SetEvent(pengine->streampresent); + while (1){OutputDebugStringA("Stream Thread Running.");Sleep(100);}; + /*Clean Stream's data*/ +} + +HANDLE addstream(LONG frequency,int channels,int bitspersample, ULONG channelmask,int volume,int mute,float balance) +{ + ServerStream * newstream,*localstream; + DWORD dwID; + + /*Add Data to Linked list*/ + localstream = pengine->serverstreamlist; + newstream = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ServerStream)); + if(newstream == NULL) {goto error;} + if(volume < 0) {newstream->volume = 0;}else if (volume > 1000) {newstream->volume = 1000;}else {newstream->volume = volume;} + if(volume < -1.0) {newstream->volume = -1.0;}else if (volume > 1.0) {newstream->volume = 1.0;}else {newstream->volume = volume;} + newstream->freq = frequency; /*TODO frequency validation required*/ + newstream->bitspersample = bitspersample; /*TODO bitspersample validation*/ + newstream->channels = channels; /*TODO validation*/ + newstream->channelmask = channelmask; /*TODO validation*/ + + newstream->next = NULL; + newstream->played = CreateEvent(NULL,FALSE,FALSE,NULL); + newstream->streamready = CreateEvent(NULL,FALSE,FALSE,NULL); + + if(newstream->played == NULL || newstream->streamready == NULL) {goto error;} + newstream->thread=CreateThread(NULL,0,RunStreamThread,newstream,0,&dwID); + if(newstream->thread == NULL) {goto error;} + + WaitForSingleObject(newstream->streamready,INFINITE); + + if(localstream == NULL) + { + pengine->serverstreamlist = localstream; + + pengine->masterfreq=frequency; + pengine->masterchannels=channels; + pengine->masterchannelmask=channelmask; + pengine->masterbitspersample=bitspersample; + } + else + { + while(localstream->next != NULL){localstream = localstream->next;} + localstream->next = newstream; + } + return newstream->thread; + +error: + HeapFree(GetProcessHeap(), 0, newstream); + return NULL; +}
Propchange: branches/nyadav-audio-branch/base/services/audsrv/stream.c ------------------------------------------------------------------------------ eol-style = native
Propchange: branches/nyadav-audio-branch/base/services/audsrv/stream.c ------------------------------------------------------------------------------ mime-type = text/plain
Propchange: branches/nyadav-audio-branch/base/services/audsrv/stream.c ------------------------------------------------------------------------------ svn:eol-style = native
Propchange: branches/nyadav-audio-branch/base/services/audsrv/stream.c ------------------------------------------------------------------------------ svn:mime-type = text/plain
Modified: branches/nyadav-audio-branch/dll/win32/audsrvapi/audsrvapi.c URL: http://svn.reactos.org/svn/reactos/branches/nyadav-audio-branch/dll/win32/au... ============================================================================== --- branches/nyadav-audio-branch/dll/win32/audsrvapi/audsrvapi.c [iso-8859-1] (original) +++ branches/nyadav-audio-branch/dll/win32/audsrvapi/audsrvapi.c [iso-8859-1] Tue May 31 16:30:46 2011 @@ -7,38 +7,25 @@ */ WINAPI int initstream (ClientStream * clientstream,LONG frequency,int channels,int bitspersample, ULONG channelmask,int volume,int mute,float balance) { - RPC_STATUS status; - unsigned short * pszStringBinding = NULL; - - - if(clientstream == NULL ) return -1; + int streamid; + if (clientstream == NULL ) return -1; if (clientstream->callbacks.OpenComplete == NULL || clientstream->callbacks.BufferCopied == NULL || clientstream->callbacks.PlayComplete == NULL) return -2; /*Validity of all other data will be checked at server*/ /*Check Connection Status If not connected call Connect()*/ /*If connected Properly call the remote audsrv_initstream() function*/ - status = RpcStringBindingComposeW(NULL,L"ncacn_np",NULL,L"\pipe\audsrv", NULL,&pszStringBinding); - - status = RpcBindingFromStringBindingW(pszStringBinding, &audsrv_v0_0_c_ifspec); - - if (status) printf("Connection Problem p %d \n",status); - - status = RpcStringFree(&pszStringBinding); - - if (status) printf("Problem Freeing String : %d \n",status); -
RpcTryExcept { - AUDInitStream (audsrv_v0_0_c_ifspec); + streamid = AUDInitStream (audsrv_v0_0_c_ifspec,frequency,channels,bitspersample,channelmask,volume,mute,balance); + printf("AUDInitStream Returned %d",streamid); } - RpcExcept(1) + RpcExcept(1) { status = RpcExceptionCode(); printf("Runtime reported exception 0x%lx = %ld\n", status, status); } RpcEndExcept - status = RpcBindingFree(&audsrv_v0_0_c_ifspec); - if (status == RPC_S_INVALID_BINDING) printf("Error : %d Invalid RPC S HANDLE\n",status); + /*Analyse the return by the function*/ /*Currently Suppose the return is 0 and a valid streamid is returned*/ clientstream->stream = &status;
Modified: branches/nyadav-audio-branch/dll/win32/audsrvapi/dllmain.c URL: http://svn.reactos.org/svn/reactos/branches/nyadav-audio-branch/dll/win32/au... ============================================================================== --- branches/nyadav-audio-branch/dll/win32/audsrvapi/dllmain.c [iso-8859-1] (original) +++ branches/nyadav-audio-branch/dll/win32/audsrvapi/dllmain.c [iso-8859-1] Tue May 31 16:30:46 2011 @@ -7,13 +7,27 @@ LPVOID lpReserved ) { - + RPC_STATUS status; + unsigned short * pszStringBinding = NULL; + switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: + status = RpcStringBindingComposeW(NULL,L"ncacn_np",NULL,L"\pipe\audsrv", NULL,&pszStringBinding); + + status = RpcBindingFromStringBindingW(pszStringBinding, &audsrv_v0_0_c_ifspec); + + if (status) printf("Connection Problem p %d \n",status); + + status = RpcStringFree(&pszStringBinding); + + if (status) printf("Problem Freeing String : %d \n",status); + break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: + status = RpcBindingFree(audsrv_v0_0_c_ifspec); + if (status == RPC_S_INVALID_BINDING) printf("Error : %d Invalid RPC S HANDLE\n",status); break; } return TRUE;
Modified: branches/nyadav-audio-branch/include/reactos/idl/audsrvrpc.idl URL: http://svn.reactos.org/svn/reactos/branches/nyadav-audio-branch/include/reac... ============================================================================== --- branches/nyadav-audio-branch/include/reactos/idl/audsrvrpc.idl [iso-8859-1] (original) +++ branches/nyadav-audio-branch/include/reactos/idl/audsrvrpc.idl [iso-8859-1] Tue May 31 16:30:46 2011 @@ -3,6 +3,7 @@ */
#include <ms-dtyp.idl> +
cpp_quote("#if !defined(__AUDSRV_H__) ") typedef long NTSTATUS; @@ -19,6 +20,7 @@ typedef AUDSRV_HANDLE *PAUDSRV_HANDLE; typedef [handle, unique] LPWSTR AUDSRV_HANDLE_W; typedef [handle, unique] LPSTR AUDSRV_HANDLE_A; +
typedef struct _RPC_CLIENT_ID { DWORD UniqueProcess; @@ -37,6 +39,6 @@ interface audsrv {
- NTSTATUS AUDInitStream([in] handle_t h1); + int AUDInitStream([in] handle_t h1,[in]LONG frequency,[in]int channels,[in]int bitspersample,[in] ULONG channelmask,[in]int volume,[in]int mute,[in]float balance);
}
Modified: branches/nyadav-audio-branch/include/reactos/libs/audsrv/audsrvapi.h URL: http://svn.reactos.org/svn/reactos/branches/nyadav-audio-branch/include/reac... ============================================================================== --- branches/nyadav-audio-branch/include/reactos/libs/audsrv/audsrvapi.h [iso-8859-1] (original) +++ branches/nyadav-audio-branch/include/reactos/libs/audsrv/audsrvapi.h [iso-8859-1] Tue May 31 16:30:46 2011 @@ -7,6 +7,7 @@ #include <stdio.h>
/********************Structures*********************/ + typedef struct CallBacks { void (*OpenComplete) (int error ); @@ -18,7 +19,7 @@ { HANDLE stream; int dead; -HANDLE ClientEventPool[1]; /*[0]th event is for Activescheduler*/ +HANDLE ClientEventPool[1]; //0]th event is for Activescheduler struct CallBacks callbacks; } ClientStream;