diff --git a/reactos/lib/drivers/sound/mmixer/mixer.c b/reactos/lib/drivers/sound/mmixer/mixer.c new file mode 100644 index 00000000000..38c23c50445 --- /dev/null +++ b/reactos/lib/drivers/sound/mmixer/mixer.c @@ -0,0 +1,376 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Kernel Streaming + * FILE: lib/drivers/sound/mmixer/mmixer.c + * PURPOSE: Mixer Handling Functions + * PROGRAMMER: Johannes Anderwald + */ + + + +#include "priv.h" + +MIXER_STATUS +MMixerVerifyContext( + IN PMIXER_CONTEXT MixerContext) +{ + if (MixerContext->SizeOfStruct != sizeof(MIXER_CONTEXT)) + return MM_STATUS_INVALID_PARAMETER; + + if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free) + return MM_STATUS_INVALID_PARAMETER; + + if (!MixerContext->MixerContext) + return MM_STATUS_INVALID_PARAMETER; + + return MM_STATUS_SUCCESS; +} + +VOID +MMixerFreeMixerInfo( + IN PMIXER_CONTEXT MixerContext, + IN LPMIXER_INFO MixerInfo) +{ + //UNIMPLEMENTED + // FIXME + // free all lines + + MixerContext->Free((PVOID)MixerInfo); +} + +ULONG +MMixerGetFilterPinCount( + IN PMIXER_CONTEXT MixerContext, + IN HANDLE hMixer) +{ + KSPROPERTY Pin; + MIXER_STATUS Status; + ULONG NumPins, BytesReturned; + + // setup property request + Pin.Flags = KSPROPERTY_TYPE_GET; + Pin.Set = KSPROPSETID_Pin; + Pin.Id = KSPROPERTY_PIN_CTYPES; + + // query pin count + Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&NumPins, sizeof(ULONG), (PULONG)&BytesReturned); + + // check for success + if (Status != MM_STATUS_SUCCESS) + return 0; + + return NumPins; +} + +ULONG +MMixerGetIndexOfGuid( + PKSMULTIPLE_ITEM MultipleItem, + LPCGUID NodeType) +{ + ULONG Index; + LPGUID Guid; + + Guid = (LPGUID)(MultipleItem+1); + + /* iterate through node type array */ + for(Index = 0; Index < MultipleItem->Count; Index++) + { + if (IsEqualGUIDAligned(NodeType, Guid)) + { + /* found matching guid */ + return Index; + } + Guid++; + } + return MAXULONG; +} + + +MIXER_STATUS +MMixerGetFilterTopologyProperty( + IN PMIXER_CONTEXT MixerContext, + IN HANDLE hMixer, + IN ULONG PropertyId, + OUT PKSMULTIPLE_ITEM * OutMultipleItem) +{ + KSPROPERTY Property; + PKSMULTIPLE_ITEM MultipleItem; + MIXER_STATUS Status; + ULONG BytesReturned; + + // setup property request + Property.Id = PropertyId; + Property.Flags = KSPROPERTY_TYPE_GET; + Property.Set = KSPROPSETID_Topology; + + // query for the size + Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned); + + if (Status != MM_STATUS_MORE_ENTRIES) + return Status; + + // allocate an result buffer + MultipleItem = (PKSMULTIPLE_ITEM)MixerContext->Alloc(BytesReturned); + + if (!MultipleItem) + { + // not enough memory + return MM_STATUS_NO_MEMORY; + } + + // query again with allocated buffer + Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)MultipleItem, BytesReturned, &BytesReturned); + + if (Status != MM_STATUS_SUCCESS) + { + // failed + MixerContext->Free((PVOID)MultipleItem); + return Status; + } + + // store result + *OutMultipleItem = MultipleItem; + + // done + return Status; +} + +MIXER_STATUS +MMixerCreateDestinationLine( + IN PMIXER_CONTEXT MixerContext, + IN LPMIXER_INFO MixerInfo, + IN ULONG bInputMixer) +{ + LPMIXERLINE_EXT DestinationLine; + + // allocate a mixer destination line + DestinationLine = (LPMIXERLINE_EXT) MixerContext->Alloc(sizeof(MIXERLINE_EXT)); + if (!MixerInfo) + { + // no memory + return MM_STATUS_NO_MEMORY; + } + + /* initialize mixer destination line */ + DestinationLine->Line.cbStruct = sizeof(MIXERLINEW); + DestinationLine->Line.dwSource = MAXULONG; + DestinationLine->Line.dwLineID = DESTINATION_LINE; + DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE; + DestinationLine->Line.dwUser = 0; + DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN); + DestinationLine->Line.cChannels = 2; //FIXME + wcscpy(DestinationLine->Line.szShortName, L"Summe"); //FIXME + wcscpy(DestinationLine->Line.szName, L"Summe"); //FIXME + DestinationLine->Line.Target.dwType = (bInputMixer == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN); + DestinationLine->Line.Target.dwDeviceID = !bInputMixer; + DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid; + DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid; + DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion; + wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname); + + + // insert into mixer info + InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry); + + // done + return MM_STATUS_SUCCESS; +} + +MIXER_STATUS +MMixerInitializeFilter( + IN PMIXER_CONTEXT MixerContext, + IN HANDLE hMixer, + IN LPWSTR DeviceName, + IN PKSMULTIPLE_ITEM NodeTypes, + IN PKSMULTIPLE_ITEM NodeConnections, + IN ULONG PinCount, + IN ULONG NodeIndex, + IN ULONG bInputMixer) +{ + LPMIXER_INFO MixerInfo; + MIXER_STATUS Status; + ULONG * Pins; + + // allocate a mixer info struct + MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO)); + if (!MixerInfo) + { + // no memory + return MM_STATUS_NO_MEMORY; + } + + // intialize mixer caps */ + MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME + MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME + MixerInfo->MixCaps.vDriverVersion = 1; //FIXME + MixerInfo->MixCaps.fdwSupport = 0; + MixerInfo->MixCaps.cDestinations = 1; + MixerInfo->hMixer = hMixer; + + // initialize line list + InitializeListHead(&MixerInfo->LineList); + + /* FIXME find mixer name */ + + Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInputMixer); + if (Status != MM_STATUS_SUCCESS) + { + // failed to create destination line + MixerContext->Free(MixerInfo); + return Status; + } + + + // now allocate an array which will receive the indices of the pin + // which has a ADC / DAC nodetype in its path + Pins = (PULONG)MixerContext->Alloc(PinCount * sizeof(ULONG)); + + if (!Pins) + { + // no memory + MMixerFreeMixerInfo(MixerContext, MixerInfo); + return MM_STATUS_NO_MEMORY; + } + + + //UNIMPLEMENTED + // get target pins and find all nodes + return MM_STATUS_NOT_IMPLEMENTED; +} + +MIXER_STATUS +MMixerSetupFilter( + IN PMIXER_CONTEXT MixerContext, + IN HANDLE hMixer, + IN PULONG DeviceCount, + IN LPWSTR DeviceName) +{ + PKSMULTIPLE_ITEM NodeTypes, NodeConnections; + MIXER_STATUS Status; + ULONG PinCount; + ULONG NodeIndex; + + // get number of pins + PinCount = MMixerGetFilterPinCount(MixerContext, hMixer); + ASSERT(PinCount); + + + // get filter node types + Status = MMixerGetFilterTopologyProperty(MixerContext, hMixer, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes); + if (Status != MM_STATUS_SUCCESS) + { + // failed + return Status; + } + + // get filter node connections + Status = MMixerGetFilterTopologyProperty(MixerContext, hMixer, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections); + if (Status != MM_STATUS_SUCCESS) + { + // failed + MixerContext->Free(NodeTypes); + return Status; + } + + // check if the filter has an wave out node + NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_DAC); + if (NodeIndex != MAXULONG) + { + // it has + Status = MMixerInitializeFilter(MixerContext, hMixer, DeviceName, NodeTypes, NodeConnections, PinCount, NodeIndex, FALSE); + + // check for success + if (Status == MM_STATUS_SUCCESS) + { + // increment mixer count + (*DeviceCount)++; + } + + } + + // check if the filter has an wave in node + NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_ADC); + if (NodeIndex != MAXULONG) + { + // it has + Status = MMixerInitializeFilter(MixerContext, hMixer, DeviceName, NodeTypes, NodeConnections, PinCount, NodeIndex, TRUE); + + // check for success + if (Status == MM_STATUS_SUCCESS) + { + // increment mixer count + (*DeviceCount)++; + } + + } + + //free resources + MixerContext->Free((PVOID)NodeTypes); + MixerContext->Free((PVOID)NodeConnections); + + // done + return Status; +} + + +MIXER_STATUS +MMixerInitialize( + IN PMIXER_CONTEXT MixerContext, + IN PMIXER_ENUM EnumFunction, + IN PVOID EnumContext) +{ + MIXER_STATUS Status; + HANDLE hMixer; + ULONG DeviceIndex, Count; + LPWSTR DeviceName; + + if (!MixerContext || !EnumFunction || !EnumContext) + { + // invalid parameter + return MM_STATUS_INVALID_PARAMETER; + } + + if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free) + { + // invalid parameter + return MM_STATUS_INVALID_PARAMETER; + } + + + // start enumerating all available devices + Count = 0; + DeviceIndex = 0; + + do + { + // enumerate a device + Status = EnumFunction(EnumContext, DeviceIndex, &DeviceName, &hMixer); + + if (Status != MM_STATUS_SUCCESS) + { + //check error code + if (Status != MM_STATUS_NO_MORE_DEVICES) + { + // enumeration has failed + return Status; + } + // last device + break; + } + + + // increment device index + DeviceIndex++; + + Status = MMixerSetupFilter(MixerContext, hMixer, &Count, DeviceName); + + if (Status != MM_STATUS_SUCCESS) + break; + + }while(TRUE); + + // done + return Status; +} + + diff --git a/reactos/lib/drivers/sound/mmixer/mmixer.h b/reactos/lib/drivers/sound/mmixer/mmixer.h new file mode 100644 index 00000000000..6557b67f6ea --- /dev/null +++ b/reactos/lib/drivers/sound/mmixer/mmixer.h @@ -0,0 +1,108 @@ +#ifndef MIXER_H__ +#define MIXER_H__ + +typedef enum +{ + MM_STATUS_SUCCESS = 0, + MM_STATUS_NOTINITIALIZED, + MM_STATUS_NOT_IMPLEMENTED, + MM_STATUS_NO_MORE_DEVICES, + MM_STATUS_MORE_ENTRIES, + MM_STATUS_INVALID_PARAMETER, + MM_STATUS_UNSUCCESSFUL, + MM_STATUS_NO_MEMORY + + +}MIXER_STATUS; + + +typedef PVOID (*PMIXER_ALLOC)( + IN ULONG NumberOfBytes); + +typedef VOID (*PMIXER_FREE)( + IN PVOID Block); + +typedef MIXER_STATUS (*PMIXER_ENUM)( + IN PVOID EnumContext, + IN ULONG DeviceIndex, + OUT LPWSTR * DeviceName, + OUT PHANDLE OutHandle); + +typedef MIXER_STATUS(*PMIXER_DEVICE_CONTROL)( + IN HANDLE hMixer, + IN ULONG dwIoControlCode, + IN PVOID lpInBuffer, + IN ULONG nInBufferSize, + OUT PVOID lpOutBuffer, + ULONG nOutBufferSize, + PULONG lpBytesReturned); + + + +typedef VOID (*PMIXER_EVENT)( + IN PVOID MixerEvent); + + +typedef struct +{ + ULONG SizeOfStruct; + PVOID MixerContext; + + PMIXER_ALLOC Alloc; + PMIXER_DEVICE_CONTROL Control; + PMIXER_FREE Free; +}MIXER_CONTEXT, *PMIXER_CONTEXT; + + + + + +MIXER_STATUS +MMixerInitialize( + IN PMIXER_CONTEXT MixerContext, + IN PMIXER_ENUM EnumFunction, + IN PVOID EnumContext); + + +ULONG +MMixerGetCount( + IN PMIXER_CONTEXT MixerContext); + +MIXER_STATUS +MMixerGetCapabilities( + IN PMIXER_CONTEXT MixerContext, + IN ULONG MixerIndex, + OUT MIXERCAPSW MixerCaps); + +MIXER_STATUS +MMixerOpen( + IN PMIXER_CONTEXT MixerContext, + IN PVOID MixerEvent, + IN PMIXER_EVENT MixerEventRoutine, + OUT PHANDLE MixerHandle); + +MIXER_STATUS +MMixerGetLineInfo( + IN HANDLE MixerHandle, + IN ULONG Flags, + OUT LPMIXERLINEW MixerLine); + +MIXER_STATUS +MMixerGetLineControls( + IN HANDLE MixerHandle, + IN ULONG Flags, + OUT LPMIXERLINECONTROLS MixerLineControls); + +MIXER_STATUS +MMixerSetControlDetails( + IN HANDLE MixerHandle, + IN ULONG Flags, + OUT LPMIXERCONTROLDETAILS MixerControlDetails); + +MIXER_STATUS +MMixerGetControlDetails( + IN HANDLE MixerHandle, + IN ULONG Flags, + OUT LPMIXERCONTROLDETAILS MixerControlDetails); + +#endif diff --git a/reactos/lib/drivers/sound/mmixer/mmixer.rbuild b/reactos/lib/drivers/sound/mmixer/mmixer.rbuild new file mode 100644 index 00000000000..a54d4dfff91 --- /dev/null +++ b/reactos/lib/drivers/sound/mmixer/mmixer.rbuild @@ -0,0 +1,7 @@ + + + + include/reactos/libs/sound + 1 + mixer.c + diff --git a/reactos/lib/drivers/sound/mmixer/priv.h b/reactos/lib/drivers/sound/mmixer/priv.h new file mode 100644 index 00000000000..416b2f8af57 --- /dev/null +++ b/reactos/lib/drivers/sound/mmixer/priv.h @@ -0,0 +1,38 @@ +#ifndef PRIV_H__ +#define PRIV_H__ + +#include +#include + +#include +#define NOBITMAP +#include +#include +#include +#include +#include + +#include "mmixer.h" + +typedef struct +{ + MIXERCAPSW MixCaps; + HANDLE hMixer; + LIST_ENTRY LineList; + ULONG ControlId; +}MIXER_INFO, *LPMIXER_INFO; + +typedef struct +{ + LIST_ENTRY Entry; + ULONG PinId; + ULONG DeviceIndex; + MIXERLINEW Line; + LPMIXERCONTROLW LineControls; + PULONG NodeIds; + LIST_ENTRY LineControlsExtraData; +}MIXERLINE_EXT, *LPMIXERLINE_EXT; + +#define DESTINATION_LINE 0xFFFF0000 + +#endif