From b1e100ebd825d51a314b5023ff7f0e22c2f48dad Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Tue, 8 Dec 2009 21:10:02 +0000 Subject: [PATCH] [MMIXER] - Finish porting of code from wdmaud svn path=/trunk/; revision=44473 --- reactos/lib/drivers/sound/mmixer/controls.c | 949 ++++++++++++++++++ reactos/lib/drivers/sound/mmixer/filter.c | 207 ++++ reactos/lib/drivers/sound/mmixer/mixer.c | 305 +----- reactos/lib/drivers/sound/mmixer/mmixer.h | 7 + .../lib/drivers/sound/mmixer/mmixer.rbuild | 3 + reactos/lib/drivers/sound/mmixer/priv.h | 115 ++- reactos/lib/drivers/sound/mmixer/sup.c | 282 ++++++ 7 files changed, 1563 insertions(+), 305 deletions(-) create mode 100644 reactos/lib/drivers/sound/mmixer/controls.c create mode 100644 reactos/lib/drivers/sound/mmixer/filter.c create mode 100644 reactos/lib/drivers/sound/mmixer/sup.c diff --git a/reactos/lib/drivers/sound/mmixer/controls.c b/reactos/lib/drivers/sound/mmixer/controls.c new file mode 100644 index 00000000000..2cc7a457ca2 --- /dev/null +++ b/reactos/lib/drivers/sound/mmixer/controls.c @@ -0,0 +1,949 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Kernel Streaming + * FILE: lib/drivers/sound/mmixer/controls.c + * PURPOSE: Mixer Control Iteration Functions + * PROGRAMMER: Johannes Anderwald + */ + +#include "priv.h" + +MIXER_STATUS +MMixerGetTargetPinsByNodeConnectionIndex( + IN PMIXER_CONTEXT MixerContext, + IN PKSMULTIPLE_ITEM NodeConnections, + IN PKSMULTIPLE_ITEM NodeTypes, + IN ULONG bUpDirection, + IN ULONG NodeConnectionIndex, + OUT PULONG Pins) +{ + PKSTOPOLOGY_CONNECTION Connection; + ULONG PinId, NodeConnectionCount, Index; + PULONG NodeConnection; + MIXER_STATUS Status; + + + /* sanity check */ + ASSERT(NodeConnectionIndex < NodeConnections->Count); + + Connection = (PKSTOPOLOGY_CONNECTION)(NodeConnections + 1); + + //DPRINT("FromNode %u FromNodePin %u -> ToNode %u ToNodePin %u\n", Connection[NodeConnectionIndex].FromNode, Connection[NodeConnectionIndex].FromNodePin, Connection[NodeConnectionIndex].ToNode, Connection[NodeConnectionIndex].ToNodePin ); + + if ((Connection[NodeConnectionIndex].ToNode == KSFILTER_NODE && bUpDirection == FALSE) || + (Connection[NodeConnectionIndex].FromNode == KSFILTER_NODE && bUpDirection == TRUE)) + { + /* iteration stops here */ + if (bUpDirection) + PinId = Connection[NodeConnectionIndex].FromNodePin; + else + PinId = Connection[NodeConnectionIndex].ToNodePin; + + //DPRINT("GetTargetPinsByNodeIndex FOUND Target Pin %u Parsed %u\n", PinId, Pins[PinId]); + + /* mark pin index as a target pin */ + Pins[PinId] = TRUE; + return MM_STATUS_SUCCESS; + } + + // get all node indexes referenced by that node + if (bUpDirection) + { + Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Connection[NodeConnectionIndex].FromNode, TRUE, FALSE, &NodeConnectionCount, &NodeConnection); + } + else + { + Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Connection[NodeConnectionIndex].ToNode, TRUE, TRUE, &NodeConnectionCount, &NodeConnection); + } + + if (Status == MM_STATUS_SUCCESS) + { + for(Index = 0; Index < NodeConnectionCount; Index++) + { + // iterate recursively into the nodes + Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Pins); + ASSERT(Status == MM_STATUS_SUCCESS); + } + // free node connection indexes + MixerContext->Free(NodeConnection); + } + + return Status; +} + +MIXER_STATUS +MMixerGetControlsFromPinByConnectionIndex( + IN PMIXER_CONTEXT MixerContext, + IN PKSMULTIPLE_ITEM NodeConnections, + IN PKSMULTIPLE_ITEM NodeTypes, + IN ULONG bUpDirection, + IN ULONG NodeConnectionIndex, + OUT PULONG Nodes) +{ + PKSTOPOLOGY_CONNECTION CurConnection; + LPGUID NodeType; + ULONG NodeIndex; + MIXER_STATUS Status; + ULONG NodeConnectionCount, Index; + PULONG NodeConnection; + + + /* get current connection */ + CurConnection = MMixerGetConnectionByIndex(NodeConnections, NodeConnectionIndex); + + if (bUpDirection) + NodeIndex = CurConnection->FromNode; + else + NodeIndex = CurConnection->ToNode; + + /* get target node type of current connection */ + NodeType = MMixerGetNodeType(NodeTypes, NodeIndex); + + if (IsEqualGUIDAligned(NodeType, &KSNODETYPE_SUM) || IsEqualGUIDAligned(NodeType, &KSNODETYPE_MUX)) + { + if (bUpDirection) + { + /* add the sum / mux node to destination line */ + Nodes[NodeIndex] = TRUE; + } + + return MM_STATUS_SUCCESS; + } + + /* now add the node */ + Nodes[NodeIndex] = TRUE; + + + /* get all node indexes referenced by that node */ + if (bUpDirection) + { + Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection); + } + else + { + Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection); + } + + if (Status != MM_STATUS_SUCCESS) + { + for(Index = 0; Index < NodeConnectionCount; Index++) + { + /* iterate recursively into the nodes */ + Status = MMixerGetControlsFromPinByConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes); + ASSERT(Status == MM_STATUS_SUCCESS); + } + /* free node connection indexes */ + MixerContext->Free(NodeConnection); + } + + return Status; +} + +MIXER_STATUS +MMixerAddMixerControl( + IN PMIXER_CONTEXT MixerContext, + IN LPMIXER_INFO MixerInfo, + IN HANDLE hDevice, + IN PKSMULTIPLE_ITEM NodeTypes, + IN ULONG NodeIndex, + IN LPMIXERLINE_EXT MixerLine, + OUT LPMIXERCONTROLW MixerControl) +{ + LPGUID NodeType; + KSP_NODE Node; + ULONG BytesReturned; + MIXER_STATUS Status; + LPWSTR Name; + + /* initialize mixer control */ + MixerControl->cbStruct = sizeof(MIXERCONTROLW); + MixerControl->dwControlID = MixerInfo->ControlId; + + /* get node type */ + NodeType = MMixerGetNodeType(NodeTypes, NodeIndex); + /* store control type */ + MixerControl->dwControlType = MMixerGetControlTypeFromTopologyNode(NodeType); + + MixerControl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM; //FIXME + MixerControl->cMultipleItems = 0; //FIXME + + if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) + { + MixerControl->Bounds.dwMinimum = 0; + MixerControl->Bounds.dwMaximum = 1; + } + else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) + { + MixerControl->Bounds.dwMinimum = 0; + MixerControl->Bounds.dwMaximum = 0xFFFF; + MixerControl->Metrics.cSteps = 0xC0; //FIXME + } + + /* setup request to retrieve name */ + Node.NodeId = NodeIndex; + Node.Property.Id = KSPROPERTY_TOPOLOGY_NAME; + Node.Property.Flags = KSPROPERTY_TYPE_GET; + Node.Property.Set = KSPROPSETID_Topology; + Node.Reserved = 0; + + /* get node name size */ + Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned); + + if (Status == MM_STATUS_MORE_ENTRIES) + { + ASSERT(BytesReturned != 0); + Name = (LPWSTR)MixerContext->Alloc(BytesReturned); + if (!Name) + { + /* not enough memory */ + return MM_STATUS_NO_MEMORY; + } + + /* get node name */ + Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned); + if (Status != MM_STATUS_SUCCESS) + { + RtlMoveMemory(MixerControl->szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR)); + MixerControl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0'; + + RtlMoveMemory(MixerControl->szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR)); + MixerControl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0'; + } + + /* free name buffer */ + MixerContext->Free(Name); + } + + MixerInfo->ControlId++; +#if 0 + if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUX) + { + KSNODEPROPERTY Property; + ULONG PinId = 2; + + /* setup the request */ + RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY)); + + Property.NodeId = NodeIndex; + Property.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE; + Property.Property.Flags = KSPROPERTY_TYPE_SET; + Property.Property.Set = KSPROPSETID_Audio; + + /* get node volume level info */ + Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY), (PVOID)&PinId, sizeof(ULONG), &BytesReturned); + + DPRINT1("Status %x NodeIndex %u PinId %u\n", Status, NodeIndex, PinId); + //DbgBreakPoint(); + }else +#endif + if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) + { + KSNODEPROPERTY_AUDIO_CHANNEL Property; + ULONG Length; + PKSPROPERTY_DESCRIPTION Desc; + PKSPROPERTY_MEMBERSHEADER Members; + PKSPROPERTY_STEPPING_LONG Range; + + Length = sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_STEPPING_LONG); + Desc = (PKSPROPERTY_DESCRIPTION)MixerContext->Alloc(Length); + ASSERT(Desc); + + /* setup the request */ + RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL)); + + Property.NodeProperty.NodeId = NodeIndex; + Property.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL; + Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT; + Property.NodeProperty.Property.Set = KSPROPSETID_Audio; + + /* get node volume level info */ + Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned); + + if (Status == MM_STATUS_SUCCESS) + { + LPMIXERVOLUME_DATA VolumeData; + ULONG Steps, MaxRange, Index; + LONG Value; + + Members = (PKSPROPERTY_MEMBERSHEADER)(Desc + 1); + Range = (PKSPROPERTY_STEPPING_LONG)(Members + 1); + + DPRINT("NodeIndex %u Range Min %d Max %d Steps %x UMin %x UMax %x\n", NodeIndex, Range->Bounds.SignedMinimum, Range->Bounds.SignedMaximum, Range->SteppingDelta, Range->Bounds.UnsignedMinimum, Range->Bounds.UnsignedMaximum); + + MaxRange = Range->Bounds.UnsignedMaximum - Range->Bounds.UnsignedMinimum; + + if (MaxRange) + { + ASSERT(MaxRange); + VolumeData = (LPMIXERVOLUME_DATA)MixerContext->Alloc(sizeof(MIXERVOLUME_DATA)); + if (!VolumeData) + return MM_STATUS_NO_MEMORY; + + Steps = MaxRange / Range->SteppingDelta + 1; + + /* store mixer control info there */ + VolumeData->Header.dwControlID = MixerControl->dwControlID; + VolumeData->SignedMaximum = Range->Bounds.SignedMaximum; + VolumeData->SignedMinimum = Range->Bounds.SignedMinimum; + VolumeData->SteppingDelta = Range->SteppingDelta; + VolumeData->ValuesCount = Steps; + VolumeData->InputSteppingDelta = 0x10000 / Steps; + + VolumeData->Values = (PLONG)MixerContext->Alloc(sizeof(LONG) * Steps); + if (!VolumeData->Values) + { + MixerContext->Free(Desc); + MixerContext->Free(VolumeData); + + return MM_STATUS_NO_MEMORY; + } + + Value = Range->Bounds.SignedMinimum; + for(Index = 0; Index < Steps; Index++) + { + VolumeData->Values[Index] = Value; + Value += Range->SteppingDelta; + } + InsertTailList(&MixerLine->LineControlsExtraData, &VolumeData->Header.Entry); + } + } + MixerContext->Free(Desc); + } + + + DPRINT("Status %x Name %S\n", Status, MixerControl->szName); + return MM_STATUS_SUCCESS; +} + +MIXER_STATUS +MMixerAddMixerSourceLine( + IN PMIXER_CONTEXT MixerContext, + IN OUT LPMIXER_INFO MixerInfo, + IN HANDLE hDevice, + IN PKSMULTIPLE_ITEM NodeConnections, + IN PKSMULTIPLE_ITEM NodeTypes, + IN ULONG PinId, + IN ULONG bBridgePin, + IN ULONG bTargetPin) +{ + LPMIXERLINE_EXT SrcLine, DstLine; + MIXER_STATUS Status; + KSP_PIN Pin; + LPWSTR PinName; + GUID NodeType; + ULONG BytesReturned, ControlCount, Index; + PULONG Nodes; + + if (!bTargetPin) + { + /* allocate src mixer line */ + SrcLine = (LPMIXERLINE_EXT)MixerContext->Alloc(sizeof(MIXERLINE_EXT)); + + if (!SrcLine) + return MM_STATUS_NO_MEMORY; + + /* zero struct */ + RtlZeroMemory(SrcLine, sizeof(MIXERLINE_EXT)); + + } + else + { + ASSERT(!IsListEmpty(&MixerInfo->LineList)); + SrcLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE); + } + + /* get destination line */ + DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE); + ASSERT(DstLine); + + + if (!bTargetPin) + { + /* initialize mixer src line */ + SrcLine->hDevice = hDevice; + SrcLine->PinId = PinId; + SrcLine->Line.cbStruct = sizeof(MIXERLINEW); + + /* initialize mixer destination line */ + SrcLine->Line.cbStruct = sizeof(MIXERLINEW); + SrcLine->Line.dwDestination = 0; + SrcLine->Line.dwSource = DstLine->Line.cConnections; + SrcLine->Line.dwLineID = (DstLine->Line.cConnections * 0x10000); + SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE; + SrcLine->Line.dwUser = 0; + SrcLine->Line.cChannels = DstLine->Line.cChannels; + SrcLine->Line.cConnections = 0; + SrcLine->Line.Target.dwType = 1; + SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID; + SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid; + SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid; + SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion; + InitializeListHead(&SrcLine->LineControlsExtraData); + wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname); + + } + + /* allocate a node arrary */ + Nodes = (PULONG)MixerContext->Alloc(sizeof(ULONG) * NodeTypes->Count); + + if (!Nodes) + { + /* not enough memory */ + if (!bTargetPin) + { + MixerContext->Free(SrcLine); + } + return MM_STATUS_NO_MEMORY; + } + + Status = MMixerGetControlsFromPin(MixerContext, NodeConnections, NodeTypes, PinId, bTargetPin, Nodes); + if (Status != MM_STATUS_SUCCESS) + { + /* something went wrong */ + if (!bTargetPin) + { + MixerContext->Free(SrcLine); + } + MixerContext->Free(Nodes); + return Status; + } + + /* now count all nodes controlled by that pin */ + ControlCount = 0; + for(Index = 0; Index < NodeTypes->Count; Index++) + { + if (Nodes[Index]) + ControlCount++; + } + + /* now allocate the line controls */ + if (ControlCount) + { + SrcLine->LineControls = (LPMIXERCONTROLW)MixerContext->Alloc(sizeof(MIXERCONTROLW) * ControlCount); + + if (!SrcLine->LineControls) + { + /* no memory available */ + if (!bTargetPin) + { + MixerContext->Free(SrcLine); + } + MixerContext->Free(Nodes); + return MM_STATUS_NO_MEMORY; + } + + SrcLine->NodeIds = (PULONG)MixerContext->Alloc(sizeof(ULONG) * ControlCount); + if (!SrcLine->NodeIds) + { + /* no memory available */ + MixerContext->Free(SrcLine->LineControls); + if (!bTargetPin) + { + MixerContext->Free(SrcLine); + } + MixerContext->Free(Nodes); + return MM_STATUS_NO_MEMORY; + } + + /* zero line controls */ + RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW) * ControlCount); + RtlZeroMemory(SrcLine->NodeIds, sizeof(ULONG) * ControlCount); + + ControlCount = 0; + for(Index = 0; Index < NodeTypes->Count; Index++) + { + if (Nodes[Index]) + { + /* store the node index for retrieving / setting details */ + SrcLine->NodeIds[ControlCount] = Index; + + Status = MMixerAddMixerControl(MixerContext, MixerInfo, hDevice, NodeTypes, Index, SrcLine, &SrcLine->LineControls[ControlCount]); + if (Status != MM_STATUS_SUCCESS) + { + /* increment control count on success */ + ControlCount++; + } + } + } + /* store control count */ + SrcLine->Line.cControls = ControlCount; + } + + /* release nodes array */ + MixerContext->Free(Nodes); + + /* get pin category */ + Pin.PinId = PinId; + Pin.Reserved = 0; + Pin.Property.Flags = KSPROPERTY_TYPE_GET; + Pin.Property.Set = KSPROPSETID_Pin; + Pin.Property.Id = KSPROPERTY_PIN_CATEGORY; + + /* try get pin category */ + Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)&NodeType, sizeof(GUID), &BytesReturned); + if (Status != MM_STATUS_SUCCESS) + { + //FIXME + //map component type + } + + /* retrieve pin name */ + Pin.PinId = PinId; + Pin.Reserved = 0; + Pin.Property.Flags = KSPROPERTY_TYPE_GET; + Pin.Property.Set = KSPROPSETID_Pin; + Pin.Property.Id = KSPROPERTY_PIN_NAME; + + /* try get pin name size */ + Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned); + + if (Status != STATUS_MORE_ENTRIES) + { + SrcLine->Line.szShortName[0] = L'\0'; + SrcLine->Line.szName[0] = L'\0'; + } + else + { + PinName = (LPWSTR)MixerContext->Alloc(BytesReturned); + if (PinName) + { + /* try get pin name */ + Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)PinName, BytesReturned, &BytesReturned); + + if (Status != MM_STATUS_SUCCESS) + { + RtlMoveMemory(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR)); + SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0'; + + RtlMoveMemory(SrcLine->Line.szName, PinName, (min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR)); + SrcLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0'; + } + MixerContext->Free(PinName); + } + } + + /* insert src line */ + if (!bTargetPin) + { + InsertTailList(&MixerInfo->LineList, &SrcLine->Entry); + DstLine->Line.cConnections++; + } + + return MM_STATUS_SUCCESS; +} + +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 +MMixerGetControlsFromPin( + IN PMIXER_CONTEXT MixerContext, + IN PKSMULTIPLE_ITEM NodeConnections, + IN PKSMULTIPLE_ITEM NodeTypes, + IN ULONG PinId, + IN ULONG bUpDirection, + OUT PULONG Nodes) +{ + ULONG NodeConnectionCount, Index; + MIXER_STATUS Status; + PULONG NodeConnection; + + /* sanity check */ + ASSERT(PinId != (ULONG)-1); + + /* get all node indexes referenced by that pin */ + if (bUpDirection) + Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, PinId, FALSE, FALSE, &NodeConnectionCount, &NodeConnection); + else + Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, PinId, FALSE, TRUE, &NodeConnectionCount, &NodeConnection); + + for(Index = 0; Index < NodeConnectionCount; Index++) + { + /* get all associated controls */ + Status = MMixerGetControlsFromPinByConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes); + } + + MixerContext->Free(NodeConnection); + + return Status; +} + + + + +MIXER_STATUS +MMixerAddMixerSourceLines( + IN PMIXER_CONTEXT MixerContext, + IN OUT LPMIXER_INFO MixerInfo, + IN HANDLE hDevice, + IN PKSMULTIPLE_ITEM NodeConnections, + IN PKSMULTIPLE_ITEM NodeTypes, + IN ULONG PinsCount, + IN ULONG BridgePinIndex, + IN ULONG TargetPinIndex, + IN PULONG Pins) +{ + ULONG Index; + + for(Index = PinsCount; Index > 0; Index--) + { + if (Pins[Index-1]) + { + MMixerAddMixerSourceLine(MixerContext, MixerInfo, hDevice, NodeConnections, NodeTypes, Index-1, (Index -1 == BridgePinIndex), (Index -1 == TargetPinIndex)); + } + } + return MM_STATUS_SUCCESS; +} + + +MIXER_STATUS +MMixerHandlePhysicalConnection( + IN PMIXER_CONTEXT MixerContext, + IN OUT LPMIXER_INFO MixerInfo, + IN ULONG bInput, + IN PKSPIN_PHYSICALCONNECTION OutConnection) +{ + PULONG PinsRef = NULL, PinConnectionIndex = NULL, PinsSrcRef; + ULONG PinsRefCount, Index, PinConnectionIndexCount; + MIXER_STATUS Status; + HANDLE hDevice = NULL; + PFILE_OBJECT FileObject = NULL; + PKSMULTIPLE_ITEM NodeTypes = NULL; + PKSMULTIPLE_ITEM NodeConnections = NULL; + PULONG MixerControls; + ULONG MixerControlsCount; + + + // open the connected filter + Status = MixerContext->Open(OutConnection->SymbolicLinkName, &hDevice); + if (Status != MM_STATUS_SUCCESS) + { + DPRINT1("OpenDevice failed with %x\n", Status); + return Status; + } + + // get connected filter pin count + PinsRefCount = MMixerGetFilterPinCount(MixerContext, hDevice); + ASSERT(PinsRefCount); + + PinsRef = (PULONG)MixerContext->Alloc(sizeof(ULONG) * PinsRefCount); + if (!PinsRef) + { + // no memory + MixerContext->Close(hDevice); + return MM_STATUS_UNSUCCESSFUL; + } + + // get topology node types + Status = MMixerGetFilterTopologyProperty(MixerContext, hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes); + if (Status != MM_STATUS_SUCCESS) + { + MixerContext->Close(hDevice); + MixerContext->Free(PinsRef); + return Status; + } + + // get topology connections + Status = MMixerGetFilterTopologyProperty(MixerContext, hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections); + if (Status != MM_STATUS_SUCCESS) + { + MixerContext->Close(hDevice); + MixerContext->Free(PinsRef); + MixerContext->Free(NodeTypes); + return Status; + } + // gets connection index of the bridge pin which connects to a node + DPRINT("Pin %u\n", OutConnection->Pin); + + Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, OutConnection->Pin, FALSE, !bInput, &PinConnectionIndexCount, &PinConnectionIndex); + if (Status != MM_STATUS_SUCCESS) + { + MixerContext->Close(hDevice); + MixerContext->Free(PinsRef); + MixerContext->Free(NodeTypes); + MixerContext->Free(NodeConnections); + return Status; + } + + /* there should be no split in the bride pin */ + ASSERT(PinConnectionIndexCount == 1); + + /* find all target pins of this connection */ + Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, FALSE, PinConnectionIndex[0], PinsRef); + if (Status != MM_STATUS_SUCCESS) + { + MixerContext->Close(hDevice); + MixerContext->Free(PinsRef); + MixerContext->Free(NodeTypes); + MixerContext->Free(NodeConnections); + MixerContext->Free(PinConnectionIndex); + return Status; + } + + for(Index = 0; Index < PinsRefCount; Index++) + { + if (PinsRef[Index]) + { + // found a target pin, now get all references + Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Index, FALSE, FALSE, &MixerControlsCount, &MixerControls); + if (Status != MM_STATUS_SUCCESS) + break; + + /* sanity check */ + ASSERT(MixerControlsCount == 1); + + PinsSrcRef = (PULONG)MixerContext->Alloc(PinsRefCount * sizeof(ULONG)); + if (!PinsSrcRef) + { + /* no memory */ + MixerContext->Close(hDevice); + MixerContext->Free(PinsRef); + MixerContext->Free(NodeTypes); + MixerContext->Free(NodeConnections); + MixerContext->Free(PinConnectionIndex); + MixerContext->Free(MixerControls); + return MM_STATUS_NO_MEMORY; + } + + // now get all connected source pins + Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, TRUE, MixerControls[0], PinsSrcRef); + if (Status != MM_STATUS_SUCCESS) + { + // failed */ + MixerContext->Close(hDevice); + MixerContext->Free(PinsRef); + MixerContext->Free(NodeTypes); + MixerContext->Free(NodeConnections); + MixerContext->Free(PinConnectionIndex); + MixerContext->Free(MixerControls); + MixerContext->Free(PinsSrcRef); + return Status; + } + + /* add pins from target line */ + if (!bInput) + { + // dont add bridge pin for input mixers + PinsSrcRef[Index] = TRUE; + PinsSrcRef[OutConnection->Pin] = TRUE; + } + PinsSrcRef[OutConnection->Pin] = TRUE; + + Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, FileObject, NodeConnections, NodeTypes, PinsRefCount, OutConnection->Pin, Index, PinsSrcRef); + + MixerContext->Free(MixerControls); + MixerContext->Free(PinsSrcRef); + } + } + + return Status; +} + + +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; + PKSPIN_PHYSICALCONNECTION OutConnection; + ULONG Index; + 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; + } + + // now get the target pins of the ADC / DAC node + Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, bInputMixer, Pins, PinCount); + + if (Status != MM_STATUS_SUCCESS) + { + // failed to locate target pins + MixerContext->Free(Pins); + MMixerFreeMixerInfo(MixerContext, MixerInfo); + return Status; + } + + // now check all pins and generate new lines for destination lines + for(Index = 0; Index < PinCount; Index++) + { + // is the current index a target pin + if (Pins[Index]) + { + // check if the pin has a physical connection + Status = MMixerGetPhysicalConnection(MixerContext, hMixer, Index, &OutConnection); + if (Status != MM_STATUS_SUCCESS) + { + // the pin has a physical connection + Status = MMixerHandlePhysicalConnection(MixerContext, MixerInfo, bInputMixer, OutConnection); + + MixerContext->Free(OutConnection); + } + } + } + MixerContext->Free(Pins); + + //FIXME + // store MixerInfo in context + + + // done + return Status; +} + +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; +} diff --git a/reactos/lib/drivers/sound/mmixer/filter.c b/reactos/lib/drivers/sound/mmixer/filter.c new file mode 100644 index 00000000000..64e19d14b01 --- /dev/null +++ b/reactos/lib/drivers/sound/mmixer/filter.c @@ -0,0 +1,207 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Kernel Streaming + * FILE: lib/drivers/sound/mmixer/filter.c + * PURPOSE: Mixer Filter Functions + * PROGRAMMER: Johannes Anderwald + */ + + + +#include "priv.h" + +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; +} + +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 +MMixerGetPhysicalConnection( + IN PMIXER_CONTEXT MixerContext, + IN HANDLE hMixer, + IN ULONG PinId, + OUT PKSPIN_PHYSICALCONNECTION *OutConnection) +{ + KSP_PIN Pin; + MIXER_STATUS Status; + ULONG BytesReturned; + PKSPIN_PHYSICALCONNECTION Connection; + + /* setup the request */ + Pin.Property.Flags = KSPROPERTY_TYPE_GET; + Pin.Property.Id = KSPROPERTY_PIN_PHYSICALCONNECTION; + Pin.Property.Set = KSPROPSETID_Pin; + Pin.PinId = PinId; + + /* query the pin for the physical connection */ + Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned); + + if (Status == MM_STATUS_UNSUCCESSFUL) + { + // pin does not have a physical connection + return Status; + } + + Connection = (PKSPIN_PHYSICALCONNECTION)MixerContext->Alloc(BytesReturned); + if (!Connection) + { + // not enough memory + return MM_STATUS_NO_MEMORY; + } + + // query the pin for the physical connection + Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Connection, BytesReturned, &BytesReturned); + if (Status != MM_STATUS_SUCCESS) + { + // failed to query the physical connection + MixerContext->Free(Connection); + return Status; + } + + // store connection + *OutConnection = Connection; + return Status; +} + +ULONG +MMixerGetControlTypeFromTopologyNode( + IN LPGUID NodeType) +{ + if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_AGC)) + { + // automatic gain control + return MIXERCONTROL_CONTROLTYPE_ONOFF; + } + else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_LOUDNESS)) + { + // loudness control + return MIXERCONTROL_CONTROLTYPE_LOUDNESS; + } + else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUTE )) + { + // mute control + return MIXERCONTROL_CONTROLTYPE_MUTE; + } + else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_TONE)) + { + // tpne control + //FIXME + // MIXERCONTROL_CONTROLTYPE_ONOFF if KSPROPERTY_AUDIO_BASS_BOOST is supported + // MIXERCONTROL_CONTROLTYPE_BASS if KSPROPERTY_AUDIO_BASS is supported + // MIXERCONTROL_CONTROLTYPE_TREBLE if KSPROPERTY_AUDIO_TREBLE is supported + UNIMPLEMENTED; + return MIXERCONTROL_CONTROLTYPE_ONOFF; + } + else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_VOLUME)) + { + // volume control + return MIXERCONTROL_CONTROLTYPE_VOLUME; + } + else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_PEAKMETER)) + { + // peakmeter control + return MIXERCONTROL_CONTROLTYPE_PEAKMETER; + } + else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUX)) + { + // mux control + return MIXERCONTROL_CONTROLTYPE_MUX; + } + else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUX)) + { + // mux control + return MIXERCONTROL_CONTROLTYPE_MUX; + } + else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_STEREO_WIDE)) + { + // stero wide control + return MIXERCONTROL_CONTROLTYPE_FADER; + } + else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_CHORUS)) + { + // chorus control + return MIXERCONTROL_CONTROLTYPE_FADER; + } + else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_REVERB)) + { + // reverb control + return MIXERCONTROL_CONTROLTYPE_FADER; + } + else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_SUPERMIX)) + { + // supermix control + // MIXERCONTROL_CONTROLTYPE_MUTE if KSPROPERTY_AUDIO_MUTE is supported + UNIMPLEMENTED; + return MIXERCONTROL_CONTROLTYPE_VOLUME; + } + UNIMPLEMENTED + return 0; +} diff --git a/reactos/lib/drivers/sound/mmixer/mixer.c b/reactos/lib/drivers/sound/mmixer/mixer.c index 38c23c50445..279d1194f76 100644 --- a/reactos/lib/drivers/sound/mmixer/mixer.c +++ b/reactos/lib/drivers/sound/mmixer/mixer.c @@ -10,312 +10,9 @@ #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_CONTEXT MixerContext, IN PMIXER_ENUM EnumFunction, IN PVOID EnumContext) { diff --git a/reactos/lib/drivers/sound/mmixer/mmixer.h b/reactos/lib/drivers/sound/mmixer/mmixer.h index 6557b67f6ea..b577774920b 100644 --- a/reactos/lib/drivers/sound/mmixer/mmixer.h +++ b/reactos/lib/drivers/sound/mmixer/mmixer.h @@ -37,7 +37,12 @@ typedef MIXER_STATUS(*PMIXER_DEVICE_CONTROL)( ULONG nOutBufferSize, PULONG lpBytesReturned); +typedef MIXER_STATUS(*PMIXER_OPEN)( + IN LPCWSTR DevicePath, + OUT PHANDLE hDevice); +typedef MIXER_STATUS(*PMIXER_CLOSE)( + IN HANDLE hDevice); typedef VOID (*PMIXER_EVENT)( IN PVOID MixerEvent); @@ -51,6 +56,8 @@ typedef struct PMIXER_ALLOC Alloc; PMIXER_DEVICE_CONTROL Control; PMIXER_FREE Free; + PMIXER_OPEN Open; + PMIXER_CLOSE Close; }MIXER_CONTEXT, *PMIXER_CONTEXT; diff --git a/reactos/lib/drivers/sound/mmixer/mmixer.rbuild b/reactos/lib/drivers/sound/mmixer/mmixer.rbuild index a54d4dfff91..86644eb6b4b 100644 --- a/reactos/lib/drivers/sound/mmixer/mmixer.rbuild +++ b/reactos/lib/drivers/sound/mmixer/mmixer.rbuild @@ -3,5 +3,8 @@ include/reactos/libs/sound 1 + controls.c + filter.c mixer.c + sup.c diff --git a/reactos/lib/drivers/sound/mmixer/priv.h b/reactos/lib/drivers/sound/mmixer/priv.h index 416b2f8af57..520fb880c6c 100644 --- a/reactos/lib/drivers/sound/mmixer/priv.h +++ b/reactos/lib/drivers/sound/mmixer/priv.h @@ -14,6 +14,8 @@ #include "mmixer.h" +#include + typedef struct { MIXERCAPSW MixCaps; @@ -26,13 +28,124 @@ typedef struct { LIST_ENTRY Entry; ULONG PinId; - ULONG DeviceIndex; + HANDLE hDevice; MIXERLINEW Line; LPMIXERCONTROLW LineControls; PULONG NodeIds; LIST_ENTRY LineControlsExtraData; }MIXERLINE_EXT, *LPMIXERLINE_EXT; +typedef struct +{ + LIST_ENTRY Entry; + ULONG dwControlID; +}MIXERCONTROL_DATA, *LPMIXERCONTROL_DATA; + +typedef struct +{ + MIXERCONTROL_DATA Header; + LONG SignedMinimum; + LONG SignedMaximum; + LONG SteppingDelta; + ULONG InputSteppingDelta; + ULONG ValuesCount; + PLONG Values; +}MIXERVOLUME_DATA, *LPMIXERVOLUME_DATA; + + #define DESTINATION_LINE 0xFFFF0000 +ULONG +MMixerGetFilterPinCount( + IN PMIXER_CONTEXT MixerContext, + IN HANDLE hMixer); + +LPGUID +MMixerGetNodeType( + IN PKSMULTIPLE_ITEM MultipleItem, + IN ULONG Index); + +MIXER_STATUS +MMixerGetNodeIndexes( + IN PMIXER_CONTEXT MixerContext, + IN PKSMULTIPLE_ITEM MultipleItem, + IN ULONG NodeIndex, + IN ULONG bNode, + IN ULONG bFrom, + OUT PULONG NodeReferenceCount, + OUT PULONG *NodeReference); + +PKSTOPOLOGY_CONNECTION +MMixerGetConnectionByIndex( + IN PKSMULTIPLE_ITEM MultipleItem, + IN ULONG Index); + +ULONG +MMixerGetControlTypeFromTopologyNode( + IN LPGUID NodeType); + +LPMIXERLINE_EXT +MMixerGetSourceMixerLineByLineId( + LPMIXER_INFO MixerInfo, + DWORD dwLineID); + +MIXER_STATUS +MMixerGetFilterTopologyProperty( + IN PMIXER_CONTEXT MixerContext, + IN HANDLE hMixer, + IN ULONG PropertyId, + OUT PKSMULTIPLE_ITEM * OutMultipleItem); + +VOID +MMixerFreeMixerInfo( + IN PMIXER_CONTEXT MixerContext, + IN LPMIXER_INFO MixerInfo); + +MIXER_STATUS +MMixerGetTargetPins( + IN PMIXER_CONTEXT MixerContext, + IN PKSMULTIPLE_ITEM NodeTypes, + IN PKSMULTIPLE_ITEM NodeConnections, + IN ULONG NodeIndex, + IN ULONG bUpDirection, + OUT PULONG Pins, + IN ULONG PinCount); + +MIXER_STATUS +MMixerGetPhysicalConnection( + IN PMIXER_CONTEXT MixerContext, + IN HANDLE hMixer, + IN ULONG PinId, + OUT PKSPIN_PHYSICALCONNECTION *OutConnection); + +ULONG +MMixerGetIndexOfGuid( + PKSMULTIPLE_ITEM MultipleItem, + LPCGUID NodeType); + +MIXER_STATUS +MMixerSetupFilter( + IN PMIXER_CONTEXT MixerContext, + IN HANDLE hMixer, + IN PULONG DeviceCount, + IN LPWSTR DeviceName); + +MIXER_STATUS +MMixerGetTargetPinsByNodeConnectionIndex( + IN PMIXER_CONTEXT MixerContext, + IN PKSMULTIPLE_ITEM NodeConnections, + IN PKSMULTIPLE_ITEM NodeTypes, + IN ULONG bUpDirection, + IN ULONG NodeConnectionIndex, + OUT PULONG Pins); + +MIXER_STATUS +MMixerGetControlsFromPin( + IN PMIXER_CONTEXT MixerContext, + IN PKSMULTIPLE_ITEM NodeConnections, + IN PKSMULTIPLE_ITEM NodeTypes, + IN ULONG PinId, + IN ULONG bUpDirection, + OUT PULONG Nodes); + #endif diff --git a/reactos/lib/drivers/sound/mmixer/sup.c b/reactos/lib/drivers/sound/mmixer/sup.c new file mode 100644 index 00000000000..a5a9107587c --- /dev/null +++ b/reactos/lib/drivers/sound/mmixer/sup.c @@ -0,0 +1,282 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Kernel Streaming + * FILE: lib/drivers/sound/mmixer/sup.c + * PURPOSE: Mixer Support 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); +} + +LPMIXERLINE_EXT +MMixerGetSourceMixerLineByLineId( + LPMIXER_INFO MixerInfo, + DWORD dwLineID) +{ + PLIST_ENTRY Entry; + LPMIXERLINE_EXT MixerLineSrc; + + /* get first entry */ + Entry = MixerInfo->LineList.Flink; + + while(Entry != &MixerInfo->LineList) + { + MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry); + DPRINT("dwLineID %x dwLineID %x\n", MixerLineSrc->Line.dwLineID, dwLineID); + if (MixerLineSrc->Line.dwLineID == dwLineID) + return MixerLineSrc; + + Entry = Entry->Flink; + } + + return NULL; +} + +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; +} + +PKSTOPOLOGY_CONNECTION +MMixerGetConnectionByIndex( + IN PKSMULTIPLE_ITEM MultipleItem, + IN ULONG Index) +{ + PKSTOPOLOGY_CONNECTION Descriptor; + + ASSERT(Index < MultipleItem->Count); + + Descriptor = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1); + return &Descriptor[Index]; +} + +LPGUID +MMixerGetNodeType( + IN PKSMULTIPLE_ITEM MultipleItem, + IN ULONG Index) +{ + LPGUID NodeType; + + ASSERT(Index < MultipleItem->Count); + + NodeType = (LPGUID)(MultipleItem + 1); + return &NodeType[Index]; +} + +MIXER_STATUS +MMixerGetNodeIndexes( + IN PMIXER_CONTEXT MixerContext, + IN PKSMULTIPLE_ITEM MultipleItem, + IN ULONG NodeIndex, + IN ULONG bNode, + IN ULONG bFrom, + OUT PULONG NodeReferenceCount, + OUT PULONG *NodeReference) +{ + ULONG Index, Count = 0; + PKSTOPOLOGY_CONNECTION Connection; + PULONG Refs; + + // KSMULTIPLE_ITEM is followed by several KSTOPOLOGY_CONNECTION + Connection = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1); + + // first count all referenced nodes + for(Index = 0; Index < MultipleItem->Count; Index++) + { + if (bNode) + { + if (bFrom) + { + if (Connection->FromNode == NodeIndex) + { + // node id has a connection + Count++; + } + } + else + { + if (Connection->ToNode == NodeIndex) + { + // node id has a connection + Count++; + } + } + } + else + { + if (bFrom) + { + if (Connection->FromNodePin == NodeIndex && Connection->FromNode == KSFILTER_NODE) + { + // node id has a connection + Count++; + } + } + else + { + if (Connection->ToNodePin == NodeIndex && Connection->ToNode == KSFILTER_NODE) + { + // node id has a connection + Count++; + } + } + } + + + // move to next connection + Connection++; + } + + ASSERT(Count != 0); + + /* now allocate node index array */ + Refs = (PULONG)MixerContext->Alloc(sizeof(ULONG) * Count); + if (!Refs) + { + // not enough memory + return MM_STATUS_NO_MEMORY; + } + + Count = 0; + Connection = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1); + for(Index = 0; Index < MultipleItem->Count; Index++) + { + if (bNode) + { + if (bFrom) + { + if (Connection->FromNode == NodeIndex) + { + /* node id has a connection */ + Refs[Count] = Index; + Count++; + } + } + else + { + if (Connection->ToNode == NodeIndex) + { + /* node id has a connection */ + Refs[Count] = Index; + Count++; + } + } + } + else + { + if (bFrom) + { + if (Connection->FromNodePin == NodeIndex && Connection->FromNode == KSFILTER_NODE) + { + /* node id has a connection */ + Refs[Count] = Index; + Count++; + } + } + else + { + if (Connection->ToNodePin == NodeIndex && Connection->ToNode == KSFILTER_NODE) + { + /* node id has a connection */ + Refs[Count] = Index; + Count++; + } + } + } + + /* move to next connection */ + Connection++; + } + + /* store result */ + *NodeReference = Refs; + *NodeReferenceCount = Count; + + return MM_STATUS_SUCCESS; +} + +MIXER_STATUS +MMixerGetTargetPins( + IN PMIXER_CONTEXT MixerContext, + IN PKSMULTIPLE_ITEM NodeTypes, + IN PKSMULTIPLE_ITEM NodeConnections, + IN ULONG NodeIndex, + IN ULONG bUpDirection, + OUT PULONG Pins, + IN ULONG PinCount) +{ + ULONG NodeConnectionCount, Index; + MIXER_STATUS Status; + PULONG NodeConnection; + + // sanity check */ + ASSERT(NodeIndex != (ULONG)-1); + + /* get all node indexes referenced by that pin */ + if (bUpDirection) + Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection); + else + Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection); + + //DPRINT("NodeIndex %u Status %x Count %u\n", NodeIndex, Status, NodeConnectionCount); + + if (Status == MM_STATUS_SUCCESS) + { + for(Index = 0; Index < NodeConnectionCount; Index++) + { + Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Pins); + ASSERT(Status == STATUS_SUCCESS); + } + MixerContext->Free((PVOID)NodeConnection); + } + + return Status; +} -- 2.17.1