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