mirror of
https://github.com/reactos/reactos.git
synced 2024-07-06 20:55:16 +00:00
[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:
commit
269e92c794
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
6
reactos/lib/drivers/sound/mmixer/TODO
Normal file
6
reactos/lib/drivers/sound/mmixer/TODO
Normal 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
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,7 +108,6 @@ MMixerOpen(
|
|||
|
||||
/* store result */
|
||||
*MixerHandle = (HANDLE)MixerInfo;
|
||||
|
||||
return MM_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -114,12 +115,14 @@ MIXER_STATUS
|
|||
MMixerGetLineInfo(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
IN HANDLE MixerHandle,
|
||||
IN ULONG MixerId,
|
||||
IN ULONG Flags,
|
||||
OUT LPMIXERLINEW MixerLine)
|
||||
{
|
||||
MIXER_STATUS Status;
|
||||
LPMIXER_INFO MixerInfo;
|
||||
LPMIXERLINE_EXT MixerLineSrc;
|
||||
ULONG DestinationLineID;
|
||||
|
||||
/* verify mixer context */
|
||||
Status = MMixerVerifyContext(MixerContext);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
DPRINT1("MixerCaps Name %S MixerLineName %S Connections %lu dwSource %lu not found\n", MixerInfo->MixCaps.szPname, MixerLineSrc->Line.szName, MixerLineSrc->Line.cConnections, MixerLine->dwSource);
|
||||
return MM_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* calculate destination line id */
|
||||
DestinationLineID = (MixerLine->dwSource * SOURCE_LINE) + MixerLine->dwDestination;
|
||||
|
||||
DPRINT("MixerName %S cDestinations %lu MixerLineName %S cConnections %lu dwSource %lu dwDestination %lu ID %lx\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations,
|
||||
MixerLineSrc->Line.szName, MixerLineSrc->Line.cConnections,
|
||||
MixerLine->dwSource, MixerLine->dwDestination,
|
||||
DestinationLineID);
|
||||
/* get target destination line id */
|
||||
MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
|
||||
|
||||
/* sanity check */
|
||||
ASSERT(MixerLineSrc);
|
||||
|
||||
DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);
|
||||
|
||||
/* copy mixer line */
|
||||
MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));
|
||||
|
||||
/* make sure it is null terminated */
|
||||
MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
|
||||
MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
|
||||
MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';
|
||||
|
||||
/* done */
|
||||
return MM_STATUS_SUCCESS;
|
||||
}
|
||||
else if (Flags == MIXER_GETLINEINFOF_LINEID)
|
||||
{
|
||||
/* cast to mixer info */
|
||||
MixerInfo = (LPMIXER_INFO)MixerHandle;
|
||||
|
||||
/* try to find line */
|
||||
MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLine->dwLineID);
|
||||
if (!MixerLineSrc)
|
||||
{
|
||||
/* invalid parameter */
|
||||
DPRINT1("MMixerGetLineInfo: MixerName %S Line not found 0x%lx\n", MixerInfo->MixCaps.szPname, MixerLine->dwLineID);
|
||||
return MM_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* 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,27 +394,36 @@ 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
@ -150,6 +150,7 @@ MIXER_STATUS
|
|||
MMixerGetLineInfo(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue