mirror of
https://github.com/reactos/reactos.git
synced 2025-05-25 04:03:56 +00:00

- More fixes for mmixer library - Store destination lines sharing the same mixer object in the same object - Fix generating destination lines id / soure lines - Add mux node for input mixers - Disable code which checked if the topology node has already been reserved for an another line. Tests in WinXP concluded that ms does not do this at all, though documentation claims it - Add source line to the correct destination line - Fix a memory leak - Fix tons of bugs in MMixerGetLineInfo svn path=/branches/audio-bringup/; revision=49949
691 lines
21 KiB
C
691 lines
21 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 "priv.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
|
|
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;
|
|
|
|
DPRINT1("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 * DESTINATION_LINE) + MixerLine->dwDestination;
|
|
|
|
/* 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("MixerName %S Line not found %lu\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;
|
|
LPMIXERCONTROLW MixerControl;
|
|
MIXER_STATUS Status;
|
|
ULONG Index;
|
|
|
|
/* 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;
|
|
}
|
|
}
|
|
|
|
Flags &= ~MIXER_OBJECTF_HMIXER;
|
|
|
|
if (Flags == MIXER_GETLINECONTROLSF_ALL)
|
|
{
|
|
/* cast to mixer info */
|
|
MixerInfo = (LPMIXER_INFO)MixerHandle;
|
|
|
|
MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
|
|
|
|
if (!MixerLineSrc)
|
|
{
|
|
/* invalid line id */
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
/* copy line control(s) */
|
|
MixerContext->Copy(MixerLineControls->pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, MixerLineControls->cControls) * sizeof(MIXERCONTROLW));
|
|
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
else if (Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
|
|
{
|
|
/* cast to mixer info */
|
|
MixerInfo = (LPMIXER_INFO)MixerHandle;
|
|
|
|
MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);
|
|
|
|
if (!MixerLineSrc)
|
|
{
|
|
/* invalid line id */
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
ASSERT(MixerLineSrc);
|
|
|
|
Index = 0;
|
|
for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
|
|
{
|
|
DPRINT("dwControlType %x\n", MixerLineSrc->LineControls[Index].dwControlType);
|
|
if (MixerLineControls->dwControlType == MixerLineSrc->LineControls[Index].dwControlType)
|
|
{
|
|
/* found a control with that type */
|
|
MixerContext->Copy(MixerLineControls->pamxctrl, &MixerLineSrc->LineControls[Index], sizeof(MIXERCONTROLW));
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
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 */
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* copy the controls */
|
|
MixerContext->Copy(MixerLineControls->pamxctrl, MixerControl, sizeof(MIXERCONTROLW));
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
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;
|
|
LPMIXERCONTROLW 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->dwControlType)
|
|
{
|
|
case MIXERCONTROL_CONTROLTYPE_MUTE:
|
|
Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo->hMixer, NodeId, MixerLine->Line.dwLineID, MixerControlDetails, TRUE);
|
|
break;
|
|
case MIXERCONTROL_CONTROLTYPE_VOLUME:
|
|
Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo->hMixer, NodeId, TRUE, 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;
|
|
LPMIXERCONTROLW 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->dwControlType)
|
|
{
|
|
case MIXERCONTROL_CONTROLTYPE_MUTE:
|
|
Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo, NodeId, MixerLine->Line.dwLineID, MixerControlDetails, FALSE);
|
|
break;
|
|
case MIXERCONTROL_CONTROLTYPE_VOLUME:
|
|
Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo, NodeId, FALSE, MixerControl, MixerControlDetails, MixerLine);
|
|
break;
|
|
default:
|
|
Status = MM_STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
MMixerPrintMixers(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN PMIXER_LIST MixerList)
|
|
{
|
|
ULONG Index, SubIndex, DestinationLineID;
|
|
LPMIXER_INFO MixerInfo;
|
|
LPMIXERLINE_EXT DstMixerLine;
|
|
|
|
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("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);
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
/* start enumerating all available devices */
|
|
Count = 0;
|
|
DeviceIndex = 0;
|
|
|
|
do
|
|
{
|
|
/* 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;
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("Failed to enumerate device %lu\n", DeviceIndex);
|
|
|
|
/* TODO cleanup */
|
|
return Status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* create a mixer data entry */
|
|
Status = MMixerCreateMixerData(MixerContext, MixerList, DeviceIndex, DeviceName, hMixer, hKey);
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
|
|
/* increment device index */
|
|
DeviceIndex++;
|
|
}while(TRUE);
|
|
|
|
/* now all filters have been pre-opened
|
|
* lets enumerate the filters
|
|
*/
|
|
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;
|
|
}
|
|
|
|
MMixerPrintMixers(MixerContext, MixerList);
|
|
|
|
/* done */
|
|
return MM_STATUS_SUCCESS;
|
|
}
|