diff --git a/reactos/lib/drivers/sound/mmebuddy/mixer/mxdMessage.c b/reactos/lib/drivers/sound/mmebuddy/mixer/mxdMessage.c index 08815ba8eee..7652d9ef7ea 100644 --- a/reactos/lib/drivers/sound/mmebuddy/mixer/mxdMessage.c +++ b/reactos/lib/drivers/sound/mmebuddy/mixer/mxdMessage.c @@ -20,6 +20,7 @@ MMRESULT MmeGetLineInfo( + IN UINT DeviceId, IN UINT Message, IN DWORD_PTR PrivateHandle, IN DWORD_PTR Parameter1, @@ -32,6 +33,21 @@ MmeGetLineInfo( //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; @@ -46,7 +62,7 @@ MmeGetLineInfo( 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; } @@ -100,7 +116,7 @@ mxdMessage( (LPWAVEOPENDESC) Parameter1, /* unused */ Parameter2, (DWORD*) PrivateHandle); - + VALIDATE_MMSYS_PARAMETER(*(DWORD_PTR*)PrivateHandle); break; } @@ -113,7 +129,8 @@ mxdMessage( case MXDM_GETCONTROLDETAILS : { - Result = MmeGetLineInfo(Message, + Result = MmeGetLineInfo(DeviceId, + Message, PrivateHandle, Parameter1, Parameter2); @@ -123,7 +140,8 @@ mxdMessage( case MXDM_SETCONTROLDETAILS : { - Result = MmeGetLineInfo(Message, + Result = MmeGetLineInfo(DeviceId, + Message, PrivateHandle, Parameter1, Parameter2); @@ -133,7 +151,8 @@ mxdMessage( case MXDM_GETLINECONTROLS : { - Result = MmeGetLineInfo(Message, + Result = MmeGetLineInfo(DeviceId, + Message, PrivateHandle, Parameter1, Parameter2); @@ -143,7 +162,8 @@ mxdMessage( case MXDM_GETLINEINFO : { - Result = MmeGetLineInfo(Message, + Result = MmeGetLineInfo(DeviceId, + Message, PrivateHandle, Parameter1, Parameter2); diff --git a/reactos/lib/drivers/sound/mmebuddy/mmewrap.c b/reactos/lib/drivers/sound/mmebuddy/mmewrap.c index 583d198ca87..9e03770c175 100644 --- a/reactos/lib/drivers/sound/mmebuddy/mmewrap.c +++ b/reactos/lib/drivers/sound/mmebuddy/mmewrap.c @@ -130,11 +130,11 @@ MmeOpenDevice( 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); diff --git a/reactos/lib/drivers/sound/mmebuddy/wave/format.c b/reactos/lib/drivers/sound/mmebuddy/wave/format.c index ecc5bbc1d9a..34541c4fa0c 100644 --- a/reactos/lib/drivers/sound/mmebuddy/wave/format.c +++ b/reactos/lib/drivers/sound/mmebuddy/wave/format.c @@ -65,8 +65,6 @@ SetWaveDeviceFormat( 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) ) @@ -74,9 +72,14 @@ SetWaveDeviceFormat( 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); diff --git a/reactos/lib/drivers/sound/mmebuddy/wave/streaming.c b/reactos/lib/drivers/sound/mmebuddy/wave/streaming.c index a28093359b5..63ac5e0a89d 100644 --- a/reactos/lib/drivers/sound/mmebuddy/wave/streaming.c +++ b/reactos/lib/drivers/sound/mmebuddy/wave/streaming.c @@ -232,6 +232,8 @@ CompleteIO( }while(dwNumberOfBytesTransferred); + // AUDIO-BRANCH DIFF + // completion callback is performed in a thread DoWaveStreaming(SoundDeviceInstance); //CompleteWavePortion(SoundDeviceInstance, dwNumberOfBytesTransferred); @@ -277,8 +279,62 @@ StopStreamingInSoundThread( 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 diff --git a/reactos/lib/drivers/sound/mmebuddy/wave/wodMessage.c b/reactos/lib/drivers/sound/mmebuddy/wave/wodMessage.c index 330c5f2aab6..a1202a8e5cc 100644 --- a/reactos/lib/drivers/sound/mmebuddy/wave/wodMessage.c +++ b/reactos/lib/drivers/sound/mmebuddy/wave/wodMessage.c @@ -109,6 +109,13 @@ wodMessage( case WODM_RESTART : { /* Continue playback when paused */ + Result = MmeSetState(PrivateHandle, TRUE); + break; + } + case WODM_PAUSE : + { + /* pause playback */ + Result = MmeSetState(PrivateHandle, FALSE); break; } diff --git a/reactos/lib/drivers/sound/mmixer/TODO b/reactos/lib/drivers/sound/mmixer/TODO new file mode 100644 index 00000000000..05cf9c29474 --- /dev/null +++ b/reactos/lib/drivers/sound/mmixer/TODO @@ -0,0 +1,6 @@ +=== MMIXER TASKS === + +- Add hacks for source lines, such that Wave Mixer line always has a volume control +- Support custom mixer controls +- Assign mixer controls after all controls have been assigned (starting on the destination lines) +- TESTING & BUGFIXING \ No newline at end of file diff --git a/reactos/lib/drivers/sound/mmixer/controls.c b/reactos/lib/drivers/sound/mmixer/controls.c index 5b5dd1831ae..e7bd2886ef5 100644 --- a/reactos/lib/drivers/sound/mmixer/controls.c +++ b/reactos/lib/drivers/sound/mmixer/controls.c @@ -8,44 +8,67 @@ #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; @@ -55,7 +78,7 @@ MMixerAddMixerControl( 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) { @@ -68,44 +91,66 @@ MMixerAddMixerControl( } /* 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); - Property.NodeId = NodeIndex; - Property.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE; - Property.Property.Flags = KSPROPERTY_TYPE_SET; - Property.Property.Set = KSPROPSETID_Audio; + if (Status != MM_STATUS_SUCCESS) + { + /* out of memory */ + return STATUS_NO_MEMORY; + } - /* get node volume level info */ - Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY), (PVOID)&PinId, sizeof(ULONG), &BytesReturned); + /* get connected node count */ + MMixerGetNextNodesFromNodeIndex(MixerContext, Topology, NodeIndex, TRUE, &NodesCount, Nodes); - DPRINT1("Status %x NodeIndex %u PinId %u\n", Status, NodeIndex, PinId); - //DbgBreakPoint(); - }else -#endif - if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) + /* TODO */ + MixerContext->Free(Nodes); + + /* 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; @@ -113,6 +158,10 @@ MMixerAddMixerControl( 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); @@ -122,11 +171,11 @@ MMixerAddMixerControl( 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) { @@ -151,7 +200,7 @@ MMixerAddMixerControl( 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; @@ -172,13 +221,13 @@ MMixerAddMixerControl( 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; } @@ -201,12 +250,16 @@ MMixerCreateDestinationLine( /* initialize mixer destination line */ DestinationLine->Line.cbStruct = sizeof(MIXERLINEW); - 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.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.dwUser = 0; + DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE; + if (LineName) { @@ -219,7 +272,7 @@ MMixerCreateDestinationLine( } 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; @@ -228,10 +281,13 @@ MMixerCreateDestinationLine( 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; @@ -241,6 +297,7 @@ MIXER_STATUS MMixerGetPinName( IN PMIXER_CONTEXT MixerContext, IN LPMIXER_INFO MixerInfo, + IN HANDLE hMixer, IN ULONG PinId, IN OUT LPWSTR * OutBuffer) { @@ -257,7 +314,7 @@ MMixerGetPinName( 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) @@ -271,7 +328,7 @@ MMixerGetPinName( } /* 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 */ @@ -292,6 +349,7 @@ MIXER_STATUS MMixerBuildMixerDestinationLine( IN PMIXER_CONTEXT MixerContext, IN OUT LPMIXER_INFO MixerInfo, + IN HANDLE hMixer, IN ULONG PinId, IN ULONG bInput) { @@ -299,7 +357,7 @@ MMixerBuildMixerDestinationLine( 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 */ @@ -385,6 +443,7 @@ MMixerCountMixerControls( IN PMIXER_CONTEXT MixerContext, IN PTOPOLOGY Topology, IN ULONG PinId, + IN ULONG bInputMixer, IN ULONG bUpStream, OUT PULONG OutNodesCount, OUT PULONG OutNodes, @@ -424,6 +483,12 @@ MMixerCountMixerControls( if (bTerminator) { /* found terminator */ + if (bInputMixer) + { + /* add mux source for source destination line */ + OutNodes[Count] = NodeIndex; + Count++; + } break; } @@ -458,10 +523,140 @@ MMixerCountMixerControls( 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, @@ -469,18 +664,8 @@ MMixerAddMixerControlsToMixerLineByNodeIndexArray( { 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; @@ -489,18 +674,36 @@ MMixerAddMixerControlsToMixerLineByNodeIndexArray( { /* 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) { @@ -516,19 +719,230 @@ MMixerAddMixerControlsToMixerLineByNodeIndexArray( 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)); @@ -540,36 +954,35 @@ MMixerBuildMixerSourceLine( } /* 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) { @@ -585,7 +998,7 @@ MMixerBuildMixerSourceLine( } /* 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 */ @@ -602,7 +1015,9 @@ MIXER_STATUS 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; @@ -612,7 +1027,7 @@ MMixerAddMixerSourceLines( 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 */ @@ -693,8 +1108,11 @@ MMixerAddMixerSourceLines( 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) { @@ -703,8 +1121,23 @@ MMixerAddMixerSourceLines( /* 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); @@ -716,9 +1149,11 @@ MIXER_STATUS 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; @@ -737,7 +1172,7 @@ MMixerAddMixerControlsToDestinationLine( } /* 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) @@ -748,7 +1183,7 @@ MMixerAddMixerControlsToDestinationLine( } /* get destination mixer line */ - DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE); + DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineId); /* sanity check */ ASSERT(DstLine); @@ -756,7 +1191,7 @@ MMixerAddMixerControlsToDestinationLine( 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 */ @@ -776,6 +1211,7 @@ VOID MMixerApplyOutputFilterHack( IN PMIXER_CONTEXT MixerContext, IN LPMIXER_DATA MixerData, + IN HANDLE hMixer, IN OUT PULONG PinsCount, IN OUT PULONG Pins) { @@ -786,7 +1222,7 @@ MMixerApplyOutputFilterHack( 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) { @@ -823,7 +1259,7 @@ MMixerHandlePhysicalConnection( IN PKSPIN_PHYSICALCONNECTION OutConnection) { MIXER_STATUS Status; - ULONG PinsCount, LineTerminator; + ULONG PinsCount, LineTerminator, DestinationLineID; PULONG Pins; PTOPOLOGY Topology; @@ -840,23 +1276,44 @@ MMixerHandlePhysicalConnection( 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 */ @@ -878,88 +1335,111 @@ MMixerHandlePhysicalConnection( * 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; + } + + /* new mixer info */ + NewMixerInfo = TRUE; + + /* 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; + + /* 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; } - /* 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; - - /* get mixer name */ - MMixerGetDeviceName(MixerContext, MixerInfo->MixCaps.szPname, MixerData->hDeviceInterfaceKey); - - /* initialize line list */ - InitializeListHead(&MixerInfo->LineList); - InitializeListHead(&MixerInfo->EventList); + /* 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 @@ -977,7 +1457,7 @@ MMixerInitializeFilter( 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 */ @@ -990,10 +1470,16 @@ MMixerInitializeFilter( 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) { @@ -1027,6 +1513,9 @@ MMixerInitializeFilter( 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); @@ -1044,26 +1533,91 @@ MMixerInitializeFilter( /* 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); + /* increment mixer count */ + MixerList->MixerListCount++; } - else - { - /* insert at back */ - InsertTailList(&MixerList->MixerList, &MixerInfo->Entry); - } - - /* 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, @@ -1074,6 +1628,7 @@ MMixerSetupFilter( MIXER_STATUS Status; PTOPOLOGY Topology; ULONG NodeIndex; + LPMIXER_INFO MixerInfo = NULL; /* check if topology has already been built */ if (MixerData->Topology == NULL) @@ -1101,7 +1656,7 @@ MMixerSetupFilter( 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) @@ -1109,7 +1664,11 @@ MMixerSetupFilter( /* increment mixer count */ (*DeviceCount)++; } - + else + { + /* reset mixer info in case of error */ + MixerInfo = NULL; + } } /* check if the filter has an wave in node */ @@ -1117,7 +1676,7 @@ MMixerSetupFilter( 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) @@ -1128,8 +1687,10 @@ MMixerSetupFilter( } + /* TODO: apply hacks for Wave source line */ + /* activate midi devices */ - MMixerInitializeMidiForFilter(MixerContext, MixerList, MixerData, Topology); + //MMixerInitializeMidiForFilter(MixerContext, MixerList, MixerData, Topology); /* done */ return Status; @@ -1175,7 +1736,7 @@ MMixerAddEvent( /* initialize notification entry */ EventData->MixerEventContext = MixerEventContext; - EventData->MixerEventRoutine; + EventData->MixerEventRoutine = MixerEventRoutine; /* store event */ InsertTailList(&MixerInfo->EventList, &EventData->Entry); diff --git a/reactos/lib/drivers/sound/mmixer/midi.c b/reactos/lib/drivers/sound/mmixer/midi.c index e60d14999c2..4809c910eab 100644 --- a/reactos/lib/drivers/sound/mmixer/midi.c +++ b/reactos/lib/drivers/sound/mmixer/midi.c @@ -11,7 +11,7 @@ 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) @@ -28,7 +28,7 @@ MMixerGetPinDataFlowAndCommunication( 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 */ @@ -39,7 +39,7 @@ MMixerGetPinDataFlowAndCommunication( 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; } @@ -142,7 +142,7 @@ MMixerCheckFilterPinMidiSupport( 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) { diff --git a/reactos/lib/drivers/sound/mmixer/mixer.c b/reactos/lib/drivers/sound/mmixer/mixer.c index b04b50c702f..980a49e6bce 100644 --- a/reactos/lib/drivers/sound/mmixer/mixer.c +++ b/reactos/lib/drivers/sound/mmixer/mixer.c @@ -89,6 +89,7 @@ MMixerOpen( if (Status != MM_STATUS_SUCCESS) { /* invalid context passed */ + DPRINT1("invalid context\n"); return Status; } @@ -97,6 +98,7 @@ MMixerOpen( if (!MixerInfo) { /* invalid mixer id */ + DPRINT1("invalid mixer id %lu\n", MixerId); return MM_STATUS_INVALID_PARAMETER; } @@ -106,20 +108,21 @@ MMixerOpen( /* 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); @@ -129,25 +132,54 @@ MMixerGetLineInfo( /* 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) - { - /* destination line member must be zero */ - return MM_STATUS_INVALID_PARAMETER; - } + /* calculate destination line id */ + DestinationLineID = (MixerLine->dwDestination + DESTINATION_LINE); - MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE); - ASSERT(MixerLineSrc); + /* get destination line */ + MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID); + + if (MixerLineSrc == NULL) + { + DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination); + return MM_STATUS_UNSUCCESSFUL; + } + /* copy mixer line */ MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW)); + /* make sure it is null terminated */ + MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0'; + MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0'; + MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0'; + + /* done */ return MM_STATUS_SUCCESS; } else if (Flags == MIXER_GETLINEINFOF_SOURCE) @@ -155,41 +187,75 @@ MMixerGetLineInfo( /* 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 (MixerLineSrc == NULL) + { + DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination); + return MM_STATUS_UNSUCCESSFUL; + } + + /* check if dwSource is out of bounds */ if (MixerLine->dwSource >= MixerLineSrc->Line.cConnections) { - DPRINT("dwSource %u > Destinations %u\n", MixerLine->dwSource, MixerLineSrc->Line.cConnections); - - /* invalid parameter */ - return MM_STATUS_INVALID_PARAMETER; + 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; } - MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLine->dwSource * 0x10000); - if (MixerLineSrc) - { - DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName); - MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW)); - return MM_STATUS_SUCCESS; - } - 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) @@ -197,6 +263,7 @@ MMixerGetLineInfo( /* cast to mixer info */ MixerInfo = (LPMIXER_INFO)MixerHandle; + /* find mixer line by component type */ MixerLineSrc = MMixerGetSourceMixerLineByComponentType(MixerInfo, MixerLine->dwComponentType); if (!MixerLineSrc) { @@ -204,12 +271,25 @@ MMixerGetLineInfo( 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; } @@ -218,13 +298,15 @@ MIXER_STATUS MMixerGetLineControls( IN PMIXER_CONTEXT MixerContext, IN HANDLE MixerHandle, + IN ULONG MixerId, IN ULONG Flags, OUT LPMIXERLINECONTROLSW MixerLineControls) { LPMIXER_INFO MixerInfo; LPMIXERLINE_EXT MixerLineSrc; - LPMIXERCONTROLW MixerControl; + LPMIXERCONTROL_EXT MixerControl; MIXER_STATUS Status; + PLIST_ENTRY Entry; ULONG Index; /* verify mixer context */ @@ -236,23 +318,75 @@ MMixerGetLineControls( 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; } - /* copy line control(s) */ - MixerContext->Copy(MixerLineControls->pamxctrl, MixerLineSrc->LineControls, min(MixerLineSrc->Line.cControls, MixerLineControls->cControls) * sizeof(MIXERCONTROLW)); + if (MixerLineSrc->Line.cControls != MixerLineControls->cControls) + { + /* invalid parameter */ + DPRINT1("Invalid control count %lu expected %lu\n", MixerLineControls->cControls, MixerLineSrc->Line.cControls); + return MM_STATUS_INVALID_PARAMETER; + } + + /* copy line control(s) */ + Entry = MixerLineSrc->ControlsList.Flink; + Index = 0; + while(Entry != &MixerLineSrc->ControlsList) + { + /* get mixer control */ + MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(Entry, MIXERCONTROL_EXT, Entry); + + /* copy mixer control */ + MixerContext->Copy(&MixerLineControls->pamxctrl[Index], &MixerControl->Control, sizeof(MIXERCONTROLW)); + + /* move to next */ + Entry = Entry->Flink; + + /* increment mixer control offset */ + Index++; + } return MM_STATUS_SUCCESS; } else if (Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE) @@ -260,29 +394,38 @@ MMixerGetLineControls( /* 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) { @@ -294,15 +437,24 @@ MMixerGetLineControls( 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; } @@ -310,6 +462,7 @@ MIXER_STATUS MMixerSetControlDetails( IN PMIXER_CONTEXT MixerContext, IN HANDLE MixerHandle, + IN ULONG MixerId, IN ULONG Flags, OUT LPMIXERCONTROLDETAILS MixerControlDetails) { @@ -317,7 +470,7 @@ MMixerSetControlDetails( ULONG NodeId; LPMIXER_INFO MixerInfo; LPMIXERLINE_EXT MixerLine; - LPMIXERCONTROLW MixerControl; + LPMIXERCONTROL_EXT MixerControl; /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); @@ -325,9 +478,23 @@ MMixerSetControlDetails( 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; @@ -338,16 +505,21 @@ MMixerSetControlDetails( 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; @@ -360,6 +532,7 @@ MIXER_STATUS MMixerGetControlDetails( IN PMIXER_CONTEXT MixerContext, IN HANDLE MixerHandle, + IN ULONG MixerId, IN ULONG Flags, OUT LPMIXERCONTROLDETAILS MixerControlDetails) { @@ -367,7 +540,7 @@ MMixerGetControlDetails( ULONG NodeId; LPMIXER_INFO MixerInfo; LPMIXERLINE_EXT MixerLine; - LPMIXERCONTROLW MixerControl; + LPMIXERCONTROL_EXT MixerControl; /* verify mixer context */ Status = MMixerVerifyContext(MixerContext); @@ -378,6 +551,18 @@ MMixerGetControlDetails( 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; @@ -391,21 +576,162 @@ MMixerGetControlDetails( 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, @@ -507,6 +833,18 @@ MMixerInitialize( 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; } diff --git a/reactos/lib/drivers/sound/mmixer/mmixer.h b/reactos/lib/drivers/sound/mmixer/mmixer.h index 846d4e9d83b..5cd530abffa 100644 --- a/reactos/lib/drivers/sound/mmixer/mmixer.h +++ b/reactos/lib/drivers/sound/mmixer/mmixer.h @@ -47,7 +47,7 @@ typedef MIXER_STATUS(*PMIXER_CLOSE)( 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, @@ -149,7 +149,8 @@ MMixerOpen( MIXER_STATUS MMixerGetLineInfo( IN PMIXER_CONTEXT MixerContext, - IN HANDLE MixerHandle, + IN HANDLE MixerHandle, + IN ULONG MixerId, IN ULONG Flags, OUT LPMIXERLINEW MixerLine); @@ -157,6 +158,7 @@ MIXER_STATUS MMixerGetLineControls( IN PMIXER_CONTEXT MixerContext, IN HANDLE MixerHandle, + IN ULONG MixerId, IN ULONG Flags, OUT LPMIXERLINECONTROLSW MixerLineControls); @@ -164,6 +166,7 @@ MIXER_STATUS MMixerSetControlDetails( IN PMIXER_CONTEXT MixerContext, IN HANDLE MixerHandle, + IN ULONG MixerId, IN ULONG Flags, OUT LPMIXERCONTROLDETAILS MixerControlDetails); @@ -171,6 +174,7 @@ MIXER_STATUS MMixerGetControlDetails( IN PMIXER_CONTEXT MixerContext, IN HANDLE MixerHandle, + IN ULONG MixerId, IN ULONG Flags, OUT LPMIXERCONTROLDETAILS MixerControlDetails); @@ -202,6 +206,12 @@ MMixerSetWaveStatus( 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, diff --git a/reactos/lib/drivers/sound/mmixer/priv.h b/reactos/lib/drivers/sound/mmixer/priv.h index 8a4855f8ca8..3746f6d247b 100644 --- a/reactos/lib/drivers/sound/mmixer/priv.h +++ b/reactos/lib/drivers/sound/mmixer/priv.h @@ -27,6 +27,7 @@ typedef struct __TOPOLOGY_NODE__ ULONG NodeConnectedFromCount; struct __TOPOLOGY_NODE__ ** NodeConnectedFrom; + PULONG LogicalPinNodeConnectedFrom; ULONG PinConnectedFromCount; PULONG PinConnectedFrom; @@ -55,6 +56,7 @@ typedef struct PULONG PinConnectedTo; ULONG Visited; + ULONG Reserved; }PIN, *PPIN; @@ -72,7 +74,6 @@ typedef struct { LIST_ENTRY Entry; MIXERCAPSW MixCaps; - HANDLE hMixer; LIST_ENTRY LineList; ULONG ControlId; LIST_ENTRY EventList; @@ -81,12 +82,19 @@ typedef struct 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 @@ -114,6 +122,7 @@ typedef struct HANDLE hDeviceInterfaceKey; LPWSTR DeviceName; PTOPOLOGY Topology; + LPMIXER_INFO MixerInfo; }MIXER_DATA, *LPMIXER_DATA; typedef struct @@ -170,8 +179,8 @@ 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, @@ -270,14 +279,14 @@ MMixerGetMixerControlById( 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); @@ -288,10 +297,22 @@ MMixerSetGetVolumeControlDetails( 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, @@ -349,6 +370,26 @@ MMixerInitializePinConnect( 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 */ @@ -462,8 +503,25 @@ MMixerIsTopologyNodeReserved( 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); diff --git a/reactos/lib/drivers/sound/mmixer/sup.c b/reactos/lib/drivers/sound/mmixer/sup.c index 126bcb53662..9052e94fb9c 100644 --- a/reactos/lib/drivers/sound/mmixer/sup.c +++ b/reactos/lib/drivers/sound/mmixer/sup.c @@ -54,6 +54,63 @@ MMixerVerifyContext( 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, @@ -67,6 +124,38 @@ MMixerFreeMixerInfo( 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, @@ -100,27 +189,31 @@ MMixerGetMixerInfoByIndex( 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 @@ -187,13 +280,13 @@ MIXER_STATUS 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; @@ -202,18 +295,21 @@ MMixerGetMixerControlById( { 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; } @@ -248,8 +344,8 @@ MMixerNotifyControlChange( 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 */ @@ -270,7 +366,7 @@ 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) @@ -290,7 +386,7 @@ MMixerSetGetMuteControlDetails( 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; @@ -310,13 +406,262 @@ MMixerSetGetMuteControlDetails( 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) { @@ -329,7 +674,7 @@ MMixerSetGetVolumeControlDetails( 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; @@ -355,12 +700,12 @@ MMixerSetGetVolumeControlDetails( 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) @@ -372,7 +717,7 @@ MMixerSetGetVolumeControlDetails( 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; } diff --git a/reactos/lib/drivers/sound/mmixer/topology.c b/reactos/lib/drivers/sound/mmixer/topology.c index 44e85da9c22..c1d4c3d1051 100644 --- a/reactos/lib/drivers/sound/mmixer/topology.c +++ b/reactos/lib/drivers/sound/mmixer/topology.c @@ -264,7 +264,9 @@ MMixerHandleNodeToNodeConnection( { PTOPOLOGY_NODE InNode, OutNode; PTOPOLOGY_NODE * NewNodes; + PULONG NewLogicalPinNodeConnectedFrom; ULONG Count; + ULONG LogicalPinId; /* sanity checks */ ASSERT(Topology->TopologyNodesCount > Connection->ToNode); @@ -274,6 +276,9 @@ MMixerHandleNodeToNodeConnection( InNode = &Topology->TopologyNodes[Connection->FromNode]; OutNode = &Topology->TopologyNodes[Connection->ToNode]; + /* get logical pin node id */ + LogicalPinId = Connection->ToNodePin; + /* get existing count */ Count = OutNode->NodeConnectedFromCount; @@ -286,21 +291,42 @@ MMixerHandleNodeToNodeConnection( 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++; @@ -745,16 +771,15 @@ MMixerGetUpOrDownstreamNodes( /* 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 @@ -1137,6 +1162,32 @@ MMixerIsNodeConnectedToPin( 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, @@ -1148,6 +1199,31 @@ MMixerGetNodeTypeFromTopology( 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, diff --git a/reactos/lib/drivers/sound/mmixer/wave.c b/reactos/lib/drivers/sound/mmixer/wave.c index c48f03bba58..1d39f37c479 100644 --- a/reactos/lib/drivers/sound/mmixer/wave.c +++ b/reactos/lib/drivers/sound/mmixer/wave.c @@ -608,6 +608,16 @@ MMixerSetWaveStatus( { 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; @@ -617,6 +627,31 @@ MMixerSetWaveStatus( 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,