reactos/reactos/lib/drivers/sound/mmixer/sup.c
Johannes Anderwald 91b69c9d1d [MMIXER]
- Implement MMixerGetLineInfo, MMixerGetLineControls, MMixerSetControlDetails, MMixerGetControlDetails, MMixerOpen
- MMixer library is now ready for testing

svn path=/trunk/; revision=44482
2009-12-09 16:00:28 +00:00

525 lines
13 KiB
C

/*
* 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 || !MixerContext->Open || !MixerContext->Close)
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);
}
LPMIXER_INFO
MMixerGetMixerInfoByIndex(
IN PMIXER_CONTEXT MixerContext,
IN ULONG MixerIndex)
{
LPMIXER_INFO MixerInfo;
PLIST_ENTRY Entry;
PMIXER_LIST MixerList;
ULONG Index = 0;
// get mixer list
MixerList = (PMIXER_LIST)MixerContext->MixerContext;
if (!MixerList->MixerListCount)
return NULL;
Entry = MixerList->MixerList.Flink;
while(Entry != &MixerList->MixerList)
{
MixerInfo = (LPMIXER_INFO)CONTAINING_RECORD(Entry, MIXER_INFO, Entry);
if (Index == MixerIndex)
return MixerInfo;
// move to next mixer entry
Index++;
Entry = Entry->Flink;
}
return NULL;
}
LPMIXERCONTROL_DATA
MMixerGetMixerControlDataById(
PLIST_ENTRY ListHead,
DWORD dwControlId)
{
PLIST_ENTRY Entry;
LPMIXERCONTROL_DATA Control;
/* get first entry */
Entry = ListHead->Flink;
while(Entry != ListHead)
{
Control = (LPMIXERCONTROL_DATA)CONTAINING_RECORD(Entry, MIXERCONTROL_DATA, Entry);
DPRINT("dwSource %x dwSource %x\n", Control->dwControlID, dwControlId);
if (Control->dwControlID == dwControlId)
return Control;
Entry = Entry->Flink;
}
return NULL;
}
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;
}
LPMIXERLINE_EXT
MMixerGetSourceMixerLineByComponentType(
LPMIXER_INFO MixerInfo,
DWORD dwComponentType)
{
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);
if (MixerLineSrc->Line.dwComponentType == dwComponentType)
return MixerLineSrc;
Entry = Entry->Flink;
}
return NULL;
}
MIXER_STATUS
MMixerGetMixerControlById(
LPMIXER_INFO MixerInfo,
DWORD dwControlID,
LPMIXERLINE_EXT *MixerLine,
LPMIXERCONTROLW *MixerControl,
PULONG NodeId)
{
PLIST_ENTRY Entry;
LPMIXERLINE_EXT MixerLineSrc;
ULONG Index;
/* get first entry */
Entry = MixerInfo->LineList.Flink;
while(Entry != &MixerInfo->LineList)
{
MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
{
if (MixerLineSrc->LineControls[Index].dwControlID == dwControlID)
{
if (MixerLine)
*MixerLine = MixerLineSrc;
if (MixerControl)
*MixerControl = &MixerLineSrc->LineControls[Index];
if (NodeId)
*NodeId = MixerLineSrc->NodeIds[Index];
return MM_STATUS_SUCCESS;
}
}
Entry = Entry->Flink;
}
return MM_STATUS_UNSUCCESSFUL;
}
ULONG
MMixerGetVolumeControlIndex(
LPMIXERVOLUME_DATA VolumeData,
LONG Value)
{
ULONG Index;
for(Index = 0; Index < VolumeData->ValuesCount; Index++)
{
if (VolumeData->Values[Index] > Value)
{
return VolumeData->InputSteppingDelta * Index;
}
}
return VolumeData->InputSteppingDelta * (VolumeData->ValuesCount-1);
}
MIXER_STATUS
MMixerSetGetMuteControlDetails(
IN PMIXER_CONTEXT MixerContext,
IN HANDLE hMixer,
IN ULONG NodeId,
IN ULONG dwLineID,
IN LPMIXERCONTROLDETAILS MixerControlDetails,
IN ULONG bSet)
{
LPMIXERCONTROLDETAILS_BOOLEAN Input;
LONG Value;
MIXER_STATUS Status;
if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_BOOLEAN))
return MM_STATUS_INVALID_PARAMETER;
/* get input */
Input = (LPMIXERCONTROLDETAILS_BOOLEAN)MixerControlDetails->paDetails;
/* FIXME SEH */
if (bSet)
Value = Input->fValue;
/* set control details */
Status = MMixerSetGetControlDetails(MixerContext, hMixer, NodeId, bSet, KSPROPERTY_AUDIO_MUTE, 0, &Value);
if (Status != MM_STATUS_SUCCESS)
return Status;
/* FIXME SEH */
if (!bSet)
{
Input->fValue = Value;
return Status;
}
else
{
// FIXME notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID
}
return Status;
}
MIXER_STATUS
MMixerSetGetVolumeControlDetails(
IN PMIXER_CONTEXT MixerContext,
IN HANDLE hMixer,
IN ULONG NodeId,
IN ULONG bSet,
LPMIXERCONTROLW MixerControl,
IN LPMIXERCONTROLDETAILS MixerControlDetails,
LPMIXERLINE_EXT MixerLine)
{
LPMIXERCONTROLDETAILS_UNSIGNED Input;
LONG Value, Index, Channel = 0;
ULONG dwValue;
MIXER_STATUS Status;
LPMIXERVOLUME_DATA VolumeData;
if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_SIGNED))
return MM_STATUS_INVALID_PARAMETER;
VolumeData = (LPMIXERVOLUME_DATA)MMixerGetMixerControlDataById(&MixerLine->LineControlsExtraData, MixerControl->dwControlID);
if (!VolumeData)
return MM_STATUS_UNSUCCESSFUL;
/* get input */
Input = (LPMIXERCONTROLDETAILS_UNSIGNED)MixerControlDetails->paDetails;
if (bSet)
{
/* FIXME SEH */
Value = Input->dwValue;
Index = Value / VolumeData->InputSteppingDelta;
if (Index >= VolumeData->ValuesCount)
{
DPRINT1("Index %u out of bounds %u \n", Index, VolumeData->ValuesCount);
DbgBreakPoint();
return MM_STATUS_INVALID_PARAMETER;
}
Value = VolumeData->Values[Index];
}
/* set control details */
if (bSet)
{
Status = MMixerSetGetControlDetails(MixerContext, hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 0, &Value);
Status = MMixerSetGetControlDetails(MixerContext, hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 1, &Value);
}
else
{
Status = MMixerSetGetControlDetails(MixerContext, hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, Channel, &Value);
}
if (!bSet)
{
dwValue = MMixerGetVolumeControlIndex(VolumeData, (LONG)Value);
/* FIXME SEH */
Input->dwValue = dwValue;
}
else
{
/* notify clients of a line change MM_MIXM_CONTROL_CHANGE with MixerControl->dwControlID */
}
return Status;
}