Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2564 lines
82 KiB

//---------------------------------------------------------------------------
//
// Module: kmxluser.c
//
// Description:
// Contains the handlers for the ring 3 mixer line api functions.
//
//
//@@BEGIN_MSINTERNAL
// Development Team:
// D. Baumberger
//
// History: Date Author Comment
//
//@@END_MSINTERNAL
//
//---------------------------------------------------------------------------
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
//
//---------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// //
// I N C L U D E S //
// //
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
#include "WDMSYS.H"
FAST_MUTEX ReferenceCountMutex;
ULONG ReferenceCount = 0;
#define NOT16( di ) if( di->dwFormat == ANSI_TAG ) DPF(DL_WARNING|FA_USER,("Invalid dwFormat.") );
#pragma PAGEABLE_CODE
///////////////////////////////////////////////////////////////////////
//
// kmxlInitializeMixer
//
// Queries SysAudio to find the number of devices and builds the mixer
// line structures for each of those devices.
//
//
NTSTATUS
kmxlInitializeMixer(
PWDMACONTEXT pWdmaContext,
PCWSTR DeviceInterface,
ULONG cDevices
)
{
NTSTATUS Status;
ULONG Device;
BOOLEAN Error = FALSE;
// PFILE_OBJECT pfo;
PMIXERDEVICE pmxd;
PAGED_CODE();
ExInitializeFastMutex( &ReferenceCountMutex );
DPF(DL_TRACE|FA_USER, ("Found %d mixer devices for DI: %ls", cDevices, DeviceInterface));
//
// Current limitation is MAXNUMDEVS. If more devices are supported
// than that, limit it to the first MAXNUMDEVS.
//
if( cDevices > MAXNUMDEVS ) {
cDevices = MAXNUMDEVS;
}
for( Device = 0; Device < cDevices; Device++ ) {
DWORD TranslatedDeviceNumber;
TranslatedDeviceNumber =
wdmaudTranslateDeviceNumber(pWdmaContext,
MixerDevice,
DeviceInterface,
Device);
if(TranslatedDeviceNumber == MAXULONG) {
continue;
}
pmxd = &pWdmaContext->MixerDevs[ TranslatedDeviceNumber ];
//
// Open SysAudio
//
DPFASSERT(pmxd->pfo == NULL);
pmxd->pfo = kmxlOpenSysAudio();
if( pmxd->pfo == NULL ) {
DPF(DL_WARNING|FA_USER,( "failed to open SYSAUDIO!" ) );
RETURN( STATUS_UNSUCCESSFUL );
}
//
// Set the current device instance in SysAudio.
//
Status = SetSysAudioProperty(
pmxd->pfo,
KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE,
sizeof( pmxd->Device ),
&pmxd->Device
);
if( !NT_SUCCESS( Status ) ) {
DPF(DL_WARNING|FA_USER, ( "failed to set SYSAUDIO device instance" ) );
// DPF(DL_ERROR|FA_ALL,("If fo is NULL, we must exit here!") );
kmxlCloseSysAudio( pmxd->pfo );
pmxd->pfo=NULL;
Error = TRUE;
} else {
//
// Initialize the topology for this device
//
Status = kmxlInit( pmxd->pfo, pmxd );
if( !NT_SUCCESS( Status ) ) {
DPF(DL_WARNING|FA_USER, ( "failed to initialize topology for device %d (%x)!",
TranslatedDeviceNumber, Status ) );
Error = TRUE;
} else {
//
// Here we want to optimize out the restoring of values on the mixer
// device. If we find that there is another mixer device in some
// other open context, then we will NOT call kmxlRetrieveAll to
// set the values on the device.
//
DPF(DL_TRACE|FA_USER,( "Looking for Mixer: %S",pmxd->DeviceInterface ) );
if( !NT_SUCCESS(EnumFsContext( HasMixerBeenInitialized, pmxd, pWdmaContext )) )
{
//
// Here we find that this device was not found, thus this is
// the first time through. Set the defaults here.
//
DPF(DL_TRACE|FA_USER,( "Did not find Mixer - initializing: %S",pmxd->DeviceInterface ) );
kmxlRetrieveAll( pmxd->pfo, pmxd );
} else {
DPF(DL_TRACE|FA_USER,( "Found Mixer: %S",pmxd->DeviceInterface ) );
}
}
}
}
if( Error ) {
RETURN( STATUS_UNSUCCESSFUL );
} else {
return( STATUS_SUCCESS );
}
}
//
// This routine looks in the WDMACONTEXT structure to see if this mixer device
// has already been initialized. It does this by walking the MixerDevice list and
// checking to see if there are any devices that match this mixer devices's
// DeviceInterface string. If it finds that there is a match, it routines
// STATUS_SUCCESS, else it returns STATUS_MORE_ENTRIES so that the enum function
// will call it again until the list is empty.
//
NTSTATUS
HasMixerBeenInitialized(
PWDMACONTEXT pContext,
PVOID pvoidRefData,
PVOID pvoidRefData2
)
{
NTSTATUS Status;
PMIXERDEVICE pmxdMatch;
PMIXERDEVICE pmxd;
DWORD TranslatedDeviceNumber;
ULONG Device;
PWDMACONTEXT pCurContext;
//
// Default is that we did not find this entry in the list.
//
Status = STATUS_MORE_ENTRIES;
//
// The reference data is a PMIXERDEVICE.
//
pmxdMatch = (PMIXERDEVICE)pvoidRefData;
pCurContext = (PWDMACONTEXT)pvoidRefData2;
if( pCurContext != pContext )
{
for( Device = 0; Device < MAXNUMDEVS; Device++ )
{
//
// If this mixer device translates, that means that it can
// be found in this context.
//
TranslatedDeviceNumber =
wdmaudTranslateDeviceNumber(pContext,
MixerDevice,
pmxdMatch->DeviceInterface,
Device);
//
// If it doesn't, we'll keep looking.
//
if( MAXULONG != TranslatedDeviceNumber )
{
DPF(DL_TRACE|FA_USER,( "Found Mixer: %S",pmxdMatch->DeviceInterface ) );
Status = STATUS_SUCCESS;
break;
}
}
} else {
DPF(DL_TRACE|FA_USER,( "Same context: %x",pCurContext ) );
}
return Status;
}
///////////////////////////////////////////////////////////////////////
//
// kmxlOpenHandler
//
// Handles the MXDM_OPEN message. Copies the callback info from the
// caller and opens an instance of SysAudio set to the device number
// the caller has selected.
//
//
NTSTATUS
kmxlOpenHandler(
IN PWDMACONTEXT pWdmaContext,
IN LPDEVICEINFO DeviceInfo, // Info structure
IN LPVOID DataBuffer // Unused
)
{
NTSTATUS Status = STATUS_SUCCESS;
PMIXERDEVICE pmxd;
PAGED_CODE();
ASSERT( DeviceInfo );
//
// BUGBUG: we should not need this any more!
//
ASSERT( DeviceInfo->dwInstance == 0 );
pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
if( pmxd == NULL ) {
goto exit;
}
DPF(DL_TRACE|FA_INSTANCE,( "param=( %d ) = pmxd = %X",
DeviceInfo->DeviceNumber,pmxd));
ExAcquireFastMutex( &ReferenceCountMutex );
++ReferenceCount;
ExReleaseFastMutex( &ReferenceCountMutex );
DeviceInfo->mmr = MMSYSERR_NOERROR;
exit:
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlCloseHandler
//
// Handles the MXDM_CLOSE message. Clears the callback info and
// closes the handle to SysAudio.
//
//
NTSTATUS
kmxlCloseHandler(
IN LPDEVICEINFO DeviceInfo, // Info structure
IN LPVOID DataBuffer // Unused
)
{
PAGED_CODE();
ASSERT( DeviceInfo );
ASSERT( DeviceInfo->dwInstance );
DPF(DL_TRACE|FA_INSTANCE,( "kmxlCloseHandler"));
ExAcquireFastMutex( &ReferenceCountMutex );
--ReferenceCount;
ExReleaseFastMutex( &ReferenceCountMutex );
DeviceInfo->mmr = MMSYSERR_NOERROR;
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlGetLineInfoHandler
//
// Handles the MXDM_GETLINEINFO message. Determines which query
// is requested by looking at dwFlags and performs that query.
//
//
NTSTATUS
kmxlGetLineInfoHandler(
IN PWDMACONTEXT pWdmaContext,
IN LPDEVICEINFO DeviceInfo, // Device Info structure
IN LPVOID DataBuffer // MIXERLINE(16) to fill
)
{
MIXERLINE ml;
PAGED_CODE();
ASSERT( DeviceInfo );
if( DataBuffer == NULL ) {
DPF(DL_WARNING|FA_USER,( "DataBuffer is NULL" ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
ml.cbStruct = sizeof( MIXERLINE );
switch( DeviceInfo->dwFlags & MIXER_GETLINEINFOF_QUERYMASK ) {
///////////////////////////////////////////////////////////////
case MIXER_GETLINEINFOF_COMPONENTTYPE:
///////////////////////////////////////////////////////////////
// Valid fields: //
// cbStruct //
// dwComponentType //
///////////////////////////////////////////////////////////////
NOT16( DeviceInfo );
ml.cbStruct = sizeof( MIXERLINE );
ml.dwComponentType = ( (LPMIXERLINE) DataBuffer) ->dwComponentType;
DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoByComponent( %s )",
ComponentTypeToString( ml.dwComponentType ) ));
return( kmxlGetLineInfoByComponent( pWdmaContext,
DeviceInfo,
DataBuffer,
ml.dwComponentType
)
);
///////////////////////////////////////////////////////////////
case MIXER_GETLINEINFOF_DESTINATION:
///////////////////////////////////////////////////////////////
// Valid fields: //
// cbStruct //
// dwDestination //
///////////////////////////////////////////////////////////////
NOT16( DeviceInfo );
ml.dwDestination = ( (LPMIXERLINE) DataBuffer)->dwDestination;
DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoById( S=%08X, D=%08X )",
-1, ml.dwDestination ));
return( kmxlGetLineInfoByID( pWdmaContext,
DeviceInfo,
DataBuffer,
(WORD) -1,
(WORD) ml.dwDestination ) );
///////////////////////////////////////////////////////////////
case MIXER_GETLINEINFOF_LINEID:
///////////////////////////////////////////////////////////////
// Valid fields: //
// cbStruct //
// dwLineID //
///////////////////////////////////////////////////////////////
NOT16( DeviceInfo );
ml.dwLineID = ( (LPMIXERLINE) DataBuffer)->dwLineID;
DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoById( S=%08X, D=%08X )",
HIWORD( ml.dwLineID ), LOWORD( ml.dwLineID ) ));
return( kmxlGetLineInfoByID( pWdmaContext,
DeviceInfo,
DataBuffer,
HIWORD( ml.dwLineID ),
LOWORD( ml.dwLineID ) ) );
///////////////////////////////////////////////////////////////
case MIXER_GETLINEINFOF_SOURCE:
///////////////////////////////////////////////////////////////
// Valid fields: //
// cbStruct //
// dwSource //
// dwDestination //
///////////////////////////////////////////////////////////////
NOT16( DeviceInfo );
ml.dwSource = ( (LPMIXERLINE) DataBuffer)->dwSource;
ml.dwDestination = ( (LPMIXERLINE) DataBuffer)->dwDestination;
DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoById( S=%08X, D=%08X )",
ml.dwSource, ml.dwDestination ));
return( kmxlGetLineInfoByID( pWdmaContext,
DeviceInfo,
DataBuffer,
(WORD) ml.dwSource,
(WORD) ml.dwDestination ) );
///////////////////////////////////////////////////////////////
case MIXER_GETLINEINFOF_TARGETTYPE:
///////////////////////////////////////////////////////////////
// Valid fields: //
// cbStruct //
// Target.dwType //
// Target.wMid //
// Target.wPid //
// Target.vDriverVersion //
// Target.szPname //
///////////////////////////////////////////////////////////////
NOT16( DeviceInfo );
ml.Target.dwType = ((LPMIXERLINE) DataBuffer)->Target.dwType;
DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoByType( %x -- %s )",
ml.Target.dwType,
TargetTypeToString( ml.Target.dwType ) ));
return( kmxlGetLineInfoByType( pWdmaContext,
DeviceInfo,
DataBuffer,
ml.Target.dwType ) );
///////////////////////////////////////////////////////////////
default:
///////////////////////////////////////////////////////////////
DPF(DL_WARNING|FA_USER,( "invalid flags ( %x )", DeviceInfo->dwFlags ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
DPF(DL_WARNING|FA_USER,("Unmatched di->dwFlag") );
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlGetLineControlsHandler
//
// Handles the MXDM_GETLINECONTROLS message. Determines the query
// requested and finds the controls.
//
//
NTSTATUS
kmxlGetLineControlsHandler(
IN PWDMACONTEXT pWdmaContext,
IN LPDEVICEINFO DeviceInfo, // Device Info structure
IN LPVOID DataBuffer, // MIXERLINECONTROLS(16) to fill
IN LPVOID pamxctrl
)
{
PMIXERDEVICE pmxd;
PMXLLINE pLine;
PMXLCONTROL pControl;
ULONG Count;
DWORD dwLineID,
dwControlID,
dwControlType,
cControls,
cbmxctrl;
PAGED_CODE();
ASSERT( DeviceInfo );
//
// Check some pre-conditions so we don't blow up later.
//
if( DataBuffer == NULL ) {
DPF(DL_WARNING|FA_USER,( "DataBuffer is NULL!" ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
if( pamxctrl == NULL ) {
DPF(DL_WARNING|FA_USER,( "pamxctrl is NULL!" ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
if( DeviceInfo->DeviceNumber > MAXNUMDEVS ) {
DPF(DL_WARNING|FA_USER,( "device Id is invalid!" ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
//
// Get a instance reference
//
pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
if( pmxd == NULL ) {
return( STATUS_SUCCESS );
}
//
// Copy out some parameters necessary to find the controls
//
NOT16( DeviceInfo );
dwLineID = ((LPMIXERLINECONTROLS) DataBuffer)->dwLineID;
dwControlID = ((LPMIXERLINECONTROLS) DataBuffer)->dwControlID;
dwControlType = ((LPMIXERLINECONTROLS) DataBuffer)->dwControlType;
cControls = ((LPMIXERLINECONTROLS) DataBuffer)->cControls;
cbmxctrl = ((LPMIXERLINECONTROLS) DataBuffer)->cbmxctrl;
switch( DeviceInfo->dwFlags & MIXER_GETLINECONTROLSF_QUERYMASK ) {
///////////////////////////////////////////////////////////////
case MIXER_GETLINECONTROLSF_ALL:
///////////////////////////////////////////////////////////////
//
// Find the line that matches the dwLineID field
//
DPF(DL_TRACE|FA_USER,( "kmxlGetLineControls( ALL, %08X )",dwLineID ));
pLine = kmxlFindLine( pmxd, dwLineID );
if( pLine == NULL ) {
DPF(DL_WARNING|FA_USER,( "ALL - invalid line Id %x!",dwLineID ));
DeviceInfo->mmr = MIXERR_INVALLINE;
return( STATUS_SUCCESS );
}
//
// Loop through the controls, copying them into the user buffer.
//
Count = 0;
pControl = kmxlFirstInList( pLine->Controls );
while( pControl && Count < cControls ) {
NOT16( DeviceInfo );
RtlCopyMemory(
&((LPMIXERCONTROL) pamxctrl)[ Count ],
&pControl->Control,
min(cbmxctrl,sizeof(MIXERCONTROL)) );
pControl = kmxlNextControl( pControl );
++Count;
}
DeviceInfo->mmr = MMSYSERR_NOERROR;
return( STATUS_SUCCESS );
///////////////////////////////////////////////////////////////
case MIXER_GETLINECONTROLSF_ONEBYID:
///////////////////////////////////////////////////////////////
pControl = kmxlFindControl( pmxd, dwControlID );
pLine = kmxlFindLineForControl(
pControl,
pmxd->listLines
);
if( pLine == NULL ) {
DPF(DL_WARNING|FA_USER,( "ONEBYID - invalid control Id %x!", dwControlID ));
DeviceInfo->mmr = MIXERR_INVALCONTROL;
return( STATUS_SUCCESS );
}
DPF(DL_TRACE|FA_USER,( "kmxlGetLineControls( ONEBYID, Ctrl=%08X, Line=%08X )",
dwControlID, pLine->Line.dwLineID ));
if( pControl ) {
NOT16( DeviceInfo );
RtlCopyMemory((LPMIXERLINECONTROLS) pamxctrl,
&pControl->Control,
min(cbmxctrl,sizeof(MIXERCONTROL)) );
((PMIXERLINECONTROLS) DataBuffer)->dwLineID =
(DWORD) pLine->Line.dwLineID;
DeviceInfo->mmr = MMSYSERR_NOERROR;
return( STATUS_SUCCESS );
} else {
DPF(DL_WARNING|FA_USER,( "ONEBYID - invalid dwControlID %08X!", dwControlID ));
DeviceInfo->mmr = MIXERR_INVALCONTROL;
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////
case MIXER_GETLINECONTROLSF_ONEBYTYPE:
///////////////////////////////////////////////////////////////
//
// Find the line that matches the dwLineID field
//
pLine = kmxlFindLine( pmxd, dwLineID );
if( pLine == NULL ) {
DPF(DL_WARNING|FA_USER,( "ONEBYTYPE - invalid dwLineID %08X!", dwControlType ));
DeviceInfo->mmr = MIXERR_INVALLINE;
return( STATUS_SUCCESS );
}
DPF(DL_TRACE|FA_USER, ("kmxlGetLineControls( ONEBYTYPE, Type=%s, Line=%08X )",
ControlTypeToString( dwControlType ),
pLine->Line.dwLineID ));
//
// Now look through the controls and find the control that
// matches the type the caller has passed.
//
pControl = kmxlFirstInList( pLine->Controls );
while( pControl ) {
if( pControl->Control.dwControlType == dwControlType )
{
NOT16 ( DeviceInfo );
RtlCopyMemory((LPMIXERCONTROL) pamxctrl,
&pControl->Control,
min(cbmxctrl,sizeof(MIXERCONTROL)) );
DeviceInfo->mmr = MMSYSERR_NOERROR;
return( STATUS_SUCCESS );
}
pControl = kmxlNextControl( pControl );
}
DPF(DL_WARNING|FA_USER,( "(ONEBYTYPE,Type=%x,Line=%08X ) no such control type on line",
dwControlType, pLine->Line.dwLineID ));
DeviceInfo->mmr = MIXERR_INVALCONTROL;
return( STATUS_SUCCESS );
///////////////////////////////////////////////////////////////
default:
///////////////////////////////////////////////////////////////
DPF(DL_WARNING|FA_USER,( "invalid flags %x",DeviceInfo->dwFlags ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
}
///////////////////////////////////////////////////////////////////////
//
// kmxlGetControlDetailsHandler
//
// Determines which control is being queried and calls the appropriate
// handler to perform the get property.
//
//
NTSTATUS
kmxlGetControlDetailsHandler(
IN PWDMACONTEXT pWdmaContext,
IN LPDEVICEINFO DeviceInfo, // Device Info Structure
IN LPVOID DataBuffer, // MIXERCONTROLDETAILS structure
IN LPVOID paDetails // Flat pointer to details struct(s)
)
{
LPMIXERCONTROLDETAILS pmcd = (LPMIXERCONTROLDETAILS) DataBuffer;
PMXLCONTROL pControl;
PMIXERDEVICE pmxd;
NTSTATUS Status;
PMXLLINE pLine;
PAGED_CODE();
ASSERT( DeviceInfo );
pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
if( pmxd == NULL ) {
return( STATUS_SUCCESS );
}
pControl = kmxlFindControl( pmxd, pmcd->dwControlID );
if( pControl == NULL ) {
DPF(DL_WARNING|FA_USER,( "control %x not found",pmcd->dwControlID ));
DeviceInfo->mmr = MIXERR_INVALCONTROL;
return( STATUS_SUCCESS );
}
pLine = kmxlFindLineForControl(
pControl,
pmxd->listLines
);
if( pLine == NULL ) {
DPF(DL_WARNING|FA_USER,( "invalid control id %x!",pmcd->dwControlID ));
DeviceInfo->mmr = MIXERR_INVALCONTROL;
return( STATUS_SUCCESS );
}
if( ( pControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) &&
( pmcd->cChannels != 1 ) &&
( pControl->Control.dwControlType != MIXERCONTROL_CONTROLTYPE_MUX )) {
DPF(DL_WARNING|FA_USER,( "incorrect cChannels ( %d ) on UNIFORM control %x!",
pmcd->cChannels, pmcd->dwControlID ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
if( pmcd->cChannels > pLine->Line.cChannels ) {
DPF(DL_WARNING|FA_USER,( "incorrect number of channels( %d )!",pmcd->cChannels ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
if( pmcd->cMultipleItems != pControl->Control.cMultipleItems ) {
DPF(DL_WARNING|FA_USER,( "incorrect number of items( %d )!",pmcd->cMultipleItems ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
switch( DeviceInfo->dwFlags & MIXER_GETCONTROLDETAILSF_QUERYMASK ) {
///////////////////////////////////////////////////////////////
case MIXER_GETCONTROLDETAILSF_LISTTEXT:
///////////////////////////////////////////////////////////////
{
ULONG cMultipleItems;
LPMIXERCONTROLDETAILS_LISTTEXT lplt;
DPF(DL_TRACE|FA_USER,( "kmxlGetControlDetails( Ctrl=%d )",
pControl->Control.dwControlID ));
NOT16( DeviceInfo );
lplt = (LPMIXERCONTROLDETAILS_LISTTEXT) paDetails;
for( cMultipleItems = 0;
cMultipleItems < pmcd->cMultipleItems;
cMultipleItems++ )
{
RtlCopyMemory(
&lplt[ cMultipleItems ],
&pControl->Parameters.lpmcd_lt[ cMultipleItems ],
sizeof( MIXERCONTROLDETAILS_LISTTEXT )
);
}
}
DeviceInfo->mmr = MMSYSERR_NOERROR;
break;
///////////////////////////////////////////////////////////////
case MIXER_GETCONTROLDETAILSF_VALUE:
///////////////////////////////////////////////////////////////
switch( pControl->Control.dwControlType ) {
///////////////////////////////////////////////////////
case MIXERCONTROL_CONTROLTYPE_MIXER:
///////////////////////////////////////////////////////
DeviceInfo->mmr = MMSYSERR_NOTSUPPORTED;
DPF(DL_WARNING|FA_USER,( "mixers are not supported" ));
break;
///////////////////////////////////////////////////////
case MIXERCONTROL_CONTROLTYPE_PEAKMETER:
///////////////////////////////////////////////////////
Status = kmxlHandleGetUnsigned(
DeviceInfo,
pmxd,
pControl,
pControl->PropertyId,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
MIXER_FLAG_SCALE
);
break;
///////////////////////////////////////////////////////
case MIXERCONTROL_CONTROLTYPE_MUTE:
///////////////////////////////////////////////////////
if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_MUTE ) ) {
Status = kmxlHandleGetUnsigned(
DeviceInfo,
pmxd,
pControl,
KSPROPERTY_AUDIO_MUTE,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
0
);
} else if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_SUPERMIX ) ) {
Status = kmxlHandleGetMuteFromSuperMix(
DeviceInfo,
pmxd,
pControl,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
0
);
} else {
DPF(DL_WARNING|FA_USER,("Unmatched GUID") );
}
break;
///////////////////////////////////////////////////////
case MIXERCONTROL_CONTROLTYPE_VOLUME:
//////////////////////////////////////////////////////
#ifdef SUPERMIX_AS_VOL
if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_VOLUME ) ) {
#endif
Status = kmxlHandleGetUnsigned(
DeviceInfo,
pmxd,
pControl,
pControl->PropertyId,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
MIXER_FLAG_SCALE
);
#ifdef SUPERMIX_AS_VOL
} else if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_SUPERMIX ) ) {
Status = kmxlHandleGetVolumeFromSuperMix(
DeviceInfo,
pmxd,
pControl,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
MIXER_FLAG_SCALE
);
} else {
DPF(DL_WARNING|FA_USER,("Invalid GUID for Control.") );
}
#endif // SUPERMIX_AS_VOL
break;
///////////////////////////////////////////////////////
case MIXERCONTROL_CONTROLTYPE_TREBLE:
case MIXERCONTROL_CONTROLTYPE_BASS:
///////////////////////////////////////////////////////
// These all take 32-bit parameters per channel but //
// need to be scale from dB to linear //
///////////////////////////////////////////////////////
Status = kmxlHandleGetUnsigned(
DeviceInfo,
pmxd,
pControl,
pControl->PropertyId,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
MIXER_FLAG_SCALE
);
break;
///////////////////////////////////////////////////////
case MIXERCONTROL_CONTROLTYPE_LOUDNESS:
case MIXERCONTROL_CONTROLTYPE_ONOFF:
case MIXERCONTROL_CONTROLTYPE_BOOLEAN:
case MIXERCONTROL_CONTROLTYPE_MUX:
case MIXERCONTROL_CONTROLTYPE_FADER:
case MIXERCONTROL_CONTROLTYPE_BASS_BOOST:
///////////////////////////////////////////////////////
// These all take up to 32-bit parameters per channel//
///////////////////////////////////////////////////////
Status = kmxlHandleGetUnsigned(
DeviceInfo,
pmxd,
pControl,
pControl->PropertyId,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
0
);
break;
///////////////////////////////////////////////////////
default:
///////////////////////////////////////////////////////
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
break;
}
break;
///////////////////////////////////////////////////////////////
default:
///////////////////////////////////////////////////////////////
DeviceInfo->mmr = MMSYSERR_NOTSUPPORTED;
break;
}
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlSetControlDetailsHandler
//
// Determines which control is being set and calls the appropriate
// handler to perform the set property.
//
//
NTSTATUS
kmxlSetControlDetailsHandler(
IN PWDMACONTEXT pWdmaContext,
IN OUT LPDEVICEINFO DeviceInfo, // Device Info structure
IN LPVOID DataBuffer, // MIXERCONTROLDETAILS structure
IN LPVOID paDetails, // Flat pointer to detail struct(s)
IN ULONG Flags
)
{
LPMIXERCONTROLDETAILS pmcd = (LPMIXERCONTROLDETAILS) DataBuffer;
PMXLCONTROL pControl;
NTSTATUS Status;
PMIXERDEVICE pmxd;
PMXLLINE pLine;
PAGED_CODE();
ASSERT( DeviceInfo );
//
// Get a instance reference
//
pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
if( pmxd == NULL ) {
return( STATUS_SUCCESS );
}
pControl = kmxlFindControl( pmxd, pmcd->dwControlID );
if( pControl == NULL ) {
DPF(DL_WARNING|FA_USER,( "control %d not found",pmcd->dwControlID ));
DeviceInfo->mmr = MIXERR_INVALCONTROL;
return( STATUS_SUCCESS );
}
pLine = kmxlFindLineForControl(
pControl,
pmxd->listLines
);
if( pLine == NULL ) {
DPF(DL_WARNING|FA_USER,( "invalid control id %d",pControl->Control.dwControlID ));
DeviceInfo->mmr = MIXERR_INVALCONTROL;
return( STATUS_SUCCESS );
}
if( ( pControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) &&
( pmcd->cChannels != 1 ) &&
( pControl->Control.dwControlType != MIXERCONTROL_CONTROLTYPE_MUX )) {
DPF(DL_WARNING|FA_USER,( "incorrect cChannels ( %d ) on UNIFORM control %d",
pmcd->cChannels,
pControl->Control.dwControlID ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
if( pmcd->cChannels > pLine->Line.cChannels ) {
DPF(DL_WARNING|FA_USER,( "incorrect number of channels ( %d ) on line %08x",
pmcd->cChannels,
pLine->Line.dwLineID ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
if( pmcd->cMultipleItems != pControl->Control.cMultipleItems ) {
DPF(DL_WARNING|FA_USER,( "incorrect number of items ( %d ) on control %d ( %d )",
pmcd->cMultipleItems,
pControl->Control.dwControlID,
pControl->Control.cMultipleItems ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
switch( DeviceInfo->dwFlags & MIXER_SETCONTROLDETAILSF_QUERYMASK ) {
///////////////////////////////////////////////////////////////
case MIXER_SETCONTROLDETAILSF_VALUE:
///////////////////////////////////////////////////////////////
switch( pControl->Control.dwControlType ) {
///////////////////////////////////////////////////////
case MIXERCONTROL_CONTROLTYPE_MIXER:
///////////////////////////////////////////////////////
DeviceInfo->mmr = MMSYSERR_NOTSUPPORTED;
DPF(DL_WARNING|FA_USER,( "mixers are not supported" ));
break;
///////////////////////////////////////////////////////
case MIXERCONTROL_CONTROLTYPE_PEAKMETER:
///////////////////////////////////////////////////////
Status = kmxlHandleSetUnsigned(
DeviceInfo,
pmxd,
pControl,
pControl->PropertyId,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
Flags | MIXER_FLAG_SCALE
);
break;
///////////////////////////////////////////////////////
case MIXERCONTROL_CONTROLTYPE_MUTE:
///////////////////////////////////////////////////////
if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_MUTE ) ) {
Status = kmxlHandleSetUnsigned(
DeviceInfo,
pmxd,
pControl,
KSPROPERTY_AUDIO_MUTE,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
Flags
);
} else if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_SUPERMIX ) ) {
Status = kmxlHandleSetMuteFromSuperMix(
DeviceInfo,
pmxd,
pControl,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
Flags
);
} else {
DPF(DL_WARNING|FA_USER,("Invalid GUID for Control Type Mute.") );
}
kmxlNotifyLineChange(
DeviceInfo,
pmxd,
pLine,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails
);
break;
///////////////////////////////////////////////////////
case MIXERCONTROL_CONTROLTYPE_VOLUME:
///////////////////////////////////////////////////////
#ifdef SUPERMIX_AS_VOL
if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_VOLUME ) ) {
#endif // SUPERMIX_AS_VOL
Status = kmxlHandleSetUnsigned(
DeviceInfo,
pmxd,
pControl,
pControl->PropertyId,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
Flags | MIXER_FLAG_SCALE
);
#ifdef SUPERMIX_AS_VOL
} else if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_SUPERMIX ) ) {
Status = kmxlHandleSetVolumeFromSuperMix(
DeviceInfo,
pmxd,
pControl,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
Flags | MIXER_FLAG_SCALE
);
} else {
DPF(DL_WARNING|FA_USER,("Invalid GUID for Control Type Volume.") );
}
#endif
break;
///////////////////////////////////////////////////////
case MIXERCONTROL_CONTROLTYPE_TREBLE:
case MIXERCONTROL_CONTROLTYPE_BASS:
///////////////////////////////////////////////////////
// These all take 32-bit parameters per channel but //
// need to be scale from linear to dB //
///////////////////////////////////////////////////////
Status = kmxlHandleSetUnsigned(
DeviceInfo,
pmxd,
pControl,
pControl->PropertyId,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
Flags | MIXER_FLAG_SCALE
);
break;
///////////////////////////////////////////////////////
case MIXERCONTROL_CONTROLTYPE_LOUDNESS:
case MIXERCONTROL_CONTROLTYPE_ONOFF:
case MIXERCONTROL_CONTROLTYPE_BOOLEAN:
case MIXERCONTROL_CONTROLTYPE_MUX:
case MIXERCONTROL_CONTROLTYPE_FADER:
case MIXERCONTROL_CONTROLTYPE_BASS_BOOST:
///////////////////////////////////////////////////////
// These all take up to 32-bit parameters per channel//
///////////////////////////////////////////////////////
Status = kmxlHandleSetUnsigned(
DeviceInfo,
pmxd,
pControl,
pControl->PropertyId,
(LPMIXERCONTROLDETAILS) DataBuffer,
(LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
Flags
);
break;
///////////////////////////////////////////////////////
default:
///////////////////////////////////////////////////////
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
break;
}
break;
///////////////////////////////////////////////////////////////
default:
///////////////////////////////////////////////////////////////
DPF(DL_WARNING|FA_USER,( "invalid flags %x",DeviceInfo->dwFlags ));
DeviceInfo->mmr = MMSYSERR_NOTSUPPORTED;
break;
}
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlFindControl
//
//
PMXLCONTROL
kmxlFindControl(
IN PMIXERDEVICE pmxd, // The mixer instance to search
IN DWORD dwControlID // The control ID to find
)
{
PMXLLINE pLine;
PMXLCONTROL pControl;
PAGED_CODE();
pLine = kmxlFirstInList( pmxd->listLines );
while( pLine ) {
pControl = kmxlFirstInList( pLine->Controls );
while( pControl ) {
if( pControl->Control.dwControlID == dwControlID ) {
return( pControl );
}
pControl = kmxlNextControl( pControl );
}
pLine = kmxlNextLine( pLine );
}
return( NULL );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlFindLine
//
// For the given line ID, kmxlFindLine will find the matching
// MXLLINE structure for it.
//
//
PMXLLINE
kmxlFindLine(
IN PMIXERDEVICE pmxd,
IN DWORD dwLineID // The line ID to find
)
{
PMXLLINE pLine;
PAGED_CODE();
pLine = kmxlFirstInList( pmxd->listLines );
while( pLine ) {
if( pLine->Line.dwLineID == dwLineID ) {
return( pLine );
}
pLine = kmxlNextLine( pLine );
}
return( NULL );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlGetLineInfoByID
//
// Loops through the lines looking for a line that has a matching
// source and destination Id.
//
//
NTSTATUS
kmxlGetLineInfoByID(
IN PWDMACONTEXT pWdmaContext,
IN LPDEVICEINFO DeviceInfo, // Device Info structure
IN LPVOID DataBuffer, // MIXERLINE(16) structure
IN WORD Source, // Source line id
IN WORD Destination // Destination line id
)
{
PMIXERDEVICE pmxd;
PMXLLINE pLine;
BOOL bDestination;
PAGED_CODE();
ASSERT( DeviceInfo );
ASSERT( DataBuffer );
if( DeviceInfo->DeviceNumber > MAXNUMDEVS ) {
DPF(DL_WARNING|FA_USER,( "invalid device number %d",DeviceInfo->DeviceNumber ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
if( pmxd == NULL ) {
return( STATUS_SUCCESS );
}
//
// If the source is -1 (0xFFFF), then this line is a destination.
//
if( Source == (WORD) -1 ) {
bDestination = TRUE;
Source = 0;
} else {
bDestination = FALSE;
}
pLine = kmxlFirstInList( pmxd->listLines );
while( pLine ) {
if( ( bDestination &&
( pLine->Line.dwDestination == Destination ) &&
( pLine->Line.cConnections > 0 ) ) ||
( ( pLine->Line.dwSource == Source ) &&
( pLine->Line.dwDestination == Destination ) ) )
{
NOT16( DeviceInfo );
RtlCopyMemory((LPMIXERLINE) DataBuffer,
&pLine->Line,
sizeof( MIXERLINE ) );
DeviceInfo->mmr = MMSYSERR_NOERROR;
return( STATUS_SUCCESS );
}
pLine = kmxlNextLine( pLine );
}
//
// There are no lines for the device number.
//
DPF(DL_WARNING|FA_USER,( "no matching lines for (S=%08X, D=%08X)",
Source,
Destination ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlGetLineInfoByType
//
// Loops through all the lines looking for the first line that matches
// the Target type specified. Note that this will always only find the
// first one!
//
//
NTSTATUS
kmxlGetLineInfoByType(
IN PWDMACONTEXT pWdmaContext,
IN LPDEVICEINFO DeviceInfo, // Device info structure
IN LPVOID DataBuffer, // MIXERLINE(16) structure
IN DWORD dwType // Line type to search for
)
{
PMXLLINE pLine;
PMIXERDEVICE pmxd;
PAGED_CODE();
ASSERT( DeviceInfo );
ASSERT( DataBuffer );
if( DeviceInfo->DeviceNumber > MAXNUMDEVS ) {
DPF(DL_WARNING|FA_USER,( "invalid device id %x",DeviceInfo->DeviceNumber ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
if( pmxd == NULL ) {
return( STATUS_SUCCESS );
}
//
// Loop through all the lines looking for a line that has the
// specified target type. Note that this will only return the
// first one.
//
pLine = kmxlFirstInList( pmxd->listLines );
while( pLine ) {
if( pLine->Line.Target.dwType == dwType ) {
LPMIXERLINE lpMxl = (LPMIXERLINE) DataBuffer;
NOT16( DeviceInfo );
if( lpMxl->Target.wMid != pLine->Line.Target.wMid ) {
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
if( lpMxl->Target.wPid != pLine->Line.Target.wPid ) {
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
if( wcscmp( pLine->Line.Target.szPname, lpMxl->Target.szPname ) )
{
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
RtlCopyMemory((LPMIXERLINE) DataBuffer,
&pLine->Line,
sizeof( MIXERLINE ) );
DeviceInfo->mmr = MMSYSERR_NOERROR;
return( STATUS_SUCCESS );
}
pLine = kmxlNextLine( pLine );
}
//
// The line was not found. Return invalid parameter.
//
DPF(DL_WARNING|FA_USER,( "no matching line found for %x",dwType ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlGetLineInfoByComponent
//
// Loops through the list of lines looking for a line that has a matching
// dwComponentType. Note that this will always find only the first!
//
//
NTSTATUS
kmxlGetLineInfoByComponent(
IN PWDMACONTEXT pWdmaContext,
IN LPDEVICEINFO DeviceInfo, // Device Info structure
IN LPVOID DataBuffer, // MIXERLINE(16) structure
IN DWORD dwComponentType // Component type to search for
)
{
PMXLLINE pLine;
PMIXERDEVICE pmxd;
PAGED_CODE();
ASSERT( DeviceInfo );
ASSERT( DataBuffer );
if( DeviceInfo->DeviceNumber > MAXNUMDEVS ) {
DPF(DL_WARNING|FA_USER,( "invalid device id %x",DeviceInfo->DeviceNumber ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
if( pmxd == NULL ) {
return( STATUS_SUCCESS );
}
//
// Loop through all the lines looking for a line that has a component
// type matching what the user requested.
//
pLine = kmxlFirstInList( pmxd->listLines );
while( pLine ) {
if( pLine->Line.dwComponentType == dwComponentType ) {
//
// Copy the data into the user buffer
//
NOT16( DeviceInfo );
RtlCopyMemory((LPMIXERLINE) DataBuffer,
&pLine->Line,
sizeof( MIXERLINE ) );
DeviceInfo->mmr = MMSYSERR_NOERROR;
return( STATUS_SUCCESS );
}
pLine = kmxlNextLine( pLine );
}
DPF(DL_WARNING|FA_USER,( "no matching line found for type %x",dwComponentType ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlGetNumDestinations
//
// Returns the number of destinations stored in the mixer device
//
//
DWORD
kmxlGetNumDestinations(
IN PMIXERDEVICE pMixerDevice // The device
)
{
PAGED_CODE();
return( pMixerDevice->cDestinations );
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// //
// I N S T A N C E R O U T I N E S //
// //
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// kmxlReferenceInstance
//
// Determines if the dwInstance field of the DeviceInfo structure
// is valid. If not, it creates a valid instance and sets a
// reference count of 1 on it.
//
//
LONG nextinstanceid=0;
DWORD kmxlUniqueInstanceId(VOID)
{
PAGED_CODE();
// Update our next valid instance id. Do NOT allow zero.
// Since that is used to signal that we want to allocate
// a new instance.
if (0==InterlockedIncrement(&nextinstanceid))
InterlockedIncrement(&nextinstanceid);
return nextinstanceid;
}
/////////////////////////////////////////////////////////////////////////////
//
// kmxlReferenceMixerDevice
//
// This routine Translates the device number and makes sure that there is a
// open SysAudio PFILE_OBJECT in this mixier device. This will be the FILE_OBJECT
// that we use to talk to this mixer device.
//
// return: PMIXERDEVICE on success NULL otherwise.
//
PMIXERDEVICE
kmxlReferenceMixerDevice(
IN PWDMACONTEXT pWdmaContext,
IN OUT LPDEVICEINFO DeviceInfo // Device Information
)
{
NTSTATUS Status;
DWORD TranslatedDeviceNumber;
PMIXERDEVICE pmxd;
PAGED_CODE();
DPFASSERT(IsValidDeviceInfo(DeviceInfo));
TranslatedDeviceNumber =
wdmaudTranslateDeviceNumber(pWdmaContext,
DeviceInfo->DeviceType,
DeviceInfo->wstrDeviceInterface,
DeviceInfo->DeviceNumber);
if( TranslatedDeviceNumber == MAXULONG ) {
DPF(DL_WARNING|FA_INSTANCE,("Could not translate DeviceNumber! DT=%08X, DI=%08X, DN=%08X",
DeviceInfo->DeviceType,
DeviceInfo->wstrDeviceInterface,
DeviceInfo->DeviceNumber) );
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( NULL );
}
pmxd = &pWdmaContext->MixerDevs[ TranslatedDeviceNumber ];
if( pmxd->pfo == NULL )
{
DPF(DL_WARNING|FA_NOTE,("pmxd->pfo should have been set!") );
//
// This is the first time through this code. Open SysAudio on this device
// and set the mixer device.
//
// set the SysAudio file object
if( NULL==(pmxd->pfo=kmxlOpenSysAudio())) {
DPF(DL_WARNING|FA_INSTANCE,("OpenSysAudio failed") );
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( NULL );
}
Status = SetSysAudioProperty(
pmxd->pfo,
KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE,
sizeof( pmxd->Device ),
&pmxd->Device
);
if( !NT_SUCCESS( Status ) ) {
kmxlCloseSysAudio( pmxd->pfo );
pmxd->pfo=NULL;
DPF(DL_WARNING|FA_INSTANCE,("SetSysAudioProperty DEVICE_INSTANCE failed %X",Status) );
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( NULL );
}
}
//
// BUGBUG: we should not need this any more.
//
DeviceInfo->dwInstance=kmxlUniqueInstanceId();;
return pmxd;
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// //
// G E T / S E T D E T A I L H A N D L E R S //
// //
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//
// kmxlIsSpeakerDestinationVolume
//
// Returns TRUE if the control is a volume control on the Speakers
// destination.
//
//
BOOL
kmxlIsSpeakerDestinationVolume(
IN PMIXERDEVICE pmxd, // The mixer
IN PMXLCONTROL pControl // The control to check
)
{
PMXLLINE pLine;
PAGED_CODE();
DPFASSERT( IsValidMixerDevice(pmxd) );
DPFASSERT( IsValidControl(pControl) );
//
// Find a line for this control. If none is found, then this can't
// be a destination volume.
//
pLine = kmxlFindLineForControl( pControl, pmxd->listLines );
if( !pLine ) {
return( FALSE );
}
if( pLine->Line.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS ) {
return( TRUE );
} else {
return( FALSE );
}
}
///////////////////////////////////////////////////////////////////////
//
// kmxlHandleGetUnsigned
//
//
// Handles getting an unsigned (32-bit) value for a control. Note
// that signed 32-bit and boolean values are also retrieved via this
// handler.
//
//
NTSTATUS
kmxlHandleGetUnsigned(
IN LPDEVICEINFO DeviceInfo,
IN PMIXERDEVICE pmxd,
IN PMXLCONTROL pControl,
IN ULONG ulProperty,
IN LPMIXERCONTROLDETAILS pmcd,
IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
IN ULONG Flags
)
{
NTSTATUS Status = STATUS_SUCCESS;
LONG Level;
DWORD dwLevel;
ULONG i;
ULONG Channel;
MIXERMAPPING Mapping = MIXER_MAPPING_LOGRITHMIC;
PAGED_CODE();
DPFASSERT( IsValidMixerDevice(pmxd) );
DPFASSERT( IsValidControl(pControl) );
if( paDetails == NULL ) {
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
//
// Use a different mapping algorithm if this is a speaker
// dest volume control.
//
if( kmxlIsSpeakerDestinationVolume( pmxd, pControl ) ) {
Mapping = pmxd->Mapping;
}
//
// Service the Mux
//
if ( pControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX) {
Status = kmxlGetNodeProperty(
pmxd->pfo,
&KSPROPSETID_Audio,
pControl->PropertyId,
pControl->Id,
0,
NULL,
&Level,
sizeof( Level )
);
if( !NT_SUCCESS( Status ) ) {
DPF(DL_WARNING|FA_USER,( "kmxlHandleGetUnsigned( Ctrl=%d, Id=%d ) failed GET on MUX with %x",
pControl->Control.dwControlID,
pControl->Id,
Status ));
DeviceInfo->mmr = MMSYSERR_ERROR;
return( STATUS_SUCCESS );
}
DPF(DL_TRACE|FA_USER,( "kmxlHandleGetUnsigned( Ctrl=%d, Id=%d ) = %d [1]",
pControl->Control.dwControlID,
pControl->Id,
Level ));
for( i = 0; i < pControl->Parameters.Count; i++ ) {
if( (ULONG) Level == pControl->Parameters.pPins[ i ] ) {
// APITRACE(( "1" ));
paDetails[ i ].dwValue = 1;
} else {
paDetails[ i ].dwValue = 0;
// APITRACE(( "1" ));
}
}
// APITRACE(( "]\n" ));
}
else {
paDetails->dwValue = 0; // initialize to zero for now so that the coalesced case works
// Loop over the channels for now. Fix this so that only one request is made.
Channel = 0;
do
{
Status = kmxlGetAudioNodeProperty(
pmxd->pfo,
ulProperty,
pControl->Id,
Channel,
NULL, 0, // No extra input bytes
&Level, sizeof( Level )
);
if ( !NT_SUCCESS( Status ) ) {
DPF(DL_TRACE|FA_USER,( "kmxlHandleGetUnsigned( Ctrl=%d [%s], Id=%d ) failed GET on MASTER channel with %x",
pControl->Control.dwControlID,
ControlTypeToString( pControl->Control.dwControlType ),
pControl->Id,
Status ));
DPF(DL_WARNING|FA_PROPERTY,
( "GetAudioNodeProp failed on MASTER channel with %X for %s!",
Status,
ControlTypeToString( pControl->Control.dwControlType ) ) );
DeviceInfo->mmr = MMSYSERR_ERROR;
return( STATUS_SUCCESS );
}
if ( pControl->bScaled ) {
dwLevel = kmxlVolLogToLinear( pControl, Level, Mapping, Channel );
} else {
dwLevel = (DWORD)Level;
}
if( ( pmcd->cChannels == 1 ) &&
!( pControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) ) {
//
// Coalesce values: If the user requests only 1 channel for a N channel
// control, then return the greatest channel value.
//
if (dwLevel > paDetails->dwValue) {
paDetails->dwValue = dwLevel;
}
} else if (Channel < pmcd->cChannels) {
paDetails[ Channel ].dwValue = dwLevel;
DPF(DL_TRACE|FA_USER,( "kmxlHandleGetUnsigned( Ctrl=%d, Id=%d ) returning (Chan#%d) = (%x)",
pControl->Control.dwControlID,
pControl->Id,
Channel,
paDetails[ Channel ].dwValue
));
} else {
// No need to keep trying
break;
}
Channel++;
} while ( Channel < pControl->NumChannels );
}
if( NT_SUCCESS( Status ) ) {
DeviceInfo->mmr = MMSYSERR_NOERROR;
} else {
DeviceInfo->mmr = MMSYSERR_ERROR;
}
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlHandleGetMuteFromSuperMix
//
// Handles getting the mute state from a supermix node.
//
NTSTATUS
kmxlHandleGetMuteFromSuperMix(
IN LPDEVICEINFO DeviceInfo,
IN PMIXERDEVICE pmxd,
IN PMXLCONTROL pControl,
IN LPMIXERCONTROLDETAILS pmcd,
IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
IN ULONG Flags
)
{
NTSTATUS Status;
ULONG i;
BOOL bMute = FALSE;
PAGED_CODE();
DPFASSERT( IsValidMixerDevice(pmxd) );
ASSERT( pControl );
ASSERT( pControl->Parameters.pMixCaps );
ASSERT( pControl->Parameters.pMixLevels );
//
// Read the current state of the supermix
//
Status = kmxlGetNodeProperty(
pmxd->pfo,
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
pControl->Id,
0,
NULL,
pControl->Parameters.pMixLevels,
pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
);
if( !NT_SUCCESS( Status ) ) {
DPF(DL_WARNING|FA_USER,( "kmxlHandleGetMuteFromSupermix ( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
pControl->Control.dwControlID,
ControlTypeToString( pControl->Control.dwControlType ),
pControl->Id,
Status
));
DeviceInfo->mmr = MMSYSERR_ERROR;
return( STATUS_SUCCESS );
}
for( i = 0; i < pControl->Parameters.Size; i++ ) {
if( pControl->Parameters.pMixLevels[ i ].Mute )
{
bMute = TRUE;
continue;
}
if( pControl->Parameters.pMixLevels[ i ].Level == LONG_MIN )
{
bMute = TRUE;
continue;
}
bMute = FALSE;
break;
}
paDetails->dwValue = (DWORD) bMute;
DeviceInfo->mmr = MMSYSERR_NOERROR;
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlHandleSetUnsigned
//
// Handles setting an unsigned (32-bit) value for a control. Note
// that signed 32-bit and boolean values are also set via this
// handler.
//
//
NTSTATUS
kmxlHandleSetUnsigned(
IN OUT LPDEVICEINFO DeviceInfo,
IN PMIXERDEVICE pmxd,
IN PMXLCONTROL pControl,
IN ULONG ulProperty,
IN LPMIXERCONTROLDETAILS pmcd,
IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
IN ULONG Flags
)
{
NTSTATUS Status = STATUS_SUCCESS;
LONG Level, Current;
DWORD dwValue;
BOOL bUniform, bEqual = TRUE;
ULONG i;
ULONG Channel;
MIXERMAPPING Mapping = MIXER_MAPPING_LOGRITHMIC;
PAGED_CODE();
DPFASSERT( IsValidMixerDevice(pmxd) );
ASSERT( pControl );
if( paDetails == NULL ) {
DPF(DL_WARNING|FA_USER,( "paDetails is NULL" ));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_INVALID_PARAMETER );
}
bUniform = ( pControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) ||
( pmcd->cChannels == 1 );
//
// Use a different mapping if this control is a speaker destination
// volume control.
//
if( kmxlIsSpeakerDestinationVolume( pmxd, pControl ) ) {
Mapping = pmxd->Mapping;
}
//
// Service the mux
//
if ( pControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX) {
// Proken APITRACE statement.
//DPF(DL_TRACE|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%d, " ));
// First validate the paDetails parameter and make sure it has the correct
// format. If not, then punt with an invalid parameter error.
{
LONG selectcount=0;
for( i = 0; i < pmcd->cMultipleItems; i++ ) {
if( paDetails[ i ].dwValue ) {
selectcount++;
// APITRACE(( "1" ));
} else {
// APITRACE(( "0" ));
}
}
if (selectcount!=1) {
DPF(DL_WARNING|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%d ) invalid paDetails parameter for SET on MUX",
pControl->Control.dwControlID,
ControlTypeToString( pControl->Control.dwControlType ),
pControl->Id));
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
return( STATUS_SUCCESS );
}
}
for( i = 0; i < pmcd->cMultipleItems; i++ ) {
if( paDetails[ i ].dwValue ) {
// APITRACE(( "1" ));
Level = pControl->Parameters.pPins[ i ];
} else {
// APITRACE(( "0" ));
}
}
// APITRACE(( " ). Setting pin %d on MUX.\n", Level ));
Status = kmxlSetNodeProperty(
pmxd->pfo,
&KSPROPSETID_Audio,
pControl->PropertyId,
pControl->Id,
0,
NULL,
&Level,
sizeof( Level )
);
if( !NT_SUCCESS( Status ) ) {
DPF(DL_WARNING|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%d ) failed SET on MUX with %x",
pControl->Control.dwControlID,
ControlTypeToString( pControl->Control.dwControlType ),
pControl->Id,
Status ));
DeviceInfo->mmr = MMSYSERR_ERROR;
return( STATUS_SUCCESS );
}
bEqual = FALSE;
}
else {
// Loop over the channels for now. Fix this so that only one request is made.
Channel = 0;
do
{
if( bUniform ) {
//
// Some controls are mono in the eyes of SNDVOL but are in
// fact stereo. This hack fixes this problem.
//
dwValue = paDetails[ 0 ].dwValue;
} else if (Channel < pmcd->cChannels) {
dwValue = paDetails[ Channel ].dwValue;
} else {
// No need to keep trying
break;
}
if( pControl->bScaled ) {
Level = kmxlVolLinearToLog( pControl, dwValue, Mapping, Channel );
} else {
Level = (LONG)dwValue;
}
Status = kmxlGetAudioNodeProperty(
pmxd->pfo,
ulProperty,
pControl->Id,
Channel,
NULL, 0, // No extra input bytes
&Current, sizeof( Current )
);
if( !NT_SUCCESS( Status ) ) {
DPF(DL_WARNING|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%d ) failed GET on channel %d with %x",
pControl->Control.dwControlID,
ControlTypeToString( pControl->Control.dwControlType ),
pControl->Id,
Channel,
Status ));
DeviceInfo->mmr = MMSYSERR_ERROR;
return( STATUS_SUCCESS );
}
if( Level != Current ) {
bEqual = FALSE;
Status = kmxlSetAudioNodeProperty(
pmxd->pfo,
ulProperty,
pControl->Id,
Channel,
NULL, 0, // No extra input bytes
&Level, sizeof( Level )
);
if( !NT_SUCCESS( Status ) ) {
DPF(DL_WARNING|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%x ) failed SET on channel %d with %x",
pControl->Control.dwControlID,
ControlTypeToString( pControl->Control.dwControlType ),
pControl->Id,
Channel,
Status ));
DeviceInfo->mmr = MMSYSERR_ERROR;
return( STATUS_SUCCESS );
}
DPF(DL_TRACE|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d, Id=%d ) using (%x) on Chan#%d",
pControl->Control.dwControlID,
pControl->Id,
paDetails[ Channel ].dwValue,
Channel
));
}
Channel++;
} while ( Channel < pControl->NumChannels );
}
if( NT_SUCCESS( Status ) ) {
DeviceInfo->mmr = MMSYSERR_NOERROR;
if( Flags & MIXER_FLAG_PERSIST ) {
kmxlPersistControl(
pmxd->pfo,
pmxd,
pControl,
paDetails
);
}
if( !bEqual && !( Flags & MIXER_FLAG_NOCALLBACK ) ) {
kmxlNotifyControlChange( DeviceInfo, pmxd, pControl );
}
} else {
DeviceInfo->mmr = MMSYSERR_ERROR;
}
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlHandleSetMuteFromSuperMix
//
// Handles setting the mute state using a supermixer.
//
//
NTSTATUS
kmxlHandleSetMuteFromSuperMix(
IN OUT LPDEVICEINFO DeviceInfo,
IN PMIXERDEVICE pmxd,
IN PMXLCONTROL pControl,
IN LPMIXERCONTROLDETAILS pmcd,
IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
IN ULONG Flags
)
{
NTSTATUS Status;
ULONG i;
PAGED_CODE();
DPFASSERT( IsValidMixerDevice(pmxd) );
ASSERT( pControl );
ASSERT( pControl->Parameters.pMixCaps );
ASSERT( pControl->Parameters.pMixLevels );
if( paDetails->dwValue ) {
//
// Query the current values from the supermix and save those away.
// These values will be used to restore the supermix to the state
// we found it prior to muting.
//
Status = kmxlGetNodeProperty(
pmxd->pfo,
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
pControl->Id,
0,
NULL,
pControl->Parameters.pMixLevels,
pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
);
if( !NT_SUCCESS( Status ) ) {
DPF(DL_WARNING|FA_USER,( "kmxlHandleSetMuteFromSuperMix( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
pControl->Control.dwControlID,
ControlTypeToString( pControl->Control.dwControlType ),
pControl->Id,
Status ));
DeviceInfo->mmr = MMSYSERR_ERROR;
return( STATUS_SUCCESS );
}
//
// For any entry in the table that supports muting, mute it.
//
for( i = 0; i < pControl->Parameters.Size; i++ ) {
if( pControl->Parameters.pMixCaps->Capabilities[ i ].Mute ) {
pControl->Parameters.pMixLevels[ i ].Mute = TRUE;
}
}
//
// Set this new supermixer state.
//
Status = kmxlSetNodeProperty(
pmxd->pfo,
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
pControl->Id,
0,
NULL,
pControl->Parameters.pMixLevels,
pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
);
if( !NT_SUCCESS( Status ) ) {
DPF(DL_WARNING|FA_USER,( "kmxlHandleSetMuteFromSuperMix( Ctrl=%d [%s], Id=%d ) failed SET on MIX_LEVEL_TABLE with %x",
pControl->Control.dwControlID,
ControlTypeToString( pControl->Control.dwControlType ),
pControl->Id,
Status ));
DeviceInfo->mmr = MMSYSERR_ERROR;
return( STATUS_SUCCESS );
}
} else {
Status = kmxlGetNodeProperty(
pmxd->pfo,
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
pControl->Id,
0,
NULL,
pControl->Parameters.pMixLevels,
pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
);
if( !NT_SUCCESS( Status ) ) {
DPF(DL_WARNING|FA_USER,( "kmxlHandleSetMuteFromSuperMix( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
pControl->Control.dwControlID,
ControlTypeToString( pControl->Control.dwControlType ),
pControl->Id,
Status ));
DeviceInfo->mmr = MMSYSERR_ERROR;
return( STATUS_SUCCESS );
}
//
// For any entry in the table that supports muting, mute it.
//
for( i = 0; i < pControl->Parameters.Size; i++ ) {
if( pControl->Parameters.pMixCaps->Capabilities[ i ].Mute ) {
pControl->Parameters.pMixLevels[ i ].Mute = FALSE;
}
}
//
// Set this new supermixer state.
//
Status = kmxlSetNodeProperty(
pmxd->pfo,
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
pControl->Id,
0,
NULL,
pControl->Parameters.pMixLevels,
pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
);
if( !NT_SUCCESS( Status ) ) {
DPF(DL_WARNING|FA_USER,( "kmxlHandleSetMuteFromSuperMix( Ctrl=%d [%s], Id=%d ) failed SET on MIX_LEVEL_TABLE with %x",
pControl->Control.dwControlID,
ControlTypeToString( pControl->Control.dwControlType ),
pControl->Id,
Status ));
DeviceInfo->mmr = MMSYSERR_ERROR;
return( STATUS_SUCCESS );
}
}
if( NT_SUCCESS( Status ) ) {
if( Flags & MIXER_FLAG_PERSIST ) {
kmxlPersistControl(
pmxd->pfo,
pmxd,
pControl,
paDetails
);
}
kmxlNotifyControlChange( DeviceInfo, pmxd, pControl );
DeviceInfo->mmr = MMSYSERR_NOERROR;
} else {
DeviceInfo->mmr = MMSYSERR_ERROR;
}
return( STATUS_SUCCESS );
}
#ifdef SUPERMIX_AS_VOL
///////////////////////////////////////////////////////////////////////
//
// kmxlHandleGetVolumeFromSuperMix
//
//
NTSTATUS
kmxlHandleGetVolumeFromSuperMix(
IN LPDEVICEINFO DeviceInfo,
IN PMIXERDEVICE pmxd,
IN PMXLCONTROL pControl,
IN LPMIXERCONTROLDETAILS pmcd,
IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
IN ULONG Flags
)
{
NTSTATUS Status;
ULONG i, Channels, Index, MaxChannel = 0;
LONG Max = LONG_MIN; // -Inf dB
PAGED_CODE();
DPFASSERT( IsValidMixerDevice(pmxd) );
ASSERT( pControl );
ASSERT( pmcd );
ASSERT( paDetails );
Status = kmxlGetNodeProperty(
pmxd->pfo,
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
pControl->Id,
0,
NULL,
pControl->Parameters.pMixLevels,
pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
);
if( !NT_SUCCESS( Status ) ) {
DPF(DL_WARNING|FA_USER,( "kmxlHandleGetVolumeFromSuperMix( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
pControl->Control.dwControlID,
ControlTypeToString( pControl->Control.dwControlType ),
pControl->Id,
Status ));
DeviceInfo->mmr = MMSYSERR_ERROR;
return( STATUS_SUCCESS );
}
//
// Count the number of channels
//
for( i = 0, Channels = 0;
i < pControl->Parameters.Size;
i += pControl->Parameters.pMixCaps->OutputChannels + 1,
Channels++ )
{
if( pControl->Parameters.pMixLevels[ i ].Level > Max ) {
Max = pControl->Parameters.pMixLevels[ i ].Level;
MaxChannel = Channels;
}
}
//
// Return the translated volume levels
//
if( ( pmcd->cChannels == 1 ) && ( Channels > 1 ) ) {
//
// As per SB16 sample, if the caller wants only 1 channel but
// the control is multichannel, return the maximum of all the
// channels.
//
paDetails->dwValue = kmxlVolLogToLinear(
pControl,
Max,
MIXER_MAPPING_LOGRITHMIC,
MaxChannel
);
} else {
//
// Translate each of the channel value into linear and
// store them away.
//
for( i = 0; i < pmcd->cChannels; i++ ) {
Index = i * ( pControl->Parameters.pMixCaps->OutputChannels + 1 );
paDetails[ i ].dwValue = kmxlVolLogToLinear(
pControl,
pControl->Parameters.pMixLevels[ Index ].Level,
MIXER_MAPPING_LOGRITHMIC,
i
);
}
}
DeviceInfo->mmr = MMSYSERR_NOERROR;
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////////////
//
// kmxlHandleSetVolumeFromSuperMix
//
//
NTSTATUS
kmxlHandleSetVolumeFromSuperMix(
IN LPDEVICEINFO DeviceInfo,
IN PMIXERDEVICE pmxd,
IN PMXLCONTROL pControl,
IN LPMIXERCONTROLDETAILS pmcd,
IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
IN ULONG Flags
)
{
NTSTATUS Status;
ULONG i, Index;
PAGED_CODE();
DPFASSERT( IsValidMixerDevice(pmxd) );
ASSERT( pControl );
ASSERT( pmcd );
ASSERT( paDetails );
//
// Query the current values for the mix levels.
//
Status = kmxlGetNodeProperty(
pmxd->pfo,
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
pControl->Id,
0,
NULL,
pControl->Parameters.pMixLevels,
pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
);
if( !NT_SUCCESS( Status ) ) {
DPF(DL_WARNING|FA_USER,( "kmxlHandleSetVolumeFromSuperMix( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
pControl->Control.dwControlID,
ControlTypeToString( pControl->Control.dwControlType ),
pControl->Id,
Status ));
DeviceInfo->mmr = MMSYSERR_ERROR;
return( STATUS_SUCCESS );
}
//
// Adjust the values on the diagonal to those the user specified.
//
for( i = 0; i < pmcd->cChannels; i++ ) {
Index = i * ( pControl->Parameters.pMixCaps->OutputChannels + 1 );
pControl->Parameters.pMixLevels[ Index ].Level = kmxlVolLinearToLog(
pControl,
paDetails[ i ].dwValue,
MIXER_MAPPING_LOGRITHMIC,
i
);
}
//
// Set these new values.
//
Status = kmxlSetNodeProperty(
pmxd->pfo,
&KSPROPSETID_Audio,
KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
pControl->Id,
0,
NULL,
pControl->Parameters.pMixLevels,
pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
);
if( NT_SUCCESS( Status ) ) {
DeviceInfo->mmr = MMSYSERR_NOERROR;
} else {
DPF(DL_WARNING|FA_USER,( "kmxlHandleSetVolumeFromSuperMix( Ctrl=%d [%s], Id=%d ) failed SET on MIX_LEVEL_TABLE with %x",
pControl->Control.dwControlID,
ControlTypeToString( pControl->Control.dwControlType ),
pControl->Id,
Status ));
DeviceInfo->mmr = MMSYSERR_ERROR;
}
return( STATUS_SUCCESS );
}
#endif // SUPERMIX_AS_VOL
///////////////////////////////////////////////////////////////////////
//
// kmxlNotifyLineChange
//
//
VOID
kmxlNotifyLineChange(
OUT LPDEVICEINFO DeviceInfo,
IN PMIXERDEVICE pmxd,
IN PMXLLINE pLine,
IN LPMIXERCONTROLDETAILS_UNSIGNED paDetails
)
{
PAGED_CODE();
ASSERT( (DeviceInfo->dwCallbackType&MIXER_LINE_CALLBACK) == 0 );
DeviceInfo->dwLineID=pLine->Line.dwLineID;
DeviceInfo->dwCallbackType|=MIXER_LINE_CALLBACK;
}
///////////////////////////////////////////////////////////////////////
//
// kmxlNotifyControlChange
//
//
VOID
kmxlNotifyControlChange(
OUT LPDEVICEINFO DeviceInfo,
IN PMIXERDEVICE pmxd,
IN PMXLCONTROL pControl
)
{
WRITE_CONTEXT* pwc;
PAGED_CODE();
//
// If there are no open instances, there is no reason to even attempt
// a callback... no one is listening.
//
ExAcquireFastMutex( &ReferenceCountMutex );
if( ReferenceCount == 0 ) {
ExReleaseFastMutex( &ReferenceCountMutex );
return;
}
ExReleaseFastMutex( &ReferenceCountMutex );
{
PMXLLINE pLine;
PMXLCONTROL pCtrl;
LONG callbackcount;
callbackcount=0;
pLine = kmxlFirstInList( pmxd->listLines );
while( pLine ) {
pCtrl = kmxlFirstInList( pLine->Controls );
while( pCtrl ) {
if ( pCtrl->Id == pControl->Id ) {
//ASSERT( (DeviceInfo->dwCallbackType&MIXER_CONTROL_CALLBACK) == 0 );
ASSERT( callbackcount < MAXCALLBACKS );
if ( callbackcount < MAXCALLBACKS ) {
(DeviceInfo->dwID)[callbackcount++]=pCtrl->Control.dwControlID;
}
DeviceInfo->dwCallbackType|=MIXER_CONTROL_CALLBACK;
}
pCtrl = kmxlNextControl( pCtrl );
}
pLine = kmxlNextLine( pLine );
}
DeviceInfo->ControlCallbackCount=callbackcount;
}
}