- Finish porting of code from wdmaud

svn path=/trunk/; revision=44473
This commit is contained in:
Johannes Anderwald 2009-12-08 21:10:02 +00:00
parent d2ae0ff3bf
commit b1e100ebd8
7 changed files with 1563 additions and 305 deletions

View 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;
}

View 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;
}

View file

@ -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)
{ {

View file

@ -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;

View file

@ -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>

View file

@ -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

View 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;
}