mirror of
https://github.com/reactos/reactos.git
synced 2025-07-01 04:31:22 +00:00

Skip unsuccessfully initialized devices and continue enumeration until all of devices are enumerated. Patch by Johannes Anderwald with additional improvements from me. This fixes 0 audio devices detected for HD audio controllers (e. g., Realtek), and hence allows to properly detect all available devices and play the sound with MMixer routines enabled (they are currently default). Tested personally with Realtek HD Audio driver version R2.74 for Windows XP/Server 2003 in pair with hdaudbus.sys from Windows Vista SP2 on real hardware. CORE-17285
877 lines
30 KiB
C
877 lines
30 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Kernel Streaming
|
|
* FILE: lib/drivers/sound/mmixer/mmixer.c
|
|
* PURPOSE: Mixer Handling Functions
|
|
* PROGRAMMER: Johannes Anderwald
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
// #define NDEBUG
|
|
#include <debug.h>
|
|
|
|
ULONG
|
|
MMixerGetCount(
|
|
IN PMIXER_CONTEXT MixerContext)
|
|
{
|
|
PMIXER_LIST MixerList;
|
|
MIXER_STATUS Status;
|
|
|
|
/* verify mixer context */
|
|
Status = MMixerVerifyContext(MixerContext);
|
|
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* invalid context passed */
|
|
return Status;
|
|
}
|
|
|
|
/* grab mixer list */
|
|
MixerList = (PMIXER_LIST)MixerContext->MixerContext;
|
|
|
|
// return number of mixers
|
|
return MixerList->MixerListCount;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerGetCapabilities(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN ULONG MixerIndex,
|
|
OUT LPMIXERCAPSW MixerCaps)
|
|
{
|
|
MIXER_STATUS Status;
|
|
LPMIXER_INFO MixerInfo;
|
|
|
|
/* verify mixer context */
|
|
Status = MMixerVerifyContext(MixerContext);
|
|
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* invalid context passed */
|
|
return Status;
|
|
}
|
|
|
|
/* get mixer info */
|
|
MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, MixerIndex);
|
|
|
|
if (!MixerInfo)
|
|
{
|
|
// invalid device index
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
MixerCaps->wMid = MixerInfo->MixCaps.wMid;
|
|
MixerCaps->wPid = MixerInfo->MixCaps.wPid;
|
|
MixerCaps->vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
|
|
MixerCaps->fdwSupport = MixerInfo->MixCaps.fdwSupport;
|
|
MixerCaps->cDestinations = MixerInfo->MixCaps.cDestinations;
|
|
|
|
ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == 0);
|
|
wcscpy(MixerCaps->szPname, MixerInfo->MixCaps.szPname);
|
|
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerOpen(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN ULONG MixerId,
|
|
IN PVOID MixerEventContext,
|
|
IN PMIXER_EVENT MixerEventRoutine,
|
|
OUT PHANDLE MixerHandle)
|
|
{
|
|
MIXER_STATUS Status;
|
|
LPMIXER_INFO MixerInfo;
|
|
|
|
/* verify mixer context */
|
|
Status = MMixerVerifyContext(MixerContext);
|
|
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* invalid context passed */
|
|
DPRINT1("invalid context\n");
|
|
return Status;
|
|
}
|
|
|
|
/* get mixer info */
|
|
MixerInfo = (LPMIXER_INFO)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
|
|
if (!MixerInfo)
|
|
{
|
|
/* invalid mixer id */
|
|
DPRINT1("invalid mixer id %lu\n", MixerId);
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* add the event */
|
|
Status = MMixerAddEvent(MixerContext, MixerInfo, MixerEventContext, MixerEventRoutine);
|
|
|
|
/* store result */
|
|
*MixerHandle = (HANDLE)MixerInfo;
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerClose(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN ULONG MixerId,
|
|
IN PVOID MixerEventContext,
|
|
IN PMIXER_EVENT MixerEventRoutine)
|
|
{
|
|
MIXER_STATUS Status;
|
|
LPMIXER_INFO MixerInfo;
|
|
|
|
/* verify mixer context */
|
|
Status = MMixerVerifyContext(MixerContext);
|
|
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* invalid context passed */
|
|
DPRINT1("invalid context\n");
|
|
return Status;
|
|
}
|
|
|
|
/* get mixer info */
|
|
MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, MixerId);
|
|
if (!MixerInfo)
|
|
{
|
|
/* invalid mixer id */
|
|
DPRINT1("invalid mixer id %lu\n", MixerId);
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* remove event from list */
|
|
return MMixerRemoveEvent(MixerContext, MixerInfo, MixerEventContext, MixerEventRoutine);
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerGetLineInfo(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN HANDLE MixerHandle,
|
|
IN ULONG MixerId,
|
|
IN ULONG Flags,
|
|
OUT LPMIXERLINEW MixerLine)
|
|
{
|
|
MIXER_STATUS Status;
|
|
LPMIXER_INFO MixerInfo;
|
|
LPMIXERLINE_EXT MixerLineSrc;
|
|
ULONG DestinationLineID;
|
|
|
|
/* verify mixer context */
|
|
Status = MMixerVerifyContext(MixerContext);
|
|
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* invalid context passed */
|
|
return Status;
|
|
}
|
|
if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
|
|
{
|
|
/* caller passed mixer id */
|
|
MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
|
|
|
|
if (!MixerHandle)
|
|
{
|
|
/* invalid parameter */
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if (MixerLine->cbStruct != sizeof(MIXERLINEW))
|
|
{
|
|
DPRINT1("MixerLine Expected %lu but got %lu\n", sizeof(MIXERLINEW), MixerLine->cbStruct);
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* clear hmixer from flags */
|
|
Flags &=~MIXER_OBJECTF_HMIXER;
|
|
|
|
DPRINT("MMixerGetLineInfo MixerId %lu Flags %lu\n", MixerId, Flags);
|
|
|
|
if (Flags == MIXER_GETLINEINFOF_DESTINATION)
|
|
{
|
|
/* cast to mixer info */
|
|
MixerInfo = (LPMIXER_INFO)MixerHandle;
|
|
|
|
/* calculate destination line id */
|
|
DestinationLineID = (MixerLine->dwDestination + DESTINATION_LINE);
|
|
|
|
/* get destination line */
|
|
MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
|
|
|
|
if (MixerLineSrc == NULL)
|
|
{
|
|
DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination);
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
/* copy mixer line */
|
|
MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
|
|
|
|
/* make sure it is null terminated */
|
|
MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
|
|
MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
|
|
MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
|
|
|
|
/* done */
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
else if (Flags == MIXER_GETLINEINFOF_SOURCE)
|
|
{
|
|
/* cast to mixer info */
|
|
MixerInfo = (LPMIXER_INFO)MixerHandle;
|
|
|
|
/* calculate destination line id */
|
|
DestinationLineID = (MixerLine->dwDestination + DESTINATION_LINE);
|
|
|
|
/* get destination line */
|
|
MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
|
|
|
|
if (MixerLineSrc == NULL)
|
|
{
|
|
DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination);
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* check if dwSource is out of bounds */
|
|
if (MixerLine->dwSource >= MixerLineSrc->Line.cConnections)
|
|
{
|
|
DPRINT1("MixerCaps Name %S MixerLineName %S Connections %lu dwSource %lu not found\n", MixerInfo->MixCaps.szPname, MixerLineSrc->Line.szName, MixerLineSrc->Line.cConnections, MixerLine->dwSource);
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* calculate destination line id */
|
|
DestinationLineID = (MixerLine->dwSource * SOURCE_LINE) + MixerLine->dwDestination;
|
|
|
|
DPRINT("MixerName %S cDestinations %lu MixerLineName %S cConnections %lu dwSource %lu dwDestination %lu ID %lx\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations,
|
|
MixerLineSrc->Line.szName, MixerLineSrc->Line.cConnections,
|
|
MixerLine->dwSource, MixerLine->dwDestination,
|
|
DestinationLineID);
|
|
/* get target destination line id */
|
|
MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
|
|
|
|
/* sanity check */
|
|
ASSERT(MixerLineSrc);
|
|
|
|
DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
|
|
|
|
/* copy mixer line */
|
|
MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
|
|
|
|
/* make sure it is null terminated */
|
|
MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
|
|
MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
|
|
MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
|
|
|
|
/* done */
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
else if (Flags == MIXER_GETLINEINFOF_LINEID)
|
|
{
|
|
/* cast to mixer info */
|
|
MixerInfo = (LPMIXER_INFO)MixerHandle;
|
|
|
|
/* try to find line */
|
|
MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLine->dwLineID);
|
|
if (!MixerLineSrc)
|
|
{
|
|
/* invalid parameter */
|
|
DPRINT1("MMixerGetLineInfo: MixerName %S Line not found 0x%lx\n", MixerInfo->MixCaps.szPname, MixerLine->dwLineID);
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
|
|
|
|
/* copy mixer line*/
|
|
MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
|
|
|
|
/* make sure it is null terminated */
|
|
MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
|
|
MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
|
|
MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
|
|
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
else if (Flags == MIXER_GETLINEINFOF_COMPONENTTYPE)
|
|
{
|
|
/* cast to mixer info */
|
|
MixerInfo = (LPMIXER_INFO)MixerHandle;
|
|
|
|
/* find mixer line by component type */
|
|
MixerLineSrc = MMixerGetSourceMixerLineByComponentType(MixerInfo, MixerLine->dwComponentType);
|
|
if (!MixerLineSrc)
|
|
{
|
|
DPRINT1("Failed to find component type %x\n", MixerLine->dwComponentType);
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* copy mixer line */
|
|
MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
|
|
|
|
/* make sure it is null terminated */
|
|
MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
|
|
MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
|
|
MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
|
|
|
|
/* done */
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
else if (Flags == MIXER_GETLINEINFOF_TARGETTYPE)
|
|
{
|
|
DPRINT1("MIXER_GETLINEINFOF_TARGETTYPE handling is unimplemented\n");
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("Unknown Flags %lx handling is unimplemented\n", Flags);
|
|
}
|
|
|
|
return MM_STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerGetLineControls(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN HANDLE MixerHandle,
|
|
IN ULONG MixerId,
|
|
IN ULONG Flags,
|
|
OUT LPMIXERLINECONTROLSW MixerLineControls)
|
|
{
|
|
LPMIXER_INFO MixerInfo;
|
|
LPMIXERLINE_EXT MixerLineSrc;
|
|
LPMIXERCONTROL_EXT MixerControl;
|
|
MIXER_STATUS Status;
|
|
PLIST_ENTRY Entry;
|
|
ULONG Index;
|
|
|
|
/* verify mixer context */
|
|
Status = MMixerVerifyContext(MixerContext);
|
|
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* invalid context passed */
|
|
return Status;
|
|
}
|
|
|
|
if (MixerLineControls->cbStruct != sizeof(MIXERLINECONTROLSW))
|
|
{
|
|
DPRINT1("Invalid MixerLineControls cbStruct passed %lu expected %lu\n", MixerLineControls->cbStruct, sizeof(MIXERLINECONTROLSW));
|
|
/* invalid parameter */
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (MixerLineControls->cbmxctrl != sizeof(MIXERCONTROLW))
|
|
{
|
|
DPRINT1("Invalid MixerLineControls cbmxctrl passed %lu expected %lu\n", MixerLineControls->cbmxctrl, sizeof(MIXERCONTROLW));
|
|
/* invalid parameter */
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
|
|
{
|
|
/* caller passed mixer id */
|
|
MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
|
|
|
|
if (!MixerHandle)
|
|
{
|
|
/* invalid parameter */
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
Flags &= ~MIXER_OBJECTF_HMIXER;
|
|
|
|
DPRINT("MMixerGetLineControls MixerId %lu Flags %lu\n", MixerId, Flags);
|
|
|
|
if (Flags == MIXER_GETLINECONTROLSF_ALL)
|
|
{
|
|
/* cast to mixer info */
|
|
MixerInfo = (LPMIXER_INFO)MixerHandle;
|
|
|
|
/* get mixer line */
|
|
MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
|
|
|
|
if (!MixerLineSrc)
|
|
{
|
|
/* invalid line id */
|
|
DPRINT("MMixerGetLineControls Line not found %lx\n", MixerLineControls->dwLineID);
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (MixerLineSrc->Line.cControls != MixerLineControls->cControls)
|
|
{
|
|
/* invalid parameter */
|
|
DPRINT1("Invalid control count %lu expected %lu\n", MixerLineControls->cControls, MixerLineSrc->Line.cControls);
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* copy line control(s) */
|
|
Entry = MixerLineSrc->ControlsList.Flink;
|
|
Index = 0;
|
|
while(Entry != &MixerLineSrc->ControlsList)
|
|
{
|
|
/* get mixer control */
|
|
MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(Entry, MIXERCONTROL_EXT, Entry);
|
|
|
|
/* copy mixer control */
|
|
MixerContext->Copy(&MixerLineControls->pamxctrl[Index], &MixerControl->Control, sizeof(MIXERCONTROLW));
|
|
|
|
/* move to next */
|
|
Entry = Entry->Flink;
|
|
|
|
/* increment mixer control offset */
|
|
Index++;
|
|
}
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
else if (Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
|
|
{
|
|
/* cast to mixer info */
|
|
MixerInfo = (LPMIXER_INFO)MixerHandle;
|
|
|
|
/* get mixer line */
|
|
MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
|
|
|
|
if (!MixerLineSrc)
|
|
{
|
|
/* invalid line id */
|
|
DPRINT1("MMixerGetLineControls Line not found %lx\n", MixerLineControls->dwLineID);
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* sanity checks */
|
|
ASSERT(MixerLineControls->cControls == 1);
|
|
ASSERT(MixerLineControls->cbmxctrl == sizeof(MIXERCONTROLW));
|
|
ASSERT(MixerLineControls->pamxctrl != NULL);
|
|
|
|
Entry = MixerLineSrc->ControlsList.Flink;
|
|
while(Entry != &MixerLineSrc->ControlsList)
|
|
{
|
|
MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(Entry, MIXERCONTROL_EXT, Entry);
|
|
if (MixerLineControls->dwControlType == MixerControl->Control.dwControlType)
|
|
{
|
|
/* found a control with that type */
|
|
MixerContext->Copy(MixerLineControls->pamxctrl, &MixerControl->Control, sizeof(MIXERCONTROLW));
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
|
|
/* move to next entry */
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
DPRINT("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x cControls %u \n", MixerLineControls->dwControlType, MixerLineControls->dwLineID, MixerLineSrc->Line.cControls);
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
else if (Flags == MIXER_GETLINECONTROLSF_ONEBYID)
|
|
{
|
|
/* cast to mixer info */
|
|
MixerInfo = (LPMIXER_INFO)MixerHandle;
|
|
|
|
Status = MMixerGetMixerControlById(MixerInfo, MixerLineControls->dwControlID, NULL, &MixerControl, NULL);
|
|
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* invalid parameter */
|
|
DPRINT("MMixerGetLineControls ControlID not found %lx\n", MixerLineControls->dwLineID);
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
ASSERT(MixerLineControls->cControls == 1);
|
|
ASSERT(MixerLineControls->cbmxctrl == sizeof(MIXERCONTROLW));
|
|
ASSERT(MixerLineControls->pamxctrl != NULL);
|
|
|
|
DPRINT("MMixerGetLineControls ControlID %lx ControlType %lx Name %S\n", MixerControl->Control.dwControlID, MixerControl->Control.dwControlType, MixerControl->Control.szName);
|
|
|
|
/* copy the controls */
|
|
MixerContext->Copy(MixerLineControls->pamxctrl, &MixerControl->Control, sizeof(MIXERCONTROLW));
|
|
MixerLineControls->pamxctrl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
|
|
MixerLineControls->pamxctrl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
|
|
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
UNIMPLEMENTED;
|
|
return MM_STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerSetControlDetails(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN HANDLE MixerHandle,
|
|
IN ULONG MixerId,
|
|
IN ULONG Flags,
|
|
OUT LPMIXERCONTROLDETAILS MixerControlDetails)
|
|
{
|
|
MIXER_STATUS Status;
|
|
ULONG NodeId;
|
|
LPMIXER_INFO MixerInfo;
|
|
LPMIXERLINE_EXT MixerLine;
|
|
LPMIXERCONTROL_EXT MixerControl;
|
|
|
|
/* verify mixer context */
|
|
Status = MMixerVerifyContext(MixerContext);
|
|
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* invalid context passed */
|
|
DPRINT1("invalid context\n");
|
|
return Status;
|
|
}
|
|
|
|
if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
|
|
{
|
|
/* caller passed mixer id */
|
|
MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
|
|
|
|
if (!MixerHandle)
|
|
{
|
|
/* invalid parameter */
|
|
DPRINT1("invalid handle\n");
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
/* get mixer info */
|
|
MixerInfo = (LPMIXER_INFO)MixerHandle;
|
|
|
|
/* get mixer control */
|
|
Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId);
|
|
|
|
/* check for success */
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* failed to find control id */
|
|
DPRINT1("invalid control id %lu\n", MixerControlDetails->dwControlID);
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
DPRINT("MMixerSetControlDetails ControlType %lx MixerControlName %S MixerLineName %S NodeID %lu\n", MixerControl->Control.dwControlType, MixerControl->Control.szName, MixerLine->Line.szName, NodeId);
|
|
switch(MixerControl->Control.dwControlType)
|
|
{
|
|
case MIXERCONTROL_CONTROLTYPE_MUTE:
|
|
Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo, MixerControl, MixerLine->Line.dwLineID, MixerControlDetails, TRUE);
|
|
break;
|
|
case MIXERCONTROL_CONTROLTYPE_VOLUME:
|
|
Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo, NodeId, TRUE, MixerControl, MixerControlDetails, MixerLine);
|
|
break;
|
|
case MIXERCONTROL_CONTROLTYPE_MUX:
|
|
Status = MMixerSetGetMuxControlDetails(MixerContext, MixerInfo, NodeId, TRUE, Flags, MixerControl, MixerControlDetails, MixerLine);
|
|
break;
|
|
default:
|
|
Status = MM_STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerGetControlDetails(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN HANDLE MixerHandle,
|
|
IN ULONG MixerId,
|
|
IN ULONG Flags,
|
|
OUT LPMIXERCONTROLDETAILS MixerControlDetails)
|
|
{
|
|
MIXER_STATUS Status;
|
|
ULONG NodeId;
|
|
LPMIXER_INFO MixerInfo;
|
|
LPMIXERLINE_EXT MixerLine;
|
|
LPMIXERCONTROL_EXT MixerControl;
|
|
|
|
/* verify mixer context */
|
|
Status = MMixerVerifyContext(MixerContext);
|
|
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* invalid context passed */
|
|
return Status;
|
|
}
|
|
|
|
if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
|
|
{
|
|
/* caller passed mixer id */
|
|
MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
|
|
|
|
if (!MixerHandle)
|
|
{
|
|
/* invalid parameter */
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
/* get mixer info */
|
|
MixerInfo = (LPMIXER_INFO)MixerHandle;
|
|
|
|
/* get mixer control */
|
|
Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId);
|
|
|
|
/* check for success */
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* failed to find control id */
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
switch(MixerControl->Control.dwControlType)
|
|
{
|
|
case MIXERCONTROL_CONTROLTYPE_MUTE:
|
|
Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo, MixerControl, MixerLine->Line.dwLineID, MixerControlDetails, FALSE);
|
|
break;
|
|
case MIXERCONTROL_CONTROLTYPE_VOLUME:
|
|
Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo, NodeId, FALSE, MixerControl, MixerControlDetails, MixerLine);
|
|
break;
|
|
case MIXERCONTROL_CONTROLTYPE_ONOFF:
|
|
DPRINT1("Not Implemented MIXERCONTROL_CONTROLTYPE_ONOFF\n");
|
|
break;
|
|
case MIXERCONTROL_CONTROLTYPE_MUX:
|
|
Status = MMixerSetGetMuxControlDetails(MixerContext, MixerInfo, NodeId, FALSE, Flags, MixerControl, MixerControlDetails, MixerLine);
|
|
break;
|
|
|
|
default:
|
|
Status = MM_STATUS_NOT_IMPLEMENTED;
|
|
DPRINT1("ControlType %lx not implemented\n", MixerControl->Control.dwControlType);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
MMixerPrintMixerLineControls(
|
|
IN LPMIXERLINE_EXT MixerLine)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
LPMIXERCONTROL_EXT MixerControl;
|
|
ULONG Index = 0;
|
|
|
|
Entry = MixerLine->ControlsList.Flink;
|
|
while(Entry != &MixerLine->ControlsList)
|
|
{
|
|
MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(Entry, MIXERCONTROL_EXT, Entry);
|
|
|
|
DPRINT1("\n");
|
|
DPRINT1("Control Index: %lu\n", Index);
|
|
DPRINT("\n");
|
|
DPRINT1("cbStruct %u\n", MixerControl->Control.cbStruct);
|
|
DPRINT1("dwControlID %lu\n", MixerControl->Control.dwControlID);
|
|
DPRINT1("dwControlType %lx\n", MixerControl->Control.dwControlType);
|
|
DPRINT1("fdwControl %lu\n", MixerControl->Control.fdwControl);
|
|
DPRINT1("cMultipleItems %lu\n", MixerControl->Control.cMultipleItems);
|
|
DPRINT1("szShortName %S\n", MixerControl->Control.szShortName);
|
|
DPRINT1("szName %S\n", MixerControl->Control.szName);
|
|
DPRINT1("Bounds.dwMinimum %lu\n", MixerControl->Control.Bounds.dwMinimum);
|
|
DPRINT1("Bounds.dwMaximum %lu\n", MixerControl->Control.Bounds.dwMaximum);
|
|
|
|
DPRINT1("Metrics.Reserved[0] %lu\n", MixerControl->Control.Metrics.dwReserved[0]);
|
|
DPRINT1("Metrics.Reserved[1] %lu\n", MixerControl->Control.Metrics.dwReserved[1]);
|
|
DPRINT1("Metrics.Reserved[2] %lu\n", MixerControl->Control.Metrics.dwReserved[2]);
|
|
DPRINT1("Metrics.Reserved[3] %lu\n", MixerControl->Control.Metrics.dwReserved[3]);
|
|
DPRINT1("Metrics.Reserved[4] %lu\n", MixerControl->Control.Metrics.dwReserved[4]);
|
|
DPRINT1("Metrics.Reserved[5] %lu\n", MixerControl->Control.Metrics.dwReserved[5]);
|
|
|
|
Entry = Entry->Flink;
|
|
Index++;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
MMixerPrintMixers(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN PMIXER_LIST MixerList)
|
|
{
|
|
ULONG Index, SubIndex, DestinationLineID, SrcIndex;
|
|
LPMIXER_INFO MixerInfo;
|
|
LPMIXERLINE_EXT DstMixerLine, SrcMixerLine;
|
|
|
|
DPRINT1("MixerList %p\n", MixerList);
|
|
DPRINT1("MidiInCount %lu\n", MixerList->MidiInListCount);
|
|
DPRINT1("MidiOutCount %lu\n", MixerList->MidiOutListCount);
|
|
DPRINT1("WaveInCount %lu\n", MixerList->WaveInListCount);
|
|
DPRINT1("WaveOutCount %lu\n", MixerList->WaveOutListCount);
|
|
DPRINT1("MixerCount %p\n", MixerList->MixerListCount);
|
|
|
|
for(Index = 0; Index < MixerList->MixerListCount; Index++)
|
|
{
|
|
/* get mixer info */
|
|
MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, Index);
|
|
|
|
ASSERT(MixerInfo);
|
|
DPRINT1("\n");
|
|
DPRINT1("Name :%S\n", MixerInfo->MixCaps.szPname);
|
|
DPRINT1("cDestinations: %lu\n", MixerInfo->MixCaps.cDestinations);
|
|
DPRINT1("fdwSupport %lu\n", MixerInfo->MixCaps.fdwSupport);
|
|
DPRINT1("vDriverVersion %lx\n", MixerInfo->MixCaps.vDriverVersion);
|
|
DPRINT1("wMid %lx\n", MixerInfo->MixCaps.wMid);
|
|
DPRINT1("wPid %lx\n", MixerInfo->MixCaps.wPid);
|
|
|
|
for(SubIndex = 0; SubIndex < MixerInfo->MixCaps.cDestinations; SubIndex++)
|
|
{
|
|
/* calculate destination line id */
|
|
DestinationLineID = (SubIndex + DESTINATION_LINE);
|
|
|
|
/* get destination line */
|
|
DstMixerLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
|
|
DPRINT1("//----------------------------------------------------------------------------------------------\n");
|
|
DPRINT1("\n");
|
|
DPRINT1("Destination Index %lu\n", SubIndex);
|
|
DPRINT1("\n");
|
|
DPRINT1("cChannels %lu\n", DstMixerLine->Line.cChannels);
|
|
DPRINT1("cConnections %lu\n", DstMixerLine->Line.cConnections);
|
|
DPRINT1("cControls %lu\n", DstMixerLine->Line.cControls);
|
|
DPRINT1("dwComponentType %lx\n", DstMixerLine->Line.dwComponentType);
|
|
DPRINT1("dwDestination %lu\n", DstMixerLine->Line.dwDestination);
|
|
DPRINT1("dwLineID %lx\n", DstMixerLine->Line.dwLineID);
|
|
DPRINT1("dwSource %lx\n", DstMixerLine->Line.dwSource);
|
|
DPRINT1("dwUser %lu\n", DstMixerLine->Line.dwUser);
|
|
DPRINT1("fdwLine %lu\n", DstMixerLine->Line.fdwLine);
|
|
DPRINT1("szName %S\n", DstMixerLine->Line.szName);
|
|
DPRINT1("szShortName %S\n", DstMixerLine->Line.szShortName);
|
|
DPRINT1("Target.dwDeviceId %lu\n", DstMixerLine->Line.Target.dwDeviceID);
|
|
DPRINT1("Target.dwType %lu\n", DstMixerLine->Line.Target.dwType);
|
|
DPRINT1("Target.szName %S\n", DstMixerLine->Line.Target.szPname);
|
|
DPRINT1("Target.vDriverVersion %lx\n", DstMixerLine->Line.Target.vDriverVersion);
|
|
DPRINT1("Target.wMid %lx\n", DstMixerLine->Line.Target.wMid );
|
|
DPRINT1("Target.wPid %lx\n", DstMixerLine->Line.Target.wPid);
|
|
MMixerPrintMixerLineControls(DstMixerLine);
|
|
|
|
for(SrcIndex = 0; SrcIndex < DstMixerLine->Line.cConnections; SrcIndex++)
|
|
{
|
|
/* calculate destination line id */
|
|
DestinationLineID = (SOURCE_LINE * SrcIndex) + SubIndex;
|
|
|
|
/* get source line */
|
|
SrcMixerLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
|
|
DPRINT1("//==============================================================================================\n");
|
|
DPRINT1("\n");
|
|
DPRINT1("SrcLineIndex : %lu\n", SrcIndex);
|
|
DPRINT1("\n");
|
|
DPRINT1("cChannels %lu\n", SrcMixerLine->Line.cChannels);
|
|
DPRINT1("cConnections %lu\n", SrcMixerLine->Line.cConnections);
|
|
DPRINT1("cControls %lu\n", SrcMixerLine->Line.cControls);
|
|
DPRINT1("dwComponentType %lx\n", SrcMixerLine->Line.dwComponentType);
|
|
DPRINT1("dwDestination %lu\n", SrcMixerLine->Line.dwDestination);
|
|
DPRINT1("dwLineID %lx\n", SrcMixerLine->Line.dwLineID);
|
|
DPRINT1("dwSource %lx\n", SrcMixerLine->Line.dwSource);
|
|
DPRINT1("dwUser %lu\n", SrcMixerLine->Line.dwUser);
|
|
DPRINT1("fdwLine %lu\n", SrcMixerLine->Line.fdwLine);
|
|
DPRINT1("szName %S\n", SrcMixerLine->Line.szName);
|
|
DPRINT1("szShortName %S\n", SrcMixerLine->Line.szShortName);
|
|
DPRINT1("Target.dwDeviceId %lu\n", SrcMixerLine->Line.Target.dwDeviceID);
|
|
DPRINT1("Target.dwType %lu\n", SrcMixerLine->Line.Target.dwType);
|
|
DPRINT1("Target.szName %S\n", SrcMixerLine->Line.Target.szPname);
|
|
DPRINT1("Target.vDriverVersion %lx\n", SrcMixerLine->Line.Target.vDriverVersion);
|
|
DPRINT1("Target.wMid %lx\n", SrcMixerLine->Line.Target.wMid );
|
|
DPRINT1("Target.wPid %lx\n", SrcMixerLine->Line.Target.wPid);
|
|
MMixerPrintMixerLineControls(SrcMixerLine);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerInitialize(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN PMIXER_ENUM EnumFunction,
|
|
IN PVOID EnumContext)
|
|
{
|
|
MIXER_STATUS Status;
|
|
HANDLE hMixer, hKey;
|
|
ULONG DeviceIndex, Count;
|
|
LPWSTR DeviceName;
|
|
LPMIXER_DATA MixerData;
|
|
PMIXER_LIST MixerList;
|
|
PLIST_ENTRY Entry;
|
|
|
|
if (!MixerContext || !EnumFunction || !EnumContext)
|
|
{
|
|
/* invalid parameter */
|
|
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)
|
|
{
|
|
/* invalid parameter */
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* allocate a mixer list */
|
|
MixerList = (PMIXER_LIST)MixerContext->Alloc(sizeof(MIXER_LIST));
|
|
if (!MixerList)
|
|
{
|
|
/* no memory */
|
|
return MM_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* initialize mixer list */
|
|
MixerList->MixerListCount = 0;
|
|
MixerList->MixerDataCount = 0;
|
|
MixerList->WaveInListCount = 0;
|
|
MixerList->WaveOutListCount = 0;
|
|
MixerList->MidiInListCount = 0;
|
|
MixerList->MidiOutListCount = 0;
|
|
InitializeListHead(&MixerList->MixerList);
|
|
InitializeListHead(&MixerList->MixerData);
|
|
InitializeListHead(&MixerList->WaveInList);
|
|
InitializeListHead(&MixerList->WaveOutList);
|
|
InitializeListHead(&MixerList->MidiInList);
|
|
InitializeListHead(&MixerList->MidiOutList);
|
|
|
|
/* store mixer list */
|
|
MixerContext->MixerContext = (PVOID)MixerList;
|
|
|
|
/* enumerate all available devices */
|
|
for (DeviceIndex = 0; ; DeviceIndex++)
|
|
{
|
|
/* enumerate a device */
|
|
Status = EnumFunction(EnumContext, DeviceIndex, &DeviceName, &hMixer, &hKey);
|
|
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* check error code */
|
|
if (Status == MM_STATUS_NO_MORE_DEVICES)
|
|
{
|
|
/* enumeration has finished */
|
|
break;
|
|
}
|
|
|
|
DPRINT1("EnumFunction() failed for device %lu, Status %x\n", DeviceIndex, Status);
|
|
|
|
/* ignore error and continue */
|
|
}
|
|
else
|
|
{
|
|
/* create a mixer data entry */
|
|
Status = MMixerCreateMixerData(MixerContext, MixerList, DeviceIndex, DeviceName, hMixer, hKey);
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
DPRINT1("MMixerCreateMixerData() failed for device %lu, Status %x\n",
|
|
DeviceIndex, Status);
|
|
|
|
/* ignore error and continue */
|
|
}
|
|
}
|
|
|
|
/* now all filters have been pre-opened
|
|
* lets enumerate the filters
|
|
*/
|
|
Count = 0;
|
|
Entry = MixerList->MixerData.Flink;
|
|
while(Entry != &MixerList->MixerData)
|
|
{
|
|
MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
|
|
MMixerSetupFilter(MixerContext, MixerList, MixerData, &Count);
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
Entry = MixerList->MixerData.Flink;
|
|
while(Entry != &MixerList->MixerData)
|
|
{
|
|
MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
|
|
|
|
/* now handle alternative mixer types */
|
|
MMixerHandleAlternativeMixers(MixerContext, MixerList, MixerData, MixerData->Topology);
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
//MMixerPrintMixers(MixerContext, MixerList);
|
|
|
|
/* done */
|
|
return MM_STATUS_SUCCESS;
|
|
}
|