From 8a0913d231f10aad70e9672c8f1365bf14c57b20 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Fri, 15 Oct 2010 00:20:15 +0000 Subject: [PATCH] [MMIXER] - Rewrite topology node enumeration algorithm - Old algorithm didnt properly take in account sum/mux nodes, may assign nodes to multiple lines and was not able to detect circuits which may lead to infinite loops - New algorithm properly partitions the nodes and also checks if nodes has already been assigned. As a plus, it is also faster - Algorithm based on msdn http://msdn.microsoft.com/en-us/library/ff538873(v=VS.85).aspx - Tested on VBox 3.28 (AC97) - Please retest supported soundcards for regressions svn path=/trunk/; revision=49150 --- reactos/lib/drivers/sound/mmixer/controls.c | 1356 ++++++++--------- reactos/lib/drivers/sound/mmixer/filter.c | 77 +- reactos/lib/drivers/sound/mmixer/mixer.c | 126 +- .../lib/drivers/sound/mmixer/mmixer.rbuild | 1 + reactos/lib/drivers/sound/mmixer/priv.h | 162 +- reactos/lib/drivers/sound/mmixer/sup.c | 245 +-- reactos/lib/drivers/sound/mmixer/topology.c | 1097 +++++++++++++ reactos/lib/drivers/sound/mmixer/wave.c | 58 +- 8 files changed, 2086 insertions(+), 1036 deletions(-) create mode 100644 reactos/lib/drivers/sound/mmixer/topology.c diff --git a/reactos/lib/drivers/sound/mmixer/controls.c b/reactos/lib/drivers/sound/mmixer/controls.c index 5b0ac71ed34..543fb1e99b6 100644 --- a/reactos/lib/drivers/sound/mmixer/controls.c +++ b/reactos/lib/drivers/sound/mmixer/controls.c @@ -8,153 +8,11 @@ #include "priv.h" -MIXER_STATUS -MMixerGetTargetPinsByNodeConnectionIndex( - IN PMIXER_CONTEXT MixerContext, - IN PKSMULTIPLE_ITEM NodeConnections, - IN PKSMULTIPLE_ITEM NodeTypes, - IN ULONG bUpDirection, - IN ULONG NodeConnectionIndex, - IN ULONG PinCount, - 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]); - - // sanity check - ASSERT(PinId < PinCount); - - /* 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], PinCount, 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; - - if (NodeIndex > NodeTypes->Count) - { - // reached end of pin connection - return MM_STATUS_SUCCESS; - } - - /* 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 PTOPOLOGY Topology, IN ULONG NodeIndex, IN LPMIXERLINE_EXT MixerLine, OUT LPMIXERCONTROLW MixerControl) @@ -170,12 +28,12 @@ MMixerAddMixerControl( MixerControl->dwControlID = MixerInfo->ControlId; /* get node type */ - NodeType = MMixerGetNodeType(NodeTypes, NodeIndex); + NodeType = MMixerGetNodeTypeFromTopology(Topology, NodeIndex); /* store control type */ MixerControl->dwControlType = MMixerGetControlTypeFromTopologyNode(NodeType); - MixerControl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM; //FIXME - MixerControl->cMultipleItems = 0; //FIXME + MixerControl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM; /* FIXME */ + MixerControl->cMultipleItems = 0; /* FIXME */ if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) { @@ -186,7 +44,7 @@ MMixerAddMixerControl( { MixerControl->Bounds.dwMinimum = 0; MixerControl->Bounds.dwMaximum = 0xFFFF; - MixerControl->Metrics.cSteps = 0xC0; //FIXME + MixerControl->Metrics.cSteps = 0xC0; /* FIXME */ } /* setup request to retrieve name */ @@ -197,7 +55,7 @@ MMixerAddMixerControl( Node.Reserved = 0; /* get node name size */ - Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned); + Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned); if (Status == MM_STATUS_MORE_ENTRIES) { @@ -210,7 +68,7 @@ MMixerAddMixerControl( } /* get node name */ - Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned); + Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned); if (Status == MM_STATUS_SUCCESS) { @@ -268,7 +126,7 @@ MMixerAddMixerControl( 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); + Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned); if (Status == MM_STATUS_SUCCESS) { @@ -325,495 +183,693 @@ MMixerAddMixerControl( } MIXER_STATUS -MMixerAddMixerSourceLine( +MMixerCreateDestinationLine( IN PMIXER_CONTEXT MixerContext, - IN OUT LPMIXER_INFO MixerInfo, - IN HANDLE hDevice, - IN PKSMULTIPLE_ITEM NodeConnections, - IN PKSMULTIPLE_ITEM NodeTypes, + IN LPMIXER_INFO MixerInfo, + IN ULONG bInputMixer, + IN LPWSTR LineName) +{ + 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 */ + + if (LineName) + { + MixerContext->Copy(DestinationLine->Line.szShortName, LineName, (min(MIXER_SHORT_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR)); + DestinationLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0'; + + MixerContext->Copy(DestinationLine->Line.szName, LineName, (min(MIXER_LONG_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR)); + DestinationLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0'; + + } + + 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; + + ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == 0); + wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname); + + /* initialize extra line */ + InitializeListHead(&DestinationLine->LineControlsExtraData); + + /* insert into mixer info */ + InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry); + + /* done */ + return MM_STATUS_SUCCESS; +} + +MIXER_STATUS +MMixerGetPinName( + IN PMIXER_CONTEXT MixerContext, + IN LPMIXER_INFO MixerInfo, IN ULONG PinId, - IN ULONG bBridgePin, - IN ULONG bTargetPin) + IN OUT LPWSTR * OutBuffer) { - LPMIXERLINE_EXT SrcLine, DstLine; - MIXER_STATUS Status; KSP_PIN Pin; - LPWSTR PinName; - GUID NodeType; - ULONG BytesReturned, ControlCount, Index; - LPGUID Node; - PULONG Nodes; + ULONG BytesReturned; + LPWSTR Buffer; + MIXER_STATUS Status; - if (!bTargetPin) - { - /* allocate src mixer line */ - SrcLine = (LPMIXERLINE_EXT)MixerContext->Alloc(sizeof(MIXERLINE_EXT)); + /* prepare pin */ + 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(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned); - if (!SrcLine) + /* check if buffer overflowed */ + if (Status == MM_STATUS_MORE_ENTRIES) + { + /* allocate buffer */ + Buffer = (LPWSTR)MixerContext->Alloc(BytesReturned); + if (!Buffer) + { + /* out of memory */ return MM_STATUS_NO_MEMORY; + } + + /* try get pin name */ + Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Buffer, BytesReturned, &BytesReturned); + if (Status != MM_STATUS_SUCCESS) + { + /* failed to get pin name */ + MixerContext->Free((PVOID)Buffer); + return Status; + } + + /* successfully obtained pin name */ + *OutBuffer = Buffer; + return MM_STATUS_SUCCESS; + } + + /* failed to get pin name */ + return Status; +} + +MIXER_STATUS +MMixerBuildMixerDestinationLine( + IN PMIXER_CONTEXT MixerContext, + IN OUT LPMIXER_INFO MixerInfo, + IN ULONG PinId, + IN ULONG bInput) +{ + LPWSTR PinName; + MIXER_STATUS Status; + + /* try get pin name */ + Status = MMixerGetPinName(MixerContext, MixerInfo, PinId, &PinName); + if (Status == MM_STATUS_SUCCESS) + { + /* create mixer destination line */ - /* zero struct */ - RtlZeroMemory(SrcLine, sizeof(MIXERLINE_EXT)); + Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInput, PinName); + /* free pin name */ + MixerContext->Free(PinName); } else { - ASSERT(!IsListEmpty(&MixerInfo->LineList)); - SrcLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE); + /* create mixer destination line unlocalized */ + Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInput, L"No Name"); } - /* get destination line */ - DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE); - ASSERT(DstLine); + return Status; +} +MIXER_STATUS +MMixerBuildTopology( + IN PMIXER_CONTEXT MixerContext, + IN LPMIXER_DATA MixerData, + OUT PTOPOLOGY * OutTopology) +{ + ULONG PinsCount; + PKSMULTIPLE_ITEM NodeTypes = NULL; + PKSMULTIPLE_ITEM NodeConnections = NULL; + MIXER_STATUS Status; - if (!bTargetPin) + if (MixerData->Topology) { - /* 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); - - ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == L'\0'); - wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname); + /* re-use existing topology */ + *OutTopology = MixerData->Topology; + return MM_STATUS_SUCCESS; } - /* allocate a node arrary */ - Nodes = (PULONG)MixerContext->Alloc(sizeof(ULONG) * NodeTypes->Count); + /* get connected filter pin count */ + PinsCount = MMixerGetFilterPinCount(MixerContext, MixerData->hDevice); - if (!Nodes) + if (!PinsCount) { - /* not enough memory */ - if (!bTargetPin) - { - MixerContext->Free(SrcLine); - } - return MM_STATUS_NO_MEMORY; + /* referenced filter does not have any pins */ + return MM_STATUS_UNSUCCESSFUL; } - Status = MMixerGetControlsFromPin(MixerContext, NodeConnections, NodeTypes, PinId, bTargetPin, Nodes); + /* get topology node types */ + Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes); if (Status != MM_STATUS_SUCCESS) { - /* something went wrong */ - if (!bTargetPin) - { - MixerContext->Free(SrcLine); - } - MixerContext->Free(Nodes); + /* failed to get topology node types */ return Status; } - /* now count all nodes controlled by that pin */ - ControlCount = 0; - for(Index = 0; Index < NodeTypes->Count; Index++) + /* get topology connections */ + Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections); + if (Status != MM_STATUS_SUCCESS) { - if (Nodes[Index]) - { - // get node type - Node = MMixerGetNodeType(NodeTypes, Index); + /* failed to get topology connections */ + MixerContext->Free(NodeTypes); + return Status; + } - if (MMixerGetControlTypeFromTopologyNode(Node)) - { - // found a node which can be resolved to a type - ControlCount++; - } - } + /* create a topology */ + Status = MMixerCreateTopology(MixerContext, PinsCount, NodeConnections, NodeTypes, OutTopology); + + /* free node types & connections */ + MixerContext->Free(NodeConnections); + MixerContext->Free(NodeTypes); + + if (Status == MM_STATUS_SUCCESS) + { + /* store topology object */ + MixerData->Topology = *OutTopology; } - /* now allocate the line controls */ - if (ControlCount) + /* done */ + return Status; +} + +MIXER_STATUS +MMixerCountMixerControls( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG PinId, + IN ULONG bUpStream, + OUT PULONG OutNodesCount, + OUT PULONG OutNodes, + OUT PULONG OutLineTerminator) +{ + PULONG Nodes; + ULONG NodesCount, NodeIndex, Count, bTerminator; + MIXER_STATUS Status; + + /* allocate an array to store all nodes which are upstream of this pin */ + Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes); + + if (Status != MM_STATUS_SUCCESS) { - SrcLine->LineControls = (LPMIXERCONTROLW)MixerContext->Alloc(sizeof(MIXERCONTROLW) * ControlCount); + /* out of memory */ + return STATUS_NO_MEMORY; + } - if (!SrcLine->LineControls) - { - /* no memory available */ - if (!bTargetPin) - { - MixerContext->Free(SrcLine); - } - MixerContext->Free(Nodes); - return MM_STATUS_NO_MEMORY; - } + /* mark result array as zero */ + *OutNodesCount = 0; + + /* get next nodes */ + MMixerGetNextNodesFromPinIndex(MixerContext, Topology, PinId, bUpStream, &NodesCount, Nodes); + + /* assume no topology split before getting line terminator */ + ASSERT(NodesCount == 1); + + /* get first node */ + NodeIndex = Nodes[0]; + Count = 0; - SrcLine->NodeIds = (PULONG)MixerContext->Alloc(sizeof(ULONG) * ControlCount); - if (!SrcLine->NodeIds) + do + { + /* check if the node is a terminator */ + MMixerIsNodeTerminator(Topology, NodeIndex, &bTerminator); + + if (bTerminator) { - /* no memory available */ - MixerContext->Free(SrcLine->LineControls); - if (!bTargetPin) - { - MixerContext->Free(SrcLine); - } - MixerContext->Free(Nodes); - return MM_STATUS_NO_MEMORY; + /* found terminator */ + break; } - /* zero line controls */ - RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW) * ControlCount); - RtlZeroMemory(SrcLine->NodeIds, sizeof(ULONG) * ControlCount); + /* store node id */ + OutNodes[Count] = NodeIndex; - ControlCount = 0; - for(Index = 0; Index < NodeTypes->Count; Index++) - { - if (Nodes[Index]) - { - // get node type - Node = MMixerGetNodeType(NodeTypes, Index); + /* increment node count */ + Count++; - if (MMixerGetControlTypeFromTopologyNode(Node)) - { - /* 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; - } + /* get next nodes upstream */ + MMixerGetNextNodesFromNodeIndex(MixerContext, Topology, NodeIndex, bUpStream, &NodesCount, Nodes); + + /* assume there is a node connected */ + ASSERT(NodesCount != 0); + ASSERT(NodesCount == 1); + + /* use first index */ + NodeIndex = Nodes[0]; + + }while(TRUE); - /* release nodes array */ + /* free node index */ 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; + /* store nodes count */ + *OutNodesCount = Count; - /* 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) + /* store line terminator */ + *OutLineTerminator = NodeIndex; + + /* done */ + return MM_STATUS_SUCCESS; +} + +MIXER_STATUS +MMixerAddMixerControlsToMixerLineByNodeIndexArray( + IN PMIXER_CONTEXT MixerContext, + IN LPMIXER_INFO MixerInfo, + IN PTOPOLOGY Topology, + IN OUT LPMIXERLINE_EXT DstLine, + IN ULONG NodesCount, + IN PULONG Nodes) +{ + ULONG Index, Count, bReserved; + MIXER_STATUS Status; + + /* store nodes array */ + DstLine->NodeIds = Nodes; + + /* allocate MIXERCONTROLSW array */ + DstLine->LineControls = MixerContext->Alloc(NodesCount * sizeof(MIXERCONTROLW)); + + if (!DstLine->LineControls) { - //FIXME - //map component type + /* out of memory */ + return MM_STATUS_NO_MEMORY; } - /* 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); + /* initialize control count */ + Count = 0; - if (Status == MM_STATUS_MORE_ENTRIES) + for(Index = 0; Index < NodesCount; Index++) { - PinName = (LPWSTR)MixerContext->Alloc(BytesReturned); - if (PinName) + /* check if the node has already been reserved to a line */ + MMixerIsTopologyNodeReserved(Topology, Nodes[Index], &bReserved); + + if (bReserved) { - /* try get pin name */ - Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)PinName, BytesReturned, &BytesReturned); + /* node is already used, skip it */ + continue; + } - if (Status == MM_STATUS_SUCCESS) - { - MixerContext->Copy(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR)); - SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0'; + /* set node status as used */ + MMixerSetTopologyNodeReserved(Topology, Nodes[Index]); - MixerContext->Copy(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); + /* now add the mixer control */ + Status = MMixerAddMixerControl(MixerContext, MixerInfo, Topology, Nodes[Index], DstLine, &DstLine->LineControls[Count]); + + if (Status == MM_STATUS_SUCCESS) + { + /* increment control count */ + Count++; } } - /* insert src line */ - if (!bTargetPin) - { - InsertTailList(&MixerInfo->LineList, &SrcLine->Entry); - DstLine->Line.cConnections++; - } + /* store control count */ + DstLine->Line.cControls = Count; + /* done */ return MM_STATUS_SUCCESS; } MIXER_STATUS -MMixerCreateDestinationLine( +MMixerBuildMixerSourceLine( IN PMIXER_CONTEXT MixerContext, - IN LPMIXER_INFO MixerInfo, - IN ULONG bInputMixer, - IN LPWSTR LineName) + IN OUT LPMIXER_INFO MixerInfo, + IN PTOPOLOGY Topology, + IN ULONG PinId, + IN ULONG NodesCount, + IN PULONG Nodes, + OUT LPMIXERLINE_EXT * OutSrcLine) { - LPMIXERLINE_EXT DestinationLine; + LPMIXERLINE_EXT SrcLine, DstLine; + LPWSTR PinName; + MIXER_STATUS Status; - // allocate a mixer destination line - DestinationLine = (LPMIXERLINE_EXT) MixerContext->Alloc(sizeof(MIXERLINE_EXT)); - if (!MixerInfo) + /* construct source line */ + SrcLine = (LPMIXERLINE_EXT)MixerContext->Alloc(sizeof(MIXERLINE_EXT)); + + if (!SrcLine) { - // no memory + /* 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 + /* get destination line */ + DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE); + ASSERT(DstLine); - if (LineName) + /* initialize mixer src line */ + SrcLine->hDevice = MixerInfo->hMixer; + SrcLine->PinId = PinId; + SrcLine->NodeIds = Nodes; + + /* initialize mixer 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); + + /* copy name */ + ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == L'\0'); + wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname); + + /* get pin name */ + Status = MMixerGetPinName(MixerContext, MixerInfo, PinId, &PinName); + + if (Status == MM_STATUS_SUCCESS) { - MixerContext->Copy(DestinationLine->Line.szShortName, LineName, (min(MIXER_SHORT_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR)); - DestinationLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0'; + /* store pin name as line name */ + MixerContext->Copy(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR)); + SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0'; - MixerContext->Copy(DestinationLine->Line.szName, LineName, (min(MIXER_LONG_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR)); - DestinationLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0'; + MixerContext->Copy(SrcLine->Line.szName, PinName, (min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR)); + SrcLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0'; + /* free pin name buffer */ + MixerContext->Free(PinName); } - else + + /* add the controls to mixer line */ + Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, Topology, SrcLine, NodesCount, Nodes); + if (Status != MM_STATUS_SUCCESS) { - /* FIXME no name was found for pin */ - wcscpy(DestinationLine->Line.szShortName, L"Summe"); - wcscpy(DestinationLine->Line.szName, L"Summe"); + /* failed */ + return Status; } - 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; - - ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == 0); - wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname); - - // initialize extra line - InitializeListHead(&DestinationLine->LineControlsExtraData); + /* store result */ + *OutSrcLine = SrcLine; - // insert into mixer info - InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry); - - // done return MM_STATUS_SUCCESS; } MIXER_STATUS -MMixerGetControlsFromPin( +MMixerAddMixerSourceLines( IN PMIXER_CONTEXT MixerContext, - IN PKSMULTIPLE_ITEM NodeConnections, - IN PKSMULTIPLE_ITEM NodeTypes, - IN ULONG PinId, - IN ULONG bUpDirection, - OUT PULONG Nodes) + IN OUT LPMIXER_INFO MixerInfo, + IN PTOPOLOGY Topology, + IN ULONG LineTerminator) { - ULONG NodeConnectionCount, Index; + PULONG AllNodes, AllPins, AllPinNodes; + ULONG AllNodesCount, AllPinsCount, AllPinNodesCount; + ULONG Index, SubIndex, PinId, CurNode, bConnected; MIXER_STATUS Status; - PULONG NodeConnection; + LPMIXERLINE_EXT DstLine, SrcLine; - /* sanity check */ - ASSERT(PinId != (ULONG)-1); + /* get destination line */ + DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE); + ASSERT(DstLine); - /* 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); + /* allocate an array to store all nodes which are upstream of the line terminator */ + Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &AllNodes); - for(Index = 0; Index < NodeConnectionCount; Index++) + /* check for success */ + if (Status != MM_STATUS_SUCCESS) { - /* get all associated controls */ - Status = MMixerGetControlsFromPinByConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes); + /* out of memory */ + return MM_STATUS_NO_MEMORY; } - MixerContext->Free(NodeConnection); + /* allocate an array to store all nodes which are downstream of a particular pin */ + Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &AllPinNodes); - return Status; -} + /* allocate an array to store all pins which are upstream of this pin */ + Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &AllPins); + + /* check for success */ + if (Status != MM_STATUS_SUCCESS) + { + /* out of memory */ + MixerContext->Free(AllNodes); + return MM_STATUS_NO_MEMORY; + } + + /* get all nodes which indirectly / directly connect to this node */ + AllNodesCount = 0; + MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext, Topology, LineTerminator, TRUE, &AllNodesCount, AllNodes); + /* get all pins which indirectly / directly connect to this node */ + MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, LineTerminator, TRUE, &AllPinsCount, AllPins); + DPRINT("LineTerminator %lu\n", LineTerminator); + DPRINT("PinCount %lu\n", AllPinsCount); + DPRINT("AllNodesCount %lu\n", AllNodesCount); + + /* now construct the source lines which are attached to the destination line */ + Index = AllPinsCount; + + do + { + /* get current pin id */ + PinId = AllPins[Index - 1]; + + /* reset nodes count */ + AllPinNodesCount = 0; + + /* now scan all nodes and add them to AllPinNodes array when they are connected to this pin */ + for(SubIndex = 0; SubIndex < AllNodesCount; SubIndex++) + { + /* get current node index */ + CurNode = AllNodes[SubIndex]; + + if (CurNode != MAXULONG && CurNode != LineTerminator) + { + /* check if that node is connected in some way to the current pin */ + Status = MMixerIsNodeConnectedToPin(MixerContext, Topology, CurNode, PinId, TRUE, &bConnected); + + if (Status != MM_STATUS_SUCCESS) + break; + + if (bConnected) + { + /* it is connected */ + AllPinNodes[AllPinNodesCount] = CurNode; + AllPinNodesCount++; + + /* clear current index */ + AllNodes[SubIndex] = MAXULONG; + } + } + } + + /* decrement pin index */ + Index--; + + if (AllPinNodesCount) + { + /* now build the mixer source line */ + Status = MMixerBuildMixerSourceLine(MixerContext, MixerInfo, Topology, PinId, AllPinNodesCount, AllPinNodes, &SrcLine); + + if (Status == MM_STATUS_SUCCESS) + { + /* insert into line list */ + InsertTailList(&MixerInfo->LineList, &SrcLine->Entry); + + /* increment destination line count */ + DstLine->Line.cConnections++; + } + } + + }while(Index != 0); + + return MM_STATUS_SUCCESS; +} MIXER_STATUS -MMixerAddMixerSourceLines( +MMixerAddMixerControlsToDestinationLine( 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) + IN PTOPOLOGY Topology, + IN ULONG PinId, + IN ULONG bInput, + OUT PULONG OutLineTerminator) { - ULONG Index; + PULONG Nodes; + ULONG NodesCount, LineTerminator; + MIXER_STATUS Status; + LPMIXERLINE_EXT DstLine; + + /* allocate nodes index array */ + Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes); + + /* check for success */ + if (Status != MM_STATUS_SUCCESS) + { + /* out of memory */ + return MM_STATUS_NO_MEMORY; + } + + /* get all destination line controls */ + Status = MMixerCountMixerControls(MixerContext, Topology, PinId, TRUE, &NodesCount, Nodes, &LineTerminator); + + /* check for success */ + if (Status != MM_STATUS_SUCCESS) + { + /* failed to count controls */ + MixerContext->Free(Nodes); + return Status; + } + + /* get destination mixer line */ + DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE); + + /* sanity check */ + ASSERT(DstLine); - for(Index = PinsCount; Index > 0; Index--) + if (NodesCount > 0) { - DPRINT("MMixerAddMixerSourceLines Index %lu Pin %lu\n", Index-1, Pins[Index-1]); - if (Pins[Index-1]) + /* add all nodes as mixer controls to the destination line */ + Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, Topology, DstLine, NodesCount, Nodes); + if (Status != MM_STATUS_SUCCESS) { - MMixerAddMixerSourceLine(MixerContext, MixerInfo, hDevice, NodeConnections, NodeTypes, Index-1, (Index -1 == BridgePinIndex), (Index -1 == TargetPinIndex)); + /* failed to add controls */ + MixerContext->Free(Nodes); + return Status; } } - return MM_STATUS_SUCCESS; -} + /* store result */ + *OutLineTerminator = LineTerminator; + + /* return result */ + return Status; +} MIXER_STATUS MMixerHandlePhysicalConnection( IN PMIXER_CONTEXT MixerContext, IN PMIXER_LIST MixerList, + IN LPMIXER_DATA MixerData, 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; - PKSMULTIPLE_ITEM NodeTypes = NULL; - PKSMULTIPLE_ITEM NodeConnections = NULL; - PULONG MixerControls; - ULONG MixerControlsCount; - LPMIXER_DATA MixerData; - + ULONG PinsCount, LineTerminator; + PULONG Pins; + PTOPOLOGY Topology; - // open the connected filter + /* first try to open the connected filter */ OutConnection->SymbolicLinkName[1] = L'\\'; MixerData = MMixerGetDataByDeviceName(MixerList, OutConnection->SymbolicLinkName); - ASSERT(MixerData); - // store connected mixer handle - MixerInfo->hMixer = MixerData->hDevice; - - // get connected filter pin count - PinsRefCount = MMixerGetFilterPinCount(MixerContext, MixerData->hDevice); - ASSERT(PinsRefCount); + /* check if the linked connection is found */ + if (!MixerData) + { + /* filter references invalid physical connection */ + return MM_STATUS_UNSUCCESSFUL; + } - PinsRef = (PULONG)MixerContext->Alloc(sizeof(ULONG) * PinsRefCount); - if (!PinsRef) - { - // no memory - return MM_STATUS_UNSUCCESSFUL; - } + DPRINT("Name %S, Pin %lu bInput %lu\n", OutConnection->SymbolicLinkName, OutConnection->Pin, bInput); - // get topology node types - Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes); - if (Status != MM_STATUS_SUCCESS) - { - MixerContext->Free(PinsRef); - return Status; - } + /* store connected mixer handle */ + MixerInfo->hMixer = MixerData->hDevice; - // get topology connections - Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections); - if (Status != MM_STATUS_SUCCESS) - { - MixerContext->Free(PinsRef); - MixerContext->Free(NodeTypes); - return Status; - } - // gets connection index of the bridge pin which connects to a node - DPRINT("Pin %lu\n", OutConnection->Pin); - Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, OutConnection->Pin, FALSE, !bInput, &PinConnectionIndexCount, &PinConnectionIndex); + Status = MMixerBuildTopology(MixerContext, MixerData, &Topology); if (Status != MM_STATUS_SUCCESS) { - MixerContext->Free(PinsRef); - MixerContext->Free(NodeTypes); - MixerContext->Free(NodeConnections); + /* failed to create topology */ return Status; } - /* there should be no split in the bridge pin */ - ASSERT(PinConnectionIndexCount == 1); + /* allocate pin index array which will hold all referenced pins */ + Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins); + ASSERT(Status == MM_STATUS_SUCCESS); - /* find all target pins of this connection */ - Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, FALSE, PinConnectionIndex[0], PinsRefCount, PinsRef); - if (Status != MM_STATUS_SUCCESS) + if (!bInput) { - MixerContext->Free(PinsRef); - MixerContext->Free(NodeTypes); - MixerContext->Free(NodeConnections); - MixerContext->Free(PinConnectionIndex); - return Status; - } + /* the mixer is an output mixer + * find end pin of the node path + */ + Status = MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext, Topology, OutConnection->Pin, FALSE, &PinsCount, Pins); - for(Index = 0; Index < PinsRefCount; Index++) - { - DPRINT("PinsRefCount %lu Index %lu Value %lu\n", PinsRefCount, Index, PinsRef[Index]); - if (PinsRef[Index]) + /* check for success */ + if (Status != MM_STATUS_SUCCESS) { - // found a target pin, now get all references - Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Index, FALSE, FALSE, &MixerControlsCount, &MixerControls); - if (Status != MM_STATUS_SUCCESS) - { - DPRINT("MMixerGetNodeIndexes failed with %u\n", Status); - break; - } + /* failed to get end pin */ + MixerContext->Free(Pins); + //MMixerFreeTopology(Topology); - /* sanity check */ - ASSERT(MixerControlsCount == 1); + /* return error code */ + return Status; + } - PinsSrcRef = (PULONG)MixerContext->Alloc(PinsRefCount * sizeof(ULONG)); - if (!PinsSrcRef) - { - /* no memory */ - MixerContext->Free(PinsRef); - MixerContext->Free(NodeTypes); - MixerContext->Free(NodeConnections); - MixerContext->Free(PinConnectionIndex); - MixerContext->Free(MixerControls); - return MM_STATUS_NO_MEMORY; - } + /* sanity checks */ + ASSERT(PinsCount != 0); + ASSERT(PinsCount == 1); - // now get all connected source pins - Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, TRUE, MixerControls[0], PinsRefCount, PinsSrcRef); - if (Status != MM_STATUS_SUCCESS) - { - // failed */ - MixerContext->Free(PinsRef); - MixerContext->Free(NodeTypes); - MixerContext->Free(NodeConnections); - MixerContext->Free(PinConnectionIndex); - MixerContext->Free(MixerControls); - MixerContext->Free(PinsSrcRef); - return Status; - } + /* create destination line */ + Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, Pins[0], bInput); - /* 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; + if (Status != MM_STATUS_SUCCESS) + { + MixerContext->Free(Pins); + //MMixerFreeTopology(Topology); + + /* return error code */ + return Status; + } + + /* add mixer controls to destination line */ + Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, Topology, Pins[0], bInput, &LineTerminator); - Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, NodeConnections, NodeTypes, PinsRefCount, OutConnection->Pin, Index, PinsSrcRef); + if (Status == MM_STATUS_SUCCESS) + { + /* now add the rest of the source lines */ + Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, Topology, LineTerminator); + } + } + else + { + Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, Topology, OutConnection->Pin, bInput, &LineTerminator); - MixerContext->Free(MixerControls); - MixerContext->Free(PinsSrcRef); + if (Status == MM_STATUS_SUCCESS) + { + /* now add the rest of the source lines */ + Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, Topology, LineTerminator); } } + /* free topology */ + //MMixerFreeTopology(Topology); + return Status; } @@ -823,193 +879,137 @@ MMixerInitializeFilter( IN PMIXER_CONTEXT MixerContext, IN PMIXER_LIST MixerList, IN LPMIXER_DATA MixerData, - IN PKSMULTIPLE_ITEM NodeTypes, - IN PKSMULTIPLE_ITEM NodeConnections, - IN ULONG PinCount, + IN PTOPOLOGY Topology, IN ULONG NodeIndex, IN ULONG bInputMixer) { LPMIXER_INFO MixerInfo; MIXER_STATUS Status; PKSPIN_PHYSICALCONNECTION OutConnection; - ULONG Index; ULONG * Pins; - ULONG bUsed; - ULONG BytesReturned; - KSP_PIN Pin; - LPWSTR Buffer = NULL; - ULONG PinId; + ULONG PinsFound; - // allocate a mixer info struct + /* allocate a mixer info struct */ MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO)); if (!MixerInfo) { - // no memory + /* 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 + /* 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 = MixerData->hDevice; - // get mixer name + /* get mixer name */ MMixerGetDeviceName(MixerContext, MixerInfo, MixerData->hDeviceInterfaceKey); - // initialize line list + /* initialize line list */ InitializeListHead(&MixerInfo->LineList); InitializeListHead(&MixerInfo->EventList); - // sanity check - ASSERT(PinCount); + /* now allocate an array which will receive the indices of the pin + * which has a ADC / DAC nodetype in its path + */ + Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins); + ASSERT(Status == MM_STATUS_SUCCESS); - // 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)); + PinsFound = 0; - if (!Pins) - { - // no memory - MMixerFreeMixerInfo(MixerContext, MixerInfo); - return MM_STATUS_NO_MEMORY; - } + /* now get all sink / source pins, which are attached to the ADC / DAC node + * For sink pins (wave out) search up stream + * For source pins (wave in) search down stream + * The search direction is always the opposite of the current mixer type + */ + MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, !bInputMixer, &PinsFound, Pins); - // now get the target pins of the ADC / DAC node - Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, !bInputMixer, Pins, PinCount); + /* if there is now pin found, we have a broken topology */ + ASSERT(PinsFound != 0); - // find a target pin with a name - PinId = PinCount +1; - for(Index = 0; Index < PinCount; Index++) + /* now create a wave info struct */ + Status = MMixerInitializeWaveInfo(MixerContext, MixerList, MixerData, MixerInfo->MixCaps.szPname, bInputMixer, PinsFound, Pins); + if (Status != MM_STATUS_SUCCESS) { - if (Pins[Index]) - { - // store index of pin - PinId = Index; - - /* retrieve pin name */ - Pin.PinId = Index; - Pin.Reserved = 0; - Pin.Property.Flags = KSPROPERTY_TYPE_GET; - Pin.Property.Set = KSPROPSETID_Pin; - Pin.Property.Id = KSPROPERTY_PIN_NAME; + /* failed to create wave info struct */ + MixerContext->Free(MixerInfo); + MixerContext->Free(Pins); + return Status; + } - /* try get pin name size */ - Status = MixerContext->Control(MixerData->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned); + if (bInputMixer) + { + /* pre create the mixer destination line for input mixers */ + Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, Pins[0], bInputMixer); - if (Status == MM_STATUS_MORE_ENTRIES) - { - Buffer = (LPWSTR)MixerContext->Alloc(BytesReturned); - if (Buffer) - { - /* try get pin name */ - Status = MixerContext->Control(MixerData->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Buffer, BytesReturned, &BytesReturned); - if (Status != MM_STATUS_SUCCESS) - { - MixerContext->Free((PVOID)Buffer); - Buffer = NULL; - } - else - { - // found name, done - break; - } - } - } + if (Status != MM_STATUS_SUCCESS) + { + /* failed to create mixer destination line */ + return Status; } } - if (PinId < PinCount) - { - // create an wave info struct - MMixerInitializeWaveInfo(MixerContext, MixerList, MixerData, MixerInfo->MixCaps.szPname, bInputMixer, PinId); - } - Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInputMixer, Buffer); + /* now get the bridge pin which is at the end of node path + * For sink pins (wave out) search down stream + * For source pins (wave in) search up stream + */ + MixerContext->Free(Pins); + Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins); + ASSERT(Status == MM_STATUS_SUCCESS); - if (Buffer) - { - // free name - MixerContext->Free(Buffer); - } + MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, bInputMixer, &PinsFound, Pins); - if (Status != MM_STATUS_SUCCESS) - { - // failed to create destination line - MixerContext->Free(MixerInfo); - MixerContext->Free(Pins); + /* if there is no pin found, we have a broken topology */ + ASSERT(PinsFound != 0); - return Status; - } + /* there should be exactly one bridge pin */ + ASSERT(PinsFound == 1); - RtlZeroMemory(Pins, sizeof(ULONG) * PinCount); - // now get the target pins of the ADC / DAC node - Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, bInputMixer, Pins, PinCount); + DPRINT("BridgePin %lu bInputMixer %lu\n", Pins[0], bInputMixer); - if (Status != MM_STATUS_SUCCESS) - { - // failed to locate target pins - MixerContext->Free(Pins); - MMixerFreeMixerInfo(MixerContext, MixerInfo); - DPRINT("MMixerGetTargetPins failed with %u\n", Status); - return Status; - } + /* does the pin have a physical connection */ + Status = MMixerGetPhysicalConnection(MixerContext, MixerData->hDevice, Pins[0], &OutConnection); - // filter hasnt been used - bUsed = FALSE; + if (Status == MM_STATUS_SUCCESS) + { + /* topology on the topoloy filter */ + Status = MMixerHandlePhysicalConnection(MixerContext, MixerList, MixerData, MixerInfo, bInputMixer, OutConnection); - // now check all pins and generate new lines for destination lines - for(Index = 0; Index < PinCount; Index++) + /* free physical connection data */ + MixerContext->Free(OutConnection); + } + else { - DPRINT("Index %lu TargetPin %lu\n", Index, Pins[Index]); - // is the current index a target pin - if (Pins[Index]) - { - // check if the pin has a physical connection - Status = MMixerGetPhysicalConnection(MixerContext, MixerData->hDevice, Index, &OutConnection); - if (Status == MM_STATUS_SUCCESS) - { - // the pin has a physical connection - Status = MMixerHandlePhysicalConnection(MixerContext, MixerList, MixerInfo, bInputMixer, OutConnection); - DPRINT("MMixerHandlePhysicalConnection status %u\n", Status); - MixerContext->Free(OutConnection); - bUsed = TRUE; - } - else - { - // filter exposes the topology on the same filter - MMixerAddMixerSourceLine(MixerContext, MixerInfo, MixerData->hDevice, NodeConnections, NodeTypes, Index, FALSE, FALSE); - bUsed = TRUE; - } - } + /* FIXME + * handle drivers which expose their topology on the same filter + */ + ASSERT(0); } + + /* free pins */ MixerContext->Free(Pins); - if (bUsed) + if (!bInputMixer && MixerList->MixerListCount == 1) { - // store mixer info in list - if (!bInputMixer && MixerList->MixerListCount == 1) - { - //FIXME preferred device should be inserted at front - //windows always inserts output mixer in front - InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry); - } - else - { - InsertTailList(&MixerList->MixerList, &MixerInfo->Entry); - } - MixerList->MixerListCount++; - DPRINT("New MixerCount %lu\n", MixerList->MixerListCount); + /* FIXME preferred device should be inserted at front + * windows always inserts output mixer in front + */ + InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry); } else { - // failed to create a mixer topology - MMixerFreeMixerInfo(MixerContext, MixerInfo); + /* insert at back */ + InsertTailList(&MixerList->MixerList, &MixerInfo->Entry); } - // done + /* increment mixer count */ + MixerList->MixerListCount++; + + /* done */ return Status; } @@ -1020,71 +1020,64 @@ MMixerSetupFilter( IN LPMIXER_DATA MixerData, IN PULONG DeviceCount) { - PKSMULTIPLE_ITEM NodeTypes = NULL, NodeConnections = NULL; MIXER_STATUS Status; - ULONG PinCount; + PTOPOLOGY Topology; ULONG NodeIndex; - // get number of pins - PinCount = MMixerGetFilterPinCount(MixerContext, MixerData->hDevice); - ASSERT(PinCount); - DPRINT("NumOfPins: %lu\n", PinCount); - - // get filter node types - Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes); - if (Status != MM_STATUS_SUCCESS) + /* check if topology has already been built */ + if (MixerData->Topology == NULL) { - // failed - return Status; - } + /* build topology */ + Status = MMixerBuildTopology(MixerContext, MixerData, &Topology); - // get filter node connections - Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections); - if (Status != MM_STATUS_SUCCESS) + if (Status != MM_STATUS_SUCCESS) + { + /* failed to build topology */ + return Status; + } + + /* store topology */ + MixerData->Topology = Topology; + } + else { - // failed - MixerContext->Free(NodeTypes); - return Status; + /* re-use topology */ + Topology = MixerData->Topology; } - // check if the filter has an wave out node - - NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_DAC); + /* check if the filter has an wave out node */ + NodeIndex = MMixerGetNodeIndexFromGuid(Topology, &KSNODETYPE_DAC); if (NodeIndex != MAXULONG) { - // it has - Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, NodeTypes, NodeConnections, PinCount, NodeIndex, FALSE); - DPRINT("MMixerInitializeFilter Status %u\n", Status); - // check for success + /* it has */ + Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, Topology, NodeIndex, FALSE); + + /* check for success */ if (Status == MM_STATUS_SUCCESS) { - // increment mixer count + /* increment mixer count */ (*DeviceCount)++; } } - // check if the filter has an wave in node - NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_ADC); + /* check if the filter has an wave in node */ + NodeIndex = MMixerGetNodeIndexFromGuid(Topology, &KSNODETYPE_ADC); if (NodeIndex != MAXULONG) { - // it has - Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, NodeTypes, NodeConnections, PinCount, NodeIndex, TRUE); - DPRINT("MMixerInitializeFilter Status %u\n", Status); - // check for success + /* it has */ + Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, Topology, NodeIndex, TRUE); + + /* check for success */ if (Status == MM_STATUS_SUCCESS) { - // increment mixer count + /* increment mixer count */ (*DeviceCount)++; } } - //free resources - MixerContext->Free((PVOID)NodeTypes); - MixerContext->Free((PVOID)NodeConnections); - - // done + /* done */ return Status; } @@ -1103,7 +1096,7 @@ MMixerAddEvent( EventData = (LPEVENT_ITEM)MixerContext->AllocEventData(sizeof(LIST_ENTRY)); if (!EventData) { - // not enough memory + /* not enough memory */ return MM_STATUS_NO_MEMORY; } @@ -1118,12 +1111,12 @@ MMixerAddEvent( Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSP_NODE), (PVOID)EventData, sizeof(KSEVENTDATA), &BytesReturned); if (Status != MM_STATUS_SUCCESS) { - // failed to add event + /* failed to add event */ MixerContext->FreeEventData(EventData); return Status; } - //store event + /* store event */ InsertTailList(&MixerInfo->EventList, &EventData->Entry); return Status; } @@ -1138,12 +1131,12 @@ MMixerAddEvents( MIXER_STATUS Status; LPGUID Guid; - // get filter node types + /* get filter node types */ Status = MMixerGetFilterTopologyProperty(MixerContext, MixerInfo->hMixer, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes); if (Status != MM_STATUS_SUCCESS) { - // failed + /* failed */ return Status; } @@ -1152,13 +1145,14 @@ MMixerAddEvents( Guid = MMixerGetNodeType(NodeTypes, Index); if (IsEqualGUID(&KSNODETYPE_VOLUME, Guid) || IsEqualGUID(&KSNODETYPE_MUTE, Guid)) { - //add an event for volume / mute controls - //TODO: extra control types + /* add an event for volume / mute controls + * TODO: support extra control types + */ MMixerAddEvent(MixerContext, MixerInfo, Index); } } - // free node types + /* free node types */ MixerContext->Free(NodeTypes); return MM_STATUS_SUCCESS; diff --git a/reactos/lib/drivers/sound/mmixer/filter.c b/reactos/lib/drivers/sound/mmixer/filter.c index 955fd273ae9..9a2739e2992 100644 --- a/reactos/lib/drivers/sound/mmixer/filter.c +++ b/reactos/lib/drivers/sound/mmixer/filter.c @@ -19,15 +19,15 @@ MMixerGetFilterPinCount( MIXER_STATUS Status; ULONG NumPins, BytesReturned; - // setup property request + /* setup property request */ Pin.Flags = KSPROPERTY_TYPE_GET; Pin.Set = KSPROPSETID_Pin; Pin.Id = KSPROPERTY_PIN_CTYPES; - // query pin count + /* query pin count */ Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&NumPins, sizeof(ULONG), (PULONG)&BytesReturned); - // check for success + /* check for success */ if (Status != MM_STATUS_SUCCESS) return 0; @@ -46,43 +46,43 @@ MMixerGetFilterTopologyProperty( MIXER_STATUS Status; ULONG BytesReturned; - // setup property request + /* setup property request */ Property.Id = PropertyId; Property.Flags = KSPROPERTY_TYPE_GET; Property.Set = KSPROPSETID_Topology; - // query for the size + /* 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; - //sanity check + /* sanity check */ ASSERT(BytesReturned); - // allocate an result buffer + /* allocate an result buffer */ MultipleItem = (PKSMULTIPLE_ITEM)MixerContext->Alloc(BytesReturned); if (!MultipleItem) { - // not enough memory + /* not enough memory */ return MM_STATUS_NO_MEMORY; } - // query again with allocated buffer + /* 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 + /* failed */ MixerContext->Free((PVOID)MultipleItem); return Status; } - // store result + /* store result */ *OutMultipleItem = MultipleItem; - // done + /* done */ return Status; } @@ -109,24 +109,23 @@ MMixerGetPhysicalConnection( if (Status == MM_STATUS_UNSUCCESSFUL) { - // pin does not have a physical connection + /* pin does not have a physical connection */ return Status; } DPRINT("Status %u BytesReturned %lu\n", Status, BytesReturned); Connection = (PKSPIN_PHYSICALCONNECTION)MixerContext->Alloc(BytesReturned); if (!Connection) { - // not enough memory + /* not enough memory */ return MM_STATUS_NO_MEMORY; } - // query the pin for the physical connection + /* 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 + /* failed to query the physical connection */ MixerContext->Free(Connection); - DPRINT("Status %u\n", Status); return Status; } @@ -141,73 +140,76 @@ MMixerGetControlTypeFromTopologyNode( { if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_AGC)) { - // automatic gain control + /* automatic gain control */ return MIXERCONTROL_CONTROLTYPE_ONOFF; } else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_LOUDNESS)) { - // loudness control + /* loudness control */ return MIXERCONTROL_CONTROLTYPE_LOUDNESS; } - else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUTE )) + else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUTE)) { - // mute control + /* 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 + /* tone 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 + /* volume control */ return MIXERCONTROL_CONTROLTYPE_VOLUME; } else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_PEAKMETER)) { - // peakmeter control + /* peakmeter control */ return MIXERCONTROL_CONTROLTYPE_PEAKMETER; } else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUX)) { - // mux control + /* mux control */ return MIXERCONTROL_CONTROLTYPE_MUX; } else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_MUX)) { - // mux control + /* mux control */ return MIXERCONTROL_CONTROLTYPE_MUX; } else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_STEREO_WIDE)) { - // stero wide control + /* stero wide control */ return MIXERCONTROL_CONTROLTYPE_FADER; } else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_CHORUS)) { - // chorus control + /* chorus control */ return MIXERCONTROL_CONTROLTYPE_FADER; } else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_REVERB)) { - // reverb control + /* reverb control */ return MIXERCONTROL_CONTROLTYPE_FADER; } else if (IsEqualGUIDAligned(NodeType, (LPGUID)&KSNODETYPE_SUPERMIX)) { - // supermix control - // MIXERCONTROL_CONTROLTYPE_MUTE if KSPROPERTY_AUDIO_MUTE is supported + /* supermix control + * MIXERCONTROL_CONTROLTYPE_MUTE if KSPROPERTY_AUDIO_MUTE is supported + */ UNIMPLEMENTED; return MIXERCONTROL_CONTROLTYPE_VOLUME; } - //TODO - //check for other supported node types + /* TODO + * check for other supported node types + */ //UNIMPLEMENTED return 0; } @@ -279,4 +281,3 @@ MMixerGetPinInstanceCount( ASSERT(Status == MM_STATUS_SUCCESS); return PinInstances.CurrentCount; } - diff --git a/reactos/lib/drivers/sound/mmixer/mixer.c b/reactos/lib/drivers/sound/mmixer/mixer.c index 4ef2ea9e62a..9b317ce6b75 100644 --- a/reactos/lib/drivers/sound/mmixer/mixer.c +++ b/reactos/lib/drivers/sound/mmixer/mixer.c @@ -17,16 +17,16 @@ MMixerGetCount( PMIXER_LIST MixerList; MIXER_STATUS Status; - // verify mixer context + /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); if (Status != MM_STATUS_SUCCESS) { - // invalid context passed + /* invalid context passed */ return Status; } - // grab mixer list + /* grab mixer list */ MixerList = (PMIXER_LIST)MixerContext->MixerContext; // return number of mixers @@ -42,16 +42,16 @@ MMixerGetCapabilities( MIXER_STATUS Status; LPMIXER_INFO MixerInfo; - // verify mixer context + /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); if (Status != MM_STATUS_SUCCESS) { - // invalid context passed + /* invalid context passed */ return Status; } - // get mixer info + /* get mixer info */ MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, MixerIndex); if (!MixerInfo) @@ -83,29 +83,30 @@ MMixerOpen( MIXER_STATUS Status; LPMIXER_INFO MixerInfo; - // verify mixer context + /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); if (Status != MM_STATUS_SUCCESS) { - // invalid context passed + /* invalid context passed */ return Status; } MixerInfo = (LPMIXER_INFO)MMixerGetMixerInfoByIndex(MixerContext, MixerId); if (!MixerInfo) { - // invalid mixer id + /* invalid mixer id */ return MM_STATUS_INVALID_PARAMETER; } - // FIXME - // handle event notification + /* FIXME + * handle event notification + */ Status = MMixerAddEvents(MixerContext, MixerInfo); - // store result + /* store result */ *MixerHandle = (HANDLE)MixerInfo; return MM_STATUS_SUCCESS; @@ -122,26 +123,26 @@ MMixerGetLineInfo( LPMIXER_INFO MixerInfo; LPMIXERLINE_EXT MixerLineSrc; - // verify mixer context + /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); if (Status != MM_STATUS_SUCCESS) { - // invalid context passed + /* invalid context passed */ return Status; } - // clear hmixer from flags + /* clear hmixer from flags */ Flags &=~MIXER_OBJECTF_HMIXER; if (Flags == MIXER_GETLINEINFOF_DESTINATION) { - // cast to mixer info + /* cast to mixer info */ MixerInfo = (LPMIXER_INFO)MixerHandle; if (MixerLine->dwDestination != 0) { - // destination line member must be zero + /* destination line member must be zero */ return MM_STATUS_INVALID_PARAMETER; } @@ -153,7 +154,7 @@ MMixerGetLineInfo( } else if (Flags == MIXER_GETLINEINFOF_SOURCE) { - // cast to mixer info + /* cast to mixer info */ MixerInfo = (LPMIXER_INFO)MixerHandle; @@ -162,9 +163,9 @@ MMixerGetLineInfo( if (MixerLine->dwSource >= MixerLineSrc->Line.cConnections) { - DPRINT1("dwSource %u > Destinations %u\n", MixerLine->dwSource, MixerLineSrc->Line.cConnections); + DPRINT("dwSource %u > Destinations %u\n", MixerLine->dwSource, MixerLineSrc->Line.cConnections); - // invalid parameter + /* invalid parameter */ return MM_STATUS_INVALID_PARAMETER; } @@ -179,13 +180,13 @@ MMixerGetLineInfo( } else if (Flags == MIXER_GETLINEINFOF_LINEID) { - // cast to mixer info + /* cast to mixer info */ MixerInfo = (LPMIXER_INFO)MixerHandle; MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLine->dwLineID); if (!MixerLineSrc) { - // invalid parameter + /* invalid parameter */ return MM_STATUS_INVALID_PARAMETER; } @@ -195,7 +196,7 @@ MMixerGetLineInfo( } else if (Flags == MIXER_GETLINEINFOF_COMPONENTTYPE) { - // cast to mixer info + /* cast to mixer info */ MixerInfo = (LPMIXER_INFO)MixerHandle; MixerLineSrc = MMixerGetSourceMixerLineByComponentType(MixerInfo, MixerLine->dwComponentType); @@ -228,12 +229,12 @@ MMixerGetLineControls( MIXER_STATUS Status; ULONG Index; - // verify mixer context + /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); if (Status != MM_STATUS_SUCCESS) { - // invalid context passed + /* invalid context passed */ return Status; } @@ -241,31 +242,31 @@ MMixerGetLineControls( if (Flags == MIXER_GETLINECONTROLSF_ALL) { - // cast to mixer info + /* cast to mixer info */ MixerInfo = (LPMIXER_INFO)MixerHandle; MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID); if (!MixerLineSrc) { - // invalid line id + /* invalid line id */ return MM_STATUS_INVALID_PARAMETER; } - // copy line control(s) + /* copy line control(s) */ MixerContext->Copy(MixerLineControls->pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, MixerLineControls->cControls) * sizeof(MIXERCONTROLW)); return MM_STATUS_SUCCESS; } else if (Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE) { - // cast to mixer info + /* cast to mixer info */ MixerInfo = (LPMIXER_INFO)MixerHandle; MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID); if (!MixerLineSrc) { - // invalid line id + /* invalid line id */ return MM_STATUS_INVALID_PARAMETER; } @@ -277,7 +278,7 @@ MMixerGetLineControls( DPRINT("dwControlType %x\n", MixerLineSrc->LineControls[Index].dwControlType); if (MixerLineControls->dwControlType == MixerLineSrc->LineControls[Index].dwControlType) { - // found a control with that type + /* found a control with that type */ MixerContext->Copy(MixerLineControls->pamxctrl, &MixerLineSrc->LineControls[Index], sizeof(MIXERCONTROLW)); return MM_STATUS_SUCCESS; } @@ -287,18 +288,18 @@ MMixerGetLineControls( } else if (Flags == MIXER_GETLINECONTROLSF_ONEBYID) { - // cast to mixer info + /* cast to mixer info */ MixerInfo = (LPMIXER_INFO)MixerHandle; Status = MMixerGetMixerControlById(MixerInfo, MixerLineControls->dwControlID, NULL, &MixerControl, NULL); if (Status != MM_STATUS_SUCCESS) { - // invalid parameter + /* invalid parameter */ return MM_STATUS_INVALID_PARAMETER; } - // copy the controls + /* copy the controls */ MixerContext->Copy(MixerLineControls->pamxctrl, MixerControl, sizeof(MIXERCONTROLW)); return MM_STATUS_SUCCESS; } @@ -320,25 +321,25 @@ MMixerSetControlDetails( LPMIXERLINE_EXT MixerLine; LPMIXERCONTROLW MixerControl; - // verify mixer context + /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); if (Status != MM_STATUS_SUCCESS) { - // invalid context passed + /* invalid context passed */ return Status; } - // get mixer info + /* get mixer info */ MixerInfo = (LPMIXER_INFO)MixerHandle; - // get mixer control + /* get mixer control */ Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId); - // check for success + /* check for success */ if (Status != MM_STATUS_SUCCESS) { - // failed to find control id + /* failed to find control id */ return MM_STATUS_INVALID_PARAMETER; } @@ -370,25 +371,25 @@ MMixerGetControlDetails( LPMIXERLINE_EXT MixerLine; LPMIXERCONTROLW MixerControl; - // verify mixer context + /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); if (Status != MM_STATUS_SUCCESS) { - // invalid context passed + /* invalid context passed */ return Status; } - // get mixer info + /* get mixer info */ MixerInfo = (LPMIXER_INFO)MixerHandle; - // get mixer control + /* get mixer control */ Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId); - // check for success + /* check for success */ if (Status != MM_STATUS_SUCCESS) { - // failed to find control id + /* failed to find control id */ return MM_STATUS_INVALID_PARAMETER; } @@ -423,7 +424,7 @@ MMixerInitialize( if (!MixerContext || !EnumFunction || !EnumContext) { - // invalid parameter + /* invalid parameter */ return MM_STATUS_INVALID_PARAMETER; } @@ -431,19 +432,19 @@ MMixerInitialize( !MixerContext->AllocEventData || !MixerContext->FreeEventData || !MixerContext->Close || !MixerContext->OpenKey || !MixerContext->QueryKeyValue || !MixerContext->CloseKey) { - // invalid parameter + /* invalid parameter */ return MM_STATUS_INVALID_PARAMETER; } - // allocate a mixer list + /* allocate a mixer list */ MixerList = (PMIXER_LIST)MixerContext->Alloc(sizeof(MIXER_LIST)); if (!MixerList) { - // no memory + /* no memory */ return MM_STATUS_NO_MEMORY; } - //initialize mixer list + /* initialize mixer list */ MixerList->MixerListCount = 0; MixerList->MixerDataCount = 0; MixerList->WaveInListCount = 0; @@ -454,48 +455,49 @@ MMixerInitialize( InitializeListHead(&MixerList->WaveOutList); - // store mixer list + /* store mixer list */ MixerContext->MixerContext = (PVOID)MixerList; - // start enumerating all available devices + /* start enumerating all available devices */ Count = 0; DeviceIndex = 0; do { - // enumerate a device + /* enumerate a device */ Status = EnumFunction(EnumContext, DeviceIndex, &DeviceName, &hMixer, &hKey); if (Status != MM_STATUS_SUCCESS) { - //check error code + /* check error code */ if (Status == MM_STATUS_NO_MORE_DEVICES) { - // enumeration has finished + /* enumeration has finished */ break; } else { DPRINT1("Failed to enumerate device %lu\n", DeviceIndex); - // TODO cleanup + /* TODO cleanup */ return Status; } } else { - // create a mixer data entry + /* create a mixer data entry */ Status = MMixerCreateMixerData(MixerContext, MixerList, DeviceIndex, DeviceName, hMixer, hKey); if (Status != MM_STATUS_SUCCESS) break; } - // increment device index + /* increment device index */ DeviceIndex++; }while(TRUE); - //now all filters have been pre-opened - // lets enumerate the filters + /* now all filters have been pre-opened + * lets enumerate the filters + */ Entry = MixerList->MixerData.Flink; while(Entry != &MixerList->MixerData) { @@ -504,6 +506,6 @@ MMixerInitialize( Entry = Entry->Flink; } - // done + /* done */ return MM_STATUS_SUCCESS; } diff --git a/reactos/lib/drivers/sound/mmixer/mmixer.rbuild b/reactos/lib/drivers/sound/mmixer/mmixer.rbuild index 582868ab1d6..21d65510061 100644 --- a/reactos/lib/drivers/sound/mmixer/mmixer.rbuild +++ b/reactos/lib/drivers/sound/mmixer/mmixer.rbuild @@ -8,4 +8,5 @@ mixer.c sup.c wave.c + topology.c diff --git a/reactos/lib/drivers/sound/mmixer/priv.h b/reactos/lib/drivers/sound/mmixer/priv.h index 1580c8a99a6..489bd983bde 100644 --- a/reactos/lib/drivers/sound/mmixer/priv.h +++ b/reactos/lib/drivers/sound/mmixer/priv.h @@ -17,6 +17,52 @@ #define YDEBUG #include +typedef struct __TOPOLOGY_NODE__ +{ + GUID NodeType; + ULONG NodeIndex; + + ULONG NodeConnectedToCount; + struct __TOPOLOGY_NODE__ ** NodeConnectedTo; + + ULONG NodeConnectedFromCount; + struct __TOPOLOGY_NODE__ ** NodeConnectedFrom; + + ULONG PinConnectedFromCount; + PULONG PinConnectedFrom; + + ULONG PinConnectedToCount; + PULONG PinConnectedTo; + + ULONG Visited; + ULONG Reserved; +}TOPOLOGY_NODE, *PTOPOLOGY_NODE; + +typedef struct +{ + ULONG PinId; + + ULONG NodesConnectedToCount; + PTOPOLOGY_NODE * NodesConnectedTo; + + ULONG NodesConnectedFromCount; + PTOPOLOGY_NODE * NodesConnectedFrom; + + ULONG Visited; +}PIN, *PPIN; + + +typedef struct +{ + ULONG TopologyPinsCount; + PPIN TopologyPins; + + ULONG TopologyNodesCount; + PTOPOLOGY_NODE TopologyNodes; + +}TOPOLOGY, *PTOPOLOGY; + + typedef struct { KSEVENTDATA EventData; @@ -68,6 +114,7 @@ typedef struct HANDLE hDevice; HANDLE hDeviceInterfaceKey; LPWSTR DeviceName; + PTOPOLOGY Topology; }MIXER_DATA, *LPMIXER_DATA; typedef struct @@ -273,9 +320,122 @@ MMixerInitializeWaveInfo( IN LPMIXER_DATA MixerData, IN LPWSTR DeviceName, IN ULONG bWaveIn, - IN ULONG PinId); + IN ULONG PinCount, + IN PULONG Pins); MIXER_STATUS MMixerAddEvents( IN PMIXER_CONTEXT MixerContext, IN OUT LPMIXER_INFO MixerInfo); + +/* topology.c */ + +MIXER_STATUS +MMixerCreateTopology( + IN PMIXER_CONTEXT MixerContext, + IN ULONG PinCount, + IN PKSMULTIPLE_ITEM NodeConnections, + IN PKSMULTIPLE_ITEM NodeTypes, + OUT PTOPOLOGY *OutTopology); + +VOID +MMixerGetAllUpOrDownstreamPinsFromNodeIndex( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG NodeIndex, + IN ULONG bUpStream, + OUT PULONG OutPinsCount, + OUT PULONG OutPins); + +MIXER_STATUS +MMixerGetAllUpOrDownstreamPinsFromPinIndex( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG PinIndex, + IN ULONG bUpStream, + OUT PULONG OutPinsCount, + OUT PULONG OutPins); + +VOID +MMixerGetNextNodesFromPinIndex( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG PinIndex, + IN ULONG bUpStream, + OUT PULONG OutNodesCount, + OUT PULONG OutNodes); + +MIXER_STATUS +MMixerAllocateTopologyPinArray( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + OUT PULONG * OutPins); + +MIXER_STATUS +MMixerAllocateTopologyNodeArray( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + OUT PULONG * OutPins); + +VOID +MMixerGetAllUpOrDownstreamNodesFromPinIndex( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG PinIndex, + IN ULONG bUpStream, + OUT PULONG OutNodesCount, + OUT PULONG OutNodes); + +VOID +MMixerIsNodeTerminator( + IN PTOPOLOGY Topology, + IN ULONG NodeIndex, + OUT ULONG * bTerminator); + +VOID +MMixerGetNextNodesFromNodeIndex( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG NodeIndex, + IN ULONG bUpStream, + OUT PULONG OutNodesCount, + OUT PULONG OutNodes); + +LPGUID +MMixerGetNodeTypeFromTopology( + IN PTOPOLOGY Topology, + IN ULONG NodeIndex); + +MIXER_STATUS +MMixerGetAllUpOrDownstreamNodesFromNodeIndex( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG NodeIndex, + IN ULONG bUpStream, + OUT PULONG OutNodesCount, + OUT PULONG OutNodes); + +MIXER_STATUS +MMixerIsNodeConnectedToPin( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG NodeIndex, + IN ULONG PinId, + IN ULONG bUpStream, + OUT PULONG bConnected); + +ULONG +MMixerGetNodeIndexFromGuid( + IN PTOPOLOGY Topology, + IN const GUID *NodeType); + +VOID +MMixerSetTopologyNodeReserved( + IN PTOPOLOGY Topology, + IN ULONG NodeIndex); + +VOID +MMixerIsTopologyNodeReserved( + IN PTOPOLOGY Topology, + IN ULONG NodeIndex, + OUT PULONG bReserved); diff --git a/reactos/lib/drivers/sound/mmixer/sup.c b/reactos/lib/drivers/sound/mmixer/sup.c index e864d1db01d..90aee6e934f 100644 --- a/reactos/lib/drivers/sound/mmixer/sup.c +++ b/reactos/lib/drivers/sound/mmixer/sup.c @@ -54,9 +54,10 @@ MMixerFreeMixerInfo( IN PMIXER_CONTEXT MixerContext, IN LPMIXER_INFO MixerInfo) { - //UNIMPLEMENTED - // FIXME - // free all lines + /* UNIMPLEMENTED + * FIXME + * free all lines + */ MixerContext->Free((PVOID)MixerInfo); } @@ -71,7 +72,7 @@ MMixerGetMixerInfoByIndex( PMIXER_LIST MixerList; ULONG Index = 0; - // get mixer list + /* get mixer list */ MixerList = (PMIXER_LIST)MixerContext->MixerContext; if (!MixerList->MixerListCount) @@ -86,7 +87,7 @@ MMixerGetMixerInfoByIndex( if (Index == MixerIndex) return MixerInfo; - // move to next mixer entry + /* move to next mixer entry */ Index++; Entry = Entry->Flink; } @@ -141,42 +142,6 @@ MMixerGetSourceMixerLineByLineId( 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, @@ -190,183 +155,6 @@ MMixerGetNodeType( 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++; - } - - if (!Count) - { - *NodeReferenceCount = 0; - *NodeReference = NULL; - return MM_STATUS_SUCCESS; - } - - 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], PinCount, Pins); - ASSERT(Status == STATUS_SUCCESS); - } - MixerContext->Free((PVOID)NodeConnection); - } - - return Status; -} - LPMIXERLINE_EXT MMixerGetSourceMixerLineByComponentType( LPMIXER_INFO MixerInfo, @@ -482,7 +270,7 @@ MMixerSetGetMuteControlDetails( } else { - // FIXME notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID + /* FIXME notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID */ } return Status; @@ -590,7 +378,7 @@ MMixerGetDataByDeviceName( MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry); if (wcsicmp(&DeviceName[2], &MixerData->DeviceName[2]) == 0) { - // found entry + /* found entry */ return MixerData; } Entry = Entry->Flink; @@ -617,6 +405,9 @@ MMixerCreateMixerData( MixerData->DeviceName = DeviceName; MixerData->hDevice = hDevice; MixerData->hDeviceInterfaceKey = hKey; + MixerData->Topology = NULL; + + InsertTailList(&MixerList->MixerData, &MixerData->Entry); MixerList->MixerDataCount++; @@ -638,16 +429,16 @@ MMixerGetDeviceName( Status = MixerContext->QueryKeyValue(hKey, L"FriendlyName", (PVOID*)&Name, &Length, &Type); if (Status == MM_STATUS_SUCCESS) { - // copy device name + /* copy device name */ MixerContext->Copy(MixerInfo->MixCaps.szPname, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR)); - // make sure its null terminated + /* make sure its null terminated */ MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] = L'\0'; - // free device name + /* free device name */ MixerContext->Free(Name); - // done + /* done */ return Status; } @@ -658,13 +449,13 @@ MMixerGetDeviceName( Status = MixerContext->QueryKeyValue(hKey, L"FriendlyName", (PVOID*)&Name, &Length, &Type); if (Status == MM_STATUS_SUCCESS) { - // copy device name + /* copy device name */ MixerContext->Copy(MixerInfo->MixCaps.szPname, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR)); - // make sure its null terminated + /* make sure its null terminated */ MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] = L'\0'; - // free device name + /* free device name */ MixerContext->Free(Name); } diff --git a/reactos/lib/drivers/sound/mmixer/topology.c b/reactos/lib/drivers/sound/mmixer/topology.c new file mode 100644 index 00000000000..3c70ad3465c --- /dev/null +++ b/reactos/lib/drivers/sound/mmixer/topology.c @@ -0,0 +1,1097 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Kernel Streaming + * FILE: lib/drivers/sound/mmixer/topology.c + * PURPOSE: Topology Handling Functions + * PROGRAMMER: Johannes Anderwald + */ + +#include "priv.h" + +VOID +MMixerPrintTopology( + PTOPOLOGY Topology) +{ + ULONG Index, SubIndex; + + DPRINT1("Num Pins %lu NumNodes %lu\n", Topology->TopologyPinsCount, Topology->TopologyNodesCount); + + for(Index = 0; Index < Topology->TopologyPinsCount; Index++) + { + DPRINT1("PinId %lu NodesConnectedFromCount %lu NodesConnectedToCount %lu Visited %lu\n", Topology->TopologyPins[Index].PinId, + Topology->TopologyPins[Index].NodesConnectedFromCount, Topology->TopologyPins[Index].NodesConnectedToCount, Topology->TopologyPins[Index].Visited); + + for(SubIndex = 0; SubIndex < Topology->TopologyPins[Index].NodesConnectedFromCount; SubIndex++) + DPRINT1("NodesConnectedFrom Index %lu NodeId %lu\n", SubIndex, Topology->TopologyPins[Index].NodesConnectedFrom[SubIndex]->NodeIndex); + + for(SubIndex = 0; SubIndex < Topology->TopologyPins[Index].NodesConnectedToCount; SubIndex++) + DPRINT1("NodesConnectedTo Index %lu NodeId %lu\n", SubIndex, Topology->TopologyPins[Index].NodesConnectedTo[SubIndex]->NodeIndex); + } + + for(Index = 0; Index < Topology->TopologyNodesCount; Index++) + { + DPRINT1("NodeId %lu NodesConnectedFromCount %lu NodesConnectedToCount %lu Visited %lu PinConnectedFromCount %lu PinConnectedToCount %lu\n", Topology->TopologyNodes[Index].NodeIndex, + Topology->TopologyNodes[Index].NodeConnectedFromCount, Topology->TopologyNodes[Index].NodeConnectedToCount, Topology->TopologyNodes[Index].Visited, + Topology->TopologyNodes[Index].PinConnectedFromCount, Topology->TopologyNodes[Index].PinConnectedToCount); + } + + +} + + +MIXER_STATUS +MMixerAllocateTopology( + IN PMIXER_CONTEXT MixerContext, + IN ULONG NodesCount, + IN ULONG PinCount, + OUT PTOPOLOGY * OutTopology) +{ + PTOPOLOGY Topology; + + /* allocate topology */ + Topology = (PTOPOLOGY)MixerContext->Alloc(sizeof(TOPOLOGY)); + + if (!Topology) + { + /* out of memory */ + return MM_STATUS_NO_MEMORY; + } + + /* allocate topology pins */ + Topology->TopologyPins = (PPIN) MixerContext->Alloc(sizeof(PIN) * PinCount); + + if (!Topology->TopologyPins) + { + /* release memory */ + MixerContext->Free(Topology); + + /* out of memory */ + return MM_STATUS_NO_MEMORY; + } + + /* allocate topology nodes */ + Topology->TopologyNodes = (PTOPOLOGY_NODE) MixerContext->Alloc(sizeof(TOPOLOGY_NODE) * NodesCount); + + if (!Topology->TopologyNodes) + { + /* release memory */ + MixerContext->Free(Topology->TopologyPins); + MixerContext->Free(Topology); + + /* out of memory */ + return MM_STATUS_NO_MEMORY; + } + + /* initialize topology */ + Topology->TopologyPinsCount = PinCount; + Topology->TopologyNodesCount = NodesCount; + + /* store result */ + *OutTopology = Topology; + + /* done */ + return MM_STATUS_SUCCESS; +} + +VOID +MMixerResetTopologyVisitStatus( + IN OUT PTOPOLOGY Topology) +{ + ULONG Index; + + for(Index = 0; Index < Topology->TopologyNodesCount; Index++) + { + /* reset visited status */ + Topology->TopologyNodes[Index].Visited = FALSE; + } + + for(Index = 0; Index < Topology->TopologyPinsCount; Index++) + { + /* reset visited status */ + Topology->TopologyPins[Index].Visited = FALSE; + } +} + +VOID +MMixerInitializeTopologyNodes( + IN PMIXER_CONTEXT MixerContext, + IN PKSMULTIPLE_ITEM NodeTypes, + IN OUT PTOPOLOGY Topology) +{ + ULONG Index; + LPGUID Guids; + + /* sanity check */ + ASSERT(Topology->TopologyNodesCount == NodeTypes->Count); + + /* get topology node types */ + Guids = (LPGUID)(NodeTypes + 1); + + for(Index = 0; Index < Topology->TopologyNodesCount; Index++) + { + /* store node connection index */ + Topology->TopologyNodes[Index].NodeIndex = Index; + + /* store topology node type */ + MixerContext->Copy(&Topology->TopologyNodes[Index].NodeType, &Guids[Index], sizeof(GUID)); + } +} + +MIXER_STATUS +MMixerAddPinConnection( + IN PMIXER_CONTEXT MixerContext, + IN PPIN Pin, + IN PTOPOLOGY_NODE Node, + IN ULONG bPinToNode) +{ + ULONG Count; + PULONG NewPinsIndex, OldPinsIndex; + PTOPOLOGY_NODE * NewNodes, *OldNodes; + + if (bPinToNode) + { + /* get existing count */ + Count = Pin->NodesConnectedToCount; + OldNodes = Pin->NodesConnectedTo; + } + else + { + /* get existing count */ + Count = Pin->NodesConnectedFromCount; + OldNodes = Pin->NodesConnectedFrom; + } + + /* allocate new nodes array */ + NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1)); + + if (!NewNodes) + { + /* out of memory */ + return MM_STATUS_NO_MEMORY; + } + + if (Count) + { + /* copy existing nodes */ + MixerContext->Copy(NewNodes, OldNodes, sizeof(PTOPOLOGY) * Count); + + /* release old nodes array */ + MixerContext->Free(OldNodes); + } + + /* add new topology node */ + NewNodes[Count] = Node; + + if (bPinToNode) + { + /* replace old nodes array */ + Pin->NodesConnectedTo = NewNodes; + + /* increment nodes count */ + Pin->NodesConnectedToCount++; + + /* now enlarge PinConnectedFromCount*/ + Count = Node->PinConnectedFromCount; + + /* connected pin count for node */ + OldPinsIndex = Node->PinConnectedFrom; + } + else + { + /* replace old nodes array */ + Pin->NodesConnectedFrom = NewNodes; + + /* increment nodes count */ + Pin->NodesConnectedFromCount++; + + /* now enlarge PinConnectedFromCount*/ + Count = Node->PinConnectedToCount; + + /* connected pin count for node */ + OldPinsIndex = Node->PinConnectedTo; + } + + /* allocate pin connection index */ + NewPinsIndex = MixerContext->Alloc(sizeof(ULONG) * (Count + 1)); + + if (!NewPinsIndex) + { + /* out of memory */ + return MM_STATUS_NO_MEMORY; + } + + if (Count) + { + /* copy existing nodes */ + MixerContext->Copy(NewPinsIndex, OldPinsIndex, sizeof(ULONG) * Count); + + /* release old nodes array */ + MixerContext->Free(OldPinsIndex); + } + + /* add new topology node */ + NewPinsIndex[Count] = Pin->PinId; + + if (bPinToNode) + { + /* replace old nodes array */ + Node->PinConnectedFrom = NewPinsIndex; + + /* increment pin count */ + Node->PinConnectedFromCount++; + } + else + { + /* replace old nodes array */ + Node->PinConnectedTo = NewPinsIndex; + + /* increment pin count */ + Node->PinConnectedToCount++; + } + + /* done */ + return MM_STATUS_SUCCESS; +} + +MIXER_STATUS +MMixerHandleNodeToNodeConnection( + IN PMIXER_CONTEXT MixerContext, + IN PKSTOPOLOGY_CONNECTION Connection, + IN OUT PTOPOLOGY Topology) +{ + PTOPOLOGY_NODE InNode, OutNode; + PTOPOLOGY_NODE * NewNodes; + ULONG Count; + + /* sanity checks */ + ASSERT(Topology->TopologyNodesCount > Connection->ToNode); + ASSERT(Topology->TopologyNodesCount > Connection->FromNode); + + /* get node */ + InNode = &Topology->TopologyNodes[Connection->FromNode]; + OutNode = &Topology->TopologyNodes[Connection->ToNode]; + + /* get existing count */ + Count = OutNode->NodeConnectedFromCount; + + /* allocate new nodes array */ + NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1)); + + if (!NewNodes) + { + /* out of memory */ + return MM_STATUS_NO_MEMORY; + } + + if (Count) + { + /* copy existing nodes */ + MixerContext->Copy(NewNodes, OutNode->NodeConnectedFrom, sizeof(PTOPOLOGY) * Count); + + /* release old nodes array */ + MixerContext->Free(OutNode->NodeConnectedFrom); + } + + /* add new topology node */ + NewNodes[OutNode->NodeConnectedFromCount] = InNode; + + /* replace old nodes array */ + OutNode->NodeConnectedFrom = NewNodes; + + /* increment nodes count */ + OutNode->NodeConnectedFromCount++; + + /* get existing count */ + Count = InNode->NodeConnectedToCount; + + /* allocate new nodes array */ + NewNodes = MixerContext->Alloc(sizeof(PTOPOLOGY_NODE) * (Count + 1)); + + if (!NewNodes) + { + /* out of memory */ + return MM_STATUS_NO_MEMORY; + } + + if (Count) + { + /* copy existing nodes */ + MixerContext->Copy(NewNodes, InNode->NodeConnectedTo, sizeof(PTOPOLOGY) * Count); + + /* release old nodes array */ + MixerContext->Free(InNode->NodeConnectedTo); + } + + /* add new topology node */ + NewNodes[InNode->NodeConnectedToCount] = OutNode; + + /* replace old nodes array */ + InNode->NodeConnectedTo = NewNodes; + + /* increment nodes count */ + InNode->NodeConnectedToCount++; + + /* done */ + return MM_STATUS_SUCCESS; +} + +MIXER_STATUS +MMixerHandleNodePinConnection( + IN PMIXER_CONTEXT MixerContext, + IN PKSTOPOLOGY_CONNECTION Connection, + IN OUT PTOPOLOGY Topology) +{ + PPIN Pin; + PTOPOLOGY_NODE Node; + + /* check type */ + if (Connection->FromNode == KSFILTER_NODE) + { + /* Pin -> Node direction */ + + /* sanity checks */ + ASSERT(Topology->TopologyPinsCount > Connection->FromNodePin); + ASSERT(Topology->TopologyNodesCount > Connection->ToNode); + ASSERT(Connection->ToNode != KSFILTER_NODE); + + /* get pin */ + Pin = &Topology->TopologyPins[Connection->FromNodePin]; + + /* get node */ + Node = &Topology->TopologyNodes[Connection->ToNode]; + + /* initialize pin */ + Pin->PinId = Connection->FromNodePin; + + /* mark as visited */ + Pin->Visited = TRUE; + Node->Visited = TRUE; + + /* add connection */ + return MMixerAddPinConnection(MixerContext, Pin, Node, TRUE); + } + else if (Connection->ToNode == KSFILTER_NODE) + { + /* Node -> Pin direction */ + + /* sanity checks */ + ASSERT(Topology->TopologyPinsCount > Connection->ToNodePin); + ASSERT(Topology->TopologyNodesCount > Connection->FromNode); + ASSERT(Connection->FromNode != KSFILTER_NODE); + + /* get pin */ + Pin = &Topology->TopologyPins[Connection->ToNodePin]; + + /* get node */ + Node = &Topology->TopologyNodes[Connection->FromNode]; + + /* initialize pin */ + Pin->PinId = Connection->ToNodePin; + + /* mark as visited */ + Pin->Visited = TRUE; + Node->Visited = TRUE; + + /* add connection */ + return MMixerAddPinConnection(MixerContext, Pin, Node, FALSE); + } + /* invalid call */ + ASSERT(0); + return MM_STATUS_INVALID_PARAMETER; +} + +MIXER_STATUS +MMixerExploreTopology( + IN PMIXER_CONTEXT MixerContext, + IN PKSMULTIPLE_ITEM NodeConnections, + IN PKSMULTIPLE_ITEM NodeTypes, + IN OUT PTOPOLOGY Topology) +{ + ULONG Index; + LPGUID Guids; + PKSTOPOLOGY_CONNECTION Connection; + MIXER_STATUS Status; + + /* sanity check */ + ASSERT(Topology->TopologyNodesCount == NodeTypes->Count); + + /* get topology node types */ + Guids = (LPGUID)(NodeTypes + 1); + + /* get node connections */ + Connection = (PKSTOPOLOGY_CONNECTION)(NodeConnections + 1); + + for(Index = 0; Index < NodeConnections->Count; Index++) + { + if (Connection[Index].FromNode == KSFILTER_NODE || + Connection[Index].ToNode == KSFILTER_NODE) + { + /* handle connection from Pin -> Node / Node->Pin */ + Status = MMixerHandleNodePinConnection(MixerContext, + &Connection[Index], + Topology); + + } + else + { + /* handle connection from Node -> Node */ + Status = MMixerHandleNodeToNodeConnection(MixerContext, + &Connection[Index], + Topology); + } + + if (Status != MM_STATUS_SUCCESS) + { + /* failed to handle connection */ + return Status; + } + } + + /* done */ + return MM_STATUS_SUCCESS; +} + +VOID +MMixerAddPinIndexToArray( + IN PMIXER_CONTEXT MixerContext, + IN ULONG PinId, + IN ULONG MaxPins, + OUT PULONG OutPinCount, + OUT PULONG OutPins) +{ + ULONG Index; + + for(Index = 0; Index < MaxPins; Index++) + { + if (OutPins[Index] != MAXULONG) + { + if (OutPins[Index] > PinId) + { + /* shift entries up */ + MixerContext->Copy(&OutPins[Index + 1], &OutPins[Index], (MaxPins - (Index + 1)) * sizeof(ULONG)); + + /* store pin id */ + OutPins[Index] = PinId; + + /* increment pin count */ + (*OutPinCount)++; + + /* done */ + return; + } + } + else + { + /* store pin id */ + OutPins[Index] = PinId; + + /* increment pin count */ + (*OutPinCount)++; + + /* done */ + return; + } + } +} + +VOID +MMixerGetUpOrDownStreamPins( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN PTOPOLOGY_NODE TopologyNode, + IN ULONG bUpStream, + OUT PULONG OutPinCount, + OUT PULONG OutPins) +{ + ULONG Index, TopologyNodesCount, PinsCount; + PTOPOLOGY_NODE *TopologyNodes; + PULONG Pins; + PPIN Pin; + + /* sanity check */ + ASSERT(TopologyNode->Visited == FALSE); + + if (bUpStream) + { + /* use pins to which a node is attached to */ + PinsCount = TopologyNode->PinConnectedFromCount; + Pins = TopologyNode->PinConnectedFrom; + + TopologyNodesCount = TopologyNode->NodeConnectedFromCount; + TopologyNodes = TopologyNode->NodeConnectedFrom; + } + else + { + /* use pins which are attached to a node */ + PinsCount = TopologyNode->PinConnectedToCount; + Pins = TopologyNode->PinConnectedTo; + + TopologyNodesCount = TopologyNode->NodeConnectedToCount; + TopologyNodes = TopologyNode->NodeConnectedTo; + } + + /* add all diretly connected pins */ + for(Index = 0; Index < PinsCount; Index++) + { + /* sanity check */ + ASSERT(Pins[Index] < Topology->TopologyPinsCount); + + /* get pin */ + Pin = &Topology->TopologyPins[Pins[Index]]; + + /* pin should not have been visited */ + ASSERT(Pin->Visited == FALSE); + ASSERT(Pins[Index] == Pin->PinId); + + /* add them to pin array */ + MMixerAddPinIndexToArray(MixerContext, Pin->PinId, Topology->TopologyPinsCount, OutPinCount, OutPins); + + /* mark pin as visited */ + Pin->Visited = TRUE; + } + + /* mark node as visited */ + TopologyNode->Visited = TRUE; + + /* now visit all connected nodes */ + for(Index = 0; Index < TopologyNodesCount; Index++) + { + /* recursively visit them */ + MMixerGetUpOrDownStreamPins(MixerContext, Topology, TopologyNodes[Index], bUpStream, OutPinCount, OutPins); + } + +} + +ULONG +MMixerGetNodeIndexFromGuid( + IN PTOPOLOGY Topology, + IN const GUID * NodeType) +{ + ULONG Index; + + for(Index = 0; Index < Topology->TopologyNodesCount; Index++) + { + if (IsEqualGUIDAligned(NodeType, &Topology->TopologyNodes[Index].NodeType)) + { + return Index; + } + } + + return MAXULONG; +} + + +VOID +MMixerGetAllUpOrDownstreamPinsFromNodeIndex( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG NodeIndex, + IN ULONG bUpStream, + OUT PULONG OutPinsCount, + OUT PULONG OutPins) +{ + PTOPOLOGY_NODE TopologyNode; + + /* mark them as empty */ + *OutPinsCount = 0; + + /* reset visited status */ + MMixerResetTopologyVisitStatus(Topology); + + /* sanity check */ + ASSERT(Topology->TopologyNodesCount > NodeIndex); + + /* get topology node */ + TopologyNode = &Topology->TopologyNodes[NodeIndex]; + + /* now visit all upstream pins & nodes */ + MMixerGetUpOrDownStreamPins(MixerContext, Topology, TopologyNode, bUpStream, OutPinsCount, OutPins); +} + +VOID +MMixerGetUpOrDownstreamNodes( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN PTOPOLOGY_NODE TopologyNode, + IN ULONG bUpStream, + OUT PULONG OutNodeCount, + OUT PULONG OutNodes) +{ + ULONG Index, TopologyNodesCount; + PTOPOLOGY_NODE Node, *TopologyNodes; + + if (bUpStream) + { + /* use nodes to which a node is attached to */ + TopologyNodesCount = TopologyNode->NodeConnectedFromCount; + TopologyNodes = TopologyNode->NodeConnectedFrom; + } + else + { + /* use nodes which are attached to a node */ + TopologyNodesCount = TopologyNode->NodeConnectedToCount; + TopologyNodes = TopologyNode->NodeConnectedTo; + } + + /* sanity check */ + ASSERT(TopologyNode->Visited == FALSE); + + /* add all connected nodes */ + for(Index = 0; Index < TopologyNodesCount; Index++) + { + /* get node */ + Node = TopologyNodes[Index]; + + /* node should not have been visited */ + ASSERT(Node->Visited == FALSE); + + /* add them to node array */ + MMixerAddPinIndexToArray(MixerContext, Node->NodeIndex, Topology->TopologyNodesCount, OutNodeCount, OutNodes); + + /* recursively visit them */ + MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNodes[Index], bUpStream, OutNodeCount, OutNodes); + } + + /* mark node as visited */ + TopologyNode->Visited = TRUE; + +} + +MIXER_STATUS +MMixerGetAllUpOrDownstreamNodesFromNodeIndex( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG NodeIndex, + IN ULONG bUpStream, + OUT PULONG OutNodesCount, + OUT PULONG OutNodes) +{ + PTOPOLOGY_NODE TopologyNode; + + /* reset visited status */ + MMixerResetTopologyVisitStatus(Topology); + + /* sanity check */ + ASSERT(Topology->TopologyNodesCount > NodeIndex); + + /* get topology node */ + TopologyNode = &Topology->TopologyNodes[NodeIndex]; + + /* now visit all upstream pins & nodes */ + MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNode, bUpStream, OutNodesCount, OutNodes); + + /* done */ + return MM_STATUS_SUCCESS; + +} + +MIXER_STATUS +MMixerGetAllUpOrDownstreamPinsFromPinIndex( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG PinIndex, + IN ULONG bUpStream, + OUT PULONG OutPinsCount, + OUT PULONG OutPins) +{ + ULONG Index, TopologyNodesCount; + PPIN Pin; + PTOPOLOGY_NODE *TopologyNodes; + + /* mark them as empty */ + *OutPinsCount = 0; + + /* get pin */ + Pin = &Topology->TopologyPins[PinIndex]; + + if (bUpStream) + { + /* use nodes to which a pin is attached to */ + TopologyNodes = Pin->NodesConnectedFrom; + TopologyNodesCount = Pin->NodesConnectedFromCount; + } + else + { + /* use nodes which are attached to a node */ + TopologyNodes = Pin->NodesConnectedTo; + TopologyNodesCount = Pin->NodesConnectedToCount; + } + + + /* reset visited status */ + MMixerResetTopologyVisitStatus(Topology); + + /* sanity check */ + ASSERT(Topology->TopologyPinsCount > PinIndex); + + /* now visit all up / down stream pins & nodes */ + for(Index = 0; Index < TopologyNodesCount; Index++) + { + /* explore all connected pins with helper */ + MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, TopologyNodes[Index]->NodeIndex, bUpStream, OutPinsCount, OutPins); + } + + /* done */ + return MM_STATUS_SUCCESS; + +} + +VOID +MMixerGetAllUpOrDownstreamNodesFromPinIndex( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG PinIndex, + IN ULONG bUpStream, + OUT PULONG OutNodesCount, + OUT PULONG OutNodes) +{ + ULONG Index, TopologyNodesCount; + PPIN Pin; + PTOPOLOGY_NODE *TopologyNodes; + + /* mark them as empty */ + *OutNodesCount = 0; + + /* get pin */ + Pin = &Topology->TopologyPins[PinIndex]; + + if (bUpStream) + { + /* use nodes to which a pin is attached to */ + TopologyNodes = Pin->NodesConnectedFrom; + TopologyNodesCount = Pin->NodesConnectedFromCount; + } + else + { + /* use nodes which are attached to a node */ + TopologyNodes = Pin->NodesConnectedTo; + TopologyNodesCount = Pin->NodesConnectedToCount; + } + + + /* reset visited status */ + MMixerResetTopologyVisitStatus(Topology); + + /* sanity check */ + ASSERT(Topology->TopologyPinsCount > PinIndex); + + /* now visit all up / down stream pins & nodes */ + for(Index = 0; Index < TopologyNodesCount; Index++) + { + /* add node to array */ + MMixerAddPinIndexToArray(MixerContext, TopologyNodes[Index]->NodeIndex, Topology->TopologyNodesCount, OutNodesCount, OutNodes); + + /* explore all connected nodes with helper */ + MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext, Topology, TopologyNodes[Index]->NodeIndex, bUpStream, OutNodesCount, OutNodes); + } +} + + +VOID +MMixerGetNextNodesFromPinIndex( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG PinIndex, + IN ULONG bUpStream, + OUT PULONG OutNodesCount, + OUT PULONG OutNodes) +{ + PPIN Pin; + TOPOLOGY_NODE **TopologyNodes; + ULONG TopologyNodesCount; + ULONG Index; + + /* sanity check */ + ASSERT(PinIndex < Topology->TopologyPinsCount); + + /* get pin */ + Pin = &Topology->TopologyPins[PinIndex]; + + if (bUpStream) + { + /* get up stream nodes */ + TopologyNodes = Pin->NodesConnectedFrom; + TopologyNodesCount = Pin->NodesConnectedFromCount; + } + else + { + /* get down stream nodes */ + TopologyNodes = Pin->NodesConnectedTo; + TopologyNodesCount = Pin->NodesConnectedToCount; + } + + /* store topology nodes ids */ + for(Index = 0; Index < TopologyNodesCount; Index++) + { + OutNodes[Index] = TopologyNodes[Index]->NodeIndex; + } + + /* store topology nodes count */ + *OutNodesCount = TopologyNodesCount; +} + +VOID +MMixerGetNextNodesFromNodeIndex( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG NodeIndex, + IN ULONG bUpStream, + OUT PULONG OutNodesCount, + OUT PULONG OutNodes) +{ + TOPOLOGY_NODE **TopologyNodes; + ULONG TopologyNodesCount; + ULONG Index; + + /* sanity check */ + ASSERT(NodeIndex < Topology->TopologyNodesCount); + + if (bUpStream) + { + /* get up stream nodes */ + TopologyNodes = Topology->TopologyNodes[NodeIndex].NodeConnectedFrom; + TopologyNodesCount = Topology->TopologyNodes[NodeIndex].NodeConnectedFromCount; + } + else + { + /* get down stream nodes */ + TopologyNodes = Topology->TopologyNodes[NodeIndex].NodeConnectedTo; + TopologyNodesCount = Topology->TopologyNodes[NodeIndex].NodeConnectedToCount; + } + + /* store topology nodes ids */ + for(Index = 0; Index < TopologyNodesCount; Index++) + { + OutNodes[Index] = TopologyNodes[Index]->NodeIndex; + } + + /* store topology nodes count */ + *OutNodesCount = TopologyNodesCount; +} + +MIXER_STATUS +MMixerAllocateTopologyPinArray( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + OUT PULONG * OutPins) +{ + PULONG Pins; + ULONG Index; + + /* sanity check */ + ASSERT(Topology->TopologyPinsCount != 0); + + /* allocate topology pins */ + Pins = MixerContext->Alloc(Topology->TopologyPinsCount * sizeof(ULONG)); + + if (!Pins) + { + /* out of memory */ + return MM_STATUS_NO_MEMORY; + } + + /* mark index as unused */ + for(Index = 0; Index < Topology->TopologyPinsCount; Index++) + Pins[Index] = MAXULONG; + + /* store result */ + *OutPins = Pins; + + /* done */ + return MM_STATUS_SUCCESS; +} + +MIXER_STATUS +MMixerAllocateTopologyNodeArray( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + OUT PULONG * OutNodes) +{ + PULONG Nodes; + ULONG Index; + + /* sanity check */ + ASSERT(Topology->TopologyNodesCount != 0); + + /* allocate topology pins */ + Nodes = MixerContext->Alloc(Topology->TopologyNodesCount * sizeof(ULONG)); + + if (!Nodes) + { + /* out of memory */ + return MM_STATUS_NO_MEMORY; + } + + /* mark index as unused */ + for(Index = 0; Index < Topology->TopologyNodesCount; Index++) + Nodes[Index] = MAXULONG; + + /* store result */ + *OutNodes = Nodes; + + /* done */ + return MM_STATUS_SUCCESS; +} + +VOID +MMixerIsNodeTerminator( + IN PTOPOLOGY Topology, + IN ULONG NodeIndex, + OUT ULONG * bTerminator) +{ + /* sanity check */ + ASSERT(NodeIndex < Topology->TopologyNodesCount); + + /* check if node has multiple parents */ + if (Topology->TopologyNodes[NodeIndex].NodeConnectedFromCount > 1) + { + /* node is connected to multiple other nodes */ + *bTerminator = TRUE; + + /* done */ + return; + } + + /* check if node is mux / sum node */ + if (IsEqualGUIDAligned(&Topology->TopologyNodes[NodeIndex].NodeType, &KSNODETYPE_SUM) || + IsEqualGUIDAligned(&Topology->TopologyNodes[NodeIndex].NodeType, &KSNODETYPE_MUX)) + { + /* classic terminator */ + *bTerminator = TRUE; + + /* done */ + return; + + } + + /* node is not a terminator */ + *bTerminator = FALSE; +} + +MIXER_STATUS +MMixerIsNodeConnectedToPin( + IN PMIXER_CONTEXT MixerContext, + IN PTOPOLOGY Topology, + IN ULONG NodeIndex, + IN ULONG PinId, + IN ULONG bUpStream, + OUT PULONG bConnected) +{ + MIXER_STATUS Status; + ULONG Index, PinsCount; + PULONG Pins; + + /* allocate pin index array */ + Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins); + + if (Status != MM_STATUS_SUCCESS) + { + /* failed to allocate */ + return Status; + } + + /* now get connected pins */ + MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, bUpStream, &PinsCount, Pins); + + /* set to false */ + *bConnected = FALSE; + + for(Index = 0; Index < PinsCount; Index++) + { + if (Pins[Index] == PinId) + { + /* pin is connected */ + *bConnected = TRUE; + break; + } + } + + /* free pin index array */ + MixerContext->Free(Pins); + + /* done */ + return MM_STATUS_SUCCESS; +} + +LPGUID +MMixerGetNodeTypeFromTopology( + IN PTOPOLOGY Topology, + IN ULONG NodeIndex) +{ + /* sanity check */ + ASSERT(NodeIndex < Topology->TopologyNodesCount); + + return &Topology->TopologyNodes[NodeIndex].NodeType; +} + +VOID +MMixerSetTopologyNodeReserved( + IN PTOPOLOGY Topology, + IN ULONG NodeIndex) +{ + /* sanity check */ + ASSERT(NodeIndex < Topology->TopologyNodesCount); + + /* set reserved */ + Topology->TopologyNodes[NodeIndex].Reserved = TRUE; +} + +VOID +MMixerIsTopologyNodeReserved( + IN PTOPOLOGY Topology, + IN ULONG NodeIndex, + OUT PULONG bReserved) +{ + /* sanity check */ + ASSERT(NodeIndex < Topology->TopologyNodesCount); + + /* get reserved status */ + *bReserved = Topology->TopologyNodes[NodeIndex].Reserved; +} + + +MIXER_STATUS +MMixerCreateTopology( + IN PMIXER_CONTEXT MixerContext, + IN ULONG PinCount, + IN PKSMULTIPLE_ITEM NodeConnections, + IN PKSMULTIPLE_ITEM NodeTypes, + OUT PTOPOLOGY *OutTopology) +{ + MIXER_STATUS Status; + PTOPOLOGY Topology; + + /* allocate topology */ + Status = MMixerAllocateTopology(MixerContext, NodeTypes->Count, PinCount, &Topology); + + if (Status != MM_STATUS_SUCCESS) + { + /* failed to allocate topology */ + return Status; + } + + /* initialize topology nodes */ + MMixerInitializeTopologyNodes(MixerContext, NodeTypes, Topology); + + /* explore topology */ + Status = MMixerExploreTopology(MixerContext, NodeConnections, NodeTypes, Topology); + + if (Status != MM_STATUS_SUCCESS) + { + /* failed to allocate topology */ + return Status; + } + + //MMixerPrintTopology(Topology); + + /* store result */ + *OutTopology = Topology; + + /* done */ + return MM_STATUS_SUCCESS; +} + + + + + diff --git a/reactos/lib/drivers/sound/mmixer/wave.c b/reactos/lib/drivers/sound/mmixer/wave.c index af29f45bb14..ee720b0eb1a 100644 --- a/reactos/lib/drivers/sound/mmixer/wave.c +++ b/reactos/lib/drivers/sound/mmixer/wave.c @@ -345,7 +345,8 @@ MMixerInitializeWaveInfo( IN LPMIXER_DATA MixerData, IN LPWSTR DeviceName, IN ULONG bWaveIn, - IN ULONG PinId) + IN ULONG PinCount, + IN PULONG Pins) { MIXER_STATUS Status; PKSMULTIPLE_ITEM MultipleItem; @@ -356,11 +357,14 @@ MMixerInitializeWaveInfo( if (!WaveInfo) return MM_STATUS_NO_MEMORY; + /* FIXME support multiple pins for wave device */ + ASSERT(PinCount == 1); + /* initialize wave info */ WaveInfo->DeviceId = MixerData->DeviceId; - WaveInfo->PinId = PinId; + WaveInfo->PinId = Pins[0]; - // sanity check + /* sanity check */ ASSERT(wcslen(DeviceName) < MAXPNAMELEN); /* copy device name */ @@ -388,7 +392,7 @@ MMixerInitializeWaveInfo( } /* get audio pin data ranges */ - Status = MMixerGetAudioPinDataRanges(MixerContext, MixerData->hDevice, PinId, &MultipleItem); + Status = MMixerGetAudioPinDataRanges(MixerContext, MixerData->hDevice, Pins[0], &MultipleItem); if (Status != MM_STATUS_SUCCESS) { /* failed to get audio pin data ranges */ @@ -451,21 +455,21 @@ MMixerOpenWave( LPWAVE_INFO WaveInfo; ACCESS_MASK DesiredAccess = 0; - // verify mixer context + /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); if (Status != MM_STATUS_SUCCESS) { - // invalid context passed + /* invalid context passed */ return Status; } - // grab mixer list + /* grab mixer list */ MixerList = (PMIXER_LIST)MixerContext->MixerContext; if (WaveFormat->wFormatTag != WAVE_FORMAT_PCM) { - // not implemented + /* not implemented */ return MM_STATUS_NOT_IMPLEMENTED; } @@ -501,16 +505,16 @@ MMixerWaveInCapabilities( MIXER_STATUS Status; LPWAVE_INFO WaveInfo; - // verify mixer context + /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); if (Status != MM_STATUS_SUCCESS) { - // invalid context passed + /* invalid context passed */ return Status; } - // grab mixer list + /* grab mixer list */ MixerList = (PMIXER_LIST)MixerContext->MixerContext; /* find destination wave */ @@ -521,7 +525,7 @@ MMixerWaveInCapabilities( return MM_STATUS_UNSUCCESSFUL; } - //copy capabilities + /* copy capabilities */ MixerContext->Copy(Caps, &WaveInfo->u.InCaps, sizeof(WAVEINCAPSW)); return MM_STATUS_SUCCESS; @@ -537,16 +541,16 @@ MMixerWaveOutCapabilities( MIXER_STATUS Status; LPWAVE_INFO WaveInfo; - // verify mixer context + /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); if (Status != MM_STATUS_SUCCESS) { - // invalid context passed + /* invalid context passed */ return Status; } - // grab mixer list + /* grab mixer list */ MixerList = (PMIXER_LIST)MixerContext->MixerContext; /* find destination wave */ @@ -557,7 +561,7 @@ MMixerWaveOutCapabilities( return MM_STATUS_UNSUCCESSFUL; } - //copy capabilities + /* copy capabilities */ MixerContext->Copy(Caps, &WaveInfo->u.OutCaps, sizeof(WAVEOUTCAPSW)); return MM_STATUS_SUCCESS; @@ -570,16 +574,16 @@ MMixerGetWaveInCount( PMIXER_LIST MixerList; MIXER_STATUS Status; - // verify mixer context + /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); if (Status != MM_STATUS_SUCCESS) { - // invalid context passed - return 0; + /* invalid context passed */ + return Status; } - // grab mixer list + /* grab mixer list */ MixerList = (PMIXER_LIST)MixerContext->MixerContext; return MixerList->WaveInListCount; @@ -592,16 +596,16 @@ MMixerGetWaveOutCount( PMIXER_LIST MixerList; MIXER_STATUS Status; - // verify mixer context + /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); if (Status != MM_STATUS_SUCCESS) { - // invalid context passed - return 0; + /* invalid context passed */ + return Status; } - // grab mixer list + /* grab mixer list */ MixerList = (PMIXER_LIST)MixerContext->MixerContext; return MixerList->WaveOutListCount; @@ -637,16 +641,16 @@ MMixerGetWaveDevicePath( ULONG Length; MIXER_STATUS Status; - // verify mixer context + /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); if (Status != MM_STATUS_SUCCESS) { - // invalid context passed + /* invalid context passed */ return Status; } - // grab mixer list + /* grab mixer list */ MixerList = (PMIXER_LIST)MixerContext->MixerContext; /* find destination wave */ -- 2.17.1