reactos/reactos/lib/drivers/sound/mmixer/sup.c
Johannes Anderwald 82dfe03d66 [MMIXER]
- Open all filters before starting enumeration. The advantage is that some filters are not opened twice
- Query the Mixer Name from Registry by opening the device interface registry key and querying for the value of FriendlyName. If it cannot be found, try to find the key under the sub key 'Device Parameters'

svn path=/trunk/; revision=44646
2009-12-18 10:25:41 +00:00

657 lines
18 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"
const GUID KSNODETYPE_SUM = {0xDA441A60L, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
const GUID KSNODETYPE_DAC = {0x507AE360L, 0xC554, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
const GUID KSNODETYPE_ADC = {0x4D837FE0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
const GUID KSNODETYPE_AGC = {0xE88C9BA0L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
const GUID KSNODETYPE_LOUDNESS = {0x41887440L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
const GUID KSNODETYPE_MUTE = {0x02B223C0L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
const GUID KSNODETYPE_TONE = {0x7607E580L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
const GUID KSNODETYPE_VOLUME = {0x3A5ACC00L, 0xC557, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
const GUID KSNODETYPE_PEAKMETER = {0xa085651e, 0x5f0d, 0x4b36, {0xa8, 0x69, 0xd1, 0x95, 0xd6, 0xab, 0x4b, 0x9e}};
const GUID KSNODETYPE_MUX = {0x2CEAF780, 0xC556, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
const GUID KSNODETYPE_STEREO_WIDE = {0xA9E69800L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
const GUID KSNODETYPE_CHORUS = {0x20173F20L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
const GUID KSNODETYPE_REVERB = {0xEF0328E0L, 0xC558, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
const GUID KSNODETYPE_SUPERMIX = {0xE573ADC0L, 0xC555, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
const GUID KSPROPSETID_Audio = {0x45FFAAA0L, 0x6E1B, 0x11D0, {0xBC, 0xF2, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
const GUID KSPROPSETID_Pin = {0x8C134960L, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
const GUID KSPROPSETID_General = {0x1464EDA5L, 0x6A8F, 0x11D1, {0x9A, 0xA7, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
const GUID KSPROPSETID_Topology = {0x720D4AC0L, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
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 || !MixerContext->OpenKey || !MixerContext->QueryKeyValue || !MixerContext->CloseKey)
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++;
}
if (!Count)
{
*NodeReferenceCount = 0;
*NodeReference = NULL;
return MM_STATUS_SUCCESS;
}
ASSERT(Count != 0);
/* now allocate node index array */
Refs = (PULONG)MixerContext->Alloc(sizeof(ULONG) * Count);
if (!Refs)
{
// not enough memory
return MM_STATUS_NO_MEMORY;
}
Count = 0;
Connection = (PKSTOPOLOGY_CONNECTION)(MultipleItem + 1);
for(Index = 0; Index < MultipleItem->Count; Index++)
{
if (bNode)
{
if (bFrom)
{
if (Connection->FromNode == NodeIndex)
{
/* node id has a connection */
Refs[Count] = Index;
Count++;
}
}
else
{
if (Connection->ToNode == NodeIndex)
{
/* node id has a connection */
Refs[Count] = Index;
Count++;
}
}
}
else
{
if (bFrom)
{
if (Connection->FromNodePin == NodeIndex && Connection->FromNode == KSFILTER_NODE)
{
/* node id has a connection */
Refs[Count] = Index;
Count++;
}
}
else
{
if (Connection->ToNodePin == NodeIndex && Connection->ToNode == KSFILTER_NODE)
{
/* node id has a connection */
Refs[Count] = Index;
Count++;
}
}
}
/* move to next connection */
Connection++;
}
/* store result */
*NodeReference = Refs;
*NodeReferenceCount = Count;
return MM_STATUS_SUCCESS;
}
MIXER_STATUS
MMixerGetTargetPins(
IN PMIXER_CONTEXT MixerContext,
IN PKSMULTIPLE_ITEM NodeTypes,
IN PKSMULTIPLE_ITEM NodeConnections,
IN ULONG NodeIndex,
IN ULONG bUpDirection,
OUT PULONG Pins,
IN ULONG PinCount)
{
ULONG NodeConnectionCount, Index;
MIXER_STATUS Status;
PULONG NodeConnection;
// sanity check */
ASSERT(NodeIndex != (ULONG)-1);
/* get all node indexes referenced by that pin */
if (bUpDirection)
Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
else
Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
//DPRINT("NodeIndex %u Status %x Count %u\n", NodeIndex, Status, NodeConnectionCount);
if (Status == MM_STATUS_SUCCESS)
{
for(Index = 0; Index < NodeConnectionCount; Index++)
{
Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], 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)
{
/* TODO */
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;
}
LPMIXER_DATA
MMixerGetDataByDeviceId(
IN PMIXER_LIST MixerList,
IN ULONG DeviceId)
{
PLIST_ENTRY Entry;
LPMIXER_DATA MixerData;
Entry = MixerList->MixerData.Flink;
while(Entry != &MixerList->MixerData)
{
MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
if (MixerData->DeviceId == DeviceId)
{
return MixerData;
}
Entry = Entry->Flink;
}
return NULL;
}
LPMIXER_DATA
MMixerGetDataByDeviceName(
IN PMIXER_LIST MixerList,
IN LPWSTR DeviceName)
{
PLIST_ENTRY Entry;
LPMIXER_DATA MixerData;
Entry = MixerList->MixerData.Flink;
while(Entry != &MixerList->MixerData)
{
MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
if (wcsicmp(DeviceName, MixerData->DeviceName) == 0)
{
// found entry
return MixerData;
}
Entry = Entry->Flink;
}
return NULL;
}
MIXER_STATUS
MMixerCreateMixerData(
IN PMIXER_CONTEXT MixerContext,
IN PMIXER_LIST MixerList,
IN ULONG DeviceId,
IN LPWSTR DeviceName,
IN HANDLE hDevice,
IN HANDLE hKey)
{
LPMIXER_DATA MixerData;
MixerData = (LPMIXER_DATA)MixerContext->Alloc(sizeof(MIXER_DATA));
if (!MixerData)
return MM_STATUS_NO_MEMORY;
MixerData->DeviceId = DeviceId;
MixerData->DeviceName = DeviceName;
MixerData->hDevice = hDevice;
MixerData->hDeviceInterfaceKey = hKey;
InsertTailList(&MixerList->MixerData, &MixerData->Entry);
MixerList->MixerDataCount++;
return MM_STATUS_SUCCESS;
}
MIXER_STATUS
MMixerGetDeviceName(
IN PMIXER_CONTEXT MixerContext,
IN LPMIXER_INFO MixerInfo,
IN HANDLE hKey)
{
LPWSTR Name;
HANDLE hTemp;
ULONG Length;
ULONG Type;
MIXER_STATUS Status;
Status = MixerContext->QueryKeyValue(hKey, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
if (Status == MM_STATUS_SUCCESS)
{
wcscpy(MixerInfo->MixCaps.szPname, Name);
MixerContext->Free(Name);
return Status;
}
Status = MixerContext->OpenKey(hKey, L"Device Parameters", KEY_READ, &hTemp);
if (Status != MM_STATUS_SUCCESS)
return Status;
Status = MixerContext->QueryKeyValue(hKey, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
if (Status == MM_STATUS_SUCCESS)
{
wcscpy(MixerInfo->MixCaps.szPname, Name);
MixerContext->Free(Name);
}
MixerContext->CloseKey(hTemp);
return Status;
}