MMRESULT
MmeGetLineInfo(
+ IN UINT DeviceId,
IN UINT Message,
IN DWORD_PTR PrivateHandle,
IN DWORD_PTR Parameter1,
//SND_TRACE(L"Getting mixer info %u\n", Message);
+ if ( PrivateHandle == 0 )
+ {
+ Result = GetSoundDevice(MIXER_DEVICE_TYPE, DeviceId, &SoundDevice);
+
+ if ( ! MMSUCCESS(Result) )
+ return TranslateInternalMmResult(Result);
+
+ Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
+ if ( ! MMSUCCESS(Result) )
+ return TranslateInternalMmResult(Result);
+
+ Result = FunctionTable->QueryMixerInfo(NULL, DeviceId, Message, (LPVOID)Parameter1, Parameter2);
+ return Result;
+ }
+
VALIDATE_MMSYS_PARAMETER( PrivateHandle );
SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
if ( ! FunctionTable->QueryMixerInfo )
return MMSYSERR_NOTSUPPORTED;
- Result = FunctionTable->QueryMixerInfo(SoundDeviceInstance, Message, (LPVOID)Parameter1, Parameter2);
+ Result = FunctionTable->QueryMixerInfo(SoundDeviceInstance, DeviceId, Message, (LPVOID)Parameter1, Parameter2);
return Result;
}
(LPWAVEOPENDESC) Parameter1, /* unused */
Parameter2,
(DWORD*) PrivateHandle);
-
+ VALIDATE_MMSYS_PARAMETER(*(DWORD_PTR*)PrivateHandle);
break;
}
case MXDM_GETCONTROLDETAILS :
{
- Result = MmeGetLineInfo(Message,
+ Result = MmeGetLineInfo(DeviceId,
+ Message,
PrivateHandle,
Parameter1,
Parameter2);
case MXDM_SETCONTROLDETAILS :
{
- Result = MmeGetLineInfo(Message,
+ Result = MmeGetLineInfo(DeviceId,
+ Message,
PrivateHandle,
Parameter1,
Parameter2);
case MXDM_GETLINECONTROLS :
{
- Result = MmeGetLineInfo(Message,
+ Result = MmeGetLineInfo(DeviceId,
+ Message,
PrivateHandle,
Parameter1,
Parameter2);
case MXDM_GETLINEINFO :
{
- Result = MmeGetLineInfo(Message,
+ Result = MmeGetLineInfo(DeviceId,
+ Message,
PrivateHandle,
Parameter1,
Parameter2);
UINT Message;
PSOUND_DEVICE SoundDevice;
PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
- LPWAVEFORMATEX Format;
+ LPWAVEFORMATEX Format = NULL;
SND_TRACE(L"Opening device");
- VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) ); /* FIXME? wave in too? */
+ VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) || IS_MIXER_DEVICE_TYPE(DeviceType) || IS_MIDI_DEVICE_TYPE(DeviceType) ); /* FIXME? wave in too? */
VALIDATE_MMSYS_PARAMETER( OpenParameters );
Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
SND_TRACE(L"Setting wave format\n");
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
- VALIDATE_MMSYS_PARAMETER( Format );
- VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) );
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
if ( ! MMSUCCESS(Result) )
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
SND_ASSERT( Result == MMSYSERR_NOERROR );
+ if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
+ {
+ VALIDATE_MMSYS_PARAMETER( Format );
+ VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) );
+ }
/* Ensure we have a wave device (TODO: check if this applies to wavein as well) */
- VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) );
+ VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) || IS_MIDI_DEVICE_TYPE(DeviceType) || IS_MIXER_DEVICE_TYPE(DeviceType));
/* Obtain the function table */
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
}while(dwNumberOfBytesTransferred);
+ // AUDIO-BRANCH DIFF
+ // completion callback is performed in a thread
DoWaveStreaming(SoundDeviceInstance);
//CompleteWavePortion(SoundDeviceInstance, dwNumberOfBytesTransferred);
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
IN PVOID Parameter)
{
- /* TODO */
- return MMSYSERR_NOTSUPPORTED;
+ MMDEVICE_TYPE DeviceType;
+ PMMFUNCTION_TABLE FunctionTable;
+ MMRESULT Result;
+ PSOUND_DEVICE SoundDevice;
+
+ /* set state reset in progress */
+ SoundDeviceInstance->ResetInProgress = TRUE;
+
+ /* Get sound device */
+ Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
+ SND_ASSERT( Result == MMSYSERR_NOERROR );
+
+ /* Obtain the function table */
+ Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
+ SND_ASSERT( Result == MMSYSERR_NOERROR );
+
+ /* Obtain device instance type */
+ Result = GetSoundDeviceType(SoundDevice, &DeviceType);
+ SND_ASSERT( Result == MMSYSERR_NOERROR );
+
+ /* Check if reset function is supported */
+ if (FunctionTable->ResetStream)
+ {
+ /* cancel all current audio buffers */
+ FunctionTable->ResetStream(SoundDeviceInstance, DeviceType, TRUE);
+ }
+
+ /* complete all current headers */
+ while( SoundDeviceInstance->HeadWaveHeader )
+ {
+ SND_TRACE(L"StopStreamingInSoundThread: Completing Header %p\n", SoundDeviceInstance->HeadWaveHeader);
+ CompleteWaveHeader( SoundDeviceInstance, SoundDeviceInstance->HeadWaveHeader );
+ }
+
+ /* there should be no oustanding buffers now */
+ SND_ASSERT(SoundDeviceInstance->OutstandingBuffers == 0);
+
+ while(SoundDeviceInstance->OutstandingBuffers)
+ {
+ SND_ERR("StopStreamingInSoundThread OutStandingBufferCount %lu\n", SoundDeviceInstance->OutstandingBuffers);
+ /* my hack of doom */
+ Sleep(10);
+ }
+
+ /* Check if reset function is supported */
+ if (FunctionTable->ResetStream)
+ {
+ /* finish the reset */
+ FunctionTable->ResetStream(SoundDeviceInstance, DeviceType, FALSE);
+ }
+
+ /* clear state reset in progress */
+ SoundDeviceInstance->ResetInProgress = FALSE;
+
+
+ return MMSYSERR_NOERROR;
}
MMRESULT
case WODM_RESTART :
{
/* Continue playback when paused */
+ Result = MmeSetState(PrivateHandle, TRUE);
+ break;
+ }
+ case WODM_PAUSE :
+ {
+ /* pause playback */
+ Result = MmeSetState(PrivateHandle, FALSE);
break;
}
--- /dev/null
+=== MMIXER TASKS ===\r
+\r
+- Add hacks for source lines, such that Wave Mixer line always has a volume control\r
+- Support custom mixer controls\r
+- Assign mixer controls after all controls have been assigned (starting on the destination lines)\r
+- TESTING & BUGFIXING
\ No newline at end of file
#include "priv.h"
+const GUID KSNODETYPE_DESKTOP_MICROPHONE = {0xDFF21BE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_LEGACY_AUDIO_CONNECTOR = {0xDFF21FE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_TELEPHONE = {0xDFF21EE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_PHONE_LINE = {0xDFF21EE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_DOWN_LINE_PHONE = {0xDFF21EE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_DESKTOP_SPEAKER = {0xDFF21CE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_ROOM_SPEAKER = {0xDFF21CE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_COMMUNICATION_SPEAKER = {0xDFF21CE6, 0xF70F, 0x11D0, {0xB9,0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_HEADPHONES = {0xDFF21CE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO = {0xDFF21CE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_MICROPHONE = {0xDFF21BE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9,0x22, 0x31, 0x96}};
+const GUID KSCATEGORY_AUDIO = {0x6994AD04L, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_SPDIF_INTERFACE = {0xDFF21FE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_ANALOG_CONNECTOR = {0xDFF21FE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_SPEAKER = {0xDFF21CE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_CD_PLAYER = {0xDFF220E3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_SYNTHESIZER = {0xDFF220F3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSNODETYPE_LINE_CONNECTOR = {0xDFF21FE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0,0xC9, 0x22, 0x31, 0x96}};
+const GUID PINNAME_VIDEO_CAPTURE = {0xfb6c4281, 0x353, 0x11d1, {0x90, 0x5f, 0x0, 0x0, 0xc0, 0xcc, 0x16, 0xba}};
+
MIXER_STATUS
MMixerAddMixerControl(
IN PMIXER_CONTEXT MixerContext,
IN LPMIXER_INFO MixerInfo,
+ IN HANDLE hMixer,
IN PTOPOLOGY Topology,
IN ULONG NodeIndex,
IN LPMIXERLINE_EXT MixerLine,
- OUT LPMIXERCONTROLW MixerControl)
+ IN ULONG MaxChannels)
{
LPGUID NodeType;
KSP_NODE Node;
ULONG BytesReturned;
MIXER_STATUS Status;
LPWSTR Name;
+ LPMIXERCONTROL_EXT MixerControl;
+
+ /* allocate mixer control */
+ MixerControl = MixerContext->Alloc(sizeof(MIXERCONTROL_EXT));
+ if (!MixerControl)
+ {
+ /* no memory */
+ return MM_STATUS_NO_MEMORY;
+ }
+
/* initialize mixer control */
- MixerControl->cbStruct = sizeof(MIXERCONTROLW);
- MixerControl->dwControlID = MixerInfo->ControlId;
+ MixerControl->hDevice = hMixer;
+ MixerControl->NodeID = NodeIndex;
+ MixerControl->ExtraData = NULL;
+
+ MixerControl->Control.cbStruct = sizeof(MIXERCONTROLW);
+ MixerControl->Control.dwControlID = MixerInfo->ControlId;
/* get node type */
NodeType = MMixerGetNodeTypeFromTopology(Topology, NodeIndex);
/* store control type */
- MixerControl->dwControlType = MMixerGetControlTypeFromTopologyNode(NodeType);
+ MixerControl->Control.dwControlType = MMixerGetControlTypeFromTopologyNode(NodeType);
- MixerControl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM; /* FIXME */
- MixerControl->cMultipleItems = 0; /* FIXME */
-
- if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
- {
- MixerControl->Bounds.dwMinimum = 0;
- MixerControl->Bounds.dwMaximum = 1;
- }
- else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
- {
- MixerControl->Bounds.dwMinimum = 0;
- MixerControl->Bounds.dwMaximum = 0xFFFF;
- MixerControl->Metrics.cSteps = 0xC0; /* FIXME */
- }
+ MixerControl->Control.fdwControl = (MaxChannels > 1 ? 0 : MIXERCONTROL_CONTROLF_UNIFORM);
+ MixerControl->Control.cMultipleItems = 0;
/* setup request to retrieve name */
Node.NodeId = NodeIndex;
Node.Reserved = 0;
/* get node name size */
- Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
+ Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
if (Status == MM_STATUS_MORE_ENTRIES)
{
}
/* get node name */
- Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
+ Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
if (Status == MM_STATUS_SUCCESS)
{
- MixerContext->Copy(MixerControl->szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
- MixerControl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
+ MixerContext->Copy(MixerControl->Control.szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
+ MixerControl->Control.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
- MixerContext->Copy(MixerControl->szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
- MixerControl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
+ MixerContext->Copy(MixerControl->Control.szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
+ MixerControl->Control.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
}
/* free name buffer */
MixerContext->Free(Name);
}
+ /* increment control count */
MixerInfo->ControlId++;
-#if 0
- if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)
+
+ /* insert control */
+ InsertTailList(&MixerLine->ControlsList, &MixerControl->Entry);
+
+ if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)
{
- KSNODEPROPERTY Property;
- ULONG PinId = 2;
+ ULONG NodesCount;
+ PULONG Nodes;
- /* setup the request */
- RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY));
+ /* allocate topology nodes array */
+ Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes);
+
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* out of memory */
+ return STATUS_NO_MEMORY;
+ }
- Property.NodeId = NodeIndex;
- Property.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
- Property.Property.Flags = KSPROPERTY_TYPE_SET;
- Property.Property.Set = KSPROPSETID_Audio;
+ /* get connected node count */
+ MMixerGetNextNodesFromNodeIndex(MixerContext, Topology, NodeIndex, TRUE, &NodesCount, Nodes);
- /* get node volume level info */
- Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY), (PVOID)&PinId, sizeof(ULONG), &BytesReturned);
+ /* TODO */
+ MixerContext->Free(Nodes);
- DPRINT1("Status %x NodeIndex %u PinId %u\n", Status, NodeIndex, PinId);
- //DbgBreakPoint();
- }else
-#endif
- if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
+ /* setup mux bounds */
+ MixerControl->Control.Bounds.dwMinimum = 0;
+ MixerControl->Control.Bounds.dwMaximum = NodesCount - 1;
+ MixerControl->Control.Metrics.dwReserved[0] = NodesCount;
+ MixerControl->Control.cMultipleItems = NodesCount;
+ MixerControl->Control.fdwControl |= MIXERCONTROL_CONTROLF_UNIFORM | MIXERCONTROL_CONTROLF_MULTIPLE;
+ }
+ else if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
+ {
+ MixerControl->Control.Bounds.dwMinimum = 0;
+ MixerControl->Control.Bounds.dwMaximum = 1;
+ }
+ else if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_ONOFF)
+ {
+ /* only needs to set bounds */
+ MixerControl->Control.Bounds.dwMinimum = 0;
+ MixerControl->Control.Bounds.dwMaximum = 1;
+ }
+ else if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
{
KSNODEPROPERTY_AUDIO_CHANNEL Property;
ULONG Length;
PKSPROPERTY_MEMBERSHEADER Members;
PKSPROPERTY_STEPPING_LONG Range;
+ MixerControl->Control.Bounds.dwMinimum = 0;
+ MixerControl->Control.Bounds.dwMaximum = 0xFFFF;
+ MixerControl->Control.Metrics.cSteps = 0xC0; /* FIXME */
+
Length = sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_STEPPING_LONG);
Desc = (PKSPROPERTY_DESCRIPTION)MixerContext->Alloc(Length);
ASSERT(Desc);
Property.NodeProperty.NodeId = NodeIndex;
Property.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
- Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT;
+ Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
Property.NodeProperty.Property.Set = KSPROPSETID_Audio;
/* get node volume level info */
- Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned);
+ Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned);
if (Status == MM_STATUS_SUCCESS)
{
Steps = MaxRange / Range->SteppingDelta + 1;
/* store mixer control info there */
- VolumeData->Header.dwControlID = MixerControl->dwControlID;
+ VolumeData->Header.dwControlID = MixerControl->Control.dwControlID;
VolumeData->SignedMaximum = Range->Bounds.SignedMaximum;
VolumeData->SignedMinimum = Range->Bounds.SignedMinimum;
VolumeData->SteppingDelta = Range->SteppingDelta;
VolumeData->Values[Index] = Value;
Value += Range->SteppingDelta;
}
- InsertTailList(&MixerLine->LineControlsExtraData, &VolumeData->Header.Entry);
+ MixerControl->ExtraData = VolumeData;
}
}
MixerContext->Free(Desc);
}
- DPRINT("Status %x Name %S\n", Status, MixerControl->szName);
+ DPRINT("Status %x Name %S\n", Status, MixerControl->Control.szName);
return MM_STATUS_SUCCESS;
}
/* initialize mixer destination line */
DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
+ DestinationLine->Line.cChannels = 2; /* FIXME */
+ DestinationLine->Line.cConnections = 0;
+ DestinationLine->Line.cControls = 0;
+ DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
+ DestinationLine->Line.dwDestination = MixerInfo->MixCaps.cDestinations;
+ DestinationLine->Line.dwLineID = MixerInfo->MixCaps.cDestinations + DESTINATION_LINE;
DestinationLine->Line.dwSource = MAXULONG;
- DestinationLine->Line.dwLineID = DESTINATION_LINE;
- DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
DestinationLine->Line.dwUser = 0;
- DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
- DestinationLine->Line.cChannels = 2; /* FIXME */
+ DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
+
if (LineName)
{
}
DestinationLine->Line.Target.dwType = (bInputMixer == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
- DestinationLine->Line.Target.dwDeviceID = !bInputMixer;
+ DestinationLine->Line.Target.dwDeviceID = 0; //FIXME
DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
/* initialize extra line */
- InitializeListHead(&DestinationLine->LineControlsExtraData);
+ InitializeListHead(&DestinationLine->ControlsList);
/* insert into mixer info */
- InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry);
+ InsertTailList(&MixerInfo->LineList, &DestinationLine->Entry);
+
+ /* increment destination count */
+ MixerInfo->MixCaps.cDestinations++;
/* done */
return MM_STATUS_SUCCESS;
MMixerGetPinName(
IN PMIXER_CONTEXT MixerContext,
IN LPMIXER_INFO MixerInfo,
+ IN HANDLE hMixer,
IN ULONG PinId,
IN OUT LPWSTR * OutBuffer)
{
Pin.Property.Id = KSPROPERTY_PIN_NAME;
/* try get pin name size */
- Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
+ Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
/* check if buffer overflowed */
if (Status == MM_STATUS_MORE_ENTRIES)
}
/* try get pin name */
- Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Buffer, BytesReturned, &BytesReturned);
+ Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Buffer, BytesReturned, &BytesReturned);
if (Status != MM_STATUS_SUCCESS)
{
/* failed to get pin name */
MMixerBuildMixerDestinationLine(
IN PMIXER_CONTEXT MixerContext,
IN OUT LPMIXER_INFO MixerInfo,
+ IN HANDLE hMixer,
IN ULONG PinId,
IN ULONG bInput)
{
MIXER_STATUS Status;
/* try get pin name */
- Status = MMixerGetPinName(MixerContext, MixerInfo, PinId, &PinName);
+ Status = MMixerGetPinName(MixerContext, MixerInfo, hMixer, PinId, &PinName);
if (Status == MM_STATUS_SUCCESS)
{
/* create mixer destination line */
IN PMIXER_CONTEXT MixerContext,
IN PTOPOLOGY Topology,
IN ULONG PinId,
+ IN ULONG bInputMixer,
IN ULONG bUpStream,
OUT PULONG OutNodesCount,
OUT PULONG OutNodes,
if (bTerminator)
{
/* found terminator */
+ if (bInputMixer)
+ {
+ /* add mux source for source destination line */
+ OutNodes[Count] = NodeIndex;
+ Count++;
+ }
break;
}
return MM_STATUS_SUCCESS;
}
+MIXER_STATUS
+MMixerGetChannelCountEnhanced(
+ IN PMIXER_CONTEXT MixerContext,
+ IN LPMIXER_INFO MixerInfo,
+ IN HANDLE hMixer,
+ IN ULONG NodeId,
+ OUT PULONG MaxChannels)
+{
+ KSPROPERTY_DESCRIPTION Description;
+ PKSPROPERTY_DESCRIPTION NewDescription;
+ PKSPROPERTY_MEMBERSHEADER Header;
+ ULONG BytesReturned;
+ KSP_NODE Request;
+ MIXER_STATUS Status;
+
+ /* try #1 obtain it via description */
+ Request.NodeId = NodeId;
+ Request.Reserved = 0;
+ Request.Property.Set = KSPROPSETID_Audio;
+ Request.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
+ Request.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
+
+
+ /* get description */
+ Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSP_NODE), (PVOID)&Description, sizeof(KSPROPERTY_DESCRIPTION), &BytesReturned);
+ if (Status == MM_STATUS_SUCCESS)
+ {
+ if (Description.DescriptionSize >= sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) && (Description.MembersListCount > 0))
+ {
+ /* allocate new description */
+ NewDescription = MixerContext->Alloc(Description.DescriptionSize);
+
+ if (!NewDescription)
+ {
+ /* not enough memory */
+ return MM_STATUS_NO_MEMORY;
+ }
+
+ /* get description */
+ Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSP_NODE), (PVOID)NewDescription, Description.DescriptionSize, &BytesReturned);
+ if (Status == MM_STATUS_SUCCESS)
+ {
+ /* get header */
+ Header = (PKSPROPERTY_MEMBERSHEADER)(NewDescription + 1);
+
+ if (Header->Flags & KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL)
+ {
+ /* found enhanced flag */
+ ASSERT(Header->MembersCount > 1);
+
+ /* store channel count */
+ *MaxChannels = Header->MembersCount;
+
+ /* free description */
+ MixerContext->Free(NewDescription);
+
+ /* done */
+ return MM_STATUS_SUCCESS;
+ }
+ }
+
+ /* free description */
+ MixerContext->Free(NewDescription);
+ }
+ }
+
+ /* failed to get channel count enhanced */
+ return MM_STATUS_UNSUCCESSFUL;
+}
+
+VOID
+MMixerGetChannelCountLegacy(
+ IN PMIXER_CONTEXT MixerContext,
+ IN LPMIXER_INFO MixerInfo,
+ IN HANDLE hMixer,
+ IN ULONG NodeId,
+ OUT PULONG MaxChannels)
+{
+ ULONG BytesReturned;
+ MIXER_STATUS Status;
+ KSNODEPROPERTY_AUDIO_CHANNEL Channel;
+ LONG Volume;
+
+ /* setup request */
+ Channel.Reserved = 0;
+ Channel.NodeProperty.NodeId = NodeId;
+ Channel.NodeProperty.Reserved = 0;
+ Channel.NodeProperty.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
+ Channel.NodeProperty.Property.Set = KSPROPSETID_Audio;
+ Channel.Channel = 0;
+ Channel.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
+
+ do
+ {
+ /* get channel volume */
+ Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Channel, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), (PVOID)&Volume, sizeof(LONG), &BytesReturned);
+ if (Status != MM_STATUS_SUCCESS)
+ break;
+
+ /* increment channel count */
+ Channel.Channel++;
+
+ }while(TRUE);
+
+ /* store channel count */
+ *MaxChannels = Channel.Channel;
+
+}
+
+VOID
+MMixerGetMaxChannelsForNode(
+ IN PMIXER_CONTEXT MixerContext,
+ IN LPMIXER_INFO MixerInfo,
+ IN HANDLE hMixer,
+ IN ULONG NodeId,
+ OUT PULONG MaxChannels)
+{
+ MIXER_STATUS Status;
+
+ /* try to get it enhanced */
+ Status = MMixerGetChannelCountEnhanced(MixerContext, MixerInfo, hMixer, NodeId, MaxChannels);
+
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* get it old-fashioned way */
+ MMixerGetChannelCountLegacy(MixerContext, MixerInfo, hMixer, NodeId, MaxChannels);
+ }
+}
+
MIXER_STATUS
MMixerAddMixerControlsToMixerLineByNodeIndexArray(
IN PMIXER_CONTEXT MixerContext,
IN LPMIXER_INFO MixerInfo,
+ IN HANDLE hMixer,
IN PTOPOLOGY Topology,
IN OUT LPMIXERLINE_EXT DstLine,
IN ULONG NodesCount,
{
ULONG Index, Count, bReserved;
MIXER_STATUS Status;
-
- /* store nodes array */
- DstLine->NodeIds = Nodes;
-
- /* allocate MIXERCONTROLSW array */
- DstLine->LineControls = MixerContext->Alloc(NodesCount * sizeof(MIXERCONTROLW));
-
- if (!DstLine->LineControls)
- {
- /* out of memory */
- return MM_STATUS_NO_MEMORY;
- }
+ LPGUID NodeType;
+ ULONG MaxChannels;
/* initialize control count */
Count = 0;
{
/* check if the node has already been reserved to a line */
MMixerIsTopologyNodeReserved(Topology, Nodes[Index], &bReserved);
-
+#if 0 /* MS lies */
if (bReserved)
{
/* node is already used, skip it */
continue;
}
-
+#endif
/* set node status as used */
MMixerSetTopologyNodeReserved(Topology, Nodes[Index]);
+ /* query node type */
+ NodeType = MMixerGetNodeTypeFromTopology(Topology, Nodes[Index]);
+
+ if (IsEqualGUIDAligned(NodeType, &KSNODETYPE_VOLUME))
+ {
+ /* calculate maximum channel count for node */
+ MMixerGetMaxChannelsForNode(MixerContext, MixerInfo, hMixer, Nodes[Index], &MaxChannels);
+
+ DPRINT("NodeId %lu MaxChannels %lu Line %S Id %lu\n", Nodes[Index], MaxChannels, DstLine->Line.szName, DstLine->Line.dwLineID);
+ /* calculate maximum channels */
+ DstLine->Line.cChannels = min(DstLine->Line.cChannels, MaxChannels);
+ }
+ else
+ {
+ /* use default of one channel */
+ MaxChannels = 1;
+ }
+
/* now add the mixer control */
- Status = MMixerAddMixerControl(MixerContext, MixerInfo, Topology, Nodes[Index], DstLine, &DstLine->LineControls[Count]);
+ Status = MMixerAddMixerControl(MixerContext, MixerInfo, hMixer, Topology, Nodes[Index], DstLine, MaxChannels);
if (Status == MM_STATUS_SUCCESS)
{
return MM_STATUS_SUCCESS;
}
+MIXER_STATUS
+MMixerGetComponentAndTargetType(
+ IN PMIXER_CONTEXT MixerContext,
+ IN OUT LPMIXER_INFO MixerInfo,
+ IN HANDLE hMixer,
+ IN ULONG PinId,
+ OUT PULONG ComponentType,
+ OUT PULONG TargetType)
+{
+ KSPIN_DATAFLOW DataFlow;
+ KSPIN_COMMUNICATION Communication;
+ MIXER_STATUS Status;
+ KSP_PIN Request;
+ ULONG BytesReturned;
+ GUID Guid;
+ BOOLEAN BridgePin = FALSE;
+ PKSPIN_PHYSICALCONNECTION Connection;
+
+ /* first dataflow type */
+ Status = MMixerGetPinDataFlowAndCommunication(MixerContext, hMixer, PinId, &DataFlow, &Communication);
+
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* failed to get dataflow */
+ return Status;
+ }
+
+ /* now get pin category guid */
+ Request.PinId = PinId;
+ Request.Reserved = 0;
+ Request.Property.Flags = KSPROPERTY_TYPE_GET;
+ Request.Property.Set = KSPROPSETID_Pin;
+ Request.Property.Id = KSPROPERTY_PIN_CATEGORY;
+
+
+ /* get pin category */
+ Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSP_PIN), &Guid, sizeof(GUID), &BytesReturned);
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* failed to get dataflow */
+ return Status;
+ }
+
+ /* check if it has a physical connection */
+ Status = MMixerGetPhysicalConnection(MixerContext, hMixer, PinId, &Connection);
+ if (Status == MM_STATUS_SUCCESS)
+ {
+ /* pin is a brige pin */
+ BridgePin = TRUE;
+
+ /* free physical connection */
+ MixerContext->Free(Connection);
+ }
+
+ if (DataFlow == KSPIN_DATAFLOW_IN)
+ {
+ if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_MICROPHONE) ||
+ IsEqualGUIDAligned(&Guid, &KSNODETYPE_DESKTOP_MICROPHONE))
+ {
+ /* type microphone */
+ *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
+ }
+ else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_LEGACY_AUDIO_CONNECTOR) ||
+ IsEqualGUIDAligned(&Guid, &KSCATEGORY_AUDIO) ||
+ IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPEAKER))
+ {
+ /* type waveout */
+ *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
+ }
+ else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_CD_PLAYER))
+ {
+ /* type cd player */
+ *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
+ }
+ else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SYNTHESIZER))
+ {
+ /* type synthesizer */
+ *TargetType = MIXERLINE_TARGETTYPE_MIDIOUT;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER;
+ }
+ else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_LINE_CONNECTOR))
+ {
+ /* type line */
+ *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_LINE;
+ }
+ else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_TELEPHONE) ||
+ IsEqualGUIDAligned(&Guid, &KSNODETYPE_PHONE_LINE) ||
+ IsEqualGUIDAligned(&Guid, &KSNODETYPE_DOWN_LINE_PHONE))
+ {
+ /* type telephone */
+ *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE;
+ }
+ else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_ANALOG_CONNECTOR))
+ {
+ /* type analog */
+ if (BridgePin)
+ *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
+ else
+ *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
+
+ *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_ANALOG;
+ }
+ else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPDIF_INTERFACE))
+ {
+ /* type analog */
+ if (BridgePin)
+ *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
+ else
+ *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
+
+ *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_DIGITAL;
+ }
+ else
+ {
+ /* unknown type */
+ *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED;
+ DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId, BridgePin);
+ }
+ }
+ else
+ {
+ if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPEAKER) ||
+ IsEqualGUIDAligned(&Guid, &KSNODETYPE_DESKTOP_SPEAKER) ||
+ IsEqualGUIDAligned(&Guid, &KSNODETYPE_ROOM_SPEAKER) ||
+ IsEqualGUIDAligned(&Guid, &KSNODETYPE_COMMUNICATION_SPEAKER))
+ {
+ /* type waveout */
+ *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
+ }
+ else if (IsEqualGUIDAligned(&Guid, &KSCATEGORY_AUDIO) ||
+ IsEqualGUIDAligned(&Guid, &PINNAME_CAPTURE))
+ {
+ /* type wavein */
+ *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
+ }
+ else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_HEADPHONES) ||
+ IsEqualGUIDAligned(&Guid, &KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO))
+ {
+ /* type head phones */
+ *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_DST_HEADPHONES;
+ }
+ else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_TELEPHONE) ||
+ IsEqualGUIDAligned(&Guid, &KSNODETYPE_PHONE_LINE) ||
+ IsEqualGUIDAligned(&Guid, &KSNODETYPE_DOWN_LINE_PHONE))
+ {
+ /* type waveout */
+ *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_DST_TELEPHONE;
+ }
+ else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_ANALOG_CONNECTOR))
+ {
+ /* type analog */
+ if (BridgePin)
+ {
+ *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
+ }
+ else
+ {
+ *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
+ }
+ }
+ else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPDIF_INTERFACE))
+ {
+ /* type spdif */
+ if (BridgePin)
+ {
+ *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
+ }
+ else
+ {
+ *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
+ }
+ }
+ else
+ {
+ /* unknown type */
+ *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
+ *ComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
+ DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId, BridgePin);
+ }
+ }
+
+ /* done */
+ return MM_STATUS_SUCCESS;
+}
+
MIXER_STATUS
MMixerBuildMixerSourceLine(
IN PMIXER_CONTEXT MixerContext,
IN OUT LPMIXER_INFO MixerInfo,
+ IN HANDLE hMixer,
IN PTOPOLOGY Topology,
IN ULONG PinId,
IN ULONG NodesCount,
IN PULONG Nodes,
+ IN ULONG DestinationLineID,
OUT LPMIXERLINE_EXT * OutSrcLine)
{
LPMIXERLINE_EXT SrcLine, DstLine;
LPWSTR PinName;
MIXER_STATUS Status;
+ ULONG ComponentType, TargetType;
+
+ /* get component and target type */
+ Status = MMixerGetComponentAndTargetType(MixerContext, MixerInfo, hMixer, PinId, &ComponentType, &TargetType);
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* failed to get component status */
+ TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
+ ComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
+ }
/* construct source line */
SrcLine = (LPMIXERLINE_EXT)MixerContext->Alloc(sizeof(MIXERLINE_EXT));
}
/* get destination line */
- DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
+ DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
ASSERT(DstLine);
/* initialize mixer src line */
- SrcLine->hDevice = MixerInfo->hMixer;
SrcLine->PinId = PinId;
- SrcLine->NodeIds = Nodes;
/* initialize mixer line */
SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
- SrcLine->Line.dwDestination = 0;
+ SrcLine->Line.dwDestination = MixerInfo->MixCaps.cDestinations-1;
SrcLine->Line.dwSource = DstLine->Line.cConnections;
- SrcLine->Line.dwLineID = (DstLine->Line.cConnections * 0x10000);
+ SrcLine->Line.dwLineID = (DstLine->Line.cConnections * SOURCE_LINE)+ (MixerInfo->MixCaps.cDestinations-1);
SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
+ SrcLine->Line.dwComponentType = ComponentType;
SrcLine->Line.dwUser = 0;
SrcLine->Line.cChannels = DstLine->Line.cChannels;
SrcLine->Line.cConnections = 0;
- SrcLine->Line.Target.dwType = 1;
+ SrcLine->Line.Target.dwType = TargetType;
SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
- InitializeListHead(&SrcLine->LineControlsExtraData);
+ InitializeListHead(&SrcLine->ControlsList);
/* copy name */
ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == L'\0');
wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
/* get pin name */
- Status = MMixerGetPinName(MixerContext, MixerInfo, PinId, &PinName);
+ Status = MMixerGetPinName(MixerContext, MixerInfo, hMixer, PinId, &PinName);
if (Status == MM_STATUS_SUCCESS)
{
}
/* add the controls to mixer line */
- Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, Topology, SrcLine, NodesCount, Nodes);
+ Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, hMixer, Topology, SrcLine, NodesCount, Nodes);
if (Status != MM_STATUS_SUCCESS)
{
/* failed */
MMixerAddMixerSourceLines(
IN PMIXER_CONTEXT MixerContext,
IN OUT LPMIXER_INFO MixerInfo,
+ IN HANDLE hMixer,
IN PTOPOLOGY Topology,
+ IN ULONG DestinationLineID,
IN ULONG LineTerminator)
{
PULONG AllNodes, AllPins, AllPinNodes;
LPMIXERLINE_EXT DstLine, SrcLine;
/* get destination line */
- DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
+ DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
ASSERT(DstLine);
/* allocate an array to store all nodes which are upstream of the line terminator */
if (AllPinNodesCount)
{
+#ifdef MMIXER_DEBUG
+ ULONG TempIndex;
+#endif
/* now build the mixer source line */
- Status = MMixerBuildMixerSourceLine(MixerContext, MixerInfo, Topology, PinId, AllPinNodesCount, AllPinNodes, &SrcLine);
+ Status = MMixerBuildMixerSourceLine(MixerContext, MixerInfo, hMixer, Topology, PinId, AllPinNodesCount, AllPinNodes, DestinationLineID, &SrcLine);
if (Status == MM_STATUS_SUCCESS)
{
/* increment destination line count */
DstLine->Line.cConnections++;
+
+ /* mark pin as reserved */
+ MMixerSetTopologyPinReserved(Topology, PinId);
+
+#ifdef MMIXER_DEBUG
+ DPRINT1("Adding PinId %lu AllPinNodesCount %lu to DestinationLine %lu\n", PinId, AllPinNodesCount, DestinationLineID);
+ for(TempIndex = 0; TempIndex < AllPinNodesCount; TempIndex++)
+ DPRINT1("NodeIndex %lu\n", AllPinNodes[TempIndex]);
+#endif
}
}
+ else
+ {
+#ifdef MMIXER_DEBUG
+ DPRINT1("Discarding DestinationLineID %lu PinId %lu NO NODES!\n", DestinationLineID, PinId);
+#endif
+ }
}while(Index != 0);
MMixerAddMixerControlsToDestinationLine(
IN PMIXER_CONTEXT MixerContext,
IN OUT LPMIXER_INFO MixerInfo,
+ IN HANDLE hMixer,
IN PTOPOLOGY Topology,
IN ULONG PinId,
IN ULONG bInput,
+ IN ULONG DestinationLineId,
OUT PULONG OutLineTerminator)
{
PULONG Nodes;
}
/* get all destination line controls */
- Status = MMixerCountMixerControls(MixerContext, Topology, PinId, TRUE, &NodesCount, Nodes, &LineTerminator);
+ Status = MMixerCountMixerControls(MixerContext, Topology, PinId, bInput, TRUE, &NodesCount, Nodes, &LineTerminator);
/* check for success */
if (Status != MM_STATUS_SUCCESS)
}
/* get destination mixer line */
- DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
+ DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineId);
/* sanity check */
ASSERT(DstLine);
if (NodesCount > 0)
{
/* add all nodes as mixer controls to the destination line */
- Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, Topology, DstLine, NodesCount, Nodes);
+ Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, hMixer, Topology, DstLine, NodesCount, Nodes);
if (Status != MM_STATUS_SUCCESS)
{
/* failed to add controls */
MMixerApplyOutputFilterHack(
IN PMIXER_CONTEXT MixerContext,
IN LPMIXER_DATA MixerData,
+ IN HANDLE hMixer,
IN OUT PULONG PinsCount,
IN OUT PULONG Pins)
{
for(Index = 0; Index < *PinsCount; Index++)
{
/* check if it has a physical connection */
- Status = MMixerGetPhysicalConnection(MixerContext, MixerData->hDevice, Pins[Index], &Connection);
+ Status = MMixerGetPhysicalConnection(MixerContext, hMixer, Pins[Index], &Connection);
if (Status == MM_STATUS_SUCCESS)
{
IN PKSPIN_PHYSICALCONNECTION OutConnection)
{
MIXER_STATUS Status;
- ULONG PinsCount, LineTerminator;
+ ULONG PinsCount, LineTerminator, DestinationLineID;
PULONG Pins;
PTOPOLOGY Topology;
DPRINT("Name %S, Pin %lu bInput %lu\n", OutConnection->SymbolicLinkName, OutConnection->Pin, bInput);
- /* store connected mixer handle */
- MixerInfo->hMixer = MixerData->hDevice;
+ /* sanity check */
+ ASSERT(MixerData->MixerInfo == NULL || MixerData->MixerInfo == MixerInfo);
+ /* associate with mixer */
+ MixerData->MixerInfo = MixerInfo;
- Status = MMixerBuildTopology(MixerContext, MixerData, &Topology);
- if (Status != MM_STATUS_SUCCESS)
+ if (MixerData->Topology == NULL)
{
- /* failed to create topology */
- return Status;
+ /* construct new topology */
+ Status = MMixerBuildTopology(MixerContext, MixerData, &Topology);
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* failed to create topology */
+ return Status;
+ }
+
+ /* store topology */
+ MixerData->Topology = Topology;
+ }
+ else
+ {
+ /* re-use existing topology */
+ Topology = MixerData->Topology;
}
- /* allocate pin index array which will hold all referenced pins */
- Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
- ASSERT(Status == MM_STATUS_SUCCESS);
+ /* mark pin as consumed */
+ MMixerSetTopologyPinReserved(Topology, OutConnection->Pin);
if (!bInput)
{
+ /* allocate pin index array which will hold all referenced pins */
+ Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* failed to create topology */
+ return Status;
+ }
+
/* the mixer is an output mixer
* find end pin of the node path
*/
* WorkArround: remove all pin ids which have a physical connection
* because bridge pins may belong to different render paths
*/
- MMixerApplyOutputFilterHack(MixerContext, MixerData, &PinsCount, Pins);
+ MMixerApplyOutputFilterHack(MixerContext, MixerData, MixerData->hDevice, &PinsCount, Pins);
/* sanity checks */
ASSERT(PinsCount != 0);
ASSERT(PinsCount == 1);
/* create destination line */
- Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, Pins[0], bInput);
+ Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Pins[0], bInput);
+
+ /* calculate destination line id */
+ DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations-1);
if (Status != MM_STATUS_SUCCESS)
{
+ /* failed to build destination line */
MixerContext->Free(Pins);
- //MMixerFreeTopology(Topology);
/* return error code */
return Status;
}
/* add mixer controls to destination line */
- Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, Topology, Pins[0], bInput, &LineTerminator);
+ Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Topology, Pins[0], bInput, DestinationLineID, &LineTerminator);
if (Status == MM_STATUS_SUCCESS)
{
/* now add the rest of the source lines */
- Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, Topology, LineTerminator);
+ Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, Topology, DestinationLineID, LineTerminator);
}
+
+ /* mark pin as consumed */
+ MMixerSetTopologyPinReserved(Topology, Pins[0]);
+
+ /* free topology pin array */
+ MixerContext->Free(Pins);
}
else
{
- Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, Topology, OutConnection->Pin, bInput, &LineTerminator);
+ /* calculate destination line id */
+ DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations-1);
+
+ /* add mixer controls */
+ Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Topology, OutConnection->Pin, bInput, DestinationLineID, &LineTerminator);
if (Status == MM_STATUS_SUCCESS)
{
/* now add the rest of the source lines */
- Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, Topology, LineTerminator);
+ Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, Topology, DestinationLineID, LineTerminator);
}
}
- /* free topology */
- //MMixerFreeTopology(Topology);
-
return Status;
}
-
MIXER_STATUS
MMixerInitializeFilter(
IN PMIXER_CONTEXT MixerContext,
IN PMIXER_LIST MixerList,
IN LPMIXER_DATA MixerData,
+ IN LPMIXER_INFO MixerInfo,
IN PTOPOLOGY Topology,
IN ULONG NodeIndex,
- IN ULONG bInputMixer)
+ IN ULONG bInputMixer,
+ IN OUT LPMIXER_INFO * OutMixerInfo)
{
- LPMIXER_INFO MixerInfo;
+ ULONG Index;
MIXER_STATUS Status;
PKSPIN_PHYSICALCONNECTION OutConnection;
ULONG * Pins;
ULONG PinsFound;
+ ULONG NewMixerInfo = FALSE;
- /* allocate a mixer info struct */
- MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
- if (!MixerInfo)
+ if (MixerInfo == NULL)
{
- /* no memory */
- return MM_STATUS_NO_MEMORY;
- }
+ /* allocate a mixer info struct */
+ MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
+ if (!MixerInfo)
+ {
+ /* no memory */
+ return MM_STATUS_NO_MEMORY;
+ }
- /* intialize mixer caps */
- MixerInfo->MixCaps.wMid = MM_MICROSOFT; /* FIXME */
- MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; /* FIXME */
- MixerInfo->MixCaps.vDriverVersion = 1; /* FIXME */
- MixerInfo->MixCaps.fdwSupport = 0;
- MixerInfo->MixCaps.cDestinations = 1;
- MixerInfo->hMixer = MixerData->hDevice;
+ /* new mixer info */
+ NewMixerInfo = TRUE;
- /* get mixer name */
- MMixerGetDeviceName(MixerContext, MixerInfo->MixCaps.szPname, MixerData->hDeviceInterfaceKey);
+ /* intialize mixer caps */
+ MixerInfo->MixCaps.wMid = MM_MICROSOFT; /* FIXME */
+ MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; /* FIXME */
+ MixerInfo->MixCaps.vDriverVersion = 1; /* FIXME */
+ MixerInfo->MixCaps.fdwSupport = 0;
+ MixerInfo->MixCaps.cDestinations = 0;
- /* initialize line list */
- InitializeListHead(&MixerInfo->LineList);
- InitializeListHead(&MixerInfo->EventList);
+ /* get mixer name */
+ MMixerGetDeviceName(MixerContext, MixerInfo->MixCaps.szPname, MixerData->hDeviceInterfaceKey);
+
+ /* initialize line list */
+ InitializeListHead(&MixerInfo->LineList);
+ InitializeListHead(&MixerInfo->EventList);
+
+ /* associate with mixer data */
+ MixerData->MixerInfo = MixerInfo;
+ }
+
+ /* store mixer info */
+ *OutMixerInfo = MixerInfo;
/* now allocate an array which will receive the indices of the pin
* which has a ADC / DAC nodetype in its path
PinsFound = 0;
MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, !bInputMixer, &PinsFound, Pins);
- /* if there is now pin found, we have a broken topology */
+ /* if there is no pin found, we have a broken topology */
ASSERT(PinsFound != 0);
/* now create a wave info struct */
return Status;
}
+ /* mark all found pins as reserved */
+ for(Index = 0; Index < PinsFound; Index++)
+ {
+ MMixerSetTopologyPinReserved(Topology, Pins[Index]);
+ }
+
if (bInputMixer)
{
/* pre create the mixer destination line for input mixers */
- Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, Pins[0], bInputMixer);
+ Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Pins[0], bInputMixer);
if (Status != MM_STATUS_SUCCESS)
{
if (Status == MM_STATUS_SUCCESS)
{
+ /* mark pin as reserved */
+ MMixerSetTopologyPinReserved(Topology, Pins[0]);
+
/* topology on the topoloy filter */
Status = MMixerHandlePhysicalConnection(MixerContext, MixerList, MixerData, MixerInfo, bInputMixer, OutConnection);
/* free pins */
MixerContext->Free(Pins);
- if (!bInputMixer && MixerList->MixerListCount == 1)
+ if (NewMixerInfo)
{
- /* FIXME preferred device should be inserted at front
- * windows always inserts output mixer in front
- */
+ /* insert mixer */
InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry);
- }
- else
- {
- /* insert at back */
- InsertTailList(&MixerList->MixerList, &MixerInfo->Entry);
+ /* increment mixer count */
+ MixerList->MixerListCount++;
}
- /* increment mixer count */
- MixerList->MixerListCount++;
-
/* done */
return Status;
}
+VOID
+MMixerHandleAlternativeMixers(
+ IN PMIXER_CONTEXT MixerContext,
+ IN PMIXER_LIST MixerList,
+ IN LPMIXER_DATA MixerData,
+ IN PTOPOLOGY Topology)
+{
+ ULONG Index, PinCount, Reserved;
+ MIXER_STATUS Status;
+ ULONG DestinationLineID, LineTerminator;
+ LPMIXERLINE_EXT DstLine;
+
+ DPRINT("DeviceName %S\n", MixerData->DeviceName);
+
+ /* get topology pin count */
+ MMixerGetTopologyPinCount(Topology, &PinCount);
+
+ for(Index = 0; Index < PinCount; Index++)
+ {
+ MMixerIsTopologyPinReserved(Topology, Index, &Reserved);
+
+ /* check if it has already been reserved */
+ if (Reserved == TRUE)
+ {
+ /* pin has already been reserved */
+ continue;
+ }
+
+ DPRINT("MixerName %S Available PinID %lu\n", MixerData->DeviceName, Index);
+
+ /* sanity check */
+ //ASSERT(MixerData->MixerInfo);
+
+ if (!MixerData->MixerInfo)
+ {
+ DPRINT1("Expected mixer info\n");
+ continue;
+ }
+
+ /* build the destination line */
+ Status = MMixerBuildMixerDestinationLine(MixerContext, MixerData->MixerInfo, MixerData->hDevice, Index, TRUE);
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* failed to build destination line */
+ continue;
+ }
+
+ /* calculate destination line id */
+ DestinationLineID = (DESTINATION_LINE + MixerData->MixerInfo->MixCaps.cDestinations-1);
+
+ /* add mixer controls to destination line */
+ Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerData->MixerInfo, MixerData->hDevice, MixerData->Topology, Index, TRUE, DestinationLineID, &LineTerminator);
+ if (Status == MM_STATUS_SUCCESS)
+ {
+ /* now add the rest of the source lines */
+ Status = MMixerAddMixerSourceLines(MixerContext, MixerData->MixerInfo, MixerData->hDevice, MixerData->Topology, DestinationLineID, LineTerminator);
+ }
+
+ /* mark pin as consumed */
+ MMixerSetTopologyPinReserved(Topology, Index);
+
+ /* now grab destination line */
+ DstLine = MMixerGetSourceMixerLineByLineId(MixerData->MixerInfo, DestinationLineID);
+
+ /* set type and target as undefined */
+ DstLine->Line.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
+ DstLine->Line.Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
+ DstLine->Line.Target.vDriverVersion = 0;
+ DstLine->Line.Target.wMid = 0;
+ DstLine->Line.Target.wPid = 0;
+ }
+}
+
MIXER_STATUS
MMixerSetupFilter(
IN PMIXER_CONTEXT MixerContext,
MIXER_STATUS Status;
PTOPOLOGY Topology;
ULONG NodeIndex;
+ LPMIXER_INFO MixerInfo = NULL;
/* check if topology has already been built */
if (MixerData->Topology == NULL)
if (NodeIndex != MAXULONG)
{
/* it has */
- Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, Topology, NodeIndex, FALSE);
+ Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, NULL, Topology, NodeIndex, FALSE, &MixerInfo);
/* check for success */
if (Status == MM_STATUS_SUCCESS)
/* increment mixer count */
(*DeviceCount)++;
}
-
+ else
+ {
+ /* reset mixer info in case of error */
+ MixerInfo = NULL;
+ }
}
/* check if the filter has an wave in node */
if (NodeIndex != MAXULONG)
{
/* it has */
- Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, Topology, NodeIndex, TRUE);
+ Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, MixerInfo, Topology, NodeIndex, TRUE, &MixerInfo);
/* check for success */
if (Status == MM_STATUS_SUCCESS)
}
+ /* TODO: apply hacks for Wave source line */
+
/* activate midi devices */
- MMixerInitializeMidiForFilter(MixerContext, MixerList, MixerData, Topology);
+ //MMixerInitializeMidiForFilter(MixerContext, MixerList, MixerData, Topology);
/* done */
return Status;
/* initialize notification entry */
EventData->MixerEventContext = MixerEventContext;
- EventData->MixerEventRoutine;
+ EventData->MixerEventRoutine = MixerEventRoutine;
/* store event */
InsertTailList(&MixerInfo->EventList, &EventData->Entry);
MIXER_STATUS
MMixerGetPinDataFlowAndCommunication(
IN PMIXER_CONTEXT MixerContext,
- IN LPMIXER_DATA MixerData,
+ IN HANDLE hDevice,
IN ULONG PinId,
OUT PKSPIN_DATAFLOW DataFlow,
OUT PKSPIN_COMMUNICATION Communication)
Pin.Property.Set = KSPROPSETID_Pin;
/* get pin dataflow */
- Status = MixerContext->Control(MixerData->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
+ Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
if (Status != MM_STATUS_SUCCESS)
{
/* failed to retrieve dataflow */
Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
/* get pin communication */
- Status = MixerContext->Control(MixerData->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
+ Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
return Status;
}
IsEqualGUIDAligned(&DataRange->Specifier, &KSDATAFORMAT_SPECIFIER_NONE))
{
/* pin supports midi datarange */
- if (MMixerGetPinDataFlowAndCommunication(MixerContext, MixerData, PinId, &DataFlow, &Communication) == MM_STATUS_SUCCESS)
+ if (MMixerGetPinDataFlowAndCommunication(MixerContext, MixerData->hDevice, PinId, &DataFlow, &Communication) == MM_STATUS_SUCCESS)
{
if (DataFlow == KSPIN_DATAFLOW_IN && Communication == KSPIN_COMMUNICATION_SINK)
{
if (Status != MM_STATUS_SUCCESS)
{
/* invalid context passed */
+ DPRINT1("invalid context\n");
return Status;
}
if (!MixerInfo)
{
/* invalid mixer id */
+ DPRINT1("invalid mixer id %lu\n", MixerId);
return MM_STATUS_INVALID_PARAMETER;
}
/* store result */
*MixerHandle = (HANDLE)MixerInfo;
-
return MM_STATUS_SUCCESS;
}
MIXER_STATUS
MMixerGetLineInfo(
IN PMIXER_CONTEXT MixerContext,
- IN HANDLE MixerHandle,
- IN ULONG Flags,
+ 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);
/* 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;
- if (MixerLine->dwDestination != 0)
+ /* calculate destination line id */
+ DestinationLineID = (MixerLine->dwDestination + DESTINATION_LINE);
+
+ /* get destination line */
+ MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
+
+ if (MixerLineSrc == NULL)
{
- /* destination line member must be zero */
- return MM_STATUS_INVALID_PARAMETER;
+ DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination);
+ return MM_STATUS_UNSUCCESSFUL;
}
-
- MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
- ASSERT(MixerLineSrc);
+ /* 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);
- MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
- ASSERT(MixerLineSrc);
+ /* get destination line */
+ MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
- if (MixerLine->dwSource >= MixerLineSrc->Line.cConnections)
+ if (MixerLineSrc == NULL)
{
- DPRINT("dwSource %u > Destinations %u\n", MixerLine->dwSource, MixerLineSrc->Line.cConnections);
-
- /* invalid parameter */
- return MM_STATUS_INVALID_PARAMETER;
+ DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination);
+ return MM_STATUS_UNSUCCESSFUL;
}
- MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLine->dwSource * 0x10000);
- if (MixerLineSrc)
+ /* check if dwSource is out of bounds */
+ if (MixerLine->dwSource >= MixerLineSrc->Line.cConnections)
{
- DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
- MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
- return MM_STATUS_SUCCESS;
+ 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;
}
- 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;
}
- /* copy cached data */
+ 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)
{
return MM_STATUS_UNSUCCESSFUL;
}
- ASSERT(MixerLineSrc);
-
- /* copy cached data */
+ /* 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;
}
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;
+ LPMIXERCONTROL_EXT MixerControl;
MIXER_STATUS Status;
+ PLIST_ENTRY Entry;
ULONG Index;
/* verify mixer context */
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->cbStruct, sizeof(MIXERLINECONTROLSW));
+ /* 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) */
- MixerContext->Copy(MixerLineControls->pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, MixerLineControls->cControls) * sizeof(MIXERCONTROLW));
+ 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;
}
- ASSERT(MixerLineSrc);
+ /* sanity checks */
+ ASSERT(MixerLineControls->cControls == 1);
+ ASSERT(MixerLineControls->cbmxctrl == sizeof(MIXERCONTROLW));
+ ASSERT(MixerLineControls->pamxctrl != NULL);
- Index = 0;
- for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
+ Entry = MixerLineSrc->ControlsList.Flink;
+ while(Entry != &MixerLineSrc->ControlsList)
{
- DPRINT("dwControlType %x\n", MixerLineSrc->LineControls[Index].dwControlType);
- if (MixerLineControls->dwControlType == MixerLineSrc->LineControls[Index].dwControlType)
+ 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, &MixerLineSrc->LineControls[Index], sizeof(MIXERCONTROLW));
+ MixerContext->Copy(MixerLineControls->pamxctrl, &MixerControl->Control, 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;
+
+ /* 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)
{
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, sizeof(MIXERCONTROLW));
+ 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;
}
MMixerSetControlDetails(
IN PMIXER_CONTEXT MixerContext,
IN HANDLE MixerHandle,
+ IN ULONG MixerId,
IN ULONG Flags,
OUT LPMIXERCONTROLDETAILS MixerControlDetails)
{
ULONG NodeId;
LPMIXER_INFO MixerInfo;
LPMIXERLINE_EXT MixerLine;
- LPMIXERCONTROLW MixerControl;
+ 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;
if (Status != MM_STATUS_SUCCESS)
{
/* failed to find control id */
+ DPRINT1("invalid control id %lu\n", MixerControlDetails->dwControlID);
return MM_STATUS_INVALID_PARAMETER;
}
- switch(MixerControl->dwControlType)
+ 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->hMixer, NodeId, MixerLine->Line.dwLineID, MixerControlDetails, TRUE);
+ Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo, MixerControl, MixerLine->Line.dwLineID, MixerControlDetails, TRUE);
break;
case MIXERCONTROL_CONTROLTYPE_VOLUME:
- Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo->hMixer, NodeId, TRUE, MixerControl, MixerControlDetails, MixerLine);
+ 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;
MMixerGetControlDetails(
IN PMIXER_CONTEXT MixerContext,
IN HANDLE MixerHandle,
+ IN ULONG MixerId,
IN ULONG Flags,
OUT LPMIXERCONTROLDETAILS MixerControlDetails)
{
ULONG NodeId;
LPMIXER_INFO MixerInfo;
LPMIXERLINE_EXT MixerLine;
- LPMIXERCONTROLW MixerControl;
+ LPMIXERCONTROL_EXT MixerControl;
/* verify mixer context */
Status = MMixerVerifyContext(MixerContext);
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;
return MM_STATUS_INVALID_PARAMETER;
}
- switch(MixerControl->dwControlType)
+ switch(MixerControl->Control.dwControlType)
{
case MIXERCONTROL_CONTROLTYPE_MUTE:
- Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo, NodeId, MixerLine->Line.dwLineID, MixerControlDetails, FALSE);
+ 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,
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;
}
typedef MIXER_STATUS(*PMIXER_CLOSEKEY)(
IN HANDLE hKey);
-typedef VOID (*PMIXER_EVENT)(
+typedef VOID (CALLBACK *PMIXER_EVENT)(
IN PVOID MixerEventContext,
IN HANDLE hMixer,
IN ULONG NotificationType,
MIXER_STATUS
MMixerGetLineInfo(
IN PMIXER_CONTEXT MixerContext,
- IN HANDLE MixerHandle,
+ IN HANDLE MixerHandle,
+ IN ULONG MixerId,
IN ULONG Flags,
OUT LPMIXERLINEW MixerLine);
MMixerGetLineControls(
IN PMIXER_CONTEXT MixerContext,
IN HANDLE MixerHandle,
+ IN ULONG MixerId,
IN ULONG Flags,
OUT LPMIXERLINECONTROLSW MixerLineControls);
MMixerSetControlDetails(
IN PMIXER_CONTEXT MixerContext,
IN HANDLE MixerHandle,
+ IN ULONG MixerId,
IN ULONG Flags,
OUT LPMIXERCONTROLDETAILS MixerControlDetails);
MMixerGetControlDetails(
IN PMIXER_CONTEXT MixerContext,
IN HANDLE MixerHandle,
+ IN ULONG MixerId,
IN ULONG Flags,
OUT LPMIXERCONTROLDETAILS MixerControlDetails);
IN HANDLE PinHandle,
IN KSSTATE State);
+MIXER_STATUS
+MMixerSetWaveResetState(
+ IN PMIXER_CONTEXT MixerContext,
+ IN HANDLE PinHandle,
+ IN ULONG bBegin);
+
MIXER_STATUS
MMixerGetWaveDevicePath(
IN PMIXER_CONTEXT MixerContext,
ULONG NodeConnectedFromCount;
struct __TOPOLOGY_NODE__ ** NodeConnectedFrom;
+ PULONG LogicalPinNodeConnectedFrom;
ULONG PinConnectedFromCount;
PULONG PinConnectedFrom;
PULONG PinConnectedTo;
ULONG Visited;
+ ULONG Reserved;
}PIN, *PPIN;
{
LIST_ENTRY Entry;
MIXERCAPSW MixCaps;
- HANDLE hMixer;
LIST_ENTRY LineList;
ULONG ControlId;
LIST_ENTRY EventList;
typedef struct
{
LIST_ENTRY Entry;
- ULONG PinId;
+ MIXERCONTROLW Control;
+ ULONG NodeID;
HANDLE hDevice;
+ PVOID ExtraData;
+}MIXERCONTROL_EXT, *LPMIXERCONTROL_EXT;
+
+typedef struct
+{
+ LIST_ENTRY Entry;
+ ULONG PinId;
MIXERLINEW Line;
- LPMIXERCONTROLW LineControls;
- PULONG NodeIds;
- LIST_ENTRY LineControlsExtraData;
+ LIST_ENTRY ControlsList;
+
}MIXERLINE_EXT, *LPMIXERLINE_EXT;
typedef struct
HANDLE hDeviceInterfaceKey;
LPWSTR DeviceName;
PTOPOLOGY Topology;
+ LPMIXER_INFO MixerInfo;
}MIXER_DATA, *LPMIXER_DATA;
typedef struct
}EVENT_NOTIFICATION_ENTRY, *PEVENT_NOTIFICATION_ENTRY;
-#define DESTINATION_LINE 0xFFFF0000
-
+#define DESTINATION_LINE (0xFFFF0000)
+#define SOURCE_LINE (0x10000)
ULONG
MMixerGetFilterPinCount(
IN PMIXER_CONTEXT MixerContext,
LPMIXER_INFO MixerInfo,
DWORD dwControlID,
LPMIXERLINE_EXT *MixerLine,
- LPMIXERCONTROLW *MixerControl,
+ LPMIXERCONTROL_EXT *MixerControl,
PULONG NodeId);
MIXER_STATUS
MMixerSetGetMuteControlDetails(
IN PMIXER_CONTEXT MixerContext,
IN LPMIXER_INFO MixerInfo,
- IN ULONG NodeId,
+ IN LPMIXERCONTROL_EXT MixerControl,
IN ULONG dwLineID,
IN LPMIXERCONTROLDETAILS MixerControlDetails,
IN ULONG bSet);
IN LPMIXER_INFO MixerInfo,
IN ULONG NodeId,
IN ULONG bSet,
- LPMIXERCONTROLW MixerControl,
+ LPMIXERCONTROL_EXT MixerControl,
IN LPMIXERCONTROLDETAILS MixerControlDetails,
LPMIXERLINE_EXT MixerLine);
+MIXER_STATUS
+MMixerSetGetMuxControlDetails(
+ IN PMIXER_CONTEXT MixerContext,
+ IN LPMIXER_INFO MixerInfo,
+ IN ULONG NodeId,
+ IN ULONG bSet,
+ IN ULONG Flags,
+ LPMIXERCONTROL_EXT MixerControl,
+ IN LPMIXERCONTROLDETAILS MixerControlDetails,
+ LPMIXERLINE_EXT MixerLine);
+
+
MIXER_STATUS
MMixerSetGetControlDetails(
IN PMIXER_CONTEXT MixerContext,
IN OUT PKSPIN_CONNECT PinConnect,
IN ULONG PinId);
+MIXER_STATUS
+MMixerGetPinDataFlowAndCommunication(
+ IN PMIXER_CONTEXT MixerContext,
+ IN HANDLE hDevice,
+ IN ULONG PinId,
+ OUT PKSPIN_DATAFLOW DataFlow,
+ OUT PKSPIN_COMMUNICATION Communication);
+
+VOID
+MMixerHandleAlternativeMixers(
+ IN PMIXER_CONTEXT MixerContext,
+ IN PMIXER_LIST MixerList,
+ IN LPMIXER_DATA MixerData,
+ IN PTOPOLOGY Topology);
+
+MIXER_STATUS
+MMixerGetMixerByName(
+ IN PMIXER_LIST MixerList,
+ IN LPWSTR MixerName,
+ OUT LPMIXER_INFO *MixerInfo);
/* topology.c */
IN ULONG NodeIndex,
OUT PULONG bReserved);
+VOID
+MMixerSetTopologyPinReserved(
+ IN PTOPOLOGY Topology,
+ IN ULONG PinId);
+
+VOID
+MMixerIsTopologyPinReserved(
+ IN PTOPOLOGY Topology,
+ IN ULONG PinId,
+ OUT PULONG bReserved);
+
VOID
MMixerGetTopologyPinCount(
IN PTOPOLOGY Topology,
OUT PULONG PinCount);
+VOID
+MMixerGetConnectedFromLogicalTopologyPins(
+ IN PTOPOLOGY Topology,
+ IN ULONG NodeIndex,
+ OUT PULONG OutPinCount,
+ OUT PULONG OutPins);
return MM_STATUS_SUCCESS;
}
+LPMIXERLINE_EXT
+MMixerGetMixerLineContainingNodeId(
+ IN LPMIXER_INFO MixerInfo,
+ IN ULONG NodeID)
+{
+ PLIST_ENTRY Entry, ControlEntry;
+ LPMIXERLINE_EXT MixerLineSrc;
+ LPMIXERCONTROL_EXT MixerControl;
+
+ /* get first entry */
+ Entry = MixerInfo->LineList.Flink;
+
+ while(Entry != &MixerInfo->LineList)
+ {
+ MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
+
+ ControlEntry = MixerLineSrc->ControlsList.Flink;
+ while(ControlEntry != &MixerLineSrc->ControlsList)
+ {
+ MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(ControlEntry, MIXERCONTROL_EXT, Entry);
+ if (MixerControl->NodeID == NodeID)
+ {
+ return MixerLineSrc;
+ }
+ ControlEntry = ControlEntry->Flink;
+ }
+ Entry = Entry->Flink;
+ }
+
+ return NULL;
+}
+
+VOID
+MMixerGetLowestLogicalTopologyPinOffsetFromArray(
+ IN ULONG LogicalPinArrayCount,
+ IN PULONG LogicalPinArray,
+ OUT PULONG PinOffset)
+{
+ ULONG Index;
+ ULONG LowestId = 0;
+
+ for(Index = 1; Index < LogicalPinArrayCount; Index++)
+ {
+ if (LogicalPinArray[Index] != MAXULONG)
+ {
+ /* sanity check: logical pin id must be unique */
+ ASSERT(LogicalPinArray[Index] != LogicalPinArray[LowestId]);
+ }
+
+ if (LogicalPinArray[Index] < LogicalPinArray[LowestId])
+ LowestId = Index;
+ }
+
+ /* store result */
+ *PinOffset = LowestId;
+}
+
VOID
MMixerFreeMixerInfo(
IN PMIXER_CONTEXT MixerContext,
MixerContext->Free((PVOID)MixerInfo);
}
+
+LPMIXER_DATA
+MMixerGetMixerDataByDeviceHandle(
+ IN PMIXER_CONTEXT MixerContext,
+ IN HANDLE hDevice)
+{
+ LPMIXER_DATA MixerData;
+ PLIST_ENTRY Entry;
+ PMIXER_LIST MixerList;
+
+ /* get mixer list */
+ MixerList = (PMIXER_LIST)MixerContext->MixerContext;
+
+ if (!MixerList->MixerDataCount)
+ return NULL;
+
+ Entry = MixerList->MixerData.Flink;
+
+ while(Entry != &MixerList->MixerData)
+ {
+ MixerData = (LPMIXER_DATA)CONTAINING_RECORD(Entry, MIXER_DATA, Entry);
+
+ if (MixerData->hDevice == hDevice)
+ return MixerData;
+
+ /* move to next mixer entry */
+ Entry = Entry->Flink;
+ }
+ return NULL;
+}
+
+
LPMIXER_INFO
MMixerGetMixerInfoByIndex(
IN PMIXER_CONTEXT MixerContext,
return NULL;
}
-LPMIXERCONTROL_DATA
-MMixerGetMixerControlDataById(
- PLIST_ENTRY ListHead,
- DWORD dwControlId)
+MIXER_STATUS
+MMixerGetMixerByName(
+ IN PMIXER_LIST MixerList,
+ IN LPWSTR MixerName,
+ OUT LPMIXER_INFO *OutMixerInfo)
{
+ LPMIXER_INFO MixerInfo;
PLIST_ENTRY Entry;
- LPMIXERCONTROL_DATA Control;
-
- /* get first entry */
- Entry = ListHead->Flink;
- while(Entry != ListHead)
+ Entry = MixerList->MixerList.Flink;
+ while(Entry != &MixerList->MixerList)
{
- Control = (LPMIXERCONTROL_DATA)CONTAINING_RECORD(Entry, MIXERCONTROL_DATA, Entry);
- DPRINT("dwSource %x dwSource %x\n", Control->dwControlID, dwControlId);
- if (Control->dwControlID == dwControlId)
- return Control;
+ MixerInfo = (LPMIXER_INFO)CONTAINING_RECORD(Entry, MIXER_INFO, Entry);
+ DPRINT1("MixerName %S MixerName %S\n", MixerInfo->MixCaps.szPname, MixerName);
+ if (wcsicmp(MixerInfo->MixCaps.szPname, MixerName) == 0)
+ {
+ *OutMixerInfo = MixerInfo;
+ return MM_STATUS_SUCCESS;
+ }
+ /* move to next mixer entry */
Entry = Entry->Flink;
}
- return NULL;
+
+ return MM_STATUS_UNSUCCESSFUL;
}
LPMIXERLINE_EXT
MMixerGetMixerControlById(
LPMIXER_INFO MixerInfo,
DWORD dwControlID,
- LPMIXERLINE_EXT *MixerLine,
- LPMIXERCONTROLW *MixerControl,
+ LPMIXERLINE_EXT *OutMixerLine,
+ LPMIXERCONTROL_EXT *OutMixerControl,
PULONG NodeId)
{
- PLIST_ENTRY Entry;
+ PLIST_ENTRY Entry, ControlEntry;
LPMIXERLINE_EXT MixerLineSrc;
- ULONG Index;
+ LPMIXERCONTROL_EXT MixerControl;
/* get first entry */
Entry = MixerInfo->LineList.Flink;
{
MixerLineSrc = (LPMIXERLINE_EXT)CONTAINING_RECORD(Entry, MIXERLINE_EXT, Entry);
- for(Index = 0; Index < MixerLineSrc->Line.cControls; Index++)
+ ControlEntry = MixerLineSrc->ControlsList.Flink;
+ while(ControlEntry != &MixerLineSrc->ControlsList)
{
- if (MixerLineSrc->LineControls[Index].dwControlID == dwControlID)
+ MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(ControlEntry, MIXERCONTROL_EXT, Entry);
+ if (MixerControl->Control.dwControlID == dwControlID)
{
- if (MixerLine)
- *MixerLine = MixerLineSrc;
- if (MixerControl)
- *MixerControl = &MixerLineSrc->LineControls[Index];
+ if (OutMixerLine)
+ *OutMixerLine = MixerLineSrc;
+ if (OutMixerControl)
+ *OutMixerControl = MixerControl;
if (NodeId)
- *NodeId = MixerLineSrc->NodeIds[Index];
+ *NodeId = MixerControl->NodeID;
return MM_STATUS_SUCCESS;
}
+ ControlEntry = ControlEntry->Flink;
}
Entry = Entry->Flink;
}
PLIST_ENTRY Entry;
PEVENT_NOTIFICATION_ENTRY NotificationEntry;
- /* enumerate list and add a notification entry */
- Entry = MixerInfo->LineList.Flink;
+ /* enumerate list and perform notification */
+ Entry = MixerInfo->EventList.Flink;
while(Entry != &MixerInfo->EventList)
{
/* get notification entry offset */
MMixerSetGetMuteControlDetails(
IN PMIXER_CONTEXT MixerContext,
IN LPMIXER_INFO MixerInfo,
- IN ULONG NodeId,
+ IN LPMIXERCONTROL_EXT MixerControl,
IN ULONG dwLineID,
IN LPMIXERCONTROLDETAILS MixerControlDetails,
IN ULONG bSet)
Value = Input->fValue;
/* set control details */
- Status = MMixerSetGetControlDetails(MixerContext, MixerInfo->hMixer, NodeId, bSet, KSPROPERTY_AUDIO_MUTE, 0, &Value);
+ Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, MixerControl->NodeID, bSet, KSPROPERTY_AUDIO_MUTE, 0, &Value);
if (Status != MM_STATUS_SUCCESS)
return Status;
return Status;
}
+MIXER_STATUS
+MMixerSetGetMuxControlDetails(
+ IN PMIXER_CONTEXT MixerContext,
+ IN LPMIXER_INFO MixerInfo,
+ IN ULONG NodeId,
+ IN ULONG bSet,
+ IN ULONG Flags,
+ IN LPMIXERCONTROL_EXT MixerControl,
+ IN LPMIXERCONTROLDETAILS MixerControlDetails,
+ IN LPMIXERLINE_EXT MixerLine)
+{
+ MIXER_STATUS Status;
+ PULONG LogicalNodes, ConnectedNodes;
+ ULONG LogicalNodesCount, ConnectedNodesCount, Index, CurLogicalPinOffset, BytesReturned, OldLogicalPinOffset;
+ LPMIXER_DATA MixerData;
+ LPMIXERCONTROLDETAILS_LISTTEXTW ListText;
+ LPMIXERCONTROLDETAILS_BOOLEAN Values;
+ LPMIXERLINE_EXT SourceLine;
+ KSNODEPROPERTY Request;
+
+ DPRINT("MixerControlDetails %p\n", MixerControlDetails);
+ DPRINT("bSet %lx\n", bSet);
+ DPRINT("Flags %lx\n", Flags);
+ DPRINT("NodeId %lu\n", MixerControl->NodeID);
+ DPRINT("MixerControlDetails dwControlID %lu\n", MixerControlDetails->dwControlID);
+ DPRINT("MixerControlDetails cChannels %lu\n", MixerControlDetails->cChannels);
+ DPRINT("MixerControlDetails cMultipleItems %lu\n", MixerControlDetails->cMultipleItems);
+ DPRINT("MixerControlDetails cbDetails %lu\n", MixerControlDetails->cbDetails);
+ DPRINT("MixerControlDetails paDetails %p\n", MixerControlDetails->paDetails);
+
+ if (MixerControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM)
+ {
+ /* control acts uniform */
+ if (MixerControlDetails->cChannels != 1)
+ {
+ /* expected 1 channel */
+ DPRINT1("Expected 1 channel but got %lu\n", MixerControlDetails->cChannels);
+ return MM_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ /* check if multiple items match */
+ if (MixerControlDetails->cMultipleItems != MixerControl->Control.cMultipleItems)
+ {
+ DPRINT1("MultipleItems mismatch %lu expected %lu\n", MixerControlDetails->cMultipleItems, MixerControl->Control.cMultipleItems);
+ return MM_STATUS_UNSUCCESSFUL;
+ }
+
+ if (bSet)
+ {
+ if ((Flags & MIXER_SETCONTROLDETAILSF_QUERYMASK) == MIXER_SETCONTROLDETAILSF_CUSTOM)
+ {
+ /* tell me when this is hit */
+ ASSERT(FALSE);
+ }
+ else if ((Flags & (MIXER_SETCONTROLDETAILSF_VALUE | MIXER_SETCONTROLDETAILSF_CUSTOM)) == MIXER_SETCONTROLDETAILSF_VALUE)
+ {
+ /* sanity check */
+ ASSERT(bSet == TRUE);
+ ASSERT(MixerControlDetails->cbDetails == sizeof(MIXERCONTROLDETAILS_BOOLEAN));
+
+ Values = (LPMIXERCONTROLDETAILS_BOOLEAN)MixerControlDetails->paDetails;
+ CurLogicalPinOffset = MAXULONG;
+ for(Index = 0; Index < MixerControlDetails->cMultipleItems; Index++)
+ {
+ if (Values[Index].fValue)
+ {
+ /* mux can only activate one line at a time */
+ ASSERT(CurLogicalPinOffset == MAXULONG);
+ CurLogicalPinOffset = Index;
+ }
+ }
+
+ /* setup request */
+ Request.NodeId = NodeId;
+ Request.Reserved = 0;
+ Request.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY | KSPROPERTY_TYPE_GET;
+ Request.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
+ Request.Property.Set = KSPROPSETID_Audio;
+
+ /* perform getting source */
+ Status = MixerContext->Control(MixerControl->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSNODEPROPERTY), &OldLogicalPinOffset, sizeof(ULONG), &BytesReturned);
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* failed to get source */
+ return Status;
+ }
+
+ DPRINT("OldLogicalPinOffset %lu CurLogicalPinOffset %lu\n", OldLogicalPinOffset, CurLogicalPinOffset);
+
+ if (OldLogicalPinOffset == CurLogicalPinOffset)
+ {
+ /* cannot be unselected */
+ return MM_STATUS_UNSUCCESSFUL;
+ }
+
+ /* perform setting source */
+ Request.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY | KSPROPERTY_TYPE_SET;
+ Status = MixerContext->Control(MixerControl->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSNODEPROPERTY), &CurLogicalPinOffset, sizeof(ULONG), &BytesReturned);
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* failed to set source */
+ return Status;
+ }
+
+ /* notify control change */
+ MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_CONTROL_CHANGE, MixerControl->Control.dwControlID );
+
+ return Status;
+ }
+ }
+ else
+ {
+ if ((Flags & MIXER_GETCONTROLDETAILSF_QUERYMASK) == MIXER_GETCONTROLDETAILSF_VALUE)
+ {
+ /* setup request */
+ Request.NodeId = NodeId;
+ Request.Reserved = 0;
+ Request.Property.Flags = KSPROPERTY_TYPE_TOPOLOGY | KSPROPERTY_TYPE_GET;
+ Request.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
+ Request.Property.Set = KSPROPSETID_Audio;
+
+ /* perform getting source */
+ Status = MixerContext->Control(MixerControl->hDevice, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSNODEPROPERTY), &OldLogicalPinOffset, sizeof(ULONG), &BytesReturned);
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* failed to get source */
+ return Status;
+ }
+
+ /* gets the corresponding mixer data */
+ MixerData = MMixerGetMixerDataByDeviceHandle(MixerContext, MixerControl->hDevice);
+
+ /* sanity check */
+ ASSERT(MixerData);
+ ASSERT(MixerData->Topology);
+ ASSERT(MixerData->MixerInfo == MixerInfo);
+
+ /* get logical pin nodes */
+ MMixerGetConnectedFromLogicalTopologyPins(MixerData->Topology, MixerControl->NodeID, &LogicalNodesCount, LogicalNodes);
+
+ /* sanity check */
+ ASSERT(LogicalNodesCount == MixerControlDetails->cMultipleItems);
+ ASSERT(LogicalNodesCount == MixerControl->Control.Metrics.dwReserved[0]);
+
+ Values = (LPMIXERCONTROLDETAILS_BOOLEAN)MixerControlDetails->paDetails;
+ for(Index = 0; Index < ConnectedNodesCount; Index++)
+ {
+ /* getting logical pin offset */
+ MMixerGetLowestLogicalTopologyPinOffsetFromArray(LogicalNodesCount, LogicalNodes, &CurLogicalPinOffset);
+
+ if (CurLogicalPinOffset == OldLogicalPinOffset)
+ {
+ /* mark index as active */
+ Values[Index].fValue = TRUE;
+ }
+ else
+ {
+ /* index not active */
+ Values[Index].fValue = FALSE;
+ }
+
+ /* mark offset as consumed */
+ LogicalNodes[CurLogicalPinOffset] = MAXULONG;
+ }
+
+ /* cleanup */
+ MixerContext->Free(LogicalNodes);
+
+ /* done */
+ return MM_STATUS_SUCCESS;
+ }
+ else if ((Flags & MIXER_GETCONTROLDETAILSF_QUERYMASK) == MIXER_GETCONTROLDETAILSF_LISTTEXT)
+ {
+ /* sanity check */
+ ASSERT(bSet == FALSE);
+
+ /* gets the corresponding mixer data */
+ MixerData = MMixerGetMixerDataByDeviceHandle(MixerContext, MixerControl->hDevice);
+
+ /* sanity check */
+ ASSERT(MixerData);
+ ASSERT(MixerData->Topology);
+ ASSERT(MixerData->MixerInfo == MixerInfo);
+
+ /* now allocate logical pin array */
+ Status = MMixerAllocateTopologyNodeArray(MixerContext, MixerData->Topology, &LogicalNodes);
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* no memory */
+ return MM_STATUS_NO_MEMORY;
+ }
+
+ /* allocate connected node array */
+ Status = MMixerAllocateTopologyNodeArray(MixerContext, MixerData->Topology, &ConnectedNodes);
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* no memory */
+ MixerContext->Free(LogicalNodes);
+ return MM_STATUS_NO_MEMORY;
+ }
+
+ /* get logical pin nodes */
+ MMixerGetConnectedFromLogicalTopologyPins(MixerData->Topology, MixerControl->NodeID, &LogicalNodesCount, LogicalNodes);
+
+ /* get connected nodes */
+ MMixerGetNextNodesFromNodeIndex(MixerContext, MixerData->Topology, MixerControl->NodeID, TRUE, &ConnectedNodesCount, ConnectedNodes);
+
+ /* sanity check */
+ ASSERT(ConnectedNodesCount == LogicalNodesCount);
+ ASSERT(ConnectedNodesCount == MixerControlDetails->cMultipleItems);
+ ASSERT(ConnectedNodesCount == MixerControl->Control.Metrics.dwReserved[0]);
+
+ ListText = (LPMIXERCONTROLDETAILS_LISTTEXTW)MixerControlDetails->paDetails;
+
+ for(Index = 0; Index < ConnectedNodesCount; Index++)
+ {
+ /* getting logical pin offset */
+ MMixerGetLowestLogicalTopologyPinOffsetFromArray(LogicalNodesCount, LogicalNodes, &CurLogicalPinOffset);
+
+ /* get mixer line with that node */
+ SourceLine = MMixerGetMixerLineContainingNodeId(MixerInfo, ConnectedNodes[CurLogicalPinOffset]);
+
+ /* sanity check */
+ ASSERT(SourceLine);
+
+ DPRINT1("PinOffset %lu LogicalPin %lu NodeId %lu LineName %S\n", CurLogicalPinOffset, LogicalNodes[CurLogicalPinOffset], ConnectedNodes[CurLogicalPinOffset], SourceLine->Line.szName);
+
+ /* copy details */
+ ListText[Index].dwParam1 = SourceLine->Line.dwLineID;
+ ListText[Index].dwParam2 = SourceLine->Line.dwComponentType;
+ MixerContext->Copy(ListText[Index].szName, SourceLine->Line.szName, (wcslen(SourceLine->Line.szName) + 1) * sizeof(WCHAR));
+
+ /* mark offset as consumed */
+ LogicalNodes[CurLogicalPinOffset] = MAXULONG;
+ }
+
+ /* cleanup */
+ MixerContext->Free(LogicalNodes);
+ MixerContext->Free(ConnectedNodes);
+
+ /* done */
+ return MM_STATUS_SUCCESS;
+ }
+ }
+
+ return MM_STATUS_NOT_IMPLEMENTED;
+}
+
MIXER_STATUS
MMixerSetGetVolumeControlDetails(
IN PMIXER_CONTEXT MixerContext,
IN LPMIXER_INFO MixerInfo,
IN ULONG NodeId,
IN ULONG bSet,
- LPMIXERCONTROLW MixerControl,
+ LPMIXERCONTROL_EXT MixerControl,
IN LPMIXERCONTROLDETAILS MixerControlDetails,
LPMIXERLINE_EXT MixerLine)
{
if (MixerControlDetails->cbDetails != sizeof(MIXERCONTROLDETAILS_SIGNED))
return MM_STATUS_INVALID_PARAMETER;
- VolumeData = (LPMIXERVOLUME_DATA)MMixerGetMixerControlDataById(&MixerLine->LineControlsExtraData, MixerControl->dwControlID);
+ VolumeData = (LPMIXERVOLUME_DATA)MixerControl->ExtraData;
if (!VolumeData)
return MM_STATUS_UNSUCCESSFUL;
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);
+ Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 0, &Value);
+ Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, 1, &Value);
}
else
{
- Status = MMixerSetGetControlDetails(MixerContext, MixerInfo->hMixer, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, Channel, &Value);
+ Status = MMixerSetGetControlDetails(MixerContext, MixerControl->hDevice, NodeId, bSet, KSPROPERTY_AUDIO_VOLUMELEVEL, Channel, &Value);
}
if (!bSet)
else
{
/* notify clients of a line change MM_MIXM_CONTROL_CHANGE with MixerControl->dwControlID */
- MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_CONTROL_CHANGE, MixerControl->dwControlID);
+ MMixerNotifyControlChange(MixerContext, MixerInfo, MM_MIXM_CONTROL_CHANGE, MixerControl->Control.dwControlID);
}
return Status;
}
{
PTOPOLOGY_NODE InNode, OutNode;
PTOPOLOGY_NODE * NewNodes;
+ PULONG NewLogicalPinNodeConnectedFrom;
ULONG Count;
+ ULONG LogicalPinId;
/* sanity checks */
ASSERT(Topology->TopologyNodesCount > Connection->ToNode);
InNode = &Topology->TopologyNodes[Connection->FromNode];
OutNode = &Topology->TopologyNodes[Connection->ToNode];
+ /* get logical pin node id */
+ LogicalPinId = Connection->ToNodePin;
+
/* get existing count */
Count = OutNode->NodeConnectedFromCount;
return MM_STATUS_NO_MEMORY;
}
+ /* allocate logical pin nodes array */
+ NewLogicalPinNodeConnectedFrom = MixerContext->Alloc((Count + 1) * sizeof(ULONG));
+ if (!NewLogicalPinNodeConnectedFrom)
+ {
+ /* out of memory */
+ MixerContext->Free(NewNodes);
+ return MM_STATUS_NO_MEMORY;
+ }
+
if (Count)
{
/* copy existing nodes */
MixerContext->Copy(NewNodes, OutNode->NodeConnectedFrom, sizeof(PTOPOLOGY) * Count);
+ /* copy existing logical pin node array */
+ MixerContext->Copy(NewLogicalPinNodeConnectedFrom, OutNode->LogicalPinNodeConnectedFrom, sizeof(ULONG) * Count);
+
/* release old nodes array */
MixerContext->Free(OutNode->NodeConnectedFrom);
+
+ /* release old logical pin node array */
+ MixerContext->Free(OutNode->LogicalPinNodeConnectedFrom);
}
/* add new topology node */
NewNodes[OutNode->NodeConnectedFromCount] = InNode;
+ /* add logical node id */
+ NewLogicalPinNodeConnectedFrom[OutNode->NodeConnectedFromCount] = LogicalPinId;
+
/* replace old nodes array */
OutNode->NodeConnectedFrom = NewNodes;
+ /* replace old logical pin node array */
+ OutNode->LogicalPinNodeConnectedFrom = NewLogicalPinNodeConnectedFrom;
+
/* increment nodes count */
OutNode->NodeConnectedFromCount++;
/* node should not have been visited */
ASSERT(Node->Visited == FALSE);
+ /* mark node as visited */
+ TopologyNode->Visited = TRUE;
+
/* add them to node array */
MMixerAddPinIndexToArray(MixerContext, Node->NodeIndex, Topology->TopologyNodesCount, OutNodeCount, OutNodes);
/* recursively visit them */
MMixerGetUpOrDownstreamNodes(MixerContext, Topology, TopologyNodes[Index], bUpStream, OutNodeCount, OutNodes);
}
-
- /* mark node as visited */
- TopologyNode->Visited = TRUE;
-
}
MIXER_STATUS
return MM_STATUS_SUCCESS;
}
+VOID
+MMixerGetConnectedFromLogicalTopologyPins(
+ IN PTOPOLOGY Topology,
+ IN ULONG NodeIndex,
+ OUT PULONG OutPinCount,
+ OUT PULONG OutPins)
+{
+ ULONG Index;
+ PTOPOLOGY_NODE Node;
+
+ /* sanity check */
+ ASSERT(NodeIndex < Topology->TopologyNodesCount);
+
+ /* get node */
+ Node = &Topology->TopologyNodes[NodeIndex];
+
+ for(Index = 0; Index < Node->NodeConnectedFromCount; Index++)
+ {
+ /* copy logical pin id */
+ OutPins[Index] = Node->LogicalPinNodeConnectedFrom[Index];
+ }
+
+ /* store pin count */
+ *OutPinCount = Node->NodeConnectedFromCount;
+}
+
LPGUID
MMixerGetNodeTypeFromTopology(
IN PTOPOLOGY Topology,
return &Topology->TopologyNodes[NodeIndex].NodeType;
}
+VOID
+MMixerSetTopologyPinReserved(
+ IN PTOPOLOGY Topology,
+ IN ULONG PinId)
+{
+ /* sanity check */
+ ASSERT(PinId < Topology->TopologyPinsCount);
+
+ /* set reserved */
+ Topology->TopologyPins[PinId].Reserved = TRUE;
+}
+
+VOID
+MMixerIsTopologyPinReserved(
+ IN PTOPOLOGY Topology,
+ IN ULONG PinId,
+ OUT PULONG bReserved)
+{
+ /* sanity check */
+ ASSERT(PinId < Topology->TopologyPinsCount);
+
+ /* get reserved status */
+ *bReserved = Topology->TopologyPins[PinId].Reserved;
+}
+
VOID
MMixerSetTopologyNodeReserved(
IN PTOPOLOGY Topology,
{
KSPROPERTY Property;
ULONG Length;
+ MIXER_STATUS Status;
+
+ /* verify mixer context */
+ Status = MMixerVerifyContext(MixerContext);
+
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* invalid context passed */
+ return Status;
+ }
/* setup property request */
Property.Set = KSPROPSETID_Connection;
return MixerContext->Control(PinHandle, IOCTL_KS_PROPERTY, &Property, sizeof(KSPROPERTY), &State, sizeof(KSSTATE), &Length);
}
+MIXER_STATUS
+MMixerSetWaveResetState(
+ IN PMIXER_CONTEXT MixerContext,
+ IN HANDLE PinHandle,
+ IN ULONG bBegin)
+{
+ ULONG Length;
+ MIXER_STATUS Status;
+ KSRESET Reset;
+
+ /* verify mixer context */
+ Status = MMixerVerifyContext(MixerContext);
+
+ if (Status != MM_STATUS_SUCCESS)
+ {
+ /* invalid context passed */
+ return Status;
+ }
+
+ /* begin / stop reset */
+ Reset = (bBegin ? KSRESET_BEGIN : KSRESET_END);
+
+ return MixerContext->Control(PinHandle, IOCTL_KS_RESET_STATE, &Reset, sizeof(KSRESET), NULL, 0, &Length);
+}
+
MIXER_STATUS
MMixerGetWaveDevicePath(
IN PMIXER_CONTEXT MixerContext,