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