summaryrefslogtreecommitdiff
path: root/audio/simpleaudiosample/Source/Main/minwavert.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'audio/simpleaudiosample/Source/Main/minwavert.cpp')
-rw-r--r--audio/simpleaudiosample/Source/Main/minwavert.cpp1683
1 files changed, 1683 insertions, 0 deletions
diff --git a/audio/simpleaudiosample/Source/Main/minwavert.cpp b/audio/simpleaudiosample/Source/Main/minwavert.cpp
new file mode 100644
index 00000000..1d92073d
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/minwavert.cpp
@@ -0,0 +1,1683 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ minwavert.cpp
+
+Abstract:
+
+ Implementation of wavert miniport.
+--*/
+
+#pragma warning (disable : 4127)
+
+#include "definitions.h"
+#include <limits.h>
+#include "endpoints.h"
+#include "minwavert.h"
+#include "minwavertstream.h"
+#include "micarraywavtable.h"
+
+#define EFFECTS_LIST_COUNT 2
+
+//=============================================================================
+// CMiniportWaveRT
+//=============================================================================
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CreateMiniportWaveRTSimpleAudioSample
+(
+ _Out_ PUNKNOWN * Unknown,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ POOL_FLAGS PoolFlags,
+ _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 (PoolFlags, 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_pDrmPort)
+ {
+ m_pDrmPort->Release();
+ m_pDrmPort = NULL;
+ }
+
+ if (m_pPortEvents)
+ {
+ m_pPortEvents->Release();
+ m_pPortEvents = NULL;
+ }
+
+ if (m_SystemStreams)
+ {
+ ExFreePoolWithTag( m_SystemStreams, MINWAVERT_POOLTAG );
+ m_SystemStreams = NULL;
+ }
+
+} // ~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 sets the ResultantFormat to be the only supported
+ format for the MicArray endpoint.
+
+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.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(PinId);
+
+ ULONG requiredSize;
+
+ PAGED_CODE();
+
+ if (!IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ //If called for the mic array pin, set ResultantFormat to be the endpoint's only supported format.
+ //Otherwise, allow the class handler to set ResultantFormat.
+ if ((this->m_DeviceType) == eMicArrayDevice1)
+ {
+ requiredSize = sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE);
+
+ //
+ // 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;
+ }
+
+ //Set ResultantFormat to be the only supported format for the MicArray endpoint.
+ PKSDATAFORMAT_WAVEFORMATEXTENSIBLE resultantFormat;
+ resultantFormat = (PKSDATAFORMAT_WAVEFORMATEXTENSIBLE)ResultantFormat;
+ *resultantFormat = *MicArrayPinSupportedDeviceFormats;
+ *ResultantFormatLength = requiredSize;
+
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ 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_ulSystemAllocated = 0;
+ m_SystemStreams = NULL;
+ m_bGfxEnabled = FALSE;
+ m_pMixFormat = NULL;
+ m_pDeviceFormat = NULL;
+ m_ulMixDrmContentId = 0;
+ m_pbMuted = NULL;
+ m_plVolumeLevel = NULL;
+ RtlZeroMemory(&m_MixDrmRights, sizeof(m_MixDrmRights));
+
+ //
+ // Init the audio-engine used by the render devices.
+ //
+ if (IsRenderDevice())
+ {
+ if (m_ulMaxSystemStreams == 0 )
+ {
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ // System streams.
+ size = sizeof(PCMiniportWaveRTStream) * m_ulMaxSystemStreams;
+ m_SystemStreams = (PCMiniportWaveRTStream *)ExAllocatePool2(POOL_FLAG_NON_PAGED, size, MINWAVERT_POOLTAG);
+ if (m_SystemStreams == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // For DRM support.
+ //
+ if (!NT_SUCCESS(Port_->QueryInterface(IID_IDrmPort2, (PVOID *)&m_pDrmPort)))
+ {
+ m_pDrmPort = NULL;
+ }
+ }
+
+ //
+ // For KS event support.
+ //
+ if (!NT_SUCCESS(Port_->QueryInterface(IID_IPortEvents, (PVOID *)&m_pPortEvents)))
+ {
+ m_pPortEvents = 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;
+
+ //
+ // If the data format attributes were specified, extract them.
+ //
+ if ( 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);
+ }
+
+ // Check if we have enough streams.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = ValidateStreamCreate(Pin, Capture);
+ }
+
+ // Determine if the format is valid.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = IsFormatSupported(Pin, Capture, DataFormat);
+ }
+
+ // Instantiate a stream. Stream must be in
+ // NonPagedPool(Nx) because of file saving.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ stream = new (POOL_FLAG_NON_PAGED, 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));
+ }
+ 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;
+
+ if (Pin >= m_pMiniportPair->WaveDescriptor->PinCount)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // 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.
+ //
+ numModes = GetPinSupportedDeviceModes(Pin, &modeInfo);
+ if (numModes == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ // 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 (IsSystemCapturePin(_Pin))
+ {
+ VERIFY_PIN_INSTANCE_RESOURCES_AVAILABLE(ntStatus, m_ulSystemAllocated, m_ulMaxSystemStreams);
+ }
+
+ }
+ else
+ {
+
+ if (IsSystemRenderPin(_Pin))
+ {
+ VERIFY_PIN_INSTANCE_RESOURCES_AVAILABLE(ntStatus, m_ulSystemAllocated, m_ulMaxSystemStreams);
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg()
+_Use_decl_annotations_
+VOID CMiniportWaveRT::AcquireFormatsAndModesLock()
+{
+ KeAcquireSpinLock(&m_DeviceFormatsAndModesLock, &m_DeviceFormatsAndModesIrql);
+}
+
+#pragma code_seg()
+_Use_decl_annotations_
+VOID CMiniportWaveRT::ReleaseFormatsAndModesLock()
+{
+ KeReleaseSpinLock(&m_DeviceFormatsAndModesLock, m_DeviceFormatsAndModesIrql);
+}
+
+//---------------------------------------------------------------------------
+// GetPinSupportedDeviceFormats
+//
+// Return supported formats for a given pin.
+//
+// Return value
+// The number of KSDATAFORMAT_WAVEFORMATEXTENSIBLE items.
+//
+// Remarks
+// Supported formats index array follows same order as filter's pin
+// descriptor list.
+//
+#pragma code_seg()
+_Use_decl_annotations_
+ULONG CMiniportWaveRT::GetPinSupportedDeviceFormats(_In_ ULONG PinId, _Outptr_opt_result_buffer_(return) KSDATAFORMAT_WAVEFORMATEXTENSIBLE **ppFormats)
+{
+ PPIN_DEVICE_FORMATS_AND_MODES pDeviceFormatsAndModes = NULL;
+
+ AcquireFormatsAndModesLock();
+
+ pDeviceFormatsAndModes = m_DeviceFormatsAndModes;
+ ASSERT(m_DeviceFormatsAndModesCount > PinId);
+ ASSERT(pDeviceFormatsAndModes[PinId].WaveFormats != NULL);
+ ASSERT(pDeviceFormatsAndModes[PinId].WaveFormatsCount > 0);
+
+ if (ppFormats != NULL)
+ {
+ *ppFormats = pDeviceFormatsAndModes[PinId].WaveFormats;
+ }
+
+ ReleaseFormatsAndModesLock();
+
+ return pDeviceFormatsAndModes[PinId].WaveFormatsCount;
+}
+
+//---------------------------------------------------------------------------
+// GetPinSupportedDeviceModes
+//
+// Return mode information for a given pin.
+//
+// Return value
+// The number of MODE_AND_DEFAULT_FORMAT items or 0 if none.
+//
+// Remarks
+// Supported formats index array follows same order as filter's pin
+// descriptor list.
+//
+#pragma code_seg()
+_Use_decl_annotations_
+ULONG CMiniportWaveRT::GetPinSupportedDeviceModes(_In_ ULONG PinId, _Outptr_opt_result_buffer_(return) _On_failure_(_Deref_post_null_) MODE_AND_DEFAULT_FORMAT **ppModes)
+{
+ PMODE_AND_DEFAULT_FORMAT modes;
+ ULONG numModes;
+
+ AcquireFormatsAndModesLock();
+
+ ASSERT(m_DeviceFormatsAndModesCount > PinId);
+ ASSERT((m_DeviceFormatsAndModes[PinId].ModeAndDefaultFormatCount == 0) == (m_DeviceFormatsAndModes[PinId].ModeAndDefaultFormat == NULL));
+
+ modes = m_DeviceFormatsAndModes[PinId].ModeAndDefaultFormat;
+ numModes = m_DeviceFormatsAndModes[PinId].ModeAndDefaultFormatCount;
+
+ if (ppModes != NULL)
+ {
+ if (numModes > 0)
+ {
+ *ppModes = modes;
+ }
+ else
+ {
+ // ensure that the returned pointer is NULL
+ // in the event of failure (SAL annotation above
+ // indicates that it must be NULL, and OACR sees a possibility
+ // that it might not be).
+ *ppModes = NULL;
+ }
+ }
+
+ ReleaseFormatsAndModesLock();
+ return numModes;
+}
+
+#pragma code_seg()
+BOOL CMiniportWaveRT::IsSystemCapturePin(ULONG nPinId)
+{
+ AcquireFormatsAndModesLock();
+
+ PINTYPE pinType = m_DeviceFormatsAndModes[nPinId].PinType;
+
+ ReleaseFormatsAndModesLock();
+ return (pinType == SystemCapturePin);
+}
+
+#pragma code_seg()
+BOOL CMiniportWaveRT::IsSystemRenderPin(ULONG nPinId)
+{
+ AcquireFormatsAndModesLock();
+
+ PINTYPE pinType = m_DeviceFormatsAndModes[nPinId].PinType;
+
+ ReleaseFormatsAndModesLock();
+ return (pinType == SystemRenderPin);
+}
+
+#pragma code_seg()
+BOOL CMiniportWaveRT::IsBridgePin(ULONG nPinId)
+{
+ AcquireFormatsAndModesLock();
+
+ PINTYPE pinType = m_DeviceFormatsAndModes[nPinId].PinType;
+
+ ReleaseFormatsAndModesLock();
+ return (pinType == BridgePin);
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::StreamCreated
+(
+ _In_ ULONG _Pin,
+ _In_ PCMiniportWaveRTStream _Stream
+)
+{
+ PAGED_CODE();
+
+ PCMiniportWaveRTStream * streams = NULL;
+ ULONG count = 0;
+
+ DPF_ENTER(("[CMiniportWaveRT::StreamCreated]"));
+
+ if (IsSystemCapturePin(_Pin))
+ {
+ ALLOCATE_PIN_INSTANCE_RESOURCES(m_ulSystemAllocated);
+ return STATUS_SUCCESS;
+ }
+ else if (IsSystemRenderPin(_Pin))
+ {
+
+ ALLOCATE_PIN_INSTANCE_RESOURCES(m_ulSystemAllocated);
+ streams = m_SystemStreams;
+ count = m_ulMaxSystemStreams;
+
+ }
+
+ //
+ // 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 (IsSystemCapturePin(_Pin))
+ {
+ FREE_PIN_INSTANCE_RESOURCES(m_ulSystemAllocated);
+ return STATUS_SUCCESS;
+ }
+ else if (IsSystemRenderPin(_Pin))
+ {
+
+ FREE_PIN_INSTANCE_RESOURCES(m_ulSystemAllocated);
+ streams = m_SystemStreams;
+ count = m_ulMaxSystemStreams;
+ 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;
+
+ UNREFERENCED_PARAMETER(_bCapture);
+
+ if (_ulPin >= m_pMiniportPair->WaveDescriptor->PinCount)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ cPinFormats = GetPinSupportedDeviceFormats(_ulPin, &pPinFormats);
+
+ 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 (IsSystemRenderPin(kspPin->PinId) ||
+ IsSystemCapturePin(kspPin->PinId))
+ {
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (IsBridgePin(kspPin->PinId))
+ {
+ ntStatus = STATUS_NOT_SUPPORTED;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ 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;
+ }
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ pKsFormat = (PKSDATAFORMAT)PropertyRequest->Value;
+ ntStatus = IsFormatSupported(kspPin->PinId, IsSystemCapturePin(kspPin->PinId) || FALSE, pKsFormat);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+ }
+
+ return ntStatus;
+} // PropertyHandlerProposedFormat
+
+//=============================================================================
+#pragma code_seg()
+NTSTATUS
+CMiniportWaveRT_EventHandler_PinCapsChange
+(
+_In_ PPCEVENT_REQUEST EventRequest
+)
+{
+ CMiniportWaveRT* miniport = reinterpret_cast<CMiniportWaveRT*>(EventRequest->MajorTarget);
+ return miniport->EventHandler_PinCapsChange(EventRequest);
+}
+
+//=============================================================================
+#pragma code_seg()
+NTSTATUS
+CMiniportWaveRT::EventHandler_PinCapsChange
+(
+_In_ PPCEVENT_REQUEST EventRequest
+)
+{
+ if (*EventRequest->EventItem->Set != KSEVENTSETID_PinCapsChange)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ switch (EventRequest->Verb)
+ {
+ // Do we support event handling?!?
+ case PCEVENT_VERB_SUPPORT:
+ break;
+ // We should add the event now!
+ case PCEVENT_VERB_ADD:
+ // If we have the interface and EventEntry is defined ...
+ if (EventRequest->EventEntry)
+ {
+ switch (EventRequest->EventItem->Id)
+ {
+ // Add pincaps format change event to support the force sample rate feature
+ case KSEVENT_PINCAPS_FORMATCHANGE:
+ m_pPortEvents->AddEventToEventList(EventRequest->EventEntry);
+ break;
+ default:
+ return STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+ else
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+ break;
+
+ case PCEVENT_VERB_REMOVE:
+ // We cannot remove the event but we can stop generating the
+ // events. However, it also doesn't hurt to always generate them ...
+ break;
+
+ default:
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#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;
+ ULONG i;
+
+ 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);
+
+ if (kspPin->PinId >= m_pMiniportPair->WaveDescriptor->PinCount)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // This property is supported only on some streaming pins.
+ //
+ numModes = GetPinSupportedDeviceModes(kspPin->PinId, &modeInfo);
+
+ ASSERT((modeInfo != NULL && numModes > 0) || (modeInfo == NULL && numModes == 0));
+
+ if (modeInfo == NULL)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // Even for pins that support modes, the pin might not support proposed formats
+ //
+ bFound = FALSE;
+ for (i=0, modeTemp=modeInfo; i<numModes; ++i, ++modeTemp)
+ {
+ if (modeTemp->DefaultFormat != NULL)
+ {
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if (!bFound)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // The property is generally supported on this pin. Handle basic support request.
+ //
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ return PropertyHandler_BasicSupport(PropertyRequest, PropertyRequest->PropertyItem->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 (i=0; i<numModes; ++i, ++modeInfo)
+ {
+ if (modeInfo->Mode == signalProcessingMode)
+ {
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ // Either the mode isn't supported, or the driver doesn't support a
+ // proprosed format for this specific mode.
+ 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::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 (POOL_FLAG_NON_PAGED, 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++;
+ }
+ }
+
+ //
+ // 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.
+ //
+ }
+
+ //
+ // 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_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]"));
+ }
+ }
+
+ pWaveHelper->Release();
+
+ return ntStatus;
+} // PropertyHandler_WaveFilter
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_GenericPin
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+{
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ CMiniportWaveRT* pWave = NULL;
+ CMiniportWaveRTStream * pStream = NULL;
+
+ PAGED_CODE();
+
+ if (PropertyRequest->MajorTarget == NULL ||
+ PropertyRequest->MinorTarget == NULL)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ //
+ // Get a ref to the miniport.
+ //
+ pWave = MajorTarget_to_Obj(PropertyRequest->MajorTarget);
+ pWave->AddRef();
+
+ //
+ // Get a ref to the stream.
+ //
+ pStream = MinorTarget_to_Obj(PropertyRequest->MinorTarget);
+ pStream->AddRef();
+
+exit:
+
+ SAFE_RELEASE(pStream);
+ SAFE_RELEASE(pWave);
+
+ return ntStatus;
+}
+
+#pragma code_seg()
+