diff options
Diffstat (limited to 'audio/sysvad/EndpointsCommon/MiniportAudioEngineNode.cpp')
| -rw-r--r-- | audio/sysvad/EndpointsCommon/MiniportAudioEngineNode.cpp | 1045 |
1 files changed, 1045 insertions, 0 deletions
diff --git a/audio/sysvad/EndpointsCommon/MiniportAudioEngineNode.cpp b/audio/sysvad/EndpointsCommon/MiniportAudioEngineNode.cpp new file mode 100644 index 00000000..db3fda39 --- /dev/null +++ b/audio/sysvad/EndpointsCommon/MiniportAudioEngineNode.cpp @@ -0,0 +1,1045 @@ +/*++ + +Module Name: + + MiniportAudioEngineNode.cpp + +Abstract: + + Implementation of IMiniportAudioEngineNode interface for wavert miniport. + +--*/ +#pragma warning (disable : 4127) + +#include <sysvad.h> +#include <limits.h> +#include "simple.h" +#include "minwavert.h" +#include "minwavertstream.h" +#include "IHVPrivatePropertySet.h" +#include "UnittestData.h" + +#define MINWAVERT_POOLTAG 'RWNM' +//============================================================================= +// IMiniportAudioEngineNode +//============================================================================= + +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::GetAudioEngineDescriptor + +Description: + + Portcls calls this method to get the pin id for each pin (host process, + offload, and loopback) on a specific audio engine node. + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _Out_ pAudioEngineDescriptor: a pointer to a KSAUDIOENGINE_DESCRIPTOR to receive the pin id informationived as input to its DriverEntry routine. + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks: + + The property value is of type KSAUDIOENGINE_DESCRIPTOR and indicates the static properties of the audio engine node. + The KSAUDIOENGINE_DESCRIPTOR structure is defined as follows: + + typedef struct _tagKSAUDIOENGINE_DESCRIPTOR + { + UINT nHostPinId; + UINT nOffloadPinId; + UINT nLoopbackPinId; + } KSAUDIOENGINE_DESCRIPTOR, *PKSAUDIOENGINE_DESCRIPTOR; + + The fields are defined as: + nHostPinId � The ID of the pin factory connected to the audio engine node that is intended for host processed audio data. This is the pin factory on which a software audio engine will run. + nOffloadPinId � The ID of the pin factory connected to the audio engine node that is intended for offloaded streams. + nLoopbackPinId � The ID of the pin factory connected to the audio engine that is intended for supplying a post-mix loopback or reference stream. + + All pin ids need to be unique for each audio engine node. + + A wave miniport might have more than one audio engine node and each engine node has their own set of engine pin ids. + A driver needs to make sure that the correct set of audio engine descriptor information is returned. +-------------------------------------------------------------------------------------------------------------------------*/ +STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetAudioEngineDescriptor(_In_ ULONG _ulNodeId, _Out_ KSAUDIOENGINE_DESCRIPTOR *_pAudioEngineDescriptor) +{ + PAGED_CODE (); + NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; + + ASSERT (_pAudioEngineDescriptor); + DPF_ENTER(("[CMiniportWaveRT::GetAudioEngineDescriptor]")); + // In this sample driver, only one single engine node is exposed in its wave filter + if (_ulNodeId == KSNODE_WAVE_AUDIO_ENGINE) + { + _pAudioEngineDescriptor->nHostPinId = GetSystemPinId(); + _pAudioEngineDescriptor->nOffloadPinId = GetOffloadPinId(); + _pAudioEngineDescriptor->nLoopbackPinId = GetLoopbackPinId(); + ntStatus = STATUS_SUCCESS; + } + else + { + ntStatus = STATUS_INVALID_DEVICE_REQUEST; + } + return ntStatus; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::GetGfxState + +Description: + + Portcls calls this method to get the audio engine GFX's state + +Parameters + + _In_ _ulNodeId: node id for the target audio engine node + _Out_ pbEnable: a pointer to a BOOL value for receieving the returned GFX state + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + The global operations (on the device stream) inside HW Audio Engine (such as src, dsp, and other special effects) are hidden from the software audio stack. +So, the driver should return TRUE if any one of the effects is on and returns FALSE when all the opertations are off. +-------------------------------------------------------------------------------------------------------------------------*/ +STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetGfxState(_In_ ULONG _ulNodeId, _Out_ BOOL *_pbEnable) +{ + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRT::GetGfxState]")); + + UNREFERENCED_PARAMETER(_ulNodeId); + + *_pbEnable = m_bGfxEnabled; + return STATUS_SUCCESS; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::SetGfxState + +Decscription: + + Portcls calls this method to set the audio engine GFX's state + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _In_ bEnable: a BOOL value. TRU: to enable GFX, FALSE: to disable GFX + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + The global operations (on the device stream) inside HW Audio Engine (such as src, dsp, and other special effects) are hidden from the software audio stack. +So, when handling disabling GFX, the driver should ALL the effects. When enabling GFX, it's up the driver+HW Audio Engine to decide what opertations to turn on +when they see appropriate. +-------------------------------------------------------------------------------------------------------------------------*/ +STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::SetGfxState(_In_ ULONG _ulNodeId, _In_ BOOL _bEnable) +{ + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRT::SetGfxState]")); + + UNREFERENCED_PARAMETER(_ulNodeId); + + // see above comments for appropriate enabling/disabling opertations on the HW Audio Engine + m_bGfxEnabled = _bEnable; + return STATUS_SUCCESS; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::GetEngineFormatSize + +Decscription: + + When handling GetMixFormat, DeviceFormat, or SupportDeviceFormatsList, Portcls calls + this method to know the correct data size to allocate for the receiving the corresponding + format information. + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _In_ eEngineFormatType: format target to indicate which format size is being asked + _Out_ pulFormatSize: a pointer to a ULONG variable for receiving returned szize information + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRT::GetEngineFormatSize +( + _In_ ULONG _ulNodeId, + _In_ eEngineFormatType _formatType, + _Out_ ULONG *_pulFormatSize +) +{ + PAGED_CODE (); + NTSTATUS ntStatus = STATUS_SUCCESS; + + DPF_ENTER(("[CMiniportWaveRT::GetEngineFormatSize]")); + ASSERT (_pulFormatSize); + + IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); + + switch (_formatType) + { + case eMixFormat: + DPF_ENTER(("[eMixFormat]")); + *_pulFormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE); + break; + case eDeviceFormat: + DPF_ENTER(("[eDeviceFormat]")); + *_pulFormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE); + break; + case eSupportedDeviceFormats: + DPF_ENTER(("[eSupportedDeviceFormats]")); + *_pulFormatSize = sizeof(KSMULTIPLE_ITEM) + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE) * GetAudioEngineSupportedDeviceFormats(NULL); + break; + default: + ntStatus = STATUS_INVALID_PARAMETER; + break; + } +Exit: + return ntStatus; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::GetMixFormat + +Decscription: + + GetMixFormat returns the current mix format used by the HW Audio Engine + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _Out_ pFormat: a buffer pointer for receiving the mix format information being asked + _In_ ulBufferSize: a pointer to a ULONG variable that has the size of the buffer pointed by pFormat + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + This is a read only operation; the HW Audio Engine mix format is determined by the HW Audio Engine alone. + +-------------------------------------------------------------------------------------------------------------------------*/ +STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetMixFormat(_In_ ULONG _ulNodeId, _Out_ KSDATAFORMAT_WAVEFORMATEX *_pFormat, _In_ ULONG _ulBufferSize) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + + ASSERT (_pFormat); + + DPF_ENTER(("[CMiniportWaveRT::GetMixFormat]")); + + IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); + IF_TRUE_ACTION_JUMP(_ulBufferSize < sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), ntStatus = STATUS_BUFFER_TOO_SMALL, Exit); +#pragma warning(push) + // IMiniportAudioEngineNode::GetMixFormat's annotation on _pFormat requires it to be KSDATAFORMAT_WAVEFORMATEX. However, + // this implementation here will always be called by our own code with _pFormat to be KSDATAFORMAT_WAVEFORMATEXTENSIBLE, + // so there should be no buffer overrun; also the IF_TRUE_ACTION_JUMP above also help to avoid buffer overrun. +#pragma warning(disable:6386) + RtlCopyMemory((PVOID)_pFormat, (PVOID)m_pMixFormat, sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE)); +#pragma warning (pop) + ntStatus = STATUS_SUCCESS; + +Exit: + return ntStatus; +} +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::GetDeviceFormat + +Decscription: + + GetDeviceFormat returns the current device format used by the HW Audio Engine + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _Out_ pFormat: a buffer pointer for receiving the device format information being asked + _In_ ulBufferSize: a pointer to a ULONG variable that has the size of the buffer pointed by pFormat + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + Setting the device format of a HW Audio Engine could potential impact the mix format inside the HD Audio Engine. +The driver might need to add appropriate src/format converter according or change mix format. + +-------------------------------------------------------------------------------------------------------------------------*/ +#pragma code_seg("PAGE") +STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetDeviceFormat(_In_ ULONG _ulNodeId, _Out_ KSDATAFORMAT_WAVEFORMATEX *_pFormat, _In_ ULONG _ulBufferSize) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + PAGED_CODE (); + + ASSERT (_pFormat); + + DPF_ENTER(("[CMiniportWaveRT::GetDeviceFormat]")); + IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); + IF_TRUE_ACTION_JUMP(_ulBufferSize < sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), ntStatus = STATUS_BUFFER_TOO_SMALL, Exit); +#pragma warning(push) + // IMiniportAudioEngineNode::GetDeviceFormat's annotation on _pFormat requires it to be KSDATAFORMAT_WAVEFORMATEX. However, + // this implementation here will always be called by our own code with _pFormat to be KSDATAFORMAT_WAVEFORMATEXTENSIBLE, + // so there should be no buffer overrun; also the IF_TRUE_ACTION_JUMP above also help to avoid buffer overrun. +#pragma warning(disable:6386) + RtlCopyMemory((PVOID)_pFormat, (PVOID)m_pDeviceFormat, sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE)); +#pragma warning (pop) + ntStatus = STATUS_SUCCESS; + +Exit: + return ntStatus; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::SetDeviceFormat + +Decscription: + + GetDeviceFormat set the current device format to be used by the HW Audio Engine + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _Out_ pFormat: a buffer pointer with the device format to be set to the hw Audio Engine + _In_ ulBufferSize: a pointer to a ULONG variable that has the size of the buffer pointed by pFormat + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + Setting the device format of a HW Audio Engine could potential impact the mix format inside the HD Audio Engine. +The driver might need to add appropriate src/format converter according or change mix format. + +-------------------------------------------------------------------------------------------------------------------------*/ +STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::SetDeviceFormat(_In_ ULONG _ulNodeId, _In_ KSDATAFORMAT_WAVEFORMATEX *_pFormat, _In_ ULONG _ulBufferSize) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + PAGED_CODE (); + + ASSERT (_pFormat); + + DPF_ENTER(("[CMiniportWaveRT::SetDeviceFormat]")); + IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); + IF_TRUE_ACTION_JUMP(_ulBufferSize < sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), ntStatus = STATUS_BUFFER_TOO_SMALL, Exit); + + RtlCopyMemory((PVOID)m_pDeviceFormat, (PVOID)_pFormat, sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE)); + ntStatus = STATUS_SUCCESS; + +Exit: + return ntStatus; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::GetSupportedDeviceFormats + +Decscription: + + GetSupportedDeviceFormats get the complete format list supported by the hw Audio Engine + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _Out_ pFormat: a buffer pointer for receiving the supported device formats + _In_ ulBufferSize: a pointer to a ULONG variable that has the size of the buffer pointed by pFormat + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + +-------------------------------------------------------------------------------------------------------------------------*/ +STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetSupportedDeviceFormats(_In_ ULONG _ulNodeId, _Out_ KSMULTIPLE_ITEM* _pFormat, _In_ ULONG _ulBufferSize) +{ + PKSDATAFORMAT_WAVEFORMATEXTENSIBLE pDeviceFormats; + ULONG cDeviceFormats; + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + PAGED_CODE (); + + ASSERT(_pFormat); + + DPF_ENTER(("[CMiniportWaveRT::GetSupportedDeviceFormats]")); + IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); + + cDeviceFormats = GetAudioEngineSupportedDeviceFormats(&pDeviceFormats); + + KSMULTIPLE_ITEM *pKsMulti = static_cast<KSMULTIPLE_ITEM*>(_pFormat); + pKsMulti->Size = sizeof(KSMULTIPLE_ITEM) + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE) * cDeviceFormats; + pKsMulti->Count = cDeviceFormats; + + IF_TRUE_ACTION_JUMP(_ulBufferSize < pKsMulti->Size, ntStatus = STATUS_BUFFER_TOO_SMALL, Exit); + + RtlCopyMemory((PVOID)(pKsMulti + 1), pDeviceFormats, + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE) * cDeviceFormats); + + ntStatus = STATUS_SUCCESS; + +Exit: + return ntStatus; +} +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::GetDeviceChannelCount + +Decscription: + + When handling volume, mute, and meter related KS properties, Portcls calls + this method, inside its property handlers, to know the number of channels for the + corresponding KS property. + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _In_ _targetType: the query target (volume. mute, or peak meter) + _Out_ _pulChannelCount: a pointer to a UINT32 variable for receiving returned channel count information + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + +-------------------------------------------------------------------------------------------------------------------------*/ +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRT::GetDeviceChannelCount +( + _In_ ULONG _ulNodeId, + _In_ eChannelTargetType _targetType, + _Out_ UINT32 *_pulChannelCount +) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + ASSERT(_pulChannelCount); + + DPF_ENTER(("[CMiniportWaveRT::GetChannelCount]")); + + IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); + + switch (_targetType) + { + case eVolumeAttribute: + ntStatus = GetVolumeChannelCount(_pulChannelCount); + break; + case eMuteAttribute: + ntStatus = GetMuteChannelCount(_pulChannelCount); + break; + case ePeakMeterAttribute: + ntStatus = GetPeakMeterChannelCount(_pulChannelCount); + break; + default: + ntStatus = STATUS_INVALID_DEVICE_REQUEST; + break; + } +Exit: + return ntStatus; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::GetDeviceAttributeSteppings + +Decscription: + + When handling volume, mute, and meter related KS properties, Portcls calls + this method, inside its property handlers, to know the property stepping information for the + corresponding KS property. + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _In_ _targetType: the query target (volume. mute, or peak meter) + _Out_ _pKsPropMembHead: a pointer to a PKSPROPERTY_STEPPING_LONG variable for receiving returned channel count information + _In_ ulBufferSize: a pointer to a ULONG variable that has the size of the buffer pointed by _pKsPropMembHead + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRT::GetDeviceAttributeSteppings(_In_ ULONG _ulNodeId, _In_ eChannelTargetType _targetType, _Out_ PKSPROPERTY_STEPPING_LONG _pKsPropMembHead, _In_ UINT32 _ui32DataSize) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRT::GetDeviceAttributeSteppings]")); + IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); + + switch (_targetType) + { + case eVolumeAttribute: + ntStatus = GetVolumeSteppings(_pKsPropMembHead, _ui32DataSize);; + break; + case eMuteAttribute: + ntStatus = GetMuteSteppings(_pKsPropMembHead, _ui32DataSize);; + break; + case ePeakMeterAttribute: + ntStatus = GetPeakMeterSteppings(_pKsPropMembHead, _ui32DataSize);; + break; + default: + ntStatus = STATUS_INVALID_DEVICE_REQUEST; + break; + } +Exit: + return ntStatus; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::GetDeviceChannelVolume + +Decscription: + + When handling GET volume KS property for the device, Portcls calls + this method, inside its property handlers, to get the current setting on the specific channel. + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _In_ _uiChannel: the target channel for this GET volume operation + _Out_ _pVolume: a pointer to a LONG variable for receiving returned information + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + +-------------------------------------------------------------------------------------------------------------------------*/ +STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetDeviceChannelVolume(_In_ ULONG _ulNodeId, _In_ UINT32 _uiChannel, _Out_ LONG *_pVolume) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRT::GetDeviceChannelVolume]")); + IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); + + ntStatus = GetChannelVolume(_uiChannel, _pVolume); + +Exit: + return ntStatus; +} + +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::SetDeviceChannelVolume + +Decscription: + + When handling SET volume KS property for the device, Portcls calls + this method, inside its property handlers, to set the current setting on the specific channel. + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _In_ _uiChannel: the target channel for this GET volume operation + _In_ _Volume: volume value to set + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + +-------------------------------------------------------------------------------------------------------------------------*/ +STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::SetDeviceChannelVolume(_In_ ULONG _ulNodeId, _In_ UINT32 _uiChannel, _In_ LONG _Volume) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRT::SetEndpointChannelVolume]")); + IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); + + // Snap the volume level to our range of steppings. + LONG lVolume = VOLUME_NORMALIZE_IN_RANGE(_Volume); + + ntStatus = SetChannelVolume(_uiChannel, lVolume); + +Exit: + return ntStatus; +} + +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::GetDeviceChannelPeakMeter + +Decscription: + + When handling GET peak meter KS property for the device, Portcls calls + this method, inside its property handlers, to get the current setting on the specific channel. + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _In_ _uiChannel: the target channel for this GET volume operation + _Out_ _pPeakMeterValue: a pointer to a LONG variable for receiving returned information + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + +-------------------------------------------------------------------------------------------------------------------------*/ +STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetDeviceChannelPeakMeter(_In_ ULONG _ulNodeId, _In_ UINT32 _uiChannel, _Out_ LONG *_pPeakMeterValue) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRT::GetDeviceChannelPeakMeter]")); + IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); + ntStatus = GetChannelPeakMeter(_uiChannel, _pPeakMeterValue); + +Exit: + return ntStatus; +} +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::GetDeviceChannelMute + +Decscription: + + When handling GET mute KS property for the device, Portcls calls + this method, inside its property handlers, to get the current setting on the specific channel. + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _In_ _uiChannel: the target channel for this GET volume operation + _Out_ _pbMute: a pointer to a BOOL variable for receiving returned information + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + +-------------------------------------------------------------------------------------------------------------------------*/ +#pragma code_seg("PAGE") +STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetDeviceChannelMute(_In_ ULONG _ulNodeId, _In_ UINT32 _uiChannel, _Out_ BOOL *_pbMute) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRT::GetEndpointChannelMute]")); + IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); + + ntStatus = GetChannelMute(_uiChannel, _pbMute); +Exit: + return ntStatus; +} + +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::SetDeviceChannelMute + +Decscription: + + When handling SET mute KS property for the device, Portcls calls + this method, inside its property handlers, to set the current setting on the specific channel. + +Parameters: + + _In_ _ulNodeId: node id for the target audio engine node + _In_ _uiChannel: the target channel for this GET volume operation + _In_ _bMute: volume value to set + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRT::SetDeviceChannelMute(_In_ ULONG _ulNodeId, _In_ UINT32 _uiChannel, _In_ BOOL _bMute) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRT::SetEndpointChannelMute]")); + IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); + + ntStatus = SetChannelMute(_uiChannel, _bMute); + +Exit: + return ntStatus; +} + + +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportAudioEngineNode::GetBufferSizeRange + +Decscription: + + Portcls calls this method, inside its property handlers, to get a buffer size capabilities for + a specifc format requested at the moment this call was made. + +Parameters: + + _In_ ULONG _ulNodeId: the node is for the target audio engine + _In_ KSDATAFORMAT_WAVEFORMATEX *_pKsDataFormatWfx: the requested format + _Out_ KSAUDIOENGINE_BUFFER_SIZE_RANGE *_pBufferSizeRange: + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + + The purpose of this call is to give an audio client (such as MF SAR or direct WASAPI clients) an idea on the supported buffer size range - + almost equivalent to the hardware's buffer capability. An application pick any size within that range that it determines it would best serve + its purpose (communication apps would like small buffer size for low latency while other media app might choose large buffer for power saving advantage). + +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRT::GetBufferSizeRange(_In_ ULONG _ulNodeId, _In_ KSDATAFORMAT_WAVEFORMATEX *_pKsDataFormatWfx, _Out_ KSAUDIOENGINE_BUFFER_SIZE_RANGE *_pBufferSizeRange) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + + PAGED_CODE (); + UNREFERENCED_PARAMETER(_ulNodeId); + ASSERT(_pBufferSizeRange); + ASSERT(_pKsDataFormatWfx); + DPF_ENTER(("[CMiniportWaveRTStream::GetStreamBufferSizeRange]")); + + _pBufferSizeRange->MinBufferBytes = (_pKsDataFormatWfx->WaveFormatEx.nAvgBytesPerSec * MIN_BUFFER_DURATION_MS) / MS_PER_SEC; + _pBufferSizeRange->MaxBufferBytes = (_pKsDataFormatWfx->WaveFormatEx.nAvgBytesPerSec * MAX_BUFFER_DURATION_MS) / MS_PER_SEC; + + return ntStatus; +} + +//------------------------------------------------------------------------------------------------------------------------ +//CMiniportWaveRT private supporting functions +//------------------------------------------------------------------------------------------------------------------------ +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRT::GetVolumeChannelCount(_Out_ UINT32 *_pulChannelCount) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + PAGED_CODE (); + ASSERT (_pulChannelCount); + + DPF_ENTER(("[CMiniportWaveRT::GetVolumeChannelCount]")); + *_pulChannelCount = m_DeviceMaxChannels; + return ntStatus; +} +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRT::GetVolumeSteppings(_Out_writes_bytes_(_ui32DataSize) PKSPROPERTY_STEPPING_LONG _pKsPropStepLong, _In_ UINT32 _ui32DataSize) +{ + PAGED_CODE (); + UINT32 ulChannelCount = _ui32DataSize / sizeof(KSPROPERTY_STEPPING_LONG); + ASSERT (_pKsPropStepLong); + DPF_ENTER(("[CMiniportWaveRT::GetVolumeSteppings]")); + + ASSERT(ulChannelCount <= m_DeviceMaxChannels); + if (ulChannelCount > m_DeviceMaxChannels) + { + return STATUS_INVALID_PARAMETER; + } + + for(UINT i = 0; i < ulChannelCount; i++) + { + _pKsPropStepLong[i].SteppingDelta = VOLUME_STEPPING_DELTA; + _pKsPropStepLong[i].Bounds.SignedMaximum = VOLUME_SIGNED_MAXIMUM; + _pKsPropStepLong[i].Bounds.SignedMinimum = VOLUME_SIGNED_MINIMUM; + } + return STATUS_SUCCESS; +} +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRT::GetChannelVolume(_In_ UINT32 _uiChannel, _Out_ LONG *_pVolume) +{ + PAGED_CODE (); + ASSERT (_pVolume); + DPF_ENTER(("[CMiniportWaveRT::GetChannelVolume]")); + + if (_uiChannel == ALL_CHANNELS_ID) + { + *_pVolume = m_plVolumeLevel[0]; + } + else + { + ASSERT(_uiChannel <= m_DeviceMaxChannels); + *_pVolume = m_plVolumeLevel[_uiChannel]; + } + return STATUS_SUCCESS; +} +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRT::SetChannelVolume(_In_ UINT32 _uiChannel, _In_ LONG _Volume) +{ + PAGED_CODE (); + DPF_ENTER(("[CMiniportWaveRT::SetChannelVolume]")); + + if (_uiChannel == ALL_CHANNELS_ID) + { + for (int i=0; i<m_DeviceMaxChannels; i++) + { + m_plVolumeLevel[i] = _Volume; + } + } + else + { + ASSERT(_uiChannel <= m_DeviceMaxChannels); + m_plVolumeLevel[_uiChannel] = _Volume; + } + + return STATUS_SUCCESS; +} +///- metering +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRT::GetPeakMeterChannelCount(_Out_ UINT32 *_pulChannelCount) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + PAGED_CODE (); + ASSERT (_pulChannelCount); + + DPF_ENTER(("[CMiniportWaveRT::GetVolumeChannelCount]")); + *_pulChannelCount = m_DeviceMaxChannels; + return ntStatus; +} +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRT::GetPeakMeterSteppings(_Out_writes_bytes_(_ui32DataSize) PKSPROPERTY_STEPPING_LONG _pKsPropStepLong, _In_ UINT32 _ui32DataSize) +{ + PAGED_CODE (); + UINT32 ulChannelCount = _ui32DataSize / sizeof(KSPROPERTY_STEPPING_LONG); + + ASSERT (_pKsPropStepLong); + DPF_ENTER(("[CMiniportWaveRT::GetVolumeSteppings]")); + + ASSERT(ulChannelCount <= m_DeviceMaxChannels); + + if (ulChannelCount > m_DeviceMaxChannels) + { + return STATUS_INVALID_PARAMETER; + } + + for(UINT i = 0; i < ulChannelCount; i++) + { + _pKsPropStepLong[i].SteppingDelta = PEAKMETER_STEPPING_DELTA; + _pKsPropStepLong[i].Bounds.SignedMaximum = PEAKMETER_SIGNED_MAXIMUM; + _pKsPropStepLong[i].Bounds.SignedMinimum = PEAKMETER_SIGNED_MINIMUM; + } + return STATUS_SUCCESS; +} +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRT::GetChannelPeakMeter(_In_ UINT32 _uiChannel, _Out_ LONG *_plPeakMeter) +{ + PAGED_CODE (); + ASSERT (_plPeakMeter); + DPF_ENTER(("[CMiniportWaveRT::GetChannelPeakMeter]")); + + ASSERT(_uiChannel < m_DeviceMaxChannels); + + if (_uiChannel >= m_DeviceMaxChannels) + { + return STATUS_INVALID_PARAMETER; + } + + if (m_ulSystemAllocated + m_ulOffloadAllocated > 0) + { + *_plPeakMeter = PEAKMETER_NORMALIZE_IN_RANGE(PEAKMETER_SIGNED_MAXIMUM / 2); + } + else + { + *_plPeakMeter = 0; + } + //*_plPeakMeter = m_plPeakMeter[lChannel]; + + return STATUS_SUCCESS; +} +// mute +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRT::GetMuteChannelCount(_Out_ UINT32 *_pulChannelCount) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + PAGED_CODE (); + ASSERT (_pulChannelCount); + + DPF_ENTER(("[CMiniportWaveRT::GetMuteChannelCount]")); + *_pulChannelCount = m_DeviceMaxChannels; + return ntStatus; +} +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRT::GetMuteSteppings(_Out_writes_bytes_(_ui32DataSize) PKSPROPERTY_STEPPING_LONG _pKsPropStepLong, _In_ UINT32 _ui32DataSize) +{ + PAGED_CODE (); + UINT32 ulChannelCount = _ui32DataSize / sizeof(KSPROPERTY_STEPPING_LONG); + + ASSERT (_pKsPropStepLong); + DPF_ENTER(("[CMiniportWaveRT::GetMuteSteppings]")); + + ASSERT(ulChannelCount <= m_DeviceMaxChannels); + + if (ulChannelCount > m_DeviceMaxChannels) + { + return STATUS_INVALID_PARAMETER; + } + + for(UINT i = 0; i < ulChannelCount; i++) + { + _pKsPropStepLong[i].SteppingDelta = 1; + _pKsPropStepLong[i].Bounds.SignedMaximum = TRUE; + _pKsPropStepLong[i].Bounds.SignedMinimum = FALSE; + } + return STATUS_SUCCESS; +} +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRT::GetChannelMute(_In_ UINT32 _uiChannel, _Out_ BOOL *_pbMute) +{ + PAGED_CODE (); + ASSERT (_pbMute); + DPF_ENTER(("[CMiniportWaveRT::GetChannelMute]")); + + + if (_uiChannel == ALL_CHANNELS_ID) + { + *_pbMute = m_pbMuted[0]; + } + else + { + ASSERT(_uiChannel <= m_DeviceMaxChannels); + *_pbMute = m_pbMuted[_uiChannel]; + } + + return STATUS_SUCCESS; +} +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRT::SetChannelMute(_In_ UINT32 _uiChannel, _In_ BOOL _bMute) +{ + PAGED_CODE (); + DPF_ENTER(("[CMiniportWaveRT::SetChannelVolume]")); + + if (_uiChannel == ALL_CHANNELS_ID) + { + for (int i=0; i<m_DeviceMaxChannels; i++) + { + m_pbMuted[i] = _bMute; + } + } + else + { + ASSERT(_uiChannel <= m_DeviceMaxChannels); + m_pbMuted[_uiChannel] = _bMute; + } + + return STATUS_SUCCESS; +} + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +CMiniportWaveRT::SetLoopbackProtection +( + _In_ CONSTRICTOR_OPTION ulProtectionOption +) +/*++ + +Routine Description: + + Allows or disallows loopback streaming. + +Arguments: + + Parameters: + _In_ protectionOption: protection option + CONSTRICTOR_OPTION_DISABLE: Turn protection off. + CONSTRICTOR_OPTION_MUTE: Mute the loopback stream + +Return Value: + + NT status code. + +--*/ +{ + PAGED_CODE (); + DPF_ENTER(("[CMiniportWaveRT::SetLoopbackProtection]")); + + NTSTATUS ntStatus = STATUS_SUCCESS; + + if (ulProtectionOption == m_LoopbackProtection) + { + goto Done; + } + + for (ULONG i = 0; i < MAX_OUTPUT_LOOPBACK_STREAMS; i++) + { + if (m_LoopbackStreams[i]) + { + ntStatus = m_LoopbackStreams[i]->SetLoopbackProtection(ulProtectionOption); + if (!NT_SUCCESS(ntStatus)) + { + break; + } + } + } + + if (NT_SUCCESS(ntStatus)) + { + m_LoopbackProtection = ulProtectionOption; + } + else + { + // + // Something went wrong, restore old protection setting. + // + for (ULONG i = 0; i < MAX_OUTPUT_LOOPBACK_STREAMS; i++) + { + if (m_LoopbackStreams[i]) + { + (void)m_LoopbackStreams[i]->SetLoopbackProtection(m_LoopbackProtection); + } + } + } + +Done: + return ntStatus; +} + + |
