Sample Code

windows driver samples/ Microsoft slate system virtual audio device driver sample/ C++/ SlateAudioSample/ minwavert.cpp/

/*++

Copyright (c) Microsoft Corporation All Rights Reserved

Module Name:

    minwavert.cpp

Abstract:

    Implementation of wavert miniport.

--*/

#pragma warning (disable : 4127)

#include <sysvad.h>
#include <limits.h>
#include "SysVadShared.h"
#include "simple.h"
#include "minwavert.h"
#include "minwavertstream.h"
#include "IHVPrivatePropertySet.h"

//=============================================================================
// CMiniportWaveRT
//=============================================================================

//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CreateMiniportWaveRTSYSVAD
( 
    _Out_           PUNKNOWN                              * Unknown,
    _In_            REFCLSID,
    _In_opt_        PUNKNOWN                                UnknownOuter,
    _When_((PoolType & NonPagedPoolMustSucceed) != 0,
       __drv_reportError("Must succeed pool allocations are forbidden. "
			 "Allocation failures cause a system crash"))
    _In_            POOL_TYPE                               PoolType,
    _In_            PUNKNOWN                                UnknownAdapter,
    _In_opt_        PVOID                                   DeviceContext,
    _In_            PENDPOINT_MINIPAIR                      MiniportPair
)
/*++

Routine Description:

  Create the wavert miniport.

Arguments:

  Unknown - 

  RefClsId -

  UnknownOuter -

  PoolType -

  UnkownAdapter -

  DeviceContext -

  MiniportPair -

Return Value:

  NT status code.

--*/
{
    UNREFERENCED_PARAMETER(UnknownOuter);

    PAGED_CODE();

    ASSERT(Unknown);
    ASSERT(MiniportPair);

    CMiniportWaveRT *obj = new (PoolType, MINWAVERT_POOLTAG) CMiniportWaveRT
                                                             (
                                                                UnknownAdapter,
                                                                MiniportPair,
                                                                DeviceContext
                                                             );
    if (NULL == obj)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    
    obj->AddRef();
    *Unknown = reinterpret_cast<IUnknown*>(obj);

    return STATUS_SUCCESS;
}

//=============================================================================
#pragma code_seg("PAGE")
CMiniportWaveRT::~CMiniportWaveRT
( 
    void 
)
/*++

Routine Description:

  Destructor for wavert miniport

Arguments:

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    DPF_ENTER(("[CMiniportWaveRT::~CMiniportWaveRT]"));

    if (m_pDeviceFormat)
    {
        ExFreePoolWithTag( m_pDeviceFormat, MINWAVERT_POOLTAG );
        m_pDeviceFormat = NULL;
    }

    if (m_pMixFormat)
    {
        ExFreePoolWithTag( m_pMixFormat, MINWAVERT_POOLTAG );
        m_pMixFormat = NULL;
    }

    if (m_pbMuted)
    {
        ExFreePoolWithTag( m_pbMuted, MINWAVERT_POOLTAG );
        m_pbMuted = NULL;
    }

    if (m_plVolumeLevel)
    {
        ExFreePoolWithTag( m_plVolumeLevel, MINWAVERT_POOLTAG );
        m_plVolumeLevel = NULL;
    }

    if (m_plPeakMeter)
    {
        ExFreePoolWithTag( m_plPeakMeter, MINWAVERT_POOLTAG );
        m_plPeakMeter = NULL;
    }

    if (m_pDrmPort)
    {
        m_pDrmPort->Release();
        m_pDrmPort = NULL;
    }

    if (m_SystemStreams)
    {
        ExFreePoolWithTag( m_SystemStreams, MINWAVERT_POOLTAG );
        m_SystemStreams = NULL;
    }

    if (m_OffloadStreams)
    {
        ExFreePoolWithTag( m_OffloadStreams, MINWAVERT_POOLTAG );
        m_OffloadStreams = NULL;
    }
    
    if (m_LoopbackStreams)
    {
        ExFreePoolWithTag( m_LoopbackStreams, MINWAVERT_POOLTAG );
        m_LoopbackStreams = NULL;
    }
    
#ifdef SYSVAD_BTH_BYPASS
    if (IsBthHfpDevice())
    {
        SAFE_RELEASE(m_BthHfpDevice);
    }
#endif // SYSVAD_BTH_BYPASS
} // ~CMiniportWaveRT

//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS)
CMiniportWaveRT::DataRangeIntersection
( 
    _In_        ULONG                       PinId,
    _In_        PKSDATARANGE                ClientDataRange,
    _In_        PKSDATARANGE                MyDataRange,
    _In_        ULONG                       OutputBufferLength,
    _Out_writes_bytes_to_opt_(OutputBufferLength, *ResultantFormatLength)
                PVOID                       ResultantFormat,
    _Out_       PULONG                      ResultantFormatLength 
)
/*++

Routine Description:

  The DataRangeIntersection function determines the highest quality 
  intersection of two data ranges.

  This sample just validates the # of channels and lets the class handler
  do the rest.

Arguments:

  PinId -           Pin for which data intersection is being determined. 

  ClientDataRange - Pointer to KSDATARANGE structure which contains the data 
                    range submitted by client in the data range intersection 
                    property request. 

  MyDataRange -         Pin's data range to be compared with client's data 
                        range. In this case we actually ignore our own data 
                        range, because we know that we only support one range.

  OutputBufferLength -  Size of the buffer pointed to by the resultant format 
                        parameter. 

  ResultantFormat -     Pointer to value where the resultant format should be 
                        returned. 

  ResultantFormatLength -   Actual length of the resultant format placed in 
                            ResultantFormat. This should be less than or equal 
                            to OutputBufferLength. 

  Return Value:

    NT status code.

  Remarks:

    This sample driver's custom data intersection handler handles all the
    audio endpoints defined in this driver. Some endpoints support mono formats
    while others do not. The handler is written such that it requires an exact
    match in MaximumChannels. This simplifies the handler but requires the pin
    data ranges to include a separate data range for mono formats if the pin
    supports mono formats.

--*/
{
    ULONG                   requiredSize;

    UNREFERENCED_PARAMETER(PinId);
    UNREFERENCED_PARAMETER(ResultantFormat);

    PAGED_CODE();

    if (!IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
    {
        return STATUS_NOT_IMPLEMENTED;
    }

    requiredSize = sizeof (KSDATAFORMAT_WAVEFORMATEX);

    //
    // Validate return buffer size, if the request is only for the
    // size of the resultant structure, return it now before
    // returning other types of errors.
    //
    if (!OutputBufferLength) 
    {
        *ResultantFormatLength = requiredSize;
        return STATUS_BUFFER_OVERFLOW;
    } 
    else if (OutputBufferLength < requiredSize) 
    {
        return STATUS_BUFFER_TOO_SMALL;
    }

    // Verify channel count is supported. This routine assumes a separate data
    // range for each supported channel count.
    if (((PKSDATARANGE_AUDIO)MyDataRange)->MaximumChannels != ((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumChannels)
    {
        return STATUS_NO_MATCH;
    }
    
    //
    // Ok, let the class handler do the rest.
    //
    return STATUS_NOT_IMPLEMENTED;
} // DataRangeIntersection

//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS)
CMiniportWaveRT::GetDescription
( 
    _Out_ PPCFILTER_DESCRIPTOR * OutFilterDescriptor 
)
/*++

Routine Description:

  The GetDescription function gets a pointer to a filter description. 
  It provides a location to deposit a pointer in miniport's description 
  structure.

Arguments:

  OutFilterDescriptor - Pointer to the filter description. 

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    ASSERT(OutFilterDescriptor);

    *OutFilterDescriptor = &m_FilterDesc;

    return STATUS_SUCCESS;
} // GetDescription

//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS)
CMiniportWaveRT::Init
( 
    _In_  PUNKNOWN                UnknownAdapter_,
    _In_  PRESOURCELIST           ResourceList_,
    _In_  PPORTWAVERT             Port_ 
)
/*++

Routine Description:

  The Init function initializes the miniport. Callers of this function 
  should run at IRQL PASSIVE_LEVEL

Arguments:

  UnknownAdapter - A pointer to the Iuknown interface of the adapter object. 

  ResourceList - Pointer to the resource list to be supplied to the miniport 
                 during initialization. The port driver is free to examine the 
                 contents of the ResourceList. The port driver will not be 
                 modify the ResourceList contents. 

  Port - Pointer to the topology port object that is linked with this miniport. 

Return Value:

  NT status code.

--*/
{
    UNREFERENCED_PARAMETER(UnknownAdapter_);
    UNREFERENCED_PARAMETER(ResourceList_);
    UNREFERENCED_PARAMETER(Port_);
    PAGED_CODE();

    ASSERT(UnknownAdapter_);
    ASSERT(Port_);

    DPF_ENTER(("[CMiniportWaveRT::Init]"));

    NTSTATUS ntStatus = STATUS_SUCCESS;
    size_t   size;

    //
    // Init class data members
    //
    m_ulLoopbackAllocated   = 0;
    m_ulSystemAllocated     = 0;
    m_ulOffloadAllocated    = 0;
    m_SystemStreams         = NULL;
    m_OffloadStreams        = NULL;
    m_LoopbackStreams       = NULL;
    m_bGfxEnabled           = FALSE;
    m_pbMuted               = NULL;
    m_plVolumeLevel         = NULL;
    m_plPeakMeter           = NULL;
    m_pMixFormat            = NULL;
    m_pDeviceFormat         = NULL;
    m_ulMixDrmContentId     = 0;
    m_LoopbackProtection    = CONSTRICTOR_OPTION_DISABLE;
    RtlZeroMemory(&m_MixDrmRights, sizeof(m_MixDrmRights));

    //
    // Init the audio-engine used by the render devices.
    //
    if (IsRenderDevice())
    {
        // Basic validation
        if (m_ulMaxSystemStreams == 0 ||
            m_ulMaxLoopbackStreams == 0)
        {
            return STATUS_INVALID_DEVICE_STATE;
        }
            
        // System streams.
        size = sizeof(PCMiniportWaveRTStream) * m_ulMaxSystemStreams;
        m_SystemStreams = (PCMiniportWaveRTStream *)ExAllocatePoolWithTag(NonPagedPoolNx, size, MINWAVERT_POOLTAG);
        if (m_SystemStreams == NULL)
        {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
        RtlZeroMemory(m_SystemStreams, size);

        // Loopback streams.
        size = sizeof(PCMiniportWaveRTStream) * m_ulMaxLoopbackStreams;
        m_LoopbackStreams = (PCMiniportWaveRTStream *)ExAllocatePoolWithTag(NonPagedPoolNx, size, MINWAVERT_POOLTAG);
        if (m_LoopbackStreams == NULL)
        {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
        RtlZeroMemory(m_LoopbackStreams, size);

        // Basic validation
        if (IsOffloadSupported())
        {
            if (m_ulMaxOffloadStreams == 0)
            {
                return STATUS_INVALID_DEVICE_STATE;
            }
            
            // Offload streams.
            size = sizeof(PCMiniportWaveRTStream) * m_ulMaxOffloadStreams;
            m_OffloadStreams = (PCMiniportWaveRTStream *)ExAllocatePoolWithTag(NonPagedPoolNx, size, MINWAVERT_POOLTAG);
            if (m_OffloadStreams == NULL)
            {
                return STATUS_INSUFFICIENT_RESOURCES;
            }
            RtlZeroMemory(m_OffloadStreams, size);

            // Formats. 
            m_pDeviceFormat = (PKSDATAFORMAT_WAVEFORMATEXTENSIBLE)ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), MINWAVERT_POOLTAG);
            if (m_pDeviceFormat == NULL)
            {
                return STATUS_INSUFFICIENT_RESOURCES;
            }
            if (GetAudioEngineSupportedDeviceFormatsCount() < 1)
            {
                return STATUS_UNSUCCESSFUL;
            }
            RtlCopyMemory((PVOID)(m_pDeviceFormat), (PVOID)(GetAudioEngineSupportedDeviceFormats()), sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE));

            m_pMixFormat = (PKSDATAFORMAT_WAVEFORMATEXTENSIBLE)ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), MINWAVERT_POOLTAG);
            if (m_pMixFormat == NULL)
            {
                return STATUS_INSUFFICIENT_RESOURCES;
            }
            m_pMixFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE);
            m_pMixFormat->DataFormat.Flags = 0;
            m_pMixFormat->DataFormat.Reserved = 0;
            m_pMixFormat->DataFormat.SampleSize = 0;
            m_pMixFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
            m_pMixFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
            m_pMixFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
            m_pMixFormat->WaveFormatExt.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
            m_pMixFormat->WaveFormatExt.Format.nChannels = 2;
            m_pMixFormat->WaveFormatExt.Format.nSamplesPerSec = 48000;
            m_pMixFormat->WaveFormatExt.Format.nBlockAlign = 4;
            m_pMixFormat->WaveFormatExt.Format.nAvgBytesPerSec = 192000;
            m_pMixFormat->WaveFormatExt.Format.wBitsPerSample = 16;
            m_pMixFormat->WaveFormatExt.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
            m_pMixFormat->WaveFormatExt.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
            m_pMixFormat->WaveFormatExt.Samples.wValidBitsPerSample = 16;
            m_pMixFormat->WaveFormatExt.dwChannelMask = KSAUDIO_SPEAKER_STEREO;

            m_bGfxEnabled = FALSE;

            m_pbMuted = (PBOOL)ExAllocatePoolWithTag(NonPagedPoolNx, m_DeviceMaxChannels * sizeof(BOOL), MINWAVERT_POOLTAG);
            if (m_pbMuted == NULL)
            {
                return STATUS_INSUFFICIENT_RESOURCES;
            }
            RtlZeroMemory(m_pbMuted, m_DeviceMaxChannels * sizeof(BOOL));

            m_plVolumeLevel = (PLONG)ExAllocatePoolWithTag(NonPagedPoolNx, m_DeviceMaxChannels * sizeof(LONG), MINWAVERT_POOLTAG);
            if (m_plVolumeLevel == NULL)
            {
                return STATUS_INSUFFICIENT_RESOURCES;
            }
            RtlZeroMemory(m_plVolumeLevel, m_DeviceMaxChannels * sizeof(LONG));

            m_plPeakMeter = (PLONG)ExAllocatePoolWithTag(NonPagedPoolNx, m_DeviceMaxChannels * sizeof(LONG), MINWAVERT_POOLTAG);
            if (m_plPeakMeter == NULL)
            {
                return STATUS_INSUFFICIENT_RESOURCES;
            }
            RtlZeroMemory(m_plPeakMeter, m_DeviceMaxChannels * sizeof(LONG));
        }
        
        // 
        // For DRM support.
        //
        if (!NT_SUCCESS(Port_->QueryInterface(IID_IDrmPort2, (PVOID *)&m_pDrmPort)))
        {
            m_pDrmPort = NULL;
        }
    }
    
    return ntStatus;
} // Init

//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS)
CMiniportWaveRT::NewStream
( 
    _Out_ PMINIPORTWAVERTSTREAM * OutStream,
    _In_  PPORTWAVERTSTREAM       OuterUnknown,
    _In_  ULONG                   Pin,
    _In_  BOOLEAN                 Capture,
    _In_  PKSDATAFORMAT           DataFormat
)
/*++

Routine Description:

  The NewStream function creates a new instance of a logical stream 
  associated with a specified physical channel. Callers of NewStream should 
  run at IRQL PASSIVE_LEVEL.

Arguments:

  OutStream -

  OuterUnknown -

  Pin - 

  Capture - 

  DataFormat -

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    ASSERT(OutStream);
    ASSERT(DataFormat);

    DPF_ENTER(("[CMiniportWaveRT::NewStream]"));

    NTSTATUS                    ntStatus = STATUS_SUCCESS;
    PCMiniportWaveRTStream      stream = NULL;
    GUID                        signalProcessingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT;
    
    *OutStream = NULL;

    // Check if we have enough streams.
    ntStatus = ValidateStreamCreate(Pin, Capture);

    // Determine if the format is valid.
    //
    if (NT_SUCCESS(ntStatus))
    {
        ntStatus = IsFormatSupported(Pin, Capture, DataFormat);
    }

    //
    // If the data format attributes were specified, extract them.
    //
    if (NT_SUCCESS(ntStatus) && (DataFormat->Flags & KSDATAFORMAT_ATTRIBUTES))
    {
        // The attributes are aligned (QWORD alignment) after the data format
        PKSMULTIPLE_ITEM attributes = (PKSMULTIPLE_ITEM) (((PBYTE)DataFormat) + ((DataFormat->FormatSize + FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT));
        ntStatus = GetAttributesFromAttributeList(attributes, attributes->Size, &signalProcessingMode);
    }

    // Instantiate a stream. Stream must be in
    // NonPagedPool(Nx) because of file saving.
    //
    if (NT_SUCCESS(ntStatus))
    {
        stream = new (NonPagedPoolNx, MINWAVERT_POOLTAG) 
            CMiniportWaveRTStream(NULL);

        if (stream)
        {
            stream->AddRef();

            ntStatus = 
                stream->Init
                ( 
                    this,
                    OuterUnknown,
                    Pin,
                    Capture,
                    DataFormat,
                    signalProcessingMode
                );
        }
        else
        {
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
        }
    }

    if (NT_SUCCESS(ntStatus))
    {
        *OutStream = PMINIPORTWAVERTSTREAM(stream);
        (*OutStream)->AddRef();

        // The stream has references now for the caller.  The caller expects these
        // references to be there.
    }

    // This is our private reference to the stream.  The caller has
    // its own, so we can release in any case.
    //
    if (stream)
    {
        stream->Release();
    }
    
    return ntStatus;
} // NewStream

//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS)
CMiniportWaveRT::NonDelegatingQueryInterface
( 
    _In_ REFIID  Interface,
    _COM_Outptr_ PVOID * Object 
)
/*++

Routine Description:

  QueryInterface

Arguments:

  Interface - GUID

  Object - interface pointer to be returned.

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    ASSERT(Object);

    if (IsEqualGUIDAligned(Interface, IID_IUnknown))
    {
        *Object = PVOID(PUNKNOWN(PMINIPORTWAVERT(this)));
    }
    else if (IsEqualGUIDAligned(Interface, IID_IMiniport))
    {
        *Object = PVOID(PMINIPORT(this));
    }
    else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRT))
    {
        *Object = PVOID(PMINIPORTWAVERT(this));
    }
    else if (IsEqualGUIDAligned(Interface, IID_IMiniportAudioSignalProcessing))
    {
        *Object = PVOID(PMINIPORTAudioSignalProcessing(this));
    }
    // In this sample, IMiniportAudioEngineNode is supported only for offloading endpoints.
    // at thso moment, offload could only be enabled for  render endpoints not capture.
    // Incorrectly support IMiniportAudioEngineNode interface by the miniport without underlying 
    // HWAudioEngine node will cause miniport::Init to fail.
    else if (IsEqualGUIDAligned(Interface, IID_IMiniportAudioEngineNode) && IsOffloadSupported())
    {
         *Object = (PVOID)(IMiniportAudioEngineNode*)this;
    }
    else
    {
        *Object = NULL;
    }

    if (*Object)
    {
        // We reference the interface for the caller.

        PUNKNOWN(*Object)->AddRef();
        return STATUS_SUCCESS;
    }

    return STATUS_INVALID_PARAMETER;
} // NonDelegatingQueryInterface

//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetDeviceDescription(_Out_ PDEVICE_DESCRIPTION DmaDeviceDescription)
{
    PAGED_CODE ();

    ASSERT (DmaDeviceDescription);

    DPF_ENTER(("[CMiniportWaveRT::GetDeviceDescription]"));

    RtlZeroMemory (DmaDeviceDescription, sizeof (DEVICE_DESCRIPTION));

    //
    // Init device description. This sample is using the same info for all m_DeviceType(s).
    // 
    
    DmaDeviceDescription->Master = TRUE;
    DmaDeviceDescription->ScatterGather = TRUE;
    DmaDeviceDescription->Dma32BitAddresses = TRUE;
    DmaDeviceDescription->InterfaceType = PCIBus;
    DmaDeviceDescription->MaximumLength = 0xFFFFFFFF;

    return STATUS_SUCCESS;
}

//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportWaveRT::GetModes
(
    _In_                                        ULONG     Pin,
    _Out_writes_opt_(*NumSignalProcessingModes) GUID*     SignalProcessingModes,
    _Inout_                                     ULONG*    NumSignalProcessingModes
)
/*

1.	If Pin is not a valid pin number, 
        return STATUS_INVALID_PARAMETER.
        
2.	If Pin is a valid pin number and it supports n modes (n>0), 
        init out-parameters and return STATUS_SUCCESS.
    
3.  Else this pin doesn't support any mode,
        return STATUS_NOT_SUPPORTED. 
        example: bridge pins or another mode-not-aware pins.

*/
{
    PAGED_CODE();

    DPF_ENTER(("[CMiniportWaveRT::GetModes]"));

    NTSTATUS                ntStatus    = STATUS_INVALID_PARAMETER;
    ULONG                   numModes    = 0;
    MODE_AND_DEFAULT_FORMAT *modeInfo   = NULL;

    //
    // This method is valid only on the following pins:
    //  render is offload capable:
    //      sink (#0) and offload (#1) pins.
    //  render is NOT offload capable:
    //      sink (#0) pin.
    //  capture device: 
    //      source (#1) pin.
    //
    if (IsRenderDevice())
    {
        if (Pin == GetSystemPinId())
        {
            numModes = GetHostPinSupportedDeviceModesCount();
            modeInfo = GetHostPinSupportedDeviceModes();
            ntStatus = numModes ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED;
        }
        else if (Pin == GetLoopbackPinId() || Pin == GetSourcePinId())
        {
            ntStatus = STATUS_NOT_SUPPORTED;
        }
        else if (IsOffloadSupported() && Pin == GetOffloadPinId())
        {
            numModes = GetOffloadPinSupportedDeviceModesCount();
            modeInfo = GetOffloadPinSupportedDeviceModes();
            ntStatus = numModes ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED;
        }
    }
    else // capture device
    {
        switch(Pin)
        {
            case KSPIN_WAVEIN_HOST:                 // source pin
                numModes = GetCapturePinSupportedDeviceModesCount();
                modeInfo = GetCapturePinSupportedDeviceModes();
                ntStatus = numModes ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED;
                break;

            case KSPIN_WAVE_BRIDGE:                 // bridge pin
                ntStatus = STATUS_NOT_SUPPORTED;
                break;
                
            default:
                break;
        }
    }

    IF_FAILED_JUMP(ntStatus, Done);
   
    // If caller requests the modes, verify sufficient buffer size then return the modes
    if (SignalProcessingModes != NULL)
    {
        if (*NumSignalProcessingModes < numModes)
        {
            *NumSignalProcessingModes = numModes;
            ntStatus = STATUS_BUFFER_TOO_SMALL;
            goto Done;
        }

        for (ULONG i=0; i<numModes; ++i)
        {
            SignalProcessingModes[i] = modeInfo[i].Mode;
        }
    }

    ASSERT(numModes > 0);
    *NumSignalProcessingModes = numModes;
    ntStatus = STATUS_SUCCESS;

Done:   
    return ntStatus;
}

//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportWaveRT::ValidateStreamCreate
(
    _In_    ULONG   _Pin,
    _In_    BOOLEAN _Capture
)
{
    PAGED_CODE();

    DPF_ENTER(("[CMiniportWaveRT::ValidateStreamCreate]"));

    NTSTATUS ntStatus = STATUS_NOT_SUPPORTED;

    if (_Capture)
    {
        if (IsRenderDevice())
        {
            if (GetLoopbackPinId() == _Pin)
            {
                if (m_ulLoopbackAllocated < m_ulMaxLoopbackStreams)
                {
                    ntStatus = STATUS_SUCCESS;
                }
                else 
                {
                    ntStatus = STATUS_INSUFFICIENT_RESOURCES;
                }
            }
        }
        else if (KSPIN_WAVEIN_HOST == _Pin)
        {
            ntStatus = STATUS_SUCCESS;
        }
    }
    else
    {
        if (GetSystemPinId() == _Pin)
        {
            if (m_ulSystemAllocated < m_ulMaxSystemStreams)
            {
                ntStatus = STATUS_SUCCESS;
            }
            else
            {
                ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            }
        }
        else if (IsOffloadSupported())
        {
            if (GetOffloadPinId() == _Pin)
            {
                if (m_ulOffloadAllocated < m_ulMaxOffloadStreams)
                {
                    ntStatus = STATUS_SUCCESS;
                }
                else
                {
                    ntStatus = STATUS_INSUFFICIENT_RESOURCES;
                }
            }
        }
    }

    return ntStatus;
}

//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportWaveRT::StreamCreated
(
    _In_ ULONG                  _Pin,
    _In_ PCMiniportWaveRTStream _Stream
)
{
    PAGED_CODE();

    PCMiniportWaveRTStream * streams        = NULL;
    ULONG                    count          = 0;
    
    DPF_ENTER(("[CMiniportWaveRT::StreamOpened]"));
    
    if (!IsRenderDevice())
    {
        return STATUS_SUCCESS;
    }

    if (_Pin == GetLoopbackPinId())
    {
        m_ulLoopbackAllocated++;
        streams = m_LoopbackStreams;
        count = m_ulMaxLoopbackStreams;
        _Stream->m_SaveData.Disable(m_MixDrmRights.CopyProtect);
    }
    else if (_Pin == GetSystemPinId())
    {
        m_ulSystemAllocated++;
        streams = m_SystemStreams;
        count = m_ulMaxSystemStreams;
    }
    else if (IsOffloadSupported() && _Pin == GetOffloadPinId())
    {
        m_ulOffloadAllocated++;
        streams = m_OffloadStreams;
        count = m_ulMaxOffloadStreams;
    }
    
    //
    // Cache this stream's ptr.
    //
    if (streams != NULL)
    {
        ULONG i = 0;
        for (; i<count; ++i)
        {
            if (streams[i] == NULL)
            {
                streams[i] = _Stream;
                break;
            }
        }
        ASSERT(i != count);
    }

    return STATUS_SUCCESS;
}

//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportWaveRT::StreamClosed
(
    _In_ ULONG                  _Pin,
    _In_ PCMiniportWaveRTStream _Stream
)
{
    PAGED_CODE();

    bool                      updateDrmRights = false;
    PCMiniportWaveRTStream  * streams         = NULL;
    ULONG                     count           = 0;

    DPF_ENTER(("[CMiniportWaveRT::StreamClosed]"));

    if (!IsRenderDevice())
    {
        return STATUS_SUCCESS;
    }
    
    if (_Pin == GetLoopbackPinId())
    {
        m_ulLoopbackAllocated--;
        streams = m_LoopbackStreams;
        count = m_ulMaxLoopbackStreams;
    }
    else if (_Pin == GetSystemPinId())
    {
        m_ulSystemAllocated--;
        streams = m_SystemStreams;
        count = m_ulMaxSystemStreams;
        updateDrmRights = true;
    }
    else if (IsOffloadSupported() && _Pin == GetOffloadPinId())
    {
        m_ulOffloadAllocated--;
        streams = m_OffloadStreams;
        count = m_ulMaxOffloadStreams;
        updateDrmRights = true;
    }

    //
    // Cleanup.
    //
    if (streams != NULL)
    {
        ULONG i = 0;
        for (; i<count; ++i)
        {
            if (streams[i] == _Stream)
            {
                streams[i] = NULL;
                break;
            }
        }
        ASSERT(i != count);
    }
    
    //
    // Update mixed drm rights.
    //
    if (updateDrmRights)
    {
        UpdateDrmRights();
    }

    return STATUS_SUCCESS;
}

//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportWaveRT::GetAttributesFromAttributeList
(
    _In_ const KSMULTIPLE_ITEM *_pAttributes,
    _In_ size_t _Size,
    _Out_ GUID* _pSignalProcessingMode
)
/*++

Routine Description:

  Processes attributes list and return known attributes.

Arguments:

  _pAttributes - pointer to KSMULTIPLE_ITEM at head of an attributes list.

  _Size - count of bytes in the buffer pointed to by _pAttributes. The routine
    verifies sufficient buffer size while processing the attributes.

  _pSignalProcessingMode - returns the signal processing mode extracted from
    the attribute list, or AUDIO_SIGNALPROCESSINGMODE_DEFAULT if the attribute
    is not present in the list.

Return Value:

  NT status code.

Remarks

    This function is currently written for a single supported attribute
    (KSATTRIBUTEID_AUDIOSIGNALPROCESSING_MODE). As additional attributes are defined in the future,
    this function should be rewritten to be data driven through tables, etc.

--*/
{
    PAGED_CODE();
    
    DPF_ENTER(("[CMiniportWaveRT::GetAttributesFromAttributeList]"));

    size_t cbRemaining = _Size;

    *_pSignalProcessingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT;

    if (cbRemaining < sizeof(KSMULTIPLE_ITEM))
    {
        return STATUS_INVALID_PARAMETER;
    }
    cbRemaining -= sizeof(KSMULTIPLE_ITEM);

    //
    // Extract attributes.
    //
    PKSATTRIBUTE attributeHeader = (PKSATTRIBUTE)(_pAttributes + 1);

    for (ULONG i = 0; i < _pAttributes->Count; i++)
    {
        if (cbRemaining < sizeof(KSATTRIBUTE))
        {
            return STATUS_INVALID_PARAMETER;
        }

        if (attributeHeader->Attribute == KSATTRIBUTEID_AUDIOSIGNALPROCESSING_MODE)
        {
            KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE* signalProcessingModeAttribute;

            if (cbRemaining < sizeof(KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE))
            {
                return STATUS_INVALID_PARAMETER;
            }

            if (attributeHeader->Size != sizeof(KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE))
            {
                return STATUS_INVALID_PARAMETER;
            }

            signalProcessingModeAttribute = (KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE*)attributeHeader;

            // Return mode to caller.
            *_pSignalProcessingMode = signalProcessingModeAttribute->SignalProcessingMode;
        }
        else
        {
            return STATUS_NOT_SUPPORTED;
        }

        // Adjust pointer and buffer size to next attribute (QWORD aligned)
        ULONG cbAttribute = ((attributeHeader->Size + FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT);

        attributeHeader = (PKSATTRIBUTE) (((PBYTE)attributeHeader) + cbAttribute);
        cbRemaining -= cbAttribute;
    }

    return STATUS_SUCCESS;
}

//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportWaveRT::IsFormatSupported
(
    _In_ ULONG          _ulPin,
    _In_ BOOLEAN        _bCapture,
    _In_ PKSDATAFORMAT  _pDataFormat
)
{
    PAGED_CODE();

    DPF_ENTER(("[CMiniportWaveRT::IsFormatSupported]"));

    NTSTATUS                            ntStatus = STATUS_NO_MATCH;
    PKSDATAFORMAT_WAVEFORMATEXTENSIBLE  pPinFormats = NULL;
    ULONG                               cPinFormats = 0;

    if (_bCapture)
    {
        if (IsRenderDevice())
        {
            if (_ulPin == GetLoopbackPinId())
            {
                pPinFormats = GetLoopbackPinSupportedDeviceFormats();
                cPinFormats = GetLoopbackPinSupportedDeviceFormatsCount();
            }
        }
        else 
        {
            if (_ulPin == KSPIN_WAVEIN_HOST) 
            {
                pPinFormats = GetCapturePinSupportedDeviceFormats();
                cPinFormats = GetCapturePinSupportedDeviceFormatsCount();
            }
        }
    }
    else
    {
        if (_ulPin == GetLoopbackPinId())
        {
            pPinFormats = GetLoopbackPinSupportedDeviceFormats();
            cPinFormats = GetLoopbackPinSupportedDeviceFormatsCount();
        }
        else if (_ulPin == GetSystemPinId())
        {
            pPinFormats = GetHostPinSupportedDeviceFormats();
            cPinFormats = GetHostPinSupportedDeviceFormatsCount();
        }
        else if (IsOffloadSupported() && _ulPin == GetOffloadPinId())
        {
            pPinFormats = GetOffloadPinSupportedDeviceFormats();
            cPinFormats = GetOffloadPinSupportedDeviceFormatsCount();
        }
    }

    for (UINT iFormat = 0; iFormat < cPinFormats; iFormat++)
    {
        PKSDATAFORMAT_WAVEFORMATEXTENSIBLE pFormat = &pPinFormats[iFormat];
        // KSDATAFORMAT VALIDATION
        if (!IsEqualGUIDAligned(pFormat->DataFormat.MajorFormat, _pDataFormat->MajorFormat)) { continue; }
        if (!IsEqualGUIDAligned(pFormat->DataFormat.SubFormat, _pDataFormat->SubFormat)) { continue; }
        if (!IsEqualGUIDAligned(pFormat->DataFormat.Specifier, _pDataFormat->Specifier)) { continue; }
        if (pFormat->DataFormat.FormatSize < sizeof(KSDATAFORMAT_WAVEFORMATEX)) { continue; }

        // WAVEFORMATEX VALIDATION
        PWAVEFORMATEX pWaveFormat = reinterpret_cast<PWAVEFORMATEX>(_pDataFormat + 1);
        
        if (pWaveFormat->wFormatTag != WAVE_FORMAT_EXTENSIBLE)
        {
            if (pWaveFormat->wFormatTag != EXTRACT_WAVEFORMATEX_ID(&(pFormat->WaveFormatExt.SubFormat))) { continue; }
        }
        if (pWaveFormat->nChannels  != pFormat->WaveFormatExt.Format.nChannels) { continue; }
        if (pWaveFormat->nSamplesPerSec != pFormat->WaveFormatExt.Format.nSamplesPerSec) { continue; }
        if (pWaveFormat->nBlockAlign != pFormat->WaveFormatExt.Format.nBlockAlign) { continue; }
        if (pWaveFormat->wBitsPerSample != pFormat->WaveFormatExt.Format.wBitsPerSample) { continue; }

        if (pWaveFormat->wFormatTag != WAVE_FORMAT_EXTENSIBLE)
        {
            ntStatus = STATUS_SUCCESS;
            break;
        }

        // WAVEFORMATEXTENSIBLE VALIDATION
        if (pWaveFormat->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) { continue; }

        PWAVEFORMATEXTENSIBLE pWaveFormatExt = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(pWaveFormat);
        if (pWaveFormatExt->Samples.wValidBitsPerSample != pFormat->WaveFormatExt.Samples.wValidBitsPerSample) { continue; }
        if (pWaveFormatExt->dwChannelMask != pFormat->WaveFormatExt.dwChannelMask) { continue; }
        if (!IsEqualGUIDAligned(pWaveFormatExt->SubFormat, pFormat->WaveFormatExt.SubFormat)) { continue; }

        ntStatus = STATUS_SUCCESS;
        break;
    }

    return ntStatus;
}    

//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportWaveRT::PropertyHandlerProposedFormat
(
    _In_ PPCPROPERTY_REQUEST      PropertyRequest
)
{
    PKSP_PIN                kspPin                  = NULL;
    PKSDATAFORMAT           pKsFormat               = NULL;
    ULONG                   cbMinSize               = 0;
    NTSTATUS                ntStatus                = STATUS_INVALID_PARAMETER;

    PAGED_CODE();

    DPF_ENTER(("[CMiniportWaveRT::PropertyHandlerProposedFormat]"));
    
    // All properties handled by this handler require at least a KSP_PIN descriptor.

    // Verify instance data stores at least KSP_PIN fields beyond KSPPROPERTY.
    if (PropertyRequest->InstanceSize < (sizeof(KSP_PIN) - RTL_SIZEOF_THROUGH_FIELD(KSP_PIN, Property)))
    {
        return STATUS_INVALID_PARAMETER;
    }

    // Extract property descriptor from property request instance data
    kspPin = CONTAINING_RECORD(PropertyRequest->Instance, KSP_PIN, PinId);

    //
    // This method is valid only on streaming pins.
    //
    if (IsRenderDevice())
    {
        if (kspPin->PinId == GetSystemPinId() ||
            kspPin->PinId == GetLoopbackPinId() ||
            (IsOffloadSupported() && kspPin->PinId == GetOffloadPinId()))
        {
            ntStatus = STATUS_SUCCESS;
        }
        else if (kspPin->PinId == GetSourcePinId())
        {
            ntStatus = STATUS_NOT_SUPPORTED;
        }
        else 
        {
            ntStatus = STATUS_INVALID_PARAMETER;
        }
    }
    else // capture device
    {
        switch(kspPin->PinId)
        {
            case KSPIN_WAVEIN_HOST:                 // source pin
                ntStatus = STATUS_SUCCESS;
                break;

            case KSPIN_WAVE_BRIDGE:                 // bridge pin
                ntStatus = STATUS_NOT_SUPPORTED;
                break;
                
            default:
                ntStatus = STATUS_INVALID_PARAMETER;
                break;
        }
    }

    if (!NT_SUCCESS(ntStatus))
    {
        return ntStatus;
    }

    cbMinSize = sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE);
   
    // Handle KSPROPERTY_TYPE_BASICSUPPORT query
    if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
    {
        ULONG flags = PropertyRequest->PropertyItem->Flags;
        
        return PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL);
    }

    // Verify value size
    if (PropertyRequest->ValueSize == 0)
    {
        PropertyRequest->ValueSize = cbMinSize;
        return STATUS_BUFFER_OVERFLOW;
    }
    if (PropertyRequest->ValueSize < cbMinSize)
    {
        return STATUS_BUFFER_TOO_SMALL;
    }

    // Only SET is supported for this property
    if ((PropertyRequest->Verb & KSPROPERTY_TYPE_SET) == 0)
    {
        return STATUS_INVALID_DEVICE_REQUEST;
    }

    pKsFormat = (PKSDATAFORMAT)PropertyRequest->Value;
    ntStatus = IsFormatSupported(kspPin->PinId, 
                                 !IsRenderDevice() || kspPin->PinId == GetLoopbackPinId(),
                                 pKsFormat);
    if (!NT_SUCCESS(ntStatus))
    {
        return ntStatus;
    }

    //
    // Make sure there are enough resources to handle a new pin creation with
    // this format.
    //
    if (IsOffloadSupported() && kspPin->PinId == GetOffloadPinId())
    {
        ntStatus = ValidateStreamCreate(kspPin->PinId, FALSE);
    }

    return ntStatus;
} // PropertyHandlerProposedFormat

//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportWaveRT::PropertyHandlerProposedFormat2
(
    _In_ PPCPROPERTY_REQUEST      PropertyRequest
)
{
    PKSP_PIN                kspPin                  = NULL;
    ULONG                   cbMinSize               = 0;
    NTSTATUS                ntStatus                = STATUS_INVALID_PARAMETER;
    ULONG                   numModes                = 0;
    MODE_AND_DEFAULT_FORMAT *modeInfo               = NULL;
    MODE_AND_DEFAULT_FORMAT *modeTemp               = NULL;
    PKSMULTIPLE_ITEM        pKsItemsHeader          = NULL;
    PKSMULTIPLE_ITEM        pKsItemsHeaderOut       = NULL;
    size_t                  cbItemsList             = 0;
    GUID                    signalProcessingMode    = {0};
    BOOLEAN                 bFound                  = FALSE;

    PAGED_CODE();

    DPF_ENTER(("[CMiniportWaveRT::PropertyHandlerProposedFormat2]"));
    
    // All properties handled by this handler require at least a KSP_PIN descriptor.

    // Verify instance data stores at least KSP_PIN fields beyond KSPPROPERTY.
    if (PropertyRequest->InstanceSize < (sizeof(KSP_PIN) - RTL_SIZEOF_THROUGH_FIELD(KSP_PIN, Property)))
    {
        return STATUS_INVALID_PARAMETER;
    }

    // Extract property descriptor from property request instance data
    kspPin = CONTAINING_RECORD(PropertyRequest->Instance, KSP_PIN, PinId);

    //
    // This method is valid only on streaming pins.
    //
    if (IsRenderDevice())
    {
        if (kspPin->PinId == GetSystemPinId())
        {
            numModes = GetHostPinSupportedDeviceModesCount();
            modeInfo = GetHostPinSupportedDeviceModes();
            ntStatus = STATUS_SUCCESS;
        }
        else if (IsOffloadSupported() && kspPin->PinId == GetOffloadPinId())
        {
            numModes = GetOffloadPinSupportedDeviceModesCount();
            modeInfo = GetOffloadPinSupportedDeviceModes();
            ntStatus = STATUS_SUCCESS;
        }
        else if (kspPin->PinId == GetLoopbackPinId() ||
                 kspPin->PinId == GetSourcePinId())
        {
            ntStatus = STATUS_NOT_SUPPORTED;
        }
        else
        {
            ntStatus = STATUS_INVALID_PARAMETER;
        }
    }
    else // capture device
    {
        switch(kspPin->PinId)
        {
            case KSPIN_WAVEIN_HOST:                 // source pin
                numModes = GetCapturePinSupportedDeviceModesCount();
                modeInfo = GetCapturePinSupportedDeviceModes();
                ntStatus = STATUS_SUCCESS;
                break;

            case KSPIN_WAVE_BRIDGE:                 // bridge pin
                ntStatus = STATUS_NOT_SUPPORTED;
                break;
                
            default:
                ntStatus = STATUS_INVALID_PARAMETER;
                break;
        }
    }

    if (!NT_SUCCESS(ntStatus))
    {
        return ntStatus;
    }

    ASSERT((modeInfo != NULL && numModes > 0) || (modeInfo == NULL && numModes == 0));
    
    // Handle KSPROPERTY_TYPE_BASICSUPPORT query
    if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
    {
        ULONG   flags = PropertyRequest->PropertyItem->Flags;
        ULONG   i;
        
        // KSPROPERTY_PIN_PROPOSEDATAFORMAT2 support is conditional. Turn off GET support if the
        // pin has no proposed formats.
        bFound = FALSE;
        for (i=0, modeTemp=modeInfo; i<numModes; ++i, ++modeTemp)
        {
            if (modeTemp->DefaultFormat != NULL)
            {
                bFound = TRUE;
                break;
            }
        }
        
        if (!bFound)
        {
            flags &= ~KSPROPERTY_TYPE_GET;
        }
        return PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL);
    }

    //
    // Get the mode if specified.
    //
    pKsItemsHeader = (PKSMULTIPLE_ITEM)(kspPin + 1);
    cbItemsList = (((PBYTE)PropertyRequest->Instance) + PropertyRequest->InstanceSize) - (PBYTE)pKsItemsHeader;

    ntStatus = GetAttributesFromAttributeList(pKsItemsHeader, cbItemsList, &signalProcessingMode);
    if (!NT_SUCCESS(ntStatus))
    {
        return ntStatus;
    }

    //
    // Get the info associated with this mode.
    //
    bFound = FALSE;
    for (ULONG i=0; i<numModes; ++i, ++modeInfo)
    {
        if (modeInfo->Mode == signalProcessingMode)
        {
            bFound = TRUE;
            break;
        }
    }
    
    if (!bFound || modeInfo->DefaultFormat == NULL)
    {
        return STATUS_NOT_SUPPORTED;
    }

    //
    // Compute output data buffer.
    //
    cbMinSize = modeInfo->DefaultFormat->FormatSize;
    cbMinSize = (cbMinSize + 7) & ~7;

    pKsItemsHeaderOut = (PKSMULTIPLE_ITEM)((PBYTE)PropertyRequest->Value + cbMinSize);

    if (cbItemsList > MAXULONG)
    {
        return STATUS_INVALID_PARAMETER;
    }

    // Total # of bytes.
    ntStatus = RtlULongAdd(cbMinSize, (ULONG)cbItemsList, &cbMinSize);
    if (!NT_SUCCESS(ntStatus))
    {
        return STATUS_INVALID_PARAMETER;
    }
        
    // Property not supported.
    if (cbMinSize == 0)
    {
        return STATUS_NOT_SUPPORTED;
    }

    // Verify value size
    if (PropertyRequest->ValueSize == 0)
    {
        PropertyRequest->ValueSize = cbMinSize;
        return STATUS_BUFFER_OVERFLOW;
    }
    if (PropertyRequest->ValueSize < cbMinSize)
    {
        return STATUS_BUFFER_TOO_SMALL;
    }

    // Only GET is supported for this property
    if ((PropertyRequest->Verb & KSPROPERTY_TYPE_GET) == 0)
    {
        return STATUS_INVALID_DEVICE_REQUEST;
    }

    // Copy the proposed default format.
    RtlCopyMemory(PropertyRequest->Value, modeInfo->DefaultFormat, modeInfo->DefaultFormat->FormatSize);

    // Copy back the attribute list.
    ASSERT(cbItemsList > 0);
    ((KSDATAFORMAT*)PropertyRequest->Value)->Flags = KSDATAFORMAT_ATTRIBUTES;
    RtlCopyMemory(pKsItemsHeaderOut, pKsItemsHeader, cbItemsList);
    
    PropertyRequest->ValueSize = cbMinSize;

    return STATUS_SUCCESS;
} // PropertyHandlerProposedFormat




//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportWaveRT::PropertyHandlerEffectListRequest
(
    _In_ PPCPROPERTY_REQUEST      PropertyRequest
)
{
    GUID StreamEffectList[] =
    {
        AUDIO_EFFECT_TYPE_LOUDNESS_EQUALIZER,
        AUDIO_EFFECT_TYPE_VIRTUAL_SURROUND
    };

    PAGED_CODE();

    DPF_ENTER(("[CMiniportWaveRT::PropertyHandlerEffectListRequest]"));

    // This specific APO->driver communication example is mainly added to show to this communication is done.
    // It skips the pin id validation and returns pin specific answers to the caller, which a real miniport 
    // audio driver probably needs to tate care of.

    // Handle KSPROPERTY_TYPE_BASICSUPPORT query
    if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
    {
        return PropertyHandler_BasicSupport(PropertyRequest, PropertyRequest->PropertyItem->Flags, VT_ILLEGAL);
    }

    // Verify instance data stores at least KSP_PIN fields beyond KSPPROPERTY.
    if (PropertyRequest->InstanceSize < (sizeof(KSP_PIN) - RTL_SIZEOF_THROUGH_FIELD(KSP_PIN, Property)))
    {
        return STATUS_INVALID_PARAMETER;
    }

    if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
    {
        PKSMULTIPLE_ITEM ksMultipleItem;
        ULONG ulEffectsCount = ARRAYSIZE(StreamEffectList);
        ULONG cbMinSize;
        LPGUID pEffectGuids = NULL;

        // Compute min value size requirements    
        cbMinSize = sizeof(KSMULTIPLE_ITEM) + ulEffectsCount * sizeof(GUID);

        // Verify value size
        if (PropertyRequest->ValueSize == 0)
        {
            PropertyRequest->ValueSize = cbMinSize;
            return STATUS_BUFFER_OVERFLOW;
        }
        if (PropertyRequest->ValueSize < cbMinSize)
        {
            return STATUS_BUFFER_TOO_SMALL;
        }
        // Value is a KSMULTIPLE_ITEM followed by list of GUIDs.
        ksMultipleItem = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
        pEffectGuids = (LPGUID)(ksMultipleItem + 1);

        // Copy effect guid 
        RtlCopyMemory(pEffectGuids, StreamEffectList, ulEffectsCount * sizeof(GUID));

        // Miniport filled in the list of GUIDs. Fill in the KSMULTIPLE_ITEM header.
        ksMultipleItem->Size = sizeof(KSMULTIPLE_ITEM) + ulEffectsCount * sizeof(GUID);
        ksMultipleItem->Count = ulEffectsCount;

        PropertyRequest->ValueSize = ksMultipleItem->Size;
        return STATUS_SUCCESS;
    }

    return STATUS_INVALID_DEVICE_REQUEST;

} // PropertyHandlerEffectListRequest
//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportWaveRT::UpdateDrmRights
(
    void
)
/*++

Routine Description:

  Updates the mixed DrmRights. This is done by creating an array of existing
  content ids and asking DrmPort to create a new contend id with a mixed
  DrmRights structure.
  The new DrmRights structure should be enforced, if everything goes well.

Arguments:

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    DPF_ENTER(("[CMiniportWaveRT::UpdateDrmRights]"));
    
    NTSTATUS        ntStatus                = STATUS_UNSUCCESSFUL;
    ULONG           ulMixDrmContentId       = 0;
    BOOL            fCreatedContentId       = FALSE;
    DRMRIGHTS       MixDrmRights            = {FALSE, 0, FALSE};
    ULONG           ulContentIndex          = 0;
    ULONG*          ulContentIds            = NULL;

    //
    // This function only runs if IID_DrmPort is implemented in Wave port.
    //
    if (!m_pDrmPort)
    {
        return STATUS_UNSUCCESSFUL;
    }

    ulContentIds = new (NonPagedPoolNx, MINWAVERT_POOLTAG) ULONG[m_ulMaxSystemStreams + m_ulMaxOffloadStreams];
    if (!ulContentIds)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    // Create an array of all StreamIds.
    //
    for (ULONG i = 0; i < m_ulMaxSystemStreams; i++)
    {
        if (m_SystemStreams[i])
        {
            ulContentIds[ulContentIndex] = m_SystemStreams[i]->m_ulContentId;
            ulContentIndex++;
        }
    }

    for (ULONG i = 0; i < m_ulMaxOffloadStreams; i++)
    {
        ASSERT(IsOffloadSupported());
        
        if (m_OffloadStreams[i])
        {
            ulContentIds[ulContentIndex] = m_OffloadStreams[i]->m_ulContentId;
            ulContentIndex++;
        }
    }

    //
    // Create the new contentId.
    //
    if (ulContentIndex)
    {
        ntStatus = 
            m_pDrmPort->CreateContentMixed
            (
                ulContentIds,
                ulContentIndex,
                &ulMixDrmContentId
            );
        
        if (NT_SUCCESS(ntStatus))
        {
            fCreatedContentId = TRUE;
            ntStatus = 
                m_pDrmPort->GetContentRights
                (
                    ulMixDrmContentId, 
                    &MixDrmRights
                );
        }
    }

    //
    // If successful, destroy the old ContentId and update global rights.
    //
    if (NT_SUCCESS(ntStatus))
    {
        m_pDrmPort->DestroyContent(m_ulMixDrmContentId);
        m_ulMixDrmContentId = ulMixDrmContentId;
        RtlCopyMemory(&m_MixDrmRights, &MixDrmRights, sizeof(m_MixDrmRights));

        //
        // At this point the driver should enforce the new DrmRights.
        // The sample driver handles DrmRights per stream basis, and 
        // stops writing the stream to disk, if CopyProtect = TRUE.
        //

        //
        // If DigitalOutputDisable or CopyProtect is true, enable HDCP
        // 
        if (m_DeviceType == eHdmiDevice &&
            (m_MixDrmRights.DigitalOutputDisable || m_MixDrmRights.CopyProtect))
        {
            // Enable HDCP here.
        }
    } 

    //
    // Cleanup if failed
    // 
    if (!NT_SUCCESS(ntStatus) && fCreatedContentId)
    {
        m_pDrmPort->DestroyContent(ulMixDrmContentId);
    }

    //
    // Free allocated memory.
    //
    ASSERT(ulContentIds);
    delete [] ulContentIds;
    ulContentIds = NULL;

    return ntStatus;
} // UpdateDrmRights

//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
PropertyHandler_WaveFilter
( 
    _In_ PPCPROPERTY_REQUEST      PropertyRequest 
)
/*++

Routine Description:

  Redirects general property request to miniport object

Arguments:

  PropertyRequest - 

Return Value:

  NT status code.

--*/
{
    PAGED_CODE();

    NTSTATUS            ntStatus = STATUS_INVALID_DEVICE_REQUEST;
    CMiniportWaveRT*    pWaveHelper = reinterpret_cast<CMiniportWaveRT*>(PropertyRequest->MajorTarget);

    if (pWaveHelper == NULL)
    {
        return STATUS_INVALID_PARAMETER;
    }

    pWaveHelper->AddRef();

    if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_SysVAD))
    {
        switch (PropertyRequest->PropertyItem->Id)
        {
            case KSPROPERTY_SYSVAD_DEFAULTSTREAMEFFECTS:
                ntStatus = pWaveHelper->PropertyHandlerEffectListRequest(PropertyRequest);
                break;
            default:
                DPF(D_TERSE, ("[PropertyHandler_WaveFilter: Invalid Device Request]"));
        }
    }
    else if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Pin))
    {
        switch (PropertyRequest->PropertyItem->Id)
        {
            case KSPROPERTY_PIN_PROPOSEDATAFORMAT:
                ntStatus = pWaveHelper->PropertyHandlerProposedFormat(PropertyRequest);
                break;
            
            case KSPROPERTY_PIN_PROPOSEDATAFORMAT2:
                ntStatus = pWaveHelper->PropertyHandlerProposedFormat2(PropertyRequest);
                break;

            default:
                DPF(D_TERSE, ("[PropertyHandler_WaveFilter: Invalid Device Request]"));
        }
    }
    else if (pWaveHelper->m_DeviceType == eHdmiDevice &&
             IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Audio))
    {
        switch (PropertyRequest->PropertyItem->Id)
        {
            case KSPROPERTY_AUDIO_VOLUMELEVEL:
                ntStatus = PropertyHandler_Volume(
                                    pWaveHelper->m_pAdapterCommon,
                                    PropertyRequest,
                                    pWaveHelper->m_DeviceMaxChannels);
                break;
            
            case KSPROPERTY_AUDIO_MUTE:
                ntStatus = PropertyHandler_Mute(
                                    pWaveHelper->m_pAdapterCommon,
                                    PropertyRequest,
                                    pWaveHelper->m_DeviceMaxChannels);
                break;
            
            case KSPROPERTY_AUDIO_PEAKMETER2:
                ntStatus = PropertyHandler_PeakMeter2(
                                    pWaveHelper->m_pAdapterCommon,
                                    PropertyRequest,
                                    pWaveHelper->m_DeviceMaxChannels);
                break;
            
            case KSPROPERTY_AUDIO_CPU_RESOURCES:
                ntStatus = PropertyHandler_CpuResources(PropertyRequest);
                break;
            
            default:
                DPF(D_TERSE, ("[PropertyHandler_WaveFilter: Invalid Device Request]"));
                
        }
    }

    pWaveHelper->Release();

    return ntStatus;
} // PropertyHandler_WaveFilter
//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
PropertyHandler_OffloadPin
( 
    _In_ PPCPROPERTY_REQUEST      PropertyRequest 
)
{
    PAGED_CODE();

    NTSTATUS                    ntStatus = STATUS_INVALID_DEVICE_REQUEST;

    if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_OffloadPin))
    {
        switch (PropertyRequest->PropertyItem->Id)
        {
            //KSPROPERTY_OFFLOAD_PIN_VERIFY_STREAM_OBJECT_POINTER

            case KSPROPERTY_OFFLOAD_PIN_GET_STREAM_OBJECT_POINTER:
            {
                if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
                {
                    ULONG cbMinSize = sizeof(ULONG_PTR);

                    if (PropertyRequest->ValueSize == 0)
                    {
                        PropertyRequest->ValueSize = cbMinSize;
                        ntStatus = STATUS_BUFFER_OVERFLOW;
                    }
                    else if (PropertyRequest->ValueSize < cbMinSize)
                    {
                        ntStatus = STATUS_BUFFER_TOO_SMALL;
                    }
                    else
                    {
                        ULONG_PTR *streamObjectPtr = static_cast<ULONG_PTR*>(PropertyRequest->Value);
                        *streamObjectPtr = (ULONG_PTR)(PropertyRequest->MinorTarget);
                        ntStatus = STATUS_SUCCESS;
                    }
                }

                else
                {
                    ntStatus = STATUS_INVALID_PARAMETER;
                }
            }
            break;
            case KSPROPERTY_OFFLOAD_PIN_VERIFY_STREAM_OBJECT_POINTER:
            {
                if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
                {
                    ULONG cbMinSize = sizeof(ULONG_PTR);
                    if (PropertyRequest->InstanceSize < cbMinSize)
                    {
                        return STATUS_INVALID_PARAMETER;
                    }
                    else
                    {
                        ULONG_PTR *streamObjectPtr = static_cast<ULONG_PTR*>(PropertyRequest->Instance);
                        if (*streamObjectPtr == (ULONG_PTR)(PropertyRequest->MinorTarget))
                        {
                            ntStatus = STATUS_SUCCESS;
                        }
                        else
                        {
                            ntStatus = STATUS_UNSUCCESSFUL;
                        }
                    }
                }
                else
                {
                    ntStatus = STATUS_INVALID_PARAMETER;
                }
            }
            break;
            default:
                DPF(D_TERSE, ("[PropertyHandler_OffloadPin: Invalid Request]"));
        }
    }
    return ntStatus;
}

  

Our Services

  • What our customers say about us?

© 2011-2025 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS