diff options
Diffstat (limited to 'audio/sysvad/EndpointsCommon/MiniportStreamAudioEngineNode.cpp')
| -rw-r--r-- | audio/sysvad/EndpointsCommon/MiniportStreamAudioEngineNode.cpp | 971 |
1 files changed, 971 insertions, 0 deletions
diff --git a/audio/sysvad/EndpointsCommon/MiniportStreamAudioEngineNode.cpp b/audio/sysvad/EndpointsCommon/MiniportStreamAudioEngineNode.cpp new file mode 100644 index 00000000..3c775d01 --- /dev/null +++ b/audio/sysvad/EndpointsCommon/MiniportStreamAudioEngineNode.cpp @@ -0,0 +1,971 @@ +/*++ + +Module Name: + + MiniportStreamAudioEngineNode.cpp + +Abstract: + + Implementation of IMiniportstreamAudioEngineNode interface for wavert steam. + +--*/ + +#include <sysvad.h> +#include <intsafe.h> +#include <ks.h> +#include "simple.h" +#include "minwavert.h" +#include "minwavertstream.h" +#include "UnittestData.h" +#define MINWAVERTSTREAM_POOLTAG 'SRWM' +#define HNSTIME_PER_MILLISECOND 10000 + +#pragma warning (disable : 4127) + +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportStreamAudioEngineNode::GetLfxState + +Description: + + Portcls calls this method to get a offload stream's Lfx state + +Parameters + + _Out_ pbEnable: a pointer to a BOOL value for receieving the returned LFX state + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + The Lfx operations (on the offload 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. +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRTStream::GetLfxState(_Out_ BOOL *_pbEnable) +{ + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRTStream::GetLfxState]")); + + *_pbEnable = m_bLfxEnabled; + return STATUS_SUCCESS; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportStreamAudioEngineNode::SetLfxState + +Decscription: + + Portcls calls this method to set a offload stream's Lfx state + +Parameters: + + _In_ bEnable: a BOOL value. TRU: to enable Lfx, FALSE: to disable Lfx + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + The local operations (on the offload stream) inside HW Audio Engine (such as src, dsp, and other special effects) are hidden from the software audio stack. +So, when handling disabling Lfx, the driver should ALL the effects. When enabling Lfx, it's up the driver+HW Audio Engine to decide what opertations to turn on +when they see appropriate. +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRTStream::SetLfxState(_In_ BOOL _bEnable) +{ + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRTStream::SetGfxState]")); + + UNREFERENCED_PARAMETER(_bEnable); + m_bLfxEnabled = _bEnable; + return STATUS_SUCCESS; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportStreamAudioEngineNode::GetStreamChannelVolume + +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_ _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 + +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRTStream::GetStreamChannelVolume(_In_ UINT32 _uiChannel, _Out_ LONG *_pVolume) +{ + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRTStream::GetStreamChannelVolume]")); + + *_pVolume = m_plVolumeLevel[_uiChannel]; + + return STATUS_SUCCESS; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportStreamAudioEngineNode::GetStreamChannelMute + +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_ _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 + +-------------------------------------------------------------------------------------------------------------------------*/ +STDMETHODIMP_(NTSTATUS) CMiniportWaveRTStream::GetStreamChannelMute(_In_ UINT32 _uiChannel, _Out_ BOOL *_pbMute) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + ASSERT (_pbMute); + + DPF_ENTER(("[CMiniportWaveRTStream::GetStreamChannelMute]")); + ntStatus = GetChannelMute(_uiChannel, _pbMute); + + return ntStatus; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportStreamAudioEngineNode::GetStreamAttributeSteppings + +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_ _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 CMiniportWaveRTStream::GetStreamAttributeSteppings(_In_ eChannelTargetType _targetType, _Out_ PKSPROPERTY_STEPPING_LONG _pKsPropMembHead, _In_ UINT32 _ui32DataSize) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRTStream::GetDeviceAttributeSteppings]")); + + 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; + } + return ntStatus; + +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportStreamAudioEngineNode::SetStreamChannelVolume + +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_ Channel: the target channel for this GET volume operation + _In_ TargetVolume: volume value to set + _In_ CurveType: type of curve to apply to the ramp + _In_ CurveDuration: amount of time in hns over which to ramp the volume + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + +-------------------------------------------------------------------------------------------------------------------------*/ +STDMETHODIMP_(NTSTATUS) CMiniportWaveRTStream::SetStreamChannelVolume +( + _In_ UINT32 Channel, + _In_ LONG TargetVolume, + _In_ AUDIO_CURVE_TYPE CurveType, + _In_ ULONGLONG CurveDuration +) +{ + UNREFERENCED_PARAMETER(CurveType); + UNREFERENCED_PARAMETER(CurveDuration); + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRTStream::SetStreamChannelVolume]")); + + // Snap the volume level to our range of steppings. + LONG lVolume = VOLUME_NORMALIZE_IN_RANGE(TargetVolume); + + // If Channel is ALL_CHANNELS_ID, then set the level on all channels + if ( ALL_CHANNELS_ID == Channel ) + { + for (UINT32 i = 0; i < m_pWfExt->Format.nChannels; i++) + { + ntStatus = SetChannelVolume(i, lVolume); + } + } + else + { + ntStatus = SetChannelVolume(Channel, lVolume); + } + + return ntStatus; +} + +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportStreamAudioEngineNode::GetStreamChannelPeakMeter + +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_ _uiChannel: the target channel for this GET peak meter 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) CMiniportWaveRTStream::GetStreamChannelPeakMeter(_In_ UINT32 _uiChannel, _Out_ LONG *_pPeakMeterValue) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRTStream::GetStreamChannelPeakMeter]")); + + ntStatus = GetChannelPeakMeter(_uiChannel, _pPeakMeterValue); + + return ntStatus; +} + +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportStreamAudioEngineNode::SetStreamChannelMute + +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_ _uiChannel: the target channel for this Set mute operation + _In_ _bMute: mute value to set + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRTStream::SetStreamChannelMute(_In_ UINT32 _uiChannel, _In_ BOOL _bMute) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRTStream::SetStreamChannelMute]")); + + // If Channel is ALL_CHANNELS_ID, then set the mute info on all channels + if ( ALL_CHANNELS_ID == _uiChannel ) + { + for (UINT32 i = 0; i < m_pWfExt->Format.nChannels; i++) + { + ntStatus = SetChannelMute(i, _bMute); + } + } + else + { + ntStatus = SetChannelMute(_uiChannel, _bMute); + } + + return ntStatus; +} +//presentation +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportStreamAudioEngineNode::GetStreamPresentationPosition + +Decscription: + + Portcls calls this method, inside its property handlers, to get a stream's presentation + postion. + +Parameters: + + _Out_ pPresentationPosition: a pointer to a KSAUDIO_PRESENTATION_POSITION variable for receiving returned information + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRTStream::GetStreamPresentationPosition(_Out_ KSAUDIO_PRESENTATION_POSITION *_pPresentationPosition) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + ASSERT(_pPresentationPosition); + DPF_ENTER(("[CMiniportWaveRTStream::GetStreamPresentationPosition]")); + + ntStatus = GetPresentationPosition(_pPresentationPosition); + + return ntStatus; +} +//StreamCurrentWritePosition +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportStreamAudioEngineNode::SetStreamCurrentWritePosition + +Decscription: + + Portcls calls this method, inside its property handlers, to set a stream's write position + postion. + +Parameters: + + _In_ ulCurrentWritePosition: a position value indicating the last valid byte in the buffer + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + +_ulCurrentWritePosition specifies the current write position in bytes, which an offload driver can use to know how much valid data in the WaveRT buffer. +Let say, BufferByteSize is the WaveRT buffer size, the valid value range for _ulCurrentWritePosition be 0... BufferByteSize (inclusive) + +0: no valid data in the buffer +n: the last valid data byte is at the offset n from the beginning of the buffer. If this is a value smaller than a previous write position, +it means a wrap-around has happened, in the case, the driver would need to take that in to consider when calculating how many bytes are valid for fetching. +BufferByteSize: the last valid data byte is at the end of the buffer + +After a pin is instantiated and before any KSPROPERTY_AUDIO_WAVERT_CURRENT_WRITE_POSITION is received, a driver should assume its current write position is zero. + +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRTStream::SetStreamCurrentWritePosition(_In_ ULONG _ulCurrentWritePosition) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + DPF_ENTER(("[CMiniportWaveRTStream::SetStreamCurrentWritePosition]")); + + ntStatus = SetCurrentWritePosition(_ulCurrentWritePosition); + + return ntStatus; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportStreamAudioEngineNode::GetStreamLinearBufferPosition + +Decscription: + + Portcls calls this method, inside its property handlers, to set a stream's write position + postion. + +Parameters: + + _Out_ pullLinearBufferPosition: a pointer to a ULONGLONG variable for receiving returned information + + +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks +The returned value is the number of bytes that the DMA has fetched from the audio buffer since the beginning of the stream +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRTStream::GetStreamLinearBufferPosition(_Out_ ULONGLONG *_pullLinearBufferPosition) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + ASSERT(_pullLinearBufferPosition); + DPF_ENTER(("[CMiniportWaveRTStream::GetStreamLinearBufferPosition]")); + + ntStatus = GetLinearBufferPosition(_pullLinearBufferPosition, NULL); + + return ntStatus; +} +//SetStreamLoopbackProtection +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportStreamAudioEngineNode::SetStreamLoopbackProtection + +Decscription: + + Portcls calls this method, inside its property handlers, to set the loopback + protection option + +Parameters: + _In_ protectionOption: protection option + CONSTRICTOR_OPTION_DISABLE: Turn protection off. + CONSTRICTOR_OPTION_MUTE: Mute the loopback stream +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + This content protection settings requestion could come in from the host process + pin or offload pin. The miniport needs to mute its loopback stream contents for + for this request from either host process pin or offload pin. +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRTStream::SetStreamLoopbackProtection(_In_ CONSTRICTOR_OPTION protectionOption) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + DPF_ENTER(("[CMiniportWaveRTStream::SetStreamLoopbackProtection]")); + + // + // Miniport driver mutes/unmutes the loopback here. + // + ntStatus = m_pMiniport->SetLoopbackProtection(protectionOption); + + return ntStatus; +} +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +IMiniportStreamAudioEngineNode::GetStreamChannelCount + +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_ _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 + +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRTStream::GetStreamChannelCount(_In_ eChannelTargetType _targetType,_Out_ UINT32 *_pulChannelCount) +{ + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + PAGED_CODE (); + + DPF_ENTER(("[CMiniportWaveRTStream::GetStreamChannelCount]")); + + 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; + } + + return ntStatus; +} + + +//------------------------------------------------------------------------------------------------------------------------ +//CMiniportWaveRTStream private supporting functions +//------------------------------------------------------------------------------------------------------------------------ +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRTStream::GetVolumeChannelCount(_Out_ UINT32 *_puiChannelCount) +{ + PAGED_CODE(); + + DPF_ENTER(("[CMiniportWaveRTStream::GetVolumeChannelCount]")); + + ASSERT(_puiChannelCount); + ASSERT(m_pWfExt); + + NTSTATUS ntStatus = STATUS_SUCCESS; + *_puiChannelCount = m_pWfExt->Format.nChannels; + return ntStatus; +} + +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRTStream::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(("[CMiniportWaveRTStream::GetVolumeSteppings]")); + + if (ulChannelCount != m_pWfExt->Format.nChannels) + { + 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 CMiniportWaveRTStream::GetChannelVolume(_In_ UINT32 _uiChannel, _Out_ LONG *_pVolume) +{ + PAGED_CODE (); + ASSERT (_pVolume); + DPF_ENTER(("[CMiniportWaveRTStream::GetChannelVolume]")); + + *_pVolume = m_plVolumeLevel[_uiChannel]; + + return STATUS_SUCCESS; +} +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRTStream::SetChannelVolume(_In_ UINT32 _uiChannel, _In_ LONG _Volume) +{ + PAGED_CODE (); + DPF_ENTER(("[CMiniportWaveRTStream::SetChannelVolume]")); + + m_plVolumeLevel[_uiChannel] = _Volume; + + return STATUS_SUCCESS; +} +///- metering +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRTStream::GetPeakMeterChannelCount(_Out_ UINT32 *puiChannelCount) +{ + PAGED_CODE(); + + DPF_ENTER(("[CMiniportWaveRTStream::GetPeakMeterChannelCount]")); + + ASSERT(puiChannelCount); + ASSERT(m_pWfExt); + + NTSTATUS ntStatus = STATUS_SUCCESS; + *puiChannelCount = m_pWfExt->Format.nChannels; + return ntStatus; +} + +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRTStream::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(("[CMiniportWaveRTStream::GetPeakMeterSteppings]")); + + if (ulChannelCount != m_pWfExt->Format.nChannels) + { + 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 CMiniportWaveRTStream::GetChannelPeakMeter(_In_ UINT32 _uiChannel, _Out_ LONG *_plPeakMeter) +{ + PAGED_CODE (); + ASSERT (_plPeakMeter); + UNREFERENCED_PARAMETER(_uiChannel); + DPF_ENTER(("[CMiniportWaveRTStream::GetChannelPeakMeter]")); + + *_plPeakMeter = PEAKMETER_NORMALIZE_IN_RANGE(PEAKMETER_SIGNED_MAXIMUM / 2); + + return STATUS_SUCCESS; +} + + //============================================================================= +// stream Mute +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRTStream::GetMuteChannelCount(_Out_ UINT32 *puiChannelCount) +{ + PAGED_CODE(); + + DPF_ENTER(("[CMiniportWaveRTStream::GetMuteChannelCount]")); + + ASSERT(puiChannelCount); + ASSERT(m_pWfExt); + + NTSTATUS ntStatus = STATUS_SUCCESS; + *puiChannelCount = m_pWfExt->Format.nChannels; + return ntStatus; +} + +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRTStream::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(("[CMiniportWaveRTStream::GetMuteSteppings]")); + + if (ulChannelCount != m_pWfExt->Format.nChannels) + { + 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 CMiniportWaveRTStream::GetChannelMute(_In_ UINT32 _uiChannel, _Out_ BOOL *_pbMute) +{ + PAGED_CODE (); + ASSERT (_pbMute); + DPF_ENTER(("[CMiniportWaveRTStream::GetChannelMute]")); + + *_pbMute = m_pbMuted[_uiChannel]; + return STATUS_SUCCESS; +} +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRTStream::SetChannelMute(_In_ UINT32 _uiChannel, _In_ BOOL _bMute) +{ + PAGED_CODE (); + DPF_ENTER(("[CMiniportWaveRTStream::SetChannelMute]")); + + m_plVolumeLevel[_uiChannel] = _bMute; + + return STATUS_SUCCESS; +} +//presentation +#pragma code_seg("PAGE") +// +// UINT64 u64PositionInBlocks; // The block offset from the start of the stream to the current post-decoded uncompressed +// // position in the stream, where a block is the group of channels in the same sample; for a PCM stream, +// // a block is same as a frame. For compressed formats, a block is a single sample within a frame +// // (eg. each MP3 frame has 1152 samples or 1152 blocks) +// UINT64 u64QPCPosition; // The value of the performance counter at the time that the audio endpoint device read the device +// // position (*pu64Position) in response to the KSAUDIO_PRESENTATION_POSITION call. + +NTSTATUS CMiniportWaveRTStream::GetPresentationPosition(_Out_ KSAUDIO_PRESENTATION_POSITION *_pPresentationPosition) +{ + PAGED_CODE (); + ASSERT (_pPresentationPosition); + LARGE_INTEGER timeStamp; + PADAPTERCOMMON pAdapterComm = m_pMiniport->GetAdapterCommObj(); + + DPF_ENTER(("[CMiniportWaveRTStream::GetPresentationPosition]")); + + ULONGLONG ullLinearPosition = {0}; + NTSTATUS status = STATUS_SUCCESS; + + status = GetLinearBufferPosition(&ullLinearPosition, &timeStamp); + if (!NT_SUCCESS(status)) + { + return status; + } + + _pPresentationPosition->u64PositionInBlocks = ullLinearPosition * m_pWfExt->Format.nSamplesPerSec / m_pWfExt->Format.nAvgBytesPerSec; + + _pPresentationPosition->u64QPCPosition = (UINT64)timeStamp.QuadPart; + + + //Event type: eMINIPORT_GET_PRESENTATION_POSITION + //Parameter 1: Current linear buffer position + //Parameter 2: the previous WaveRtBufferWritePosition that the drive received + //Parameter 3: Presentation position + //Parameter 4:0 + pAdapterComm->WriteEtwEvent(eMINIPORT_GET_PRESENTATION_POSITION, + ullLinearPosition, // replace with the correct "Current linear buffer position" + m_ulCurrentWritePosition, + _pPresentationPosition->u64PositionInBlocks, + 0); // always zero + + return STATUS_SUCCESS; +} +NTSTATUS CMiniportWaveRTStream::SetCurrentWritePosition(_In_ ULONG _ulCurrentWritePosition) +{ + PAGED_CODE (); + DPF_ENTER(("[CMiniportWaveRTStream::SetCurrentWritePosition]")); + + NTSTATUS ntStatus; + +#ifdef SYSVAD_BTH_BYPASS + if (m_ScoOpen) + { + ntStatus = GetScoStreamNtStatus(); + IF_FAILED_JUMP(ntStatus, Done); + } +#endif // SYSVAD_BTH_BYPASS + + // + // Basic validation. WritePosition indicates the position (1-based) of the last valid byte. + // + if (_ulCurrentWritePosition == 0) + { + ntStatus = STATUS_INVALID_DEVICE_REQUEST; + goto Done; + } + + ntStatus = SetCurrentWritePositionInternal(_ulCurrentWritePosition); + +Done: + return ntStatus; +} +NTSTATUS CMiniportWaveRTStream::SetCurrentWritePositionInternal(_In_ ULONG _ulCurrentWritePosition) +{ + PAGED_CODE (); + DPF_ENTER(("[CMiniportWaveRTStream::SetCurrentWritePositionInternal]")); + + if (_ulCurrentWritePosition > m_ulDmaBufferSize) + { + return STATUS_INVALID_DEVICE_REQUEST; + } + + PADAPTERCOMMON pAdapterComm = m_pMiniport->GetAdapterCommObj(); + + //Event type: eMINIPORT_SET_WAVERT_BUFFER_WRITE_POSITION + //Parameter 1: Current linear buffer position + //Parameter 2: the previous WaveRtBufferWritePosition that the drive received + //Parameter 3: Target WaveRtBufferWritePosition received from portcls + //Parameter 4:0 + pAdapterComm->WriteEtwEvent(eMINIPORT_SET_WAVERT_BUFFER_WRITE_POSITION, + 100, // replace with the correct "Current linear buffer position" + m_ulCurrentWritePosition, + _ulCurrentWritePosition, // this is the passed in parameter + 0); // always zero + + + // + // Check for eMINIPORT_GLITCH_REPORT - 'same writert buffer' only when in event mode. + // + if (m_ulNotificationIntervalMs > 0) + { + if (m_ulCurrentWritePosition == _ulCurrentWritePosition) + { + //Event type: eMINIPORT_GLITCH_REPORT + //Parameter 1: Current linear buffer position + //Parameter 2: the previous WaveRtBufferWritePosition that the drive received + //Parameter 3: major glitch code: 3:receive the same wavert buffer two in a row in event driven mode + //Parameter 4: minor code for the glitch cause + pAdapterComm->WriteEtwEvent(eMINIPORT_GLITCH_REPORT, + 100, // replace with the correct "Current linear buffer position" + m_ulCurrentWritePosition, + 3, // receive the same wavert buffer two in a row in event driven mode + _ulCurrentWritePosition); + } + } + + m_ulCurrentWritePosition = _ulCurrentWritePosition; + InterlockedExchange(&m_IsCurrentWritePositionUpdated, 1); + + return STATUS_SUCCESS; +} +//linear position +#pragma code_seg("PAGE") +NTSTATUS CMiniportWaveRTStream::GetLinearBufferPosition(_Out_ ULONGLONG *_pullLinearBufferPosition, LARGE_INTEGER *_pliQPCTime) +{ + PAGED_CODE (); + ASSERT (_pullLinearBufferPosition); + DPF_ENTER(("[CMiniportWaveRTStream::GetLinearBufferPosition]")); + + NTSTATUS ntStatus; + LARGE_INTEGER ilQPC; + +#ifdef SYSVAD_BTH_BYPASS + if (m_ScoOpen) + { + ntStatus = GetScoStreamNtStatus(); + IF_FAILED_JUMP(ntStatus, Done); + } +#endif // SYSVAD_BTH_BYPASS + + // Update *_pullLinearBufferPosition with the the number of bytes fetched from waveRT ever since a stream got set into RUN + // state. + // Once the stream is set to STOP state, any further read on this call would return zero. + + // + // Get the current time and update position. + // + ilQPC = KeQueryPerformanceCounter(NULL); + if (m_KsState == KSSTATE_RUN) + { + UpdatePosition(ilQPC); + } + if (_pliQPCTime) + { + *_pliQPCTime = ilQPC; + } + *_pullLinearBufferPosition = m_ullLinearPosition; + + ntStatus = STATUS_SUCCESS; + +#ifdef SYSVAD_BTH_BYPASS +Done: +#endif // SYSVAD_BTH_BYPASS + return ntStatus; +} + +#pragma code_seg("PAGE") +/*----------------------------------------------------------------------------- +CMiniportWaveRTStream::SetLoopbackProtection + +Decscription: + + Portcls calls this method, inside its property handlers, to set the loopback + protection option + +Parameters: + _In_ protectionOption: protection option + CONSTRICTOR_OPTION_DISABLE: Turn protection off. + CONSTRICTOR_OPTION_MUTE: Mute the loopback stream +Return Value: + + Appropriate NTSTATUS code + +Called at PASSIVE_LEVEL + +Remarks + This content protection settings requestion could come in from the host process + pin or offload pin. The miniport needs to mute its loopback stream contents for + for this request from either host process pin or offload pin. +-------------------------------------------------------------------------------------------------------------------------*/ +NTSTATUS CMiniportWaveRTStream::SetLoopbackProtection(_In_ CONSTRICTOR_OPTION protectionOption) +{ + PAGED_CODE (); + DPF_ENTER(("[CMiniportWaveRTStream::SetLoopbackProtection]")); + + // + // Miniport driver mutes/unmutes the loopback here. + // + m_ToneGenerator.SetMute(protectionOption == CONSTRICTOR_OPTION_MUTE); + + return STATUS_SUCCESS; +} + +#pragma code_seg("PAGE") +//---------------------------------------------------------------------------------- +// Description: +// Set current write position for the very last buffer in a stream +// +// Parameters: +// ULONG _ulWritePosition: point to the last valid data byte +// +// Remark: +// +// In Win 8, for offload streams, double buffering mechanism is used and the buffer completion contact +// between the audio stack and driver is: a driver signals buffer completion only when it reaches the +// end of either buffer. Thus, there is no concept of partial buffer (not all the data in a buffer are +// valid, only the first N frames are valid and the rest of the buffer might contain invalid or silence +// data. So, when the very last buffer is partially filled, its completion will not get singled until +// all data is consumed, which might become undesirable when the size of a buffer is large and valid frame +// count is low. +// In WinBlue, a driver implements IMiniportStreamAudioEngineNode2 to claim being able to handle the very +// last buffer that's partial filled. +// For a driver claiming supporting IMiniportStreamAudioEngineNode2, for the very last buffer position write, +// it will receive the very last buffer write via SetStreamCurrentWritePositionForLastBuffer() call instead of +// SetStreamCurrentWritePosition(). A driver should check _ulWritePosition parameter to see how much valid data +// in the buffer (instead of blindly assuming all the data are valid) before signaling buffer completion. +// No more SetStreamCurrentWritePositionForLastBuffer or SetStreamCurrentWritePosition will be called after this +// SetStreamCurrentWritePositionForLastBuffer() call. +//----------------------------------------------------------------------------------------------------------------------- + +NTSTATUS CMiniportWaveRTStream::SetStreamCurrentWritePositionForLastBuffer(_In_ ULONG _ulWritePosition) +{ + PAGED_CODE (); + DPF_ENTER(("[CMiniportWaveRT::SetStreamCurrentWritePositionForLastBuffer]")); + + return SetCurrentWritePositionInternal(_ulWritePosition); + // Miniport driver needs to prepare to signal buffer completion event + // when it's done with reading the last valid byte - an _ulWritePosition offset from the beginning WaveRT buffer + // Note: _ulWritePosition will be smaller than buffer size in most of the cases +} + |
