reactos/lib/drivers/sound/mmixer/sup.c
Timo Kreuzer 406dfdbc87 [CMAKE]
Sync trunk (rr49606)

svn path=/branches/cmake-bringup/; revision=49607
2010-11-16 13:43:39 +00:00

515 lines
15 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}};
const GUID KSEVENTSETID_AudioControlChange = {0xE85E9698L, 0xFA2F, 0x11D1, {0x95, 0xBD, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3}};
const GUID KSDATAFORMAT_TYPE_MUSIC = {0xE725D360L, 0x62CC, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
const GUID KSDATAFORMAT_SUBTYPE_MIDI = {0x1D262760L, 0xE957, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
const GUID KSDATAFORMAT_SPECIFIER_NONE = {0x0F6417D6L, 0xC318, 0x11D0, {0xA4, 0x3F, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
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->AllocEventData || !MixerContext->FreeEventData ||
!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 MixerLineSrc %p\n", MixerLineSrc->Line.dwLineID, dwLineID, MixerLineSrc);
if (MixerLineSrc->Line.dwLineID == dwLineID)
return MixerLineSrc;
Entry = Entry->Flink;
}
return NULL;
}
LPGUID
MMixerGetNodeType(
IN PKSMULTIPLE_ITEM MultipleItem,
IN ULONG Index)
{
LPGUID NodeType;
ASSERT(Index < MultipleItem->Count);
NodeType = (LPGUID)(MultipleItem + 1);
return &NodeType[Index];
}
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);
}
VOID
MMixerNotifyControlChange(
IN PMIXER_CONTEXT MixerContext,
IN LPMIXER_INFO MixerInfo,
IN ULONG NotificationType,
IN ULONG Value)
{
PLIST_ENTRY Entry;
PEVENT_NOTIFICATION_ENTRY NotificationEntry;
/* enumerate list and add a notification entry */
Entry = MixerInfo->LineList.Flink;
while(Entry != &MixerInfo->EventList)
{
/* get notification entry offset */
NotificationEntry = (PEVENT_NOTIFICATION_ENTRY)CONTAINING_RECORD(Entry, EVENT_NOTIFICATION_ENTRY, Entry);
if (NotificationEntry->MixerEventRoutine)
{
/* now perform the callback */
NotificationEntry->MixerEventRoutine(NotificationEntry->MixerEventContext, (HANDLE)MixerInfo, NotificationType, Value);
}
/* move to next notification entry */
Entry = Entry->Flink;
}
}
MIXER_STATUS
MMixerSetGetMuteControlDetails(
IN PMIXER_CONTEXT MixerContext,
IN LPMIXER_INFO MixerInfo,
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, MixerInfo->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
{
/* notify wdmaud clients MM_MIXM_LINE_CHANGE dwLineID */
MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_LINE_CHANGE, dwLineID);
}
return Status;
}
MIXER_STATUS
MMixerSetGetVolumeControlDetails(
IN PMIXER_CONTEXT MixerContext,
IN LPMIXER_INFO MixerInfo,
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);
return MM_STATUS_INVALID_PARAMETER;
}
Value = VolumeData->Values[Index];
}
/* set control details */
if (bSet)
{
/* TODO */
Status = MMixerSetGetControlDetails(MixerContext, MixerInfo->hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 0, &Value);
Status = MMixerSetGetControlDetails(MixerContext, MixerInfo->hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 1, &Value);
}
else
{
Status = MMixerSetGetControlDetails(MixerContext, MixerInfo->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 */
MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_CONTROL_CHANGE, 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[2], &MixerData->DeviceName[2]) == 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;
MixerData->Topology = NULL;
InsertTailList(&MixerList->MixerData, &MixerData->Entry);
MixerList->MixerDataCount++;
return MM_STATUS_SUCCESS;
}
MIXER_STATUS
MMixerGetDeviceName(
IN PMIXER_CONTEXT MixerContext,
OUT LPWSTR DeviceName,
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)
{
/* copy device name */
MixerContext->Copy(DeviceName, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
/* make sure its null terminated */
DeviceName[MAXPNAMELEN-1] = L'\0';
/* free device name */
MixerContext->Free(Name);
/* done */
return Status;
}
Status = MixerContext->OpenKey(hKey, L"Device Parameters", KEY_READ, &hTemp);
if (Status != MM_STATUS_SUCCESS)
return Status;
Status = MixerContext->QueryKeyValue(hTemp, L"FriendlyName", (PVOID*)&Name, &Length, &Type);
if (Status == MM_STATUS_SUCCESS)
{
/* copy device name */
MixerContext->Copy(DeviceName, Name, min(wcslen(Name), MAXPNAMELEN-1) * sizeof(WCHAR));
/* make sure its null terminated */
DeviceName[MAXPNAMELEN-1] = L'\0';
/* free device name */
MixerContext->Free(Name);
}
MixerContext->CloseKey(hTemp);
return Status;
}
VOID
MMixerInitializePinConnect(
IN OUT PKSPIN_CONNECT PinConnect,
IN ULONG PinId)
{
PinConnect->Interface.Set = KSINTERFACESETID_Standard;
PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
PinConnect->Interface.Flags = 0;
PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
PinConnect->Medium.Flags = 0;
PinConnect->PinToHandle = NULL;
PinConnect->PinId = PinId;
PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
PinConnect->Priority.PrioritySubClass = 1;
}