[MMEBUDDY]

- Merge from audio branch
- Handle mixers identified by id, not by handle
- Fix opening of mixer devices
- Waveformat struct is only provided when type is wave device
- Implement wave reset routine, fixes audio recording on ReactOS SndRec, AudaCity etc. Also fixes random hang in WinAmp when skipping audio bytes
- Implement wave pausing / restarting, should lead to smoother playback
[MMIXER]
- Merge from audio branch
- Tons of fixes to enumeration of mixerlines, controls / etc
- Fix mixer event notification callbacks
- For more info, read audio-bringup log


svn path=/trunk/; revision=50528
This commit is contained in:
Johannes Anderwald 2011-01-28 10:17:01 +00:00
commit 269e92c794
14 changed files with 1781 additions and 266 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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)
{

View file

@ -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;
}

View file

@ -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,

View file

@ -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);

View file

@ -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;
}

View file

@ -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,

View file

@ -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,