mirror of
https://github.com/reactos/reactos
synced 2025-10-06 16:32:42 +02:00
Compare commits
40 Commits
backups/c+
...
backups/ny
Author | SHA1 | Date | |
---|---|---|---|
|
44890cc54f | ||
|
ed4ed6c5ab | ||
|
a2d31f3759 | ||
|
548c4078d5 | ||
|
6e480ff031 | ||
|
0fbb37be93 | ||
|
0039ae9f4d | ||
|
4f2a3e8196 | ||
|
1fd76abbae | ||
|
e4ea774182 | ||
|
3b4f5e313c | ||
|
de1bd0a605 | ||
|
608d51b7f1 | ||
|
56e0ac6ab6 | ||
|
938eb58a2e | ||
|
2d9aa9c767 | ||
|
b162936df8 | ||
|
c86206d456 | ||
|
23859ae322 | ||
|
796708eaed | ||
|
bda4efccd4 | ||
|
1853a835fc | ||
|
4c970849fc | ||
|
8200abb90e | ||
|
c046e1125a | ||
|
3cf76813a1 | ||
|
3566e33421 | ||
|
e8ad899398 | ||
|
f65941c481 | ||
|
e6598f4f34 | ||
|
77b41ca6a0 | ||
|
8065701376 | ||
|
51726a9785 | ||
|
ee5931681b | ||
|
4e4fee5c45 | ||
|
c825b9f249 | ||
|
0fad2e4d67 | ||
|
3f32f73948 | ||
|
40b0390d6d | ||
|
e78f8c2434 |
@@ -22,6 +22,9 @@ set(CMAKE_SKIP_ASSEMBLY_SOURCE_RULES TRUE)
|
||||
set(CMAKE_COLOR_MAKEFILE OFF)
|
||||
set_property(GLOBAL PROPERTY RULE_MESSAGES OFF)
|
||||
|
||||
#Show Debug Output while Building
|
||||
#SET(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
|
||||
if(NOT ARCH)
|
||||
set(ARCH i386)
|
||||
endif()
|
||||
|
@@ -1,5 +1,6 @@
|
||||
|
||||
add_subdirectory(audiosrv)
|
||||
add_subdirectory(audsrv)
|
||||
add_subdirectory(eventlog)
|
||||
add_subdirectory(rpcss)
|
||||
add_subdirectory(spoolsv)
|
||||
|
21
base/services/audsrv/CMakeLists.txt
Normal file
21
base/services/audsrv/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
include_directories(${REACTOS_BINARY_DIR}/include/reactos/idl)
|
||||
|
||||
set_unicode()
|
||||
|
||||
list(APPEND SOURCE
|
||||
audsrv.c
|
||||
audsrv.rc
|
||||
rpc.c
|
||||
mixer.c
|
||||
stream.c)
|
||||
|
||||
add_executable(audsrv ${SOURCE})
|
||||
|
||||
target_link_libraries(audsrv audsrvrpc ${PSEH_LIB})
|
||||
|
||||
add_pch(audsrv ${CMAKE_CURRENT_SOURCE_DIR}/audsrv.h ${SOURCE})
|
||||
|
||||
set_module_type(audsrv win32cui)
|
||||
add_importlibs(audsrv advapi32 rpcrt4 msvcrt kernel32 ntdll user32 ksuser setupapi)
|
||||
add_cab_target(audsrv 1)
|
635
base/services/audsrv/audsrv.c
Normal file
635
base/services/audsrv/audsrv.c
Normal file
@@ -0,0 +1,635 @@
|
||||
/*
|
||||
* PROJECT: ReactOS kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: services/audsrv.c
|
||||
* PURPOSE: Audio Server
|
||||
* COPYRIGHT: Copyright 2011 Neeraj Yadav
|
||||
|
||||
*/
|
||||
|
||||
#include "audsrv.h"
|
||||
|
||||
static VOID CALLBACK ServiceMain(DWORD,
|
||||
LPWSTR *);
|
||||
|
||||
static DWORD ServiceInit(VOID);
|
||||
|
||||
static BOOL WINAPI Close (DWORD dwCtrlType);
|
||||
|
||||
static WCHAR ServiceName[] = L"AudSrv";
|
||||
|
||||
static SERVICE_TABLE_ENTRYW ServiceTable[2] =
|
||||
{
|
||||
{ ServiceName, ServiceMain },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
SERVICE_STATUS ServiceStatus;
|
||||
SERVICE_STATUS_HANDLE ServiceStatusHandle;
|
||||
|
||||
#define _2pi 6.283185307179586476925286766559
|
||||
|
||||
GUID CategoryGuid = {STATIC_KSCATEGORY_AUDIO};
|
||||
|
||||
const GUID KSPROPSETID_Pin = {0x8C134960L, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
|
||||
const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
|
||||
const GUID KSPROPSETID_Sysaudio = {0xCBE3FAA0L, 0xCC75, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
|
||||
const GUID KSPROPSETID_General = {0x1464EDA5L, 0x6A8F, 0x11D1, {0x9A, 0xA7, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
|
||||
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_SUBTYPE_PCM = {0x00000001L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
|
||||
const GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003L, 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}};
|
||||
|
||||
/*Global Pointer to MixerEngine Structure*/
|
||||
MixerEngine engine,*pengine;
|
||||
|
||||
static
|
||||
VOID
|
||||
UpdateServiceStatus(DWORD dwState)
|
||||
{
|
||||
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
ServiceStatus.dwCurrentState = dwState;
|
||||
ServiceStatus.dwControlsAccepted = 0;
|
||||
ServiceStatus.dwWin32ExitCode = 0;
|
||||
ServiceStatus.dwServiceSpecificExitCode = 0;
|
||||
ServiceStatus.dwCheckPoint = 0;
|
||||
|
||||
if (dwState == SERVICE_START_PENDING ||
|
||||
dwState == SERVICE_STOP_PENDING ||
|
||||
dwState == SERVICE_PAUSE_PENDING ||
|
||||
dwState == SERVICE_CONTINUE_PENDING)
|
||||
ServiceStatus.dwWaitHint = 10000;
|
||||
else
|
||||
ServiceStatus.dwWaitHint = 0;
|
||||
|
||||
SetServiceStatus(ServiceStatusHandle,
|
||||
&ServiceStatus);
|
||||
}
|
||||
|
||||
static DWORD WINAPI
|
||||
ServiceControlHandler(DWORD dwControl,
|
||||
DWORD dwEventType,
|
||||
LPVOID lpEventData,
|
||||
LPVOID lpContext)
|
||||
{
|
||||
DPRINT("ServiceControlHandler() called\n");
|
||||
|
||||
switch (dwControl)
|
||||
{
|
||||
case SERVICE_CONTROL_STOP:
|
||||
DPRINT(" SERVICE_CONTROL_STOP received\n");
|
||||
Close(CTRL_CLOSE_EVENT);
|
||||
UpdateServiceStatus(SERVICE_STOPPED);
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
case SERVICE_CONTROL_PAUSE:
|
||||
DPRINT(" SERVICE_CONTROL_PAUSE received\n");
|
||||
UpdateServiceStatus(SERVICE_PAUSED);
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
case SERVICE_CONTROL_CONTINUE:
|
||||
DPRINT(" SERVICE_CONTROL_CONTINUE received\n");
|
||||
UpdateServiceStatus(SERVICE_RUNNING);
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
case SERVICE_CONTROL_INTERROGATE:
|
||||
DPRINT(" SERVICE_CONTROL_INTERROGATE received\n");
|
||||
SetServiceStatus(ServiceStatusHandle,
|
||||
&ServiceStatus);
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
case SERVICE_CONTROL_SHUTDOWN:
|
||||
DPRINT(" SERVICE_CONTROL_SHUTDOWN received\n");
|
||||
Close(CTRL_CLOSE_EVENT);
|
||||
UpdateServiceStatus(SERVICE_STOPPED);
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
default :
|
||||
DPRINT1(" Control %lu received\n");
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
CALLBACK
|
||||
ServiceMain(DWORD argc,
|
||||
LPWSTR *argv)
|
||||
{
|
||||
DWORD dwError;
|
||||
|
||||
UNREFERENCED_PARAMETER(argc);
|
||||
UNREFERENCED_PARAMETER(argv);
|
||||
|
||||
DPRINT("ServiceMain() called\n");
|
||||
|
||||
ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
|
||||
ServiceControlHandler,
|
||||
NULL);
|
||||
if (!ServiceStatusHandle)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
DPRINT1("RegisterServiceCtrlHandlerW() failed! (Error %lu)\n", dwError);
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateServiceStatus(SERVICE_START_PENDING);
|
||||
|
||||
dwError = ServiceInit();
|
||||
if (dwError != ERROR_SUCCESS)
|
||||
{
|
||||
DPRINT("Service stopped (dwError: %lu\n", dwError);
|
||||
UpdateServiceStatus(SERVICE_START_PENDING);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Service started\n");
|
||||
UpdateServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
|
||||
DPRINT("ServiceMain() done\n");
|
||||
}
|
||||
|
||||
/*This Function is called repeatedly by mixer thread.
|
||||
*This functions fetches FilteredBuffer from Every ClientStream Stucture
|
||||
*and mixes them in oder to feed player thread*/
|
||||
void
|
||||
MixAndFill(MixerEngine * mixer,
|
||||
int buffer)
|
||||
{
|
||||
while(WaitForSingleObject(mixer->newStreamEvent,
|
||||
100) != 0)
|
||||
{
|
||||
if(mixer->dead)
|
||||
return;
|
||||
}
|
||||
|
||||
/*Master Stream's Datatype is signed int,unsigned int or float when masterdatatype =0,1 and 2 respectively*/
|
||||
if(mixer->masterdatatype == 0)
|
||||
{
|
||||
switch(mixer->masterbitspersample)
|
||||
{
|
||||
case 8:
|
||||
MixS8(mixer,buffer);
|
||||
break;
|
||||
case 16:
|
||||
MixS16(mixer,buffer);
|
||||
break;
|
||||
case 32:
|
||||
MixS32(mixer,buffer);
|
||||
break;
|
||||
case 64:
|
||||
MixS64(mixer,buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (mixer->masterdatatype == 1)
|
||||
{
|
||||
switch(mixer->masterbitspersample)
|
||||
{
|
||||
case 8:
|
||||
MixU8(mixer,buffer);
|
||||
break;
|
||||
case 16:
|
||||
MixU16(mixer,buffer);
|
||||
break;
|
||||
case 32:
|
||||
MixU32(mixer,buffer);
|
||||
break;
|
||||
case 64:
|
||||
MixU64(mixer,buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(mixer->masterdatatype == 2)
|
||||
{
|
||||
switch(mixer->masterbitspersample)
|
||||
{
|
||||
case 32:
|
||||
MixFL32(mixer,buffer);
|
||||
break;
|
||||
case 64:
|
||||
MixFL64(mixer,buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Frees the Buffer Created in mixer thread*/
|
||||
void FreeBuffer()
|
||||
{
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
pengine->masterbuf[pengine->playcurrent]);
|
||||
|
||||
pengine->masterbuf[pengine->playcurrent] = NULL;
|
||||
}
|
||||
|
||||
/*Plays Master buffer pengine->masterbuf[pengine->playcurrent]*/
|
||||
void PlayBuffer(MixerEngine * mixer,
|
||||
int buffer)
|
||||
{
|
||||
SP_DEVICE_INTERFACE_DATA InterfaceData;
|
||||
SP_DEVINFO_DATA DeviceData;
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA DetailData;
|
||||
HDEVINFO DeviceHandle;
|
||||
PKSDATAFORMAT DataFormat;
|
||||
PWAVEFORMATEXTENSIBLE WaveFormat;
|
||||
PKSPIN_CONNECT PinConnect;
|
||||
KSSTATE State;
|
||||
DWORD Length;
|
||||
BOOL Result;
|
||||
NTSTATUS Status;
|
||||
|
||||
if(mixer->masterbuf[buffer])
|
||||
{
|
||||
//
|
||||
// Get a handle to KS Audio Interfaces
|
||||
//
|
||||
DeviceHandle = SetupDiGetClassDevs(&CategoryGuid,
|
||||
NULL,
|
||||
NULL,
|
||||
DIGCF_DEVICEINTERFACE |DIGCF_PRESENT);
|
||||
|
||||
|
||||
//
|
||||
// Enumerate the first interface
|
||||
//
|
||||
InterfaceData.cbSize = sizeof(InterfaceData);
|
||||
InterfaceData.Reserved = 0;
|
||||
Result = SetupDiEnumDeviceInterfaces(DeviceHandle,
|
||||
NULL,
|
||||
&CategoryGuid,
|
||||
1,
|
||||
&InterfaceData);
|
||||
|
||||
|
||||
//
|
||||
// Get the interface details (namely the device path)
|
||||
//
|
||||
Length = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH * sizeof(WCHAR);
|
||||
DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
Length);
|
||||
DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
||||
DeviceData.cbSize = sizeof(DeviceData);
|
||||
DeviceData.Reserved = 0;
|
||||
Result = SetupDiGetDeviceInterfaceDetail(DeviceHandle,
|
||||
&InterfaceData,
|
||||
DetailData,
|
||||
Length,
|
||||
NULL,
|
||||
&DeviceData);
|
||||
|
||||
|
||||
//
|
||||
// Open a handle to the device
|
||||
//
|
||||
mixer->FilterHandle = CreateFile(DetailData->DevicePath,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
|
||||
//
|
||||
// Close the interface handle and clean up
|
||||
//
|
||||
//SetupDiDestroyDeviceInfoList(DeviceHandle);
|
||||
|
||||
//
|
||||
// Allocate a KS Pin Connection Request Structure
|
||||
//
|
||||
Length = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX) + sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
|
||||
PinConnect = (PKSPIN_CONNECT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Length);
|
||||
DataFormat = (PKSDATAFORMAT)(PinConnect + 1);
|
||||
WaveFormat = (PWAVEFORMATEXTENSIBLE)(DataFormat + 1);
|
||||
|
||||
//
|
||||
// Setup the KS Pin Data
|
||||
//
|
||||
|
||||
PinConnect->Interface.Set = KSINTERFACESETID_Standard;
|
||||
PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
|
||||
PinConnect->Interface.Flags = 0;
|
||||
PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
|
||||
PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
|
||||
PinConnect->Medium.Flags = 0;
|
||||
PinConnect->PinId = 0;
|
||||
PinConnect->PinToHandle = NULL;
|
||||
PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
|
||||
PinConnect->Priority.PrioritySubClass = 1;
|
||||
|
||||
//
|
||||
// Setup the KS Data Format Information
|
||||
//
|
||||
|
||||
DataFormat->Flags = 0;
|
||||
DataFormat->Reserved = 0;
|
||||
DataFormat->MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
|
||||
if(mixer->masterdatatype == 0 || mixer->masterdatatype == 1)
|
||||
DataFormat->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
||||
else
|
||||
DataFormat->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||
DataFormat->Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
|
||||
DataFormat->SampleSize = mixer->masterchannels * mixer->masterbitspersample / 8;
|
||||
DataFormat->FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEXTENSIBLE);
|
||||
|
||||
WaveFormat->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
WaveFormat->Format.nChannels = mixer->masterchannels;
|
||||
WaveFormat->Format.nSamplesPerSec = mixer->masterfreq;
|
||||
WaveFormat->Format.nBlockAlign = (mixer->masterchannels * mixer->masterbitspersample)/8;;
|
||||
WaveFormat->Format.nAvgBytesPerSec = WaveFormat->Format.nSamplesPerSec * WaveFormat->Format.nBlockAlign;
|
||||
WaveFormat->Format.wBitsPerSample = mixer->masterbitspersample;
|
||||
WaveFormat->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
|
||||
WaveFormat->dwChannelMask = mixer->masterchannelmask;
|
||||
WaveFormat->Samples.wValidBitsPerSample = mixer->masterbitspersample;
|
||||
if(mixer->masterdatatype == 0 || mixer->masterdatatype == 1)
|
||||
WaveFormat->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
||||
else
|
||||
WaveFormat->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||
|
||||
|
||||
//
|
||||
// Create the pin
|
||||
//
|
||||
Status = KsCreatePin(mixer->FilterHandle, PinConnect, GENERIC_READ|GENERIC_WRITE, &(mixer->PinHandle));
|
||||
|
||||
Length = mixer->masterfreq * mixer->masterchannels * mixer->masterbitspersample / 8;
|
||||
//
|
||||
// Create and fill out the KS Stream Packet
|
||||
//
|
||||
mixer->Packet = (PKSSTREAM_HEADER)HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
sizeof(KSSTREAM_HEADER));
|
||||
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;
|
||||
|
||||
//
|
||||
// Setup a KS Property to change the state
|
||||
//
|
||||
mixer->Property = (PKSPROPERTY)HeapAlloc(GetProcessHeap(), 0, sizeof(KSPROPERTY));
|
||||
mixer->Property->Set = KSPROPSETID_Connection;
|
||||
mixer->Property->Id = KSPROPERTY_CONNECTION_STATE;
|
||||
mixer->Property->Flags = KSPROPERTY_TYPE_SET;
|
||||
|
||||
//
|
||||
// Change the state to run
|
||||
//
|
||||
State = KSSTATE_RUN;
|
||||
DeviceIoControl(mixer->PinHandle,
|
||||
IOCTL_KS_PROPERTY,
|
||||
mixer->Property,
|
||||
sizeof(KSPROPERTY),
|
||||
&State,
|
||||
sizeof(State),
|
||||
&Length,
|
||||
NULL);
|
||||
|
||||
DeviceIoControl(mixer->PinHandle,
|
||||
IOCTL_KS_WRITE_STREAM,
|
||||
NULL,
|
||||
0,
|
||||
mixer->Packet,
|
||||
mixer->Packet->Size,
|
||||
&Length,
|
||||
NULL);
|
||||
|
||||
State = KSSTATE_STOP;
|
||||
DeviceIoControl(mixer->PinHandle,
|
||||
IOCTL_KS_PROPERTY,
|
||||
mixer->Property,
|
||||
sizeof(KSPROPERTY),
|
||||
&State,
|
||||
sizeof(State),
|
||||
&Length,
|
||||
NULL);
|
||||
|
||||
CloseHandle(mixer->PinHandle);
|
||||
CloseHandle(mixer->FilterHandle);
|
||||
}
|
||||
}
|
||||
|
||||
/*Thread Routine For Mixer Thread*/
|
||||
DWORD WINAPI RunMixerThread(LPVOID param)
|
||||
{
|
||||
MixerEngine * mixer = (MixerEngine *) param;
|
||||
|
||||
SetEvent(mixer->played);
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
while(WaitForSingleObject(mixer->played,
|
||||
100)!=0)
|
||||
{
|
||||
if(mixer->dead)
|
||||
break;
|
||||
}
|
||||
|
||||
if(mixer->dead)
|
||||
break;
|
||||
|
||||
MixAndFill(mixer,
|
||||
1-mixer->playcurrent);
|
||||
|
||||
SetEvent(mixer->filled);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*Thread Routine For Player Thread*/
|
||||
DWORD WINAPI RunPlayerThread(LPVOID param)
|
||||
{
|
||||
MixerEngine * mixer = (MixerEngine *) param;
|
||||
|
||||
while(1)
|
||||
{
|
||||
while(WaitForSingleObject(mixer->filled,
|
||||
100)!=0)
|
||||
{
|
||||
if(mixer->dead)
|
||||
break;
|
||||
}
|
||||
|
||||
if(mixer->dead)
|
||||
break;
|
||||
|
||||
SetEvent(mixer->played);
|
||||
PlayBuffer(mixer,
|
||||
mixer->playcurrent);
|
||||
|
||||
FreeBuffer();
|
||||
|
||||
mixer->playcurrent=1-mixer->playcurrent;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*Create Mixer Thread*/
|
||||
void SpawnMixerThread(MixerEngine * mixer)
|
||||
{
|
||||
DWORD dwID;
|
||||
mixer->mixerthread=CreateThread(NULL,
|
||||
0,
|
||||
RunMixerThread,
|
||||
pengine,
|
||||
0,
|
||||
&dwID);
|
||||
}
|
||||
|
||||
/*Create Player Thread*/
|
||||
void SpawnPlayerThread(MixerEngine * mixer)
|
||||
{
|
||||
DWORD dwID;
|
||||
mixer->playerthread=CreateThread(NULL,
|
||||
0,
|
||||
RunPlayerThread,
|
||||
pengine,
|
||||
0,
|
||||
&dwID);
|
||||
}
|
||||
|
||||
/*Create RPC Thread*/
|
||||
void SpawnRPCThread(MixerEngine * mixer)
|
||||
{
|
||||
DWORD dwID;
|
||||
mixer->rpcthread=CreateThread(NULL,
|
||||
0,
|
||||
RunRPCThread,
|
||||
pengine,
|
||||
0,
|
||||
&dwID);
|
||||
}
|
||||
|
||||
void ShutdownRPC(void)
|
||||
{
|
||||
RPC_STATUS status;
|
||||
|
||||
status = RpcMgmtStopServerListening(NULL);
|
||||
|
||||
if (status)
|
||||
{
|
||||
exit(status);
|
||||
}
|
||||
|
||||
status = RpcServerUnregisterIf(NULL, NULL, FALSE);
|
||||
|
||||
if (status)
|
||||
{
|
||||
exit(status);
|
||||
}
|
||||
}
|
||||
|
||||
/*This Functions Kills the application, in any condition*/
|
||||
static BOOL WINAPI Close ( DWORD dwCtrlType )
|
||||
{
|
||||
pengine->dead=1;
|
||||
|
||||
WaitForSingleObject(pengine->mixerthread,
|
||||
INFINITE);
|
||||
WaitForSingleObject(pengine->playerthread,
|
||||
INFINITE);
|
||||
|
||||
ShutdownRPC();
|
||||
|
||||
WaitForSingleObject(pengine->rpcthread,INFINITE);
|
||||
|
||||
CloseHandle(pengine->mixerthread);
|
||||
CloseHandle(pengine->playerthread);
|
||||
CloseHandle(pengine->rpcthread);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
INT wmain(int argc, char *argv[])
|
||||
{
|
||||
INT RetCode = 0;
|
||||
|
||||
/*For Temporary Debugging purpose, If there is any argument it acts as simple command line app,otherwise it is a NTSERVICE*/
|
||||
if(argc==1)
|
||||
{
|
||||
StartServiceCtrlDispatcher(ServiceTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
pengine=&engine;
|
||||
|
||||
/*Later these will be loaded from a Conf file*/
|
||||
pengine->mastervolume=1000;
|
||||
pengine->mute=FALSE;
|
||||
|
||||
pengine->dead=0;
|
||||
pengine->streamidpool=0;
|
||||
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->newStreamEvent=CreateEvent(NULL,
|
||||
TRUE,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
SetConsoleCtrlHandler(Close,
|
||||
TRUE);
|
||||
|
||||
SpawnMixerThread(pengine);
|
||||
SpawnPlayerThread(pengine);
|
||||
SpawnRPCThread(pengine);
|
||||
|
||||
WaitForSingleObject(pengine->mixerthread,
|
||||
INFINITE);
|
||||
WaitForSingleObject(pengine->playerthread,
|
||||
INFINITE);
|
||||
WaitForSingleObject(pengine->rpcthread,INFINITE);
|
||||
}
|
||||
|
||||
CloseHandle(pengine->mixerthread);
|
||||
CloseHandle(pengine->playerthread);
|
||||
CloseHandle(pengine->rpcthread);
|
||||
|
||||
return RetCode;
|
||||
}
|
||||
|
||||
static DWORD
|
||||
ServiceInit(VOID)
|
||||
{
|
||||
pengine=&engine;
|
||||
|
||||
/*Later these will be loaded from a Conf file*/
|
||||
pengine->mastervolume=1000;
|
||||
pengine->mute=FALSE;
|
||||
|
||||
pengine->dead=0;
|
||||
pengine->streamidpool=0;
|
||||
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->newStreamEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
|
||||
SetConsoleCtrlHandler(Close,TRUE);
|
||||
SpawnMixerThread(pengine);
|
||||
SpawnPlayerThread(pengine);
|
||||
SpawnRPCThread(pengine);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
155
base/services/audsrv/audsrv.h
Normal file
155
base/services/audsrv/audsrv.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* PROJECT: ReactOS kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: services/audsrv/audsrv.h
|
||||
* PURPOSE: Audio Service
|
||||
* COPYRIGHT: Copyright 2011 Neeraj Yadav
|
||||
*/
|
||||
|
||||
#ifndef __AUDSRV_H__
|
||||
#define __AUDSRV_H__
|
||||
|
||||
#define NDEBUG
|
||||
#define WIN32_NO_STATUS
|
||||
|
||||
#include <windows.h>
|
||||
#include <wincon.h>
|
||||
#include <memory.h>
|
||||
#include <mmsystem.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <setupapi.h>
|
||||
#include <ndk/ntndk.h>
|
||||
#include <ks.h>
|
||||
#include <ksmedia.h>
|
||||
#include <ks.h>
|
||||
#include <debug.h>
|
||||
#include "audsrvrpc_s.h"
|
||||
|
||||
|
||||
typedef struct ServerStream
|
||||
{
|
||||
long streamid;
|
||||
int volume;
|
||||
LONG freq;
|
||||
int bitspersample;
|
||||
|
||||
/*0=signed int,1=unsigned int,2=float*/
|
||||
int datatype;
|
||||
|
||||
int channels;
|
||||
|
||||
/*Standard channelmasks from WINAPI/ksmeida.h*/
|
||||
ULONG channelmask;
|
||||
|
||||
/*Balance from -1.0 to 1.0*/
|
||||
float balance;
|
||||
/*state cycle 0->buffer write -> 1 -> filtering -> 2 ->playback -> 0*/
|
||||
char state;
|
||||
/*This buffer is filled by the client using RPC calls*/
|
||||
PVOID genuinebuf;
|
||||
int length_genuine;
|
||||
/*This Buffer is filled by Stream-Specific Server Thread, This Buffer's matches masterbuffer specifications*/
|
||||
PVOID filteredbuf;
|
||||
int length_filtered;
|
||||
/*These values must be filled by Stream-Specific Server Thread,these are helful for Mixer Thread*/
|
||||
PVOID minsamplevalue;
|
||||
PVOID maxsamplevalue;
|
||||
|
||||
HANDLE stream_played_event;
|
||||
HANDLE buffer_write_event;
|
||||
HANDLE threadready;
|
||||
HANDLE thread;
|
||||
CRITICAL_SECTION CriticalSection;
|
||||
|
||||
struct ServerStream * next;
|
||||
} ServerStream;
|
||||
|
||||
typedef struct MixerEngine
|
||||
{
|
||||
/*Should be Initialized at Server Start*/
|
||||
char dead;
|
||||
long streamidpool;
|
||||
HANDLE played;
|
||||
HANDLE filled;
|
||||
HANDLE newStreamEvent;
|
||||
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;
|
||||
/*Should be Initialized before playing First Stream*/
|
||||
long masterfreq;
|
||||
int masterchannels;
|
||||
unsigned long masterchannelmask;
|
||||
int masterbitspersample;
|
||||
int masterdatatype;
|
||||
PVOID masterbuf[2];
|
||||
/*Currently don't know the future of following variables*/
|
||||
long bytes_to_play;
|
||||
HANDLE FilterHandle;
|
||||
HANDLE PinHandle;
|
||||
PKSPROPERTY Property;
|
||||
PKSSTREAM_HEADER Packet;
|
||||
ServerStream * serverstreamlist;
|
||||
} MixerEngine;
|
||||
|
||||
extern MixerEngine engine,*pengine;
|
||||
|
||||
/* rpc.c */
|
||||
DWORD WINAPI RunRPCThread(LPVOID lpParameter);
|
||||
|
||||
/* audsrv.c*/
|
||||
void MixAndFill(MixerEngine * mixer,
|
||||
int buffer);
|
||||
void PlayBuffer(MixerEngine * mixer,
|
||||
int buffer);
|
||||
|
||||
/*stream.c*/
|
||||
long GetNewStreamID();
|
||||
long AddStream(LONG frequency,
|
||||
int channels,
|
||||
int bitspersample,
|
||||
int datatype,
|
||||
ULONG channelmask,
|
||||
int volume,
|
||||
int mute,
|
||||
float balance);
|
||||
|
||||
long WriteBuffer(LONG streamid,
|
||||
LONG length,
|
||||
char * buffer);
|
||||
/*mixer.c*/
|
||||
void * MixS8(MixerEngine * mixer,
|
||||
int buffer);
|
||||
|
||||
void * MixS16(MixerEngine * mixer,
|
||||
int buffer);
|
||||
|
||||
void * MixS32(MixerEngine * mixer,
|
||||
int buffer);
|
||||
|
||||
void * MixS64(MixerEngine * mixer,
|
||||
int buffer);
|
||||
|
||||
void * MixU8(MixerEngine * mixer,
|
||||
int buffer);
|
||||
|
||||
void * MixU16(MixerEngine * mixer,
|
||||
int buffer);
|
||||
|
||||
void * MixU32(MixerEngine * mixer,
|
||||
int buffer);
|
||||
|
||||
void * MixU64(MixerEngine * mixer,
|
||||
int buffer);
|
||||
|
||||
void * MixFL32(MixerEngine * mixer,
|
||||
int buffer);
|
||||
|
||||
void * MixFL64(MixerEngine * mixer,
|
||||
int buffer);
|
||||
|
||||
#endif /* __AUDSRV_H__ */
|
4
base/services/audsrv/audsrv.rc
Normal file
4
base/services/audsrv/audsrv.rc
Normal file
@@ -0,0 +1,4 @@
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "Audio Server\0"
|
||||
#define REACTOS_STR_INTERNAL_NAME "Audsrv\0"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "Audsrv.exe\0"
|
||||
#include <reactos/version.rc>
|
135
base/services/audsrv/mixer.c
Normal file
135
base/services/audsrv/mixer.c
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* PROJECT: ReactOS kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: services/mixer.c
|
||||
* PURPOSE: Audio Server
|
||||
* COPYRIGHT: Copyright 2011 Neeraj Yadav
|
||||
*/
|
||||
|
||||
#include "audsrv.h"
|
||||
void * MixS8(MixerEngine * mixer,
|
||||
int buffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*Filter Should ensure that sample data is divided equally on both side of Analog-Zero Sample value[0 for signed data,maxattainablevalue/2 for unsigned]*/
|
||||
|
||||
void * MixS16(MixerEngine * mixer,
|
||||
int buffer)
|
||||
{
|
||||
int length=0;
|
||||
short minsamplevalue,maxsamplevalue;
|
||||
float coefficient = 1.0;
|
||||
int streamcount = 0,i;
|
||||
PSHORT localsinkbuf,localsrcbuf;
|
||||
ServerStream * stream = mixer->serverstreamlist;
|
||||
|
||||
/*TODOAssert(mixer->serverstreamlist == NULL)*/
|
||||
|
||||
/*Find the Longest Buffer within all ServerStreams*/
|
||||
length = stream->length_filtered;
|
||||
while(stream->next != NULL)
|
||||
{
|
||||
if(stream->length_filtered > length && stream->state == 2 )
|
||||
length = stream->length_filtered;
|
||||
stream = stream->next;
|
||||
}
|
||||
|
||||
/*Allocate MasterBuffer*/
|
||||
mixer->masterbuf[buffer] = HeapAlloc(GetProcessHeap(), 0, length);
|
||||
localsinkbuf = mixer->masterbuf[buffer];
|
||||
mixer->bytes_to_play = length;
|
||||
|
||||
/*Perform Actual Mixing*/
|
||||
stream = mixer->serverstreamlist;
|
||||
minsamplevalue = 0;
|
||||
maxsamplevalue = 0;
|
||||
|
||||
while(stream != NULL)
|
||||
{
|
||||
EnterCriticalSection(&(stream->CriticalSection));
|
||||
|
||||
if(stream->state == 2 && *(short *) stream->minsamplevalue != 0 && *(short *) stream->minsamplevalue != 0)
|
||||
{
|
||||
coefficient = 1.0;
|
||||
|
||||
localsrcbuf = stream->filteredbuf;
|
||||
|
||||
if(minsamplevalue == 0)
|
||||
minsamplevalue = *(short *) stream->minsamplevalue;
|
||||
|
||||
if(maxsamplevalue == 0)
|
||||
maxsamplevalue = *(short *) stream->maxsamplevalue;
|
||||
|
||||
if( *(short *)stream->maxsamplevalue != maxsamplevalue ||
|
||||
*(short *)stream->minsamplevalue != minsamplevalue )
|
||||
{
|
||||
if( (float) maxsamplevalue / (float)*(short *)stream->maxsamplevalue <
|
||||
(float) minsamplevalue / (float)*(short *)stream->minsamplevalue )
|
||||
coefficient = (float) maxsamplevalue / (float)*(short *)stream->maxsamplevalue;
|
||||
else
|
||||
coefficient = (float) minsamplevalue / (float)*(short *)stream->minsamplevalue;
|
||||
}
|
||||
|
||||
for(i=0;i<stream->length_filtered/sizeof(short);i++)
|
||||
{
|
||||
localsinkbuf[i] = (short) (( (localsinkbuf[i] * streamcount) + ((short)((float) localsrcbuf[i] ) * coefficient) ) / (streamcount +1));
|
||||
}
|
||||
|
||||
stream->state = 0;
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
stream->filteredbuf);
|
||||
|
||||
SetEvent(stream->stream_played_event);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&(stream->CriticalSection));
|
||||
|
||||
streamcount++;
|
||||
stream = stream->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
void * MixS32(MixerEngine * mixer,
|
||||
int buffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
void * MixS64(MixerEngine * mixer,
|
||||
int buffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
void * MixU8(MixerEngine * mixer,
|
||||
int buffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
void * MixU16(MixerEngine * mixer,
|
||||
int buffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
void * MixU32(MixerEngine * mixer,
|
||||
int buffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
void * MixU64(MixerEngine * mixer,
|
||||
int buffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
void * MixFL32(MixerEngine * mixer,
|
||||
int buffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
void * MixFL64(MixerEngine * mixer,
|
||||
int buffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
105
base/services/audsrv/rpc.c
Normal file
105
base/services/audsrv/rpc.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* PROJECT: ReactOS kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: services/audsrv/rpc.c
|
||||
* PURPOSE: Audio Server
|
||||
* COPYRIGHT: Copyright 2011 Neeraj Yadav
|
||||
*/
|
||||
|
||||
#include "audsrv.h"
|
||||
|
||||
LIST_ENTRY LogHandleListHead;
|
||||
|
||||
/*RPC Listener Thread,Returns values less than 0 in failures*/
|
||||
DWORD WINAPI RunRPCThread(LPVOID lpParameter)
|
||||
{
|
||||
RPC_STATUS Status;
|
||||
|
||||
InitializeListHead(&LogHandleListHead);
|
||||
|
||||
Status = RpcServerUseProtseqEp(L"ncacn_np",
|
||||
20,
|
||||
L"\\pipe\\audsrv",
|
||||
NULL);
|
||||
if (Status != RPC_S_OK)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
Status = RpcServerRegisterIfEx(audsrv_v0_0_s_ifspec,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
|
||||
NULL );
|
||||
if (Status != RPC_S_OK)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
Status = RpcServerListen(1,
|
||||
20,
|
||||
FALSE);
|
||||
|
||||
if (Status != RPC_S_OK)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************RPC Functions**********************************/
|
||||
|
||||
long AUDInitStream( IN RPC_BINDING_HANDLE hBinding,
|
||||
LONG frequency,
|
||||
int channels,
|
||||
int bitspersample,
|
||||
int datatype,
|
||||
ULONG channelmask,
|
||||
int volume,
|
||||
int mute,
|
||||
float balance )
|
||||
{
|
||||
long stream;
|
||||
|
||||
stream = AddStream(frequency,
|
||||
channels,
|
||||
bitspersample,
|
||||
datatype,
|
||||
channelmask,
|
||||
volume,
|
||||
mute,
|
||||
balance);
|
||||
|
||||
if( stream != 0 )
|
||||
{
|
||||
/*ERROR*/
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
long AUDPlayBuffer( IN RPC_BINDING_HANDLE hBinding,
|
||||
LONG streamid,
|
||||
LONG length,
|
||||
char* buffer)
|
||||
{
|
||||
WriteBuffer(streamid,length,buffer);
|
||||
return 0;
|
||||
}
|
||||
/*************************************************************************/
|
||||
void __RPC_FAR *__RPC_USER midl_user_allocate(SIZE_T len)
|
||||
{
|
||||
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
|
||||
}
|
||||
|
||||
|
||||
void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, ptr);
|
||||
}
|
||||
|
||||
|
||||
void __RPC_USER IELF_HANDLE_rundown(AUDSRV_HANDLE LogHandle)
|
||||
{
|
||||
}
|
232
base/services/audsrv/stream.c
Normal file
232
base/services/audsrv/stream.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* PROJECT: ReactOS kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: services/stream.c
|
||||
* PURPOSE: Audio Server
|
||||
* COPYRIGHT: Copyright 2011 Neeraj Yadav
|
||||
*/
|
||||
|
||||
#include "audsrv.h"
|
||||
|
||||
long GetNewStreamID()
|
||||
{
|
||||
long streamid= pengine->streamidpool;
|
||||
pengine->streamidpool += 1;
|
||||
return streamid;
|
||||
}
|
||||
BOOL FilterAudio(LPVOID param)
|
||||
{
|
||||
ServerStream * localstream = (ServerStream *) param;
|
||||
|
||||
EnterCriticalSection(&(localstream->CriticalSection));
|
||||
|
||||
if(localstream->state == 1)
|
||||
{
|
||||
/*Fake Filter,Simply gives the genuine buffer as filtered buffer*/
|
||||
/*minsamplevalue and maxsamplevalue must be calculated during filtering*/
|
||||
/*Filter must ensure that all the samples are distributed evenly about 0 in case of signed samples*/
|
||||
localstream->length_filtered = localstream->length_genuine;
|
||||
localstream->filteredbuf = HeapAlloc(GetProcessHeap(),
|
||||
0,
|
||||
localstream->length_filtered);
|
||||
|
||||
memcpy(localstream->filteredbuf,localstream->genuinebuf,localstream->length_filtered);
|
||||
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
localstream->genuinebuf);
|
||||
|
||||
*((int *)localstream->minsamplevalue) = -32766;
|
||||
*((int *)localstream->maxsamplevalue) = 32766;
|
||||
|
||||
localstream->state = 2;
|
||||
|
||||
LeaveCriticalSection(&(localstream->CriticalSection));
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LeaveCriticalSection(&(localstream->CriticalSection));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI RunStreamThread(LPVOID param)
|
||||
{
|
||||
ServerStream * localstream = (ServerStream *) param;
|
||||
|
||||
SetEvent(localstream->threadready);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
if(FilterAudio(param) == TRUE )
|
||||
WaitForSingleObject(localstream->stream_played_event,INFINITE);
|
||||
}
|
||||
/*Clean Stream's data*/
|
||||
}
|
||||
|
||||
long AddStream(LONG frequency,
|
||||
int channels,
|
||||
int bitspersample,
|
||||
int datatype,
|
||||
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*/
|
||||
|
||||
if(datatype==0 || datatype==1 || datatype==2)
|
||||
newstream->datatype=datatype;
|
||||
else
|
||||
goto error;
|
||||
|
||||
if ((datatype==0 && (bitspersample == 8 || bitspersample == 16 || bitspersample == 32 || bitspersample == 64 )) ||
|
||||
(datatype==1 && (bitspersample == 8 || bitspersample == 16 || bitspersample == 32 || bitspersample == 64)) ||
|
||||
(datatype==2 && (bitspersample == 32 || bitspersample == 64)) )
|
||||
newstream->bitspersample = bitspersample; /*TODO bitspersample validation*/
|
||||
else
|
||||
goto error;
|
||||
|
||||
newstream->channels = channels; /*TODO validation*/
|
||||
newstream->channelmask = channelmask; /*TODO validation*/
|
||||
|
||||
newstream->state = 0;
|
||||
newstream->length_genuine = 0;
|
||||
newstream->genuinebuf = NULL;
|
||||
newstream->length_filtered = 0;
|
||||
newstream->filteredbuf = NULL;
|
||||
newstream->minsamplevalue = HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
bitspersample/8);
|
||||
|
||||
newstream->maxsamplevalue = HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
bitspersample/8);
|
||||
|
||||
newstream->next = NULL;
|
||||
|
||||
newstream->stream_played_event = CreateEvent(NULL,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
newstream->buffer_write_event = CreateEvent(NULL,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
newstream->threadready = CreateEvent(NULL,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
if(newstream->stream_played_event == NULL || newstream->threadready == NULL)
|
||||
goto error;
|
||||
|
||||
newstream->streamid=GetNewStreamID();
|
||||
|
||||
if (!InitializeCriticalSectionAndSpinCount(&(newstream->CriticalSection),
|
||||
0x00000400) )
|
||||
goto error;
|
||||
|
||||
newstream->thread=CreateThread(NULL,
|
||||
0,
|
||||
RunStreamThread,
|
||||
newstream,
|
||||
0,
|
||||
&dwID);
|
||||
|
||||
if(newstream->thread == NULL)
|
||||
goto error;
|
||||
|
||||
WaitForSingleObject(newstream->threadready,
|
||||
INFINITE);
|
||||
|
||||
|
||||
|
||||
if(localstream == NULL)
|
||||
{
|
||||
pengine->serverstreamlist = newstream;
|
||||
pengine->masterfreq=frequency;
|
||||
pengine->masterchannels=channels;
|
||||
pengine->masterchannelmask=channelmask;
|
||||
pengine->masterbitspersample=bitspersample;
|
||||
pengine->masterdatatype = datatype;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(localstream->next != NULL)
|
||||
localstream = localstream->next;
|
||||
localstream->next = newstream;
|
||||
}
|
||||
SetEvent(pengine->newStreamEvent);
|
||||
return newstream->streamid;
|
||||
|
||||
error:
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
newstream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
long WriteBuffer(LONG streamid,
|
||||
LONG length,
|
||||
char * buffer)
|
||||
{
|
||||
ServerStream * localstream = pengine->serverstreamlist;
|
||||
while(localstream!=NULL)
|
||||
{
|
||||
if(localstream->streamid == streamid) break;
|
||||
localstream = localstream->next;
|
||||
}
|
||||
|
||||
if(localstream == NULL)
|
||||
return -1;
|
||||
|
||||
EnterCriticalSection(&(localstream->CriticalSection));
|
||||
|
||||
if(localstream->state == 0)
|
||||
{
|
||||
localstream->length_genuine = length;
|
||||
localstream->genuinebuf = (PSHORT) HeapAlloc(GetProcessHeap(),
|
||||
0,
|
||||
length);
|
||||
|
||||
memcpy(localstream->genuinebuf,buffer,length);
|
||||
|
||||
localstream->state = 1;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&(localstream->CriticalSection));
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*Dont forget to clean ServerStream's minsamplevalue and maxsamplevalue while removing the stream*/
|
||||
/*Delete Critical Section while cleaning Stream*/
|
@@ -7,6 +7,7 @@ add_subdirectory(advapi32)
|
||||
add_subdirectory(advpack)
|
||||
add_subdirectory(atl)
|
||||
add_subdirectory(authz)
|
||||
add_subdirectory(audsrvapi)
|
||||
add_subdirectory(avicap32)
|
||||
add_subdirectory(avifil32)
|
||||
add_subdirectory(batt)
|
||||
|
22
dll/win32/audsrvapi/CMakeLists.txt
Normal file
22
dll/win32/audsrvapi/CMakeLists.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
set_unicode()
|
||||
include_directories(${REACTOS_BINARY_DIR}/include/reactos/idl)
|
||||
include_directories(${REACTOS_SOURCE_DIR}/include/reactos/libs)
|
||||
|
||||
spec2def(audsrvapi.dll audsrvapi.spec)
|
||||
|
||||
list(APPEND SOURCE
|
||||
dllmain.c
|
||||
audsrvapi.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/audsrvapi.def)
|
||||
|
||||
add_library(audsrvapi SHARED ${SOURCE})
|
||||
set_module_type(audsrvapi win32dll)
|
||||
|
||||
target_link_libraries(audsrvapi audsrvrpc uuid wine ${PSEH_LIB})
|
||||
|
||||
|
||||
add_pch(audsrv ${CMAKE_CURRENT_SOURCE_DIR}/audsrv.h ${SOURCE})
|
||||
|
||||
add_importlibs(audsrvapi rpcrt4 ole32 oleaut32 user32 advapi32 msvcrt kernel32 ntdll)
|
||||
add_cab_target(audsrvapi 1)
|
||||
add_importlib_target(audsrvapi.spec)
|
203
dll/win32/audsrvapi/audsrvapi.c
Normal file
203
dll/win32/audsrvapi/audsrvapi.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* PROJECT: ReactOS kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: dll\win32\audsrvapi\audsrvapi.c
|
||||
* PURPOSE: Audio Server
|
||||
* COPYRIGHT: Copyright 2011 Neeraj Yadav
|
||||
|
||||
*/
|
||||
|
||||
#include "audsrvapi.h"
|
||||
#include <math.h>
|
||||
|
||||
/*All the wrappers for Remote Function should be here*/
|
||||
int status = 0;
|
||||
/*Initialize an audio stream
|
||||
*Return -1 if callbacks are NULL pointers
|
||||
*/
|
||||
int
|
||||
WINAPI
|
||||
InitStream (ClientStream * clientstream,
|
||||
LONG frequency,
|
||||
int channels,
|
||||
int bitspersample,
|
||||
int datatype,
|
||||
ULONG channelmask,
|
||||
int volume,
|
||||
int mute,
|
||||
float balance)
|
||||
{
|
||||
long 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*/
|
||||
|
||||
RpcTryExcept
|
||||
{
|
||||
streamid = AUDInitStream (audsrv_v0_0_c_ifspec,
|
||||
frequency,
|
||||
channels,
|
||||
bitspersample,
|
||||
datatype,
|
||||
channelmask,
|
||||
volume,
|
||||
mute,
|
||||
balance);
|
||||
|
||||
if(streamid != 0)
|
||||
clientstream->stream = streamid;
|
||||
}
|
||||
RpcExcept(1)
|
||||
{
|
||||
status = RpcExceptionCode();
|
||||
}
|
||||
RpcEndExcept
|
||||
|
||||
/*Analyse the return by the function*/
|
||||
/*Currently Suppose the return is 0 and a valid streamid is returned*/
|
||||
clientstream->ClientEventPool[0]=CreateEvent(NULL,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
clientstream->dead = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
WINAPI
|
||||
PlayAudio ( ClientStream * clientstream )
|
||||
{
|
||||
/******************************************/
|
||||
int i =0;
|
||||
PSHORT tempbuf;
|
||||
/******************************************/
|
||||
/*This is an ActiveScheduler*/
|
||||
clientstream->callbacks.OpenComplete(0);
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
while(WaitForSingleObject(clientstream->ClientEventPool[0],
|
||||
100)!=0)
|
||||
{
|
||||
if(clientstream->dead)
|
||||
break;
|
||||
}
|
||||
|
||||
if(clientstream->dead)
|
||||
break;
|
||||
|
||||
/*Check Connection Status If not connected call Connect()*/
|
||||
/*If connected Properly call the remote audsrv_play() function,This will be a blocking call, placing a dummy wait function here is a good idea.*/
|
||||
tempbuf = (PSHORT) HeapAlloc(GetProcessHeap(),
|
||||
0,
|
||||
44100);
|
||||
|
||||
for(i = 0;i<22050;i+=2)
|
||||
{
|
||||
tempbuf[i+1] = tempbuf[i] = 0x7FFF * sin( i * 500 * 3.14 / clientstream->wavefreq);
|
||||
}
|
||||
|
||||
RpcTryExcept
|
||||
{
|
||||
AUDPlayBuffer (audsrv_v0_0_c_ifspec,
|
||||
clientstream->stream,
|
||||
44100,
|
||||
(char *)tempbuf);
|
||||
}
|
||||
RpcExcept(1)
|
||||
{
|
||||
status = RpcExceptionCode();
|
||||
}
|
||||
RpcEndExcept
|
||||
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
tempbuf);
|
||||
|
||||
clientstream->callbacks.BufferCopied(0);
|
||||
}
|
||||
clientstream->callbacks.PlayComplete(0);
|
||||
|
||||
/*Audio Thread Ended*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
WINAPI
|
||||
StopAudio (ClientStream * clientstream )
|
||||
{
|
||||
/*Server Side termination is remaining*/
|
||||
/*If connected Properly call the remote audsrv_stop() function*/
|
||||
clientstream->dead = 1; /*Client Side termination*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
WINAPI
|
||||
Volume(ClientStream * clientstream,
|
||||
int * volume )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
WINAPI
|
||||
SetVolume(ClientStream * clientstream ,
|
||||
const int newvolume)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
WINAPI
|
||||
Write(ClientStream * clientstream ,
|
||||
const char * aData)
|
||||
{
|
||||
if(clientstream->dead)
|
||||
return -1;
|
||||
|
||||
SetEvent(clientstream->ClientEventPool[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
WINAPI
|
||||
SetBalance(ClientStream * clientstream ,
|
||||
float balance)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
WINAPI
|
||||
GetBalance(ClientStream * clientstream ,
|
||||
float * balance)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************/
|
||||
/* MIDL allocate and free */
|
||||
/******************************************************/
|
||||
|
||||
void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
|
||||
{
|
||||
return(malloc(len));
|
||||
}
|
||||
|
||||
void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
11
dll/win32/audsrvapi/audsrvapi.h
Normal file
11
dll/win32/audsrvapi/audsrvapi.h
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* PROJECT: ReactOS kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: dll\win32\audsrvapi\audsrvapi.h
|
||||
* PURPOSE: Audio Server
|
||||
* COPYRIGHT: Copyright 2011 Neeraj Yadav
|
||||
|
||||
*/
|
||||
|
||||
#include "audsrvrpc_c.h"
|
||||
#include <audsrv/audsrvapi.h>
|
8
dll/win32/audsrvapi/audsrvapi.spec
Normal file
8
dll/win32/audsrvapi/audsrvapi.spec
Normal file
@@ -0,0 +1,8 @@
|
||||
@ stdcall InitStream (ptr long long long long long long long long)
|
||||
@ stdcall PlayAudio ( ptr);
|
||||
@ stdcall StopAudio (ptr );
|
||||
@ stdcall Volume(ptr ptr );
|
||||
@ stdcall SetVolume(ptr long);
|
||||
@ stdcall Write(ptr ptr);
|
||||
@ stdcall SetBalance(ptr long);
|
||||
@ stdcall GetBalance(ptr ptr);
|
57
dll/win32/audsrvapi/dllmain.c
Normal file
57
dll/win32/audsrvapi/dllmain.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* PROJECT: ReactOS kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: dll\win32\audsrvapi\dllmain.c
|
||||
* PURPOSE: Audio Server
|
||||
* COPYRIGHT: Copyright 2011 Neeraj Yadav
|
||||
|
||||
*/
|
||||
|
||||
#include "audsrvapi.h"
|
||||
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
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)
|
||||
{
|
||||
/*Connection Problem*/
|
||||
}
|
||||
|
||||
status = RpcStringFree(&pszStringBinding);
|
||||
|
||||
if (status)
|
||||
{
|
||||
/*problem*/
|
||||
}
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
status = RpcBindingFree(audsrv_v0_0_c_ifspec);
|
||||
if (status == RPC_S_INVALID_BINDING)
|
||||
OutputDebugStringA("Error Closing RPC Connection\n");
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
@@ -1,3 +1,4 @@
|
||||
|
||||
add_subdirectory(audio_test)
|
||||
add_subdirectory(audclient)
|
||||
add_subdirectory(portcls)
|
||||
|
11
drivers/wdm/audio/backpln/audclient/CMakeLists.txt
Normal file
11
drivers/wdm/audio/backpln/audclient/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
set_unicode(audclient yes)
|
||||
|
||||
|
||||
|
||||
add_executable(audclient
|
||||
audclient.c)
|
||||
include_directories(${REACTOS_SOURCE_DIR}/include/reactos/libs/audsrv)
|
||||
set_module_type(audclient win32cui)
|
||||
add_importlibs(audclient audsrvapi advapi32 user32 ksuser setupapi msvcrt kernel32)
|
||||
add_cab_target(audclient 1)
|
||||
add_dependencies(audclient audsrvapi)
|
94
drivers/wdm/audio/backpln/audclient/audclient.c
Normal file
94
drivers/wdm/audio/backpln/audclient/audclient.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* PROJECT: ReactOS kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: services/audsrv.c
|
||||
* PURPOSE: Audio Server
|
||||
* COPYRIGHT: Copyright 2011 Neeraj Yadav
|
||||
|
||||
*/
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
#define _KSDDK_
|
||||
|
||||
#include <audsrvapi.h>
|
||||
#include <stdio.h>
|
||||
#include <debug.h>
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
|
||||
void OpenComplete (int error );
|
||||
void BufferCopied (int error );
|
||||
void PlayComplete (int error );
|
||||
|
||||
ClientStream clientstream = {0,
|
||||
0,
|
||||
{NULL},
|
||||
{OpenComplete,
|
||||
BufferCopied,
|
||||
PlayComplete}
|
||||
};
|
||||
|
||||
DWORD WINAPI RunAudioThread(LPVOID param)
|
||||
{
|
||||
ClientStream * localstream = (ClientStream *) param;
|
||||
PlayAudio(localstream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
void OpenComplete (int error )
|
||||
{
|
||||
/*Copy First Buffer and write*/
|
||||
Write(&clientstream,
|
||||
"HELLO_RANDOM_STRING");
|
||||
}
|
||||
void BufferCopied (int error )
|
||||
{
|
||||
Write(&clientstream,
|
||||
"HELLO_RANDOM_STRING");
|
||||
}
|
||||
void PlayComplete (int error )
|
||||
{
|
||||
}
|
||||
int
|
||||
__cdecl
|
||||
wmain(int argc,
|
||||
char* argv[])
|
||||
{
|
||||
int error;
|
||||
DWORD dwID;
|
||||
HANDLE audiothread = NULL;
|
||||
char input='\0';
|
||||
printf("ReactOS Audio Mixer Sample Client.Enter 'a' to Stop.\nPlease Enter the frequency of the sinusoidal wave [Hz] : ");
|
||||
scanf("%ld",&(clientstream.wavefreq));
|
||||
|
||||
/*[out]HANDLE * streamhandle,[in] long frequency,[in] int number of channels,[in] int bitspersample,[in]ULONG channelmask,[in] int volume,[in] int mute,[in] float balance*/
|
||||
error = InitStream ( &clientstream ,
|
||||
44100 ,
|
||||
2 ,
|
||||
16 ,
|
||||
0,
|
||||
KSAUDIO_SPEAKER_STEREO ,
|
||||
1000 ,
|
||||
0,
|
||||
0.0 );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
audiothread = CreateThread(NULL,0,RunAudioThread,&clientstream,0,&dwID);
|
||||
}
|
||||
|
||||
while ( input != 'a' )
|
||||
scanf("%c",&input);
|
||||
|
||||
StopAudio(&clientstream);
|
||||
WaitForSingleObject(audiothread,INFINITE);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
@@ -42,7 +42,8 @@ TestKs()
|
||||
SP_DEVINFO_DATA DeviceData;
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA DetailData;
|
||||
HDEVINFO DeviceHandle;
|
||||
PKSDATAFORMAT_WAVEFORMATEX DataFormat;
|
||||
PKSDATAFORMAT DataFormat;
|
||||
PWAVEFORMATEXTENSIBLE WaveFormat;
|
||||
PKSPIN_CONNECT PinConnect;
|
||||
PKSSTREAM_HEADER Packet;
|
||||
PKSPROPERTY Property;
|
||||
@@ -61,7 +62,7 @@ TestKs()
|
||||
DeviceHandle = SetupDiGetClassDevs(&CategoryGuid,
|
||||
NULL,
|
||||
NULL,
|
||||
DIGCF_DEVICEINTERFACE); //DIGCF_PRESENT
|
||||
DIGCF_DEVICEINTERFACE |DIGCF_PRESENT);
|
||||
|
||||
printf("DeviceHandle %p\n", DeviceHandle);
|
||||
|
||||
@@ -83,7 +84,7 @@ TestKs()
|
||||
//
|
||||
Length = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH * sizeof(WCHAR);
|
||||
DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)HeapAlloc(GetProcessHeap(),
|
||||
0,
|
||||
HEAP_ZERO_MEMORY,
|
||||
Length);
|
||||
DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
||||
DeviceData.cbSize = sizeof(DeviceData);
|
||||
@@ -118,14 +119,15 @@ TestKs()
|
||||
//
|
||||
// Allocate a KS Pin Connection Request Structure
|
||||
//
|
||||
Length = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX);
|
||||
printf("Length %ld KSPIN %u DATAFORMAT %u\n", Length, sizeof(KSPIN_CONNECT), sizeof(KSDATAFORMAT_WAVEFORMATEX));
|
||||
PinConnect = (PKSPIN_CONNECT)HeapAlloc(GetProcessHeap(), 0, Length);
|
||||
DataFormat = (PKSDATAFORMAT_WAVEFORMATEX)(PinConnect + 1);
|
||||
Length = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX) + sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
|
||||
PinConnect = (PKSPIN_CONNECT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Length);
|
||||
DataFormat = (PKSDATAFORMAT)(PinConnect + 1);
|
||||
WaveFormat = (PWAVEFORMATEXTENSIBLE)(DataFormat + 1);
|
||||
|
||||
//
|
||||
// Setup the KS Pin Data
|
||||
//
|
||||
|
||||
PinConnect->Interface.Set = KSINTERFACESETID_Standard;
|
||||
PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
|
||||
PinConnect->Interface.Flags = 0;
|
||||
@@ -140,23 +142,30 @@ TestKs()
|
||||
//
|
||||
// Setup the KS Data Format Information
|
||||
//
|
||||
DataFormat->WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
DataFormat->WaveFormatEx.nChannels = 2;
|
||||
DataFormat->WaveFormatEx.nSamplesPerSec = 48000;
|
||||
DataFormat->WaveFormatEx.nBlockAlign = 4;
|
||||
DataFormat->WaveFormatEx.nAvgBytesPerSec = 48000 * 4;
|
||||
DataFormat->WaveFormatEx.wBitsPerSample = 16;
|
||||
DataFormat->WaveFormatEx.cbSize = 0;
|
||||
DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) +
|
||||
sizeof(WAVEFORMATEX);
|
||||
DataFormat->DataFormat.Flags = KSDATAFORMAT_ATTRIBUTES;
|
||||
DataFormat->DataFormat.Reserved = 0;
|
||||
DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
|
||||
DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
||||
DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
|
||||
DataFormat->DataFormat.SampleSize = 4;
|
||||
printf("DataFormat %p %p\n", DataFormat,(PVOID)((((ULONG_PTR)DataFormat + 7)) & ~7));
|
||||
|
||||
//
|
||||
DataFormat->Flags = 0;
|
||||
DataFormat->Reserved = 0;
|
||||
DataFormat->MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
|
||||
DataFormat->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
||||
DataFormat->Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
|
||||
DataFormat->SampleSize = 4;
|
||||
DataFormat->FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEXTENSIBLE);
|
||||
|
||||
WaveFormat->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
WaveFormat->Format.nChannels = 2;
|
||||
WaveFormat->Format.nSamplesPerSec = 48000;
|
||||
WaveFormat->Format.nBlockAlign = 4;
|
||||
WaveFormat->Format.nAvgBytesPerSec = WaveFormat->Format.nSamplesPerSec * WaveFormat->Format.nBlockAlign;
|
||||
WaveFormat->Format.wBitsPerSample = 16;
|
||||
WaveFormat->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
|
||||
WaveFormat->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
|
||||
WaveFormat->Samples.wValidBitsPerSample = 16;
|
||||
WaveFormat->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
||||
|
||||
printf("Creating pin\n");
|
||||
|
||||
//
|
||||
// Create the pin
|
||||
//
|
||||
Status = KsCreatePin(FilterHandle, PinConnect, GENERIC_WRITE, &PinHandle);
|
||||
|
@@ -348,6 +348,25 @@ typedef struct {
|
||||
WAVEFORMATEX WaveFormatEx;
|
||||
} KSDATAFORMAT_WAVEFORMATEX, *PKSDATAFORMAT_WAVEFORMATEX;
|
||||
|
||||
#ifndef _WAVEFORMATEXTENSIBLE_
|
||||
#define _WAVEFORMATEXTENSIBLE_
|
||||
typedef struct {
|
||||
WAVEFORMATEX Format;
|
||||
union
|
||||
{
|
||||
WORD wValidBitsPerSample;
|
||||
WORD wSamplesPerBlock;
|
||||
WORD wReserved;
|
||||
}Samples;
|
||||
DWORD dwChannelMask;
|
||||
GUID SubFormat;
|
||||
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
|
||||
#endif
|
||||
|
||||
#if !defined(WAVE_FORMAT_EXTENSIBLE)
|
||||
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
ULONG Flags;
|
||||
ULONG Control;
|
||||
@@ -734,4 +753,50 @@ typedef struct
|
||||
ULONG ChannelMask;
|
||||
} KSDATARANGE_MUSIC, *PKSDATARANGE_MUSIC;
|
||||
|
||||
#ifndef _SPEAKER_POSITIONS_
|
||||
#define _SPEAKER_POSITIONS_
|
||||
|
||||
|
||||
#define SPEAKER_FRONT_LEFT 0x1
|
||||
#define SPEAKER_FRONT_RIGHT 0x2
|
||||
#define SPEAKER_FRONT_CENTER 0x4
|
||||
#define SPEAKER_LOW_FREQUENCY 0x8
|
||||
#define SPEAKER_BACK_LEFT 0x10
|
||||
#define SPEAKER_BACK_RIGHT 0x20
|
||||
#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
|
||||
#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
|
||||
#define SPEAKER_BACK_CENTER 0x100
|
||||
#define SPEAKER_SIDE_LEFT 0x200
|
||||
#define SPEAKER_SIDE_RIGHT 0x400
|
||||
#define SPEAKER_TOP_CENTER 0x800
|
||||
#define SPEAKER_TOP_FRONT_LEFT 0x1000
|
||||
#define SPEAKER_TOP_FRONT_CENTER 0x2000
|
||||
#define SPEAKER_TOP_FRONT_RIGHT 0x4000
|
||||
#define SPEAKER_TOP_BACK_LEFT 0x8000
|
||||
#define SPEAKER_TOP_BACK_CENTER 0x10000
|
||||
#define SPEAKER_TOP_BACK_RIGHT 0x20000
|
||||
|
||||
#define SPEAKER_RESERVED 0x7FFC0000
|
||||
#define SPEAKER_ALL 0x80000000
|
||||
|
||||
#endif
|
||||
|
||||
#if (NTDDI_VERSION >= NTDDI_WINXP)
|
||||
#define KSAUDIO_SPEAKER_DIRECTOUT 0
|
||||
#endif
|
||||
|
||||
#define KSAUDIO_SPEAKER_MONO (SPEAKER_FRONT_CENTER)
|
||||
#define KSAUDIO_SPEAKER_STEREO (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)
|
||||
#define KSAUDIO_SPEAKER_QUAD (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \
|
||||
SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)
|
||||
#define KSAUDIO_SPEAKER_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \
|
||||
SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER)
|
||||
#define KSAUDIO_SPEAKER_5POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \
|
||||
SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | \
|
||||
SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)
|
||||
#define KSAUDIO_SPEAKER_7POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \
|
||||
SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | \
|
||||
SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | \
|
||||
SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER)
|
||||
|
||||
#endif
|
||||
|
@@ -2,6 +2,7 @@
|
||||
include_directories(.)
|
||||
|
||||
add_rpc_library(eventlogrpc eventlogrpc.idl)
|
||||
add_rpc_library(audsrvrpc audsrvrpc.idl)
|
||||
add_rpc_library(lsarpc lsa.idl)
|
||||
add_rpc_library(svcctlrpc svcctl.idl)
|
||||
add_rpc_library(wlansvcrpc wlansvc.idl)
|
||||
|
6
include/reactos/idl/audsrvrpc.acf
Normal file
6
include/reactos/idl/audsrvrpc.acf
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
implicit_handle(handle_t bindhandle), strict_context_handle
|
||||
]
|
||||
interface audsrv
|
||||
{
|
||||
}
|
44
include/reactos/idl/audsrvrpc.idl
Normal file
44
include/reactos/idl/audsrvrpc.idl
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Event Log RPC interface definition
|
||||
*/
|
||||
|
||||
#include <wtypes.idl>
|
||||
|
||||
|
||||
cpp_quote("#if !defined(__AUDSRV_H__) ")
|
||||
typedef long NTSTATUS;
|
||||
cpp_quote("#endif")
|
||||
|
||||
typedef [range(0, 0x0007FFFF)] unsigned long RULONG;
|
||||
typedef struct _RPC_STRING {
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
[size_is(MaximumLength), length_is(Length)] LPSTR Buffer;
|
||||
} RPC_STRING, *PRPC_STRING;
|
||||
|
||||
typedef [context_handle] PVOID AUDSRV_HANDLE;
|
||||
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;
|
||||
DWORD UniqueThread;
|
||||
} RPC_CLIENT_ID, *PRPC_CLIENT_ID;
|
||||
|
||||
[
|
||||
uuid(F4CB5F3D-84CC-4BFF-BB16-1397896E3A38),
|
||||
version(0.0),
|
||||
pointer_default(unique)
|
||||
#ifndef __midl
|
||||
,explicit_handle
|
||||
#endif
|
||||
]
|
||||
|
||||
interface audsrv
|
||||
{
|
||||
|
||||
long AUDInitStream([in] handle_t h1,[in]LONG frequency,[in]int channels,[in]int bitspersample,[in]int datatype,[in] ULONG channelmask,[in]int volume,[in]int mute,[in]float balance);
|
||||
long AUDPlayBuffer([in] handle_t h1,[in]LONG streamid,[in]LONG length,[in, size_is(length)]char* buffer);
|
||||
}
|
72
include/reactos/libs/audsrv/audsrvapi.h
Normal file
72
include/reactos/libs/audsrv/audsrvapi.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef _AUDSRVAPI_H
|
||||
#define _AUDSRVAPI_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <ks.h>
|
||||
#include <ksmedia.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/********************Structures*********************/
|
||||
|
||||
typedef struct CallBacks
|
||||
{
|
||||
void (*OpenComplete) (int error );
|
||||
void (*BufferCopied) (int error );
|
||||
void (*PlayComplete) (int error );
|
||||
} CallBacks;
|
||||
|
||||
typedef struct ClientStream
|
||||
{
|
||||
long stream;
|
||||
int dead;
|
||||
HANDLE ClientEventPool[1];
|
||||
struct CallBacks callbacks;
|
||||
|
||||
/*Just for the time being when we dont have any audio source*/
|
||||
long wavefreq;
|
||||
} ClientStream;
|
||||
|
||||
/********************API Functions******************/
|
||||
int
|
||||
WINAPI
|
||||
InitStream (ClientStream * clientstream,
|
||||
LONG frequency,
|
||||
int channels,
|
||||
int bitspersample,
|
||||
int datatype, /*0=signed int,1=unsigned int,2=float*/
|
||||
ULONG channelmask,
|
||||
int volume,
|
||||
int mute,
|
||||
float balance);
|
||||
|
||||
int
|
||||
WINAPI
|
||||
PlayAudio ( ClientStream * clientstream);
|
||||
|
||||
int
|
||||
WINAPI
|
||||
StopAudio (ClientStream * clientstream );
|
||||
|
||||
int
|
||||
WINAPI
|
||||
Volume(ClientStream * clientstream,
|
||||
int * volume );
|
||||
|
||||
int
|
||||
WINAPI
|
||||
SetVolume(ClientStream * clientstream ,
|
||||
const int newvolume);
|
||||
int
|
||||
WINAPI
|
||||
Write(ClientStream * clientstream ,
|
||||
const char * aData);
|
||||
|
||||
int
|
||||
WINAPI
|
||||
SetBalance(ClientStream * clientstream ,
|
||||
float balance);
|
||||
int
|
||||
WINAPI
|
||||
GetBalance(ClientStream * clientstream ,
|
||||
float * balance);
|
||||
#endif
|
Reference in New Issue
Block a user