|
|
//---------------------------------------------------------------------------
//
// Module: gni.cpp
//
// Description:
//
// Graph Node Instance
//
//@@BEGIN_MSINTERNAL
// Development Team:
// Mike McLaughlin
//
// History: Date Author Comment
//
// To Do: Date Author Comment
//
//@@END_MSINTERNAL
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1996-1999 Microsoft Corporation. All Rights Reserved.
//
//---------------------------------------------------------------------------
#include "common.h"
//---------------------------------------------------------------------------
GUID aguidSysAudioCategories[] = { STATICGUIDOF(KSCATEGORY_SYSAUDIO) };
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
CGraphNodeInstance::CGraphNodeInstance( PGRAPH_NODE pGraphNode, PFILTER_INSTANCE pFilterInstance ) { Assert(pGraphNode); Assert(pFilterInstance); this->pFilterInstance = pFilterInstance; this->ulFlags = pFilterInstance->ulFlags; this->pGraphNode = pGraphNode; AddList(&pGraphNode->lstGraphNodeInstance); }
CGraphNodeInstance::CGraphNodeInstance( PGRAPH_NODE pGraphNode ) { Assert(pGraphNode); this->ulFlags = pGraphNode->ulFlags; this->pGraphNode = pGraphNode; AddList(&pGraphNode->lstGraphNodeInstance); }
CGraphNodeInstance::~CGraphNodeInstance( ) { Assert(this); RemoveList(); if(pFilterInstance != NULL) { Assert(pFilterInstance); pFilterInstance->pGraphNodeInstance = NULL; pFilterInstance->ParentInstance.Invalidate(); } DestroyPinDescriptors(); DestroySysAudioTopology(); delete[] paulNodeNumber; }
NTSTATUS CGraphNodeInstance::Create( ) { NTSTATUS Status = STATUS_SUCCESS; ULONG i, n;
if(this == NULL) { Status = STATUS_NO_SUCH_DEVICE; goto exit; } Assert(this); Assert(pGraphNode);
Status = CreatePinDescriptors(); if(!NT_SUCCESS(Status)) { goto exit; } Status = CreateSysAudioTopology(); if(!NT_SUCCESS(Status)) { goto exit; } if(gcVirtualSources != 0) { paulNodeNumber = new ULONG[gcVirtualSources]; if(paulNodeNumber == NULL) { Trap(); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } for(i = 0; i < gcVirtualSources; i++) { for(n = 0; n < cTopologyNodes; n++) { if(pGraphNode->pDeviceNode->papVirtualSourceData[i]-> pTopologyNode == papTopologyNode[n]) { paulNodeNumber[i] = n; break; } } } } exit: return(Status); }
//---------------------------------------------------------------------------
NTSTATUS CGraphNodeInstance::GetTopologyNodeFileObject( OUT PFILE_OBJECT *ppFileObject, IN ULONG NodeId ) { NTSTATUS Status = STATUS_SUCCESS;
if(this == NULL) { Status = STATUS_NO_SUCH_DEVICE; goto exit; } Assert(this);
if(NodeId >= cTopologyNodes) { DPF2(100, "GetTopologyNodeFileObject: NodeId(%d) >= cTopologyNodes(%d)", NodeId, cTopologyNodes); Status = STATUS_INVALID_DEVICE_REQUEST; goto exit; }
// If virtual topology node, return error
if(papTopologyNode[NodeId]->ulRealNodeNumber == MAXULONG) { DPF(100, "GetTopologyNodeFileObject: ulRealNodeNumber == MAXULONG"); Status = STATUS_INVALID_DEVICE_REQUEST; goto exit; }
if(papFilterNodeInstanceTopologyTable == NULL) { Trap(); Status = STATUS_INVALID_DEVICE_REQUEST; goto exit; }
if(papFilterNodeInstanceTopologyTable[NodeId] == NULL) { Status = CFilterNodeInstance::Create( &papFilterNodeInstanceTopologyTable[NodeId], papTopologyNode[NodeId]->lstLogicalFilterNode.GetListFirstData(), pGraphNode->pDeviceNode, TRUE); // Reuse an instance
if(!NT_SUCCESS(Status)) { goto exit; } } Assert(papFilterNodeInstanceTopologyTable[NodeId]); *ppFileObject = papFilterNodeInstanceTopologyTable[NodeId]->pFileObject;
DPF1(110, "GetToplogyNodeFileObject: using filter for node: %d\n", NodeId); exit: return(Status); }
//---------------------------------------------------------------------------
NTSTATUS CGraphNodeInstance::CreateSysAudioTopology( ) { NTSTATUS Status = STATUS_SUCCESS;
Assert(this); ASSERT(Topology.TopologyNodes == NULL); ASSERT(Topology.TopologyConnections == NULL); ASSERT(papFilterNodeInstanceTopologyTable == NULL);
Topology.CategoriesCount = SIZEOF_ARRAY(aguidSysAudioCategories); Topology.Categories = aguidSysAudioCategories;
CreateTopologyTables();
if(cTopologyNodes != 0) {
Topology.TopologyNodes = new GUID[cTopologyNodes]; if(Topology.TopologyNodes == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; }
papFilterNodeInstanceTopologyTable = new PFILTER_NODE_INSTANCE[cTopologyNodes];
if(papFilterNodeInstanceTopologyTable == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; }
papTopologyNode = new PTOPOLOGY_NODE[cTopologyNodes]; if(papTopologyNode == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } } if(cTopologyConnections != 0) {
Topology.TopologyConnections = new KSTOPOLOGY_CONNECTION[cTopologyConnections];
if(Topology.TopologyConnections == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } } CreateTopologyTables(); exit: if(!NT_SUCCESS(Status)) { DestroySysAudioTopology(); } return(Status); }
VOID CGraphNodeInstance::DestroySysAudioTopology( ) { ULONG n;
delete[] (PVOID)Topology.TopologyNodes; Topology.TopologyNodes = NULL; delete[] (PVOID)Topology.TopologyConnections; Topology.TopologyConnections = NULL; delete[] papTopologyNode; papTopologyNode = NULL;
if(papFilterNodeInstanceTopologyTable != NULL) { for(n = 0; n < cTopologyNodes; n++) { papFilterNodeInstanceTopologyTable[n]->Destroy(); } delete[] papFilterNodeInstanceTopologyTable; papFilterNodeInstanceTopologyTable = NULL; } }
typedef ENUMFUNC (CTopologyNode::*CLIST_TN_PFN2)(PVOID, PVOID);
VOID CGraphNodeInstance::CreateTopologyTables( ) { Assert(this); Assert(pGraphNode);
cTopologyNodes = 0; cTopologyConnections = 0;
// Initialize the "ulSysaudioNodeNumber" field in the TopologyNodes first
ProcessLogicalFilterNodeTopologyNode( &pGraphNode->pDeviceNode->lstLogicalFilterNode, CTopologyNode::InitializeTopologyNode);
ProcessLogicalFilterNodeTopologyNode( &pGraphNode->lstLogicalFilterNode, CTopologyNode::InitializeTopologyNode);
// All the nodes need to be processed first so the ulSysaudioNodeNumber in
// the TopologyNode is correct before any connections are processed.
ProcessLogicalFilterNodeTopologyNode( &pGraphNode->pDeviceNode->lstLogicalFilterNode, CTopologyNode::AddTopologyNode);
ProcessLogicalFilterNodeTopologyNode( &pGraphNode->lstLogicalFilterNode, CTopologyNode::AddTopologyNode);
// Now process all the topology connection lists
ProcessLogicalFilterNodeTopologyConnection( &pGraphNode->pDeviceNode->lstLogicalFilterNode, CTopologyConnection::ProcessTopologyConnection);
ProcessLogicalFilterNodeTopologyConnection( &pGraphNode->lstLogicalFilterNode, CTopologyConnection::ProcessTopologyConnection);
pGraphNode->lstTopologyConnection.EnumerateList( CTopologyConnection::ProcessTopologyConnection, (PVOID)this); }
VOID CGraphNodeInstance::ProcessLogicalFilterNodeTopologyNode( PLIST_MULTI_LOGICAL_FILTER_NODE plstLogicalFilterNode, NTSTATUS (CTopologyNode::*Function)( PVOID pGraphNodeInstance ) ) { PLOGICAL_FILTER_NODE pLogicalFilterNode;
FOR_EACH_LIST_ITEM( plstLogicalFilterNode, pLogicalFilterNode) { Assert(pLogicalFilterNode); pLogicalFilterNode->lstTopologyNode.EnumerateList(Function, this); } END_EACH_LIST_ITEM }
VOID CGraphNodeInstance::ProcessLogicalFilterNodeTopologyConnection( PLIST_MULTI_LOGICAL_FILTER_NODE plstLogicalFilterNode, NTSTATUS (CTopologyConnection::*Function)( PVOID pGraphNodeInstance ) ) { PLOGICAL_FILTER_NODE pLogicalFilterNode;
FOR_EACH_LIST_ITEM( plstLogicalFilterNode, pLogicalFilterNode) { Assert(pLogicalFilterNode); pLogicalFilterNode->lstTopologyConnection.EnumerateList(Function, this); } END_EACH_LIST_ITEM }
ENUMFUNC CTopologyConnection::ProcessTopologyConnection( PVOID pReference ) { PGRAPH_NODE_INSTANCE pGraphNodeInstance = (PGRAPH_NODE_INSTANCE)pReference; PSTART_NODE pStartNode; ULONG ulFromPin; ULONG ulFromNode; ULONG ulToPin; ULONG ulToNode; ULONG PinId;
Assert(this); Assert(pGraphNodeInstance);
ulFromPin = MAXULONG; ulToPin = MAXULONG; #ifdef DEBUG
ulFromNode = MAXULONG; ulToNode = MAXULONG; #endif
// If the connection doesn't connect LFNs on this GraphNode, skip connection
if(!IsTopologyConnectionOnGraphNode(pGraphNodeInstance->pGraphNode)) { DPF3(100, "ProcessTC: %s TC %08x GN %08x - skip TC", pGraphNodeInstance->pGraphNode->pDeviceNode->DumpName(), this, pGraphNodeInstance->pGraphNode); goto exit; }
if(pTopologyPinFrom != NULL) { ulFromNode = pTopologyPinFrom->pTopologyNode->ulSysaudioNodeNumber; ulFromPin = pTopologyPinFrom->ulPinNumber;
ASSERT(pPinInfoFrom == NULL); ASSERT(ulFromNode != MAXULONG); ASSERT(ulFromPin != MAXULONG); }
if(pTopologyPinTo != NULL) { ulToNode = pTopologyPinTo->pTopologyNode->ulSysaudioNodeNumber; ulToPin = pTopologyPinTo->ulPinNumber;
ASSERT(pPinInfoTo == NULL); ASSERT(ulToNode != MAXULONG); ASSERT(ulToPin != MAXULONG); }
if(pGraphNodeInstance->aplstStartNode != NULL) {
for(PinId = 0; PinId < pGraphNodeInstance->cPins; PinId++) {
FOR_EACH_LIST_ITEM( pGraphNodeInstance->aplstStartNode[PinId], pStartNode) {
Assert(pStartNode); if(pPinInfoFrom != NULL) { ASSERT(pTopologyPinFrom == NULL);
if(pStartNode->pPinNode->pPinInfo == pPinInfoFrom) { // This code assumes that a filter's pininfo will show
// up in one SAD pin. If a filter exposes more than one
// major format on the same pin, that pininfo show on
// two different SAD pins.
ASSERT(ulFromNode == KSFILTER_NODE); ASSERT(ulFromPin == MAXULONG || ulFromPin == PinId);
pStartNode->GetStartInfo()-> ulTopologyConnectionTableIndex = pGraphNodeInstance->cTopologyConnections;
ulFromNode = KSFILTER_NODE; ulFromPin = PinId; } }
if(pPinInfoTo != NULL) { ASSERT(pTopologyPinTo == NULL);
if(pStartNode->pPinNode->pPinInfo == pPinInfoTo) { // See above.
ASSERT(ulToNode == KSFILTER_NODE); ASSERT(ulToPin == MAXULONG || ulToPin == PinId);
pStartNode->GetStartInfo()-> ulTopologyConnectionTableIndex = pGraphNodeInstance->cTopologyConnections;
ulToNode = KSFILTER_NODE; ulToPin = PinId; } }
} END_EACH_LIST_ITEM } } if(ulFromPin != MAXULONG && ulToPin != MAXULONG) { pGraphNodeInstance->AddTopologyConnection( ulFromNode, ulFromPin, ulToNode, ulToPin); } exit: return(STATUS_CONTINUE); }
ENUMFUNC CTopologyNode::InitializeTopologyNode( PVOID pReference ) { PGRAPH_NODE_INSTANCE pGraphNodeInstance = (PGRAPH_NODE_INSTANCE)pReference;
Assert(this); Assert(pGraphNodeInstance); ulSysaudioNodeNumber = MAXULONG; return(STATUS_CONTINUE); }
ENUMFUNC CTopologyNode::AddTopologyNode( PVOID pReference ) { PGRAPH_NODE_INSTANCE pGraphNodeInstance = (PGRAPH_NODE_INSTANCE)pReference;
Assert(this); Assert(pGraphNodeInstance);
// Skip duplicate TopologyNodes
if(ulSysaudioNodeNumber != MAXULONG) { DPF1(100, "AddTopologyNode: dup TN: %08x", this); goto exit; } ulSysaudioNodeNumber = pGraphNodeInstance->cTopologyNodes;
if(pGraphNodeInstance->papTopologyNode != NULL) { pGraphNodeInstance->papTopologyNode[ pGraphNodeInstance->cTopologyNodes] = this; } if(pGraphNodeInstance->Topology.TopologyNodes != NULL) { ((GUID *)(pGraphNodeInstance->Topology.TopologyNodes))[ pGraphNodeInstance->cTopologyNodes] = *pguidType; } DPF3(115, "AddTopologyNode: %02x GNI: %08x TN: %08x", pGraphNodeInstance->cTopologyNodes, pGraphNodeInstance, this);
++pGraphNodeInstance->cTopologyNodes; exit: return(STATUS_CONTINUE); }
VOID CGraphNodeInstance::AddTopologyConnection( ULONG ulFromNode, ULONG ulFromPin, ULONG ulToNode, ULONG ulToPin ) { Assert(this); if(Topology.TopologyConnections != NULL) { PKSTOPOLOGY_CONNECTION pKSTopologyConnection = (PKSTOPOLOGY_CONNECTION)&Topology.TopologyConnections[ cTopologyConnections];
pKSTopologyConnection->FromNode = ulFromNode; pKSTopologyConnection->FromNodePin = ulFromPin; pKSTopologyConnection->ToNode = ulToNode; pKSTopologyConnection->ToNodePin = ulToPin; } ++cTopologyConnections;
DPF4(115, "AddTopologyConnection: FN:%02x FNP:%02x TN:%02x TNP:%02x", ulFromNode, ulFromPin, ulToNode, ulToPin); }
//---------------------------------------------------------------------------
NTSTATUS CGraphNodeInstance::CreatePinDescriptors( ) { NTSTATUS Status = STATUS_SUCCESS; ListDataAssertLess<LIST_DATA_START_NODE> lstStartNodeLists; ListDataAssertLess<KSDATARANGE> lstDataRange; PLIST_DATA_START_NODE plstStartNodeOrdered; PSTART_NODE pStartNodeSorted; PSTART_NODE pStartNode; BOOL fSorted; ULONG PinId;
Assert(this); Assert(pGraphNode); ASSERT(paPinDescriptors == NULL); ASSERT(aplstStartNode == NULL); ASSERT(palstTopologyNodeSelect == NULL); ASSERT(palstTopologyNodeNotSelect == NULL); ASSERT(pacPinInstances == NULL); ASSERT(pulPinFlags == NULL); ASSERT(cPins == 0);
// Sort StartNodes by Communication, DataFlow and Major Format GUID
FOR_EACH_LIST_ITEM(&pGraphNode->lstStartNode, pStartNode) { Assert(pStartNode->pPinNode); Assert(pStartNode->pPinNode->pPinInfo);
// Skip any start nodes with no data range
if(pStartNode->pPinNode->pDataRange == NULL) { Trap(); continue; } // Skip any start nodes with no instances left on the pin
if(ulFlags & FLAGS_COMBINE_PINS) { if(pStartNode->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_SINK || pStartNode->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_SOURCE || pStartNode->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_BOTH) {
if(!pStartNode->IsPossibleInstances()) { continue; } } } fSorted = FALSE; FOR_EACH_LIST_ITEM(&lstStartNodeLists, plstStartNodeOrdered) {
FOR_EACH_LIST_ITEM(plstStartNodeOrdered, pStartNodeSorted) { Assert(pStartNodeSorted); Assert(pStartNodeSorted->pPinNode); Assert(pStartNodeSorted->pPinNode->pPinInfo);
// If the same actual pin, combine the pin nodes
if((pStartNode->pPinNode->pPinInfo == pStartNodeSorted->pPinNode->pPinInfo) ||
// Combine only if client wants it that way
(ulFlags & FLAGS_COMBINE_PINS) &&
// Combine only AUDIO major formats
IsEqualGUID( &pStartNode->pPinNode->pDataRange->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
// Only combine SINK, SOURCE, BOTH StartNodes; keep
// NONE and BRIDGE as separate SAD pins
((pStartNode->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_SINK) || (pStartNode->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_SOURCE) || (pStartNode->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_BOTH)) &&
// Combine if same data flow
(pStartNode->pPinNode->pPinInfo->DataFlow == pStartNodeSorted->pPinNode->pPinInfo->DataFlow) &&
// Combine if same communication type OR
((pStartNode->pPinNode->pPinInfo->Communication == pStartNodeSorted->pPinNode->pPinInfo->Communication) ||
// Combine a SINK and a BOTH
((pStartNode->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_SINK) && (pStartNodeSorted->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_BOTH)) ||
// Combine a BOTH and a SINK
((pStartNode->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_BOTH) && (pStartNodeSorted->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_SINK)) ||
// Combine a SOURCE and a BOTH
((pStartNode->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_SOURCE) && (pStartNodeSorted->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_BOTH)) ||
// Combine a BOTH and a SOURCE
((pStartNode->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_BOTH) && (pStartNodeSorted->pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_SOURCE))) &&
// Combine if major format is the same
IsEqualGUID( &pStartNode->pPinNode->pDataRange->MajorFormat, &pStartNodeSorted->pPinNode->pDataRange->MajorFormat)) {
Status = plstStartNodeOrdered->AddListOrdered( pStartNode, FIELD_OFFSET(START_NODE, ulOverhead));
if(!NT_SUCCESS(Status)) { goto exit; } fSorted = TRUE; break; }
} END_EACH_LIST_ITEM
if(fSorted) { break; }
} END_EACH_LIST_ITEM
if(!fSorted) { plstStartNodeOrdered = new LIST_DATA_START_NODE; if(plstStartNodeOrdered == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } Status = plstStartNodeOrdered->AddListOrdered( pStartNode, FIELD_OFFSET(START_NODE, ulOverhead));
if(!NT_SUCCESS(Status)) { goto exit; } Status = lstStartNodeLists.AddList(plstStartNodeOrdered); if(!NT_SUCCESS(Status)) { goto exit; } }
} END_EACH_LIST_ITEM
// Allocate the pin descriptors, pin instance and start node arrays
cPins = lstStartNodeLists.CountList();
// if there are no pins, exit
if(cPins == 0) { goto exit; }
paPinDescriptors = new KSPIN_DESCRIPTOR[cPins]; if(paPinDescriptors == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; }
aplstStartNode = new PLIST_DATA_START_NODE[cPins]; if(aplstStartNode == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } DPF1(100, "CreatePinDescriptors: cPins %d", cPins);
// For each pin, create a list of interfaces, mediums and dataranges
PinId = 0; FOR_EACH_LIST_ITEM(&lstStartNodeLists, plstStartNodeOrdered) { PKSDATARANGE pDataRange, *apDataRanges; BOOL fBoth = TRUE;
ASSERT(PinId < cPins); ASSERT(!plstStartNodeOrdered->IsLstEmpty()); aplstStartNode[PinId] = plstStartNodeOrdered;
FOR_EACH_LIST_ITEM(plstStartNodeOrdered, pStartNode) { Assert(pStartNode); Assert(pStartNode->pPinNode); Assert(pStartNode->pPinNode->pPinInfo);
paPinDescriptors[PinId].DataFlow = pStartNode->pPinNode->pPinInfo->DataFlow;
if(pStartNode->pPinNode->pPinInfo->Communication != KSPIN_COMMUNICATION_BOTH) { fBoth = FALSE; paPinDescriptors[PinId].Communication = pStartNode->pPinNode->pPinInfo->Communication; }
if(paPinDescriptors[PinId].Category == NULL || IsEqualGUID( paPinDescriptors[PinId].Category, &GUID_NULL)) {
paPinDescriptors[PinId].Category = pStartNode->pPinNode->pPinInfo->pguidCategory;
paPinDescriptors[PinId].Name = pStartNode->pPinNode->pPinInfo->pguidName; }
} END_EACH_LIST_ITEM
if(fBoth) { paPinDescriptors[PinId].Communication = KSPIN_COMMUNICATION_SINK; }
// Make a list of all the DataRanges this pin will support
Status = plstStartNodeOrdered->CreateUniqueList( &lstDataRange, (UNIQUE_LIST_PFN)GetStartNodeDataRange, (UNIQUE_LIST_PFN2)CompareDataRangeExact);
if(!NT_SUCCESS(Status)) { goto exit; }
// Put the number of data ranges into the pin descriptor
paPinDescriptors[PinId].DataRangesCount = lstDataRange.CountList(); if(paPinDescriptors[PinId].DataRangesCount != 0) {
// Allocate the array of ptrs to DataRanges; put it into the desc
paPinDescriptors[PinId].DataRanges = new PKSDATARANGE[ paPinDescriptors[PinId].DataRangesCount];
if(paPinDescriptors[PinId].DataRanges == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; }
// Put each data range pointer into the array
apDataRanges = (PKSDATARANGE *)paPinDescriptors[PinId].DataRanges;
FOR_EACH_LIST_ITEM(&lstDataRange, pDataRange) {
*apDataRanges = pDataRange; apDataRanges++; } END_EACH_LIST_ITEM }
// Destroy the data range list
lstDataRange.DestroyList();
// Create the interface array for the pin descriptor
Status = CreateIdentifierArray( plstStartNodeOrdered, &paPinDescriptors[PinId].InterfacesCount, (PKSIDENTIFIER *)&paPinDescriptors[PinId].Interfaces, GetStartNodeInterface);
if(!NT_SUCCESS(Status)) { goto exit; }
// Create the medium array for the pin descriptor
Status = CreateIdentifierArray( plstStartNodeOrdered, &paPinDescriptors[PinId].MediumsCount, (PKSIDENTIFIER *)&paPinDescriptors[PinId].Mediums, GetStartNodeMedium);
if(!NT_SUCCESS(Status)) { goto exit; } DPF6(100, "PinId %d DataFlow %d cD %d cI %d cM %d cSN %d", PinId, paPinDescriptors[PinId].DataFlow, paPinDescriptors[PinId].DataRangesCount, paPinDescriptors[PinId].InterfacesCount, paPinDescriptors[PinId].MediumsCount, aplstStartNode[PinId]->CountList());
// Next pin number
PinId++;
} END_EACH_LIST_ITEM
if((ulFlags & FLAGS_MIXER_TOPOLOGY) == 0) { palstTopologyNodeSelect = new LIST_DATA_TOPOLOGY_NODE[cPins]; if(palstTopologyNodeSelect == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; }
palstTopologyNodeNotSelect = new LIST_DATA_TOPOLOGY_NODE[cPins]; if(palstTopologyNodeNotSelect == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } PLOGICAL_FILTER_NODE pLogicalFilterNode; PTOPOLOGY_NODE pTopologyNode;
FOR_EACH_LIST_ITEM( &pGraphNode->lstLogicalFilterNode, pLogicalFilterNode) {
if(pLogicalFilterNode->GetFlags() & LFN_FLAGS_NOT_SELECT) { FOR_EACH_LIST_ITEM( &pLogicalFilterNode->lstTopologyNode, pTopologyNode) {
for(PinId = 0; PinId < cPins; PinId++) { Status = palstTopologyNodeNotSelect[PinId].AddList( pTopologyNode);
if(!NT_SUCCESS(Status)) { goto exit; } }
} END_EACH_LIST_ITEM }
} END_EACH_LIST_ITEM }
pacPinInstances = new KSPIN_CINSTANCES[cPins]; if(pacPinInstances == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; }
pulPinFlags = new ULONG[cPins]; if (NULL == pulPinFlags) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; }
for(PinId = 0; PinId < cPins; PinId++) { LIST_DATA_GRAPH_PIN_INFO lstGraphPinInfo; PSTART_NODE pStartNode2; PPIN_INFO pPinInfo; BOOL fHWRender = TRUE;
FOR_EACH_LIST_ITEM(aplstStartNode[PinId], pStartNode2) { PGRAPH_PIN_INFO pGraphPinInfo;
pGraphPinInfo = pStartNode2->GetGraphPinInfo(); Assert(pGraphPinInfo);
//
// Set pin type.
// If all startnodes are connected directly to renderer.
//
pPinInfo = pGraphPinInfo->GetPinInfo();
ASSERT(pPinInfo); if ((!(pPinInfo->pFilterNode->GetType() & FILTER_TYPE_RENDERER)) || (KSPIN_DATAFLOW_IN != pPinInfo->DataFlow) || (KSPIN_COMMUNICATION_SINK != pPinInfo->Communication)) { fHWRender = FALSE; }
if(lstGraphPinInfo.CheckDupList(pGraphPinInfo)) { continue; }
Status = lstGraphPinInfo.AddList(pGraphPinInfo); if(!NT_SUCCESS(Status)) { goto exit; }
//
// Set cinstances.
//
if(pGraphPinInfo->IsPinReserved()) { pacPinInstances[PinId].CurrentCount = 1; } if(pGraphPinInfo->GetPinInstances()->PossibleCount == MAXULONG) { pacPinInstances[PinId].PossibleCount = MAXULONG; break; } pacPinInstances[PinId].PossibleCount += pGraphPinInfo->GetPinInstances()->PossibleCount;
if (fHWRender) { fHWRender = (1 < pGraphPinInfo->GetPinInstances()->PossibleCount); }
} END_EACH_LIST_ITEM
pulPinFlags[PinId] = fHWRender;
lstGraphPinInfo.DestroyList(); } exit: if(!NT_SUCCESS(Status)) { DestroyPinDescriptors(); } return(Status); }
VOID CGraphNodeInstance::DestroyPinDescriptors( ) { ULONG PinId;
Assert(this); for(PinId = 0; PinId < cPins; PinId++) { if(paPinDescriptors != NULL) { delete (PVOID)paPinDescriptors[PinId].DataRanges; if(paPinDescriptors[PinId].InterfacesCount > 1) { delete (PVOID)paPinDescriptors[PinId].Interfaces; } if(paPinDescriptors[PinId].MediumsCount > 1) { delete (PVOID)paPinDescriptors[PinId].Mediums; } } if(aplstStartNode != NULL) { delete aplstStartNode[PinId]; } } delete[cPins] aplstStartNode; aplstStartNode = NULL; delete[cPins] paPinDescriptors; paPinDescriptors = NULL; delete[cPins] palstTopologyNodeSelect; palstTopologyNodeSelect = NULL; delete[cPins] palstTopologyNodeNotSelect; palstTopologyNodeNotSelect = NULL; delete[cPins] pacPinInstances; pacPinInstances = NULL; delete[cPins] pulPinFlags; pulPinFlags = NULL; }
NTSTATUS CreateIdentifierArray( PLIST_DATA_START_NODE plstStartNode, PULONG pulCount, PKSIDENTIFIER *ppIdentifier, PKSIDENTIFIER (*GetFunction)( PSTART_NODE pStartNode ) ) { NTSTATUS Status = STATUS_SUCCESS; KSIDENTIFIER *pIdentifier1, *pIdentifier2; ListDataAssertLess<KSIDENTIFIER> lstIdentifier;
Status = plstStartNode->CreateUniqueList( &lstIdentifier, (UNIQUE_LIST_PFN)GetFunction, (UNIQUE_LIST_PFN2)CompareIdentifier);
if(!NT_SUCCESS(Status)) { goto exit; } if((*pulCount = lstIdentifier.CountList()) == 0) { *ppIdentifier = NULL; } else { if(*pulCount == 1) { *ppIdentifier = lstIdentifier.GetListFirstData(); } else { *ppIdentifier = new KSIDENTIFIER[*pulCount]; if(*ppIdentifier == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } pIdentifier1 = *ppIdentifier; AssertAligned(pIdentifier1); FOR_EACH_LIST_ITEM(&lstIdentifier, pIdentifier2) { AssertAligned(pIdentifier1); AssertAligned(pIdentifier2); RtlCopyMemory(pIdentifier1, pIdentifier2, sizeof(KSIDENTIFIER)); pIdentifier1++; } END_EACH_LIST_ITEM } } exit: return(Status); }
PKSDATARANGE GetStartNodeDataRange( PSTART_NODE pStartNode ) { return(pStartNode->pPinNode->pDataRange); }
PKSIDENTIFIER GetStartNodeInterface( PSTART_NODE pStartNode ) { return(pStartNode->pPinNode->pInterface); }
PKSIDENTIFIER GetStartNodeMedium( PSTART_NODE pStartNode ) { return(pStartNode->pPinNode->pMedium); }
//---------------------------------------------------------------------------
//
// This functions checks whether a given TopologyNode is in the Topology
// Connection list.
//
ENUMFUNC FindTopologyNode( IN PTOPOLOGY_CONNECTION pTopologyConnection, IN BOOL fToDirection, IN PTOPOLOGY_NODE pTopologyNode ) { Assert(pTopologyConnection);
if(IS_CONNECTION_TYPE(pTopologyConnection, GRAPH)) { return(STATUS_DEAD_END); } if(fToDirection) { if(pTopologyConnection->pTopologyPinTo != NULL) { if(pTopologyNode == pTopologyConnection->pTopologyPinTo->pTopologyNode) { return(STATUS_SUCCESS); } } } else { if(pTopologyConnection->pTopologyPinFrom != NULL) { if(pTopologyNode == pTopologyConnection->pTopologyPinFrom->pTopologyNode) { return(STATUS_SUCCESS); } } } return(STATUS_CONTINUE); }
BOOL CGraphNodeInstance::IsGraphValid( PSTART_NODE pStartNode, ULONG PinId ) { PFILTER_INSTANCE pFilterInstance; PTOPOLOGY_NODE pTopologyNode; BOOL fCheck;
Assert(this); Assert(pGraphNode); Assert(pStartNode); Assert(pStartNode->pPinNode); Assert(pStartNode->pPinNode->pPinInfo); Assert(pGraphNode->pDeviceNode); ASSERT(PinId < cPins);
//
// First make sure that all GlobalSelect nodes are in StartNode graph.
//
if(pStartNode->pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_IN) {
FOR_EACH_LIST_ITEM( &pGraphNode->pDeviceNode->lstFilterInstance, pFilterInstance) {
if(pFilterInstance->pGraphNodeInstance == NULL) { continue; } Assert(pFilterInstance->pGraphNodeInstance);
FOR_EACH_LIST_ITEM( &pFilterInstance->pGraphNodeInstance->lstTopologyNodeGlobalSelect, pTopologyNode) {
if(EnumerateGraphTopology( pStartNode->GetStartInfo(), (TOP_PFN)FindTopologyNode, pTopologyNode) == STATUS_CONTINUE) {
DPF2(80, "IsGraphValid: TN %08x SN %08x not found Global", pTopologyNode, pStartNode);
return(FALSE); }
} END_EACH_LIST_ITEM
} END_EACH_LIST_ITEM }
//
// Make sure that all Selected nodes are in StartNode graph.
//
if (palstTopologyNodeSelect) { FOR_EACH_LIST_ITEM(&palstTopologyNodeSelect[PinId], pTopologyNode) {
if(EnumerateGraphTopology( pStartNode->GetStartInfo(), (TOP_PFN)FindTopologyNode, pTopologyNode) == STATUS_CONTINUE) {
DPF2(80, "IsGraphValid: TN %08x SN %08x not found Select", pTopologyNode, pStartNode);
return(FALSE); }
} END_EACH_LIST_ITEM } // If a NotSelectNode is in the GlobalSelectList of another FilterInstance,
// don't consider this as an invalid Graph.
// This behaves like an implicit SelectGraph.
//
if (palstTopologyNodeNotSelect) { PTOPOLOGY_NODE pDestroyTopologyNode = NULL; FOR_EACH_LIST_ITEM(&palstTopologyNodeNotSelect[PinId], pTopologyNode) {
if (pDestroyTopologyNode) { DPF2(50, "Removing (1) TN %X %s", pDestroyTopologyNode, pDestroyTopologyNode->pFilterNode->DumpName());
// Remove the topologynode from NotSelect list.
palstTopologyNodeNotSelect[PinId]. RemoveList(pDestroyTopologyNode);
pDestroyTopologyNode = NULL; } fCheck = TRUE; if(pStartNode->pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_IN) {
FOR_EACH_LIST_ITEM( &pGraphNode->pDeviceNode->lstFilterInstance, pFilterInstance) {
if(pFilterInstance->pGraphNodeInstance == NULL) { continue; } Assert(pFilterInstance->pGraphNodeInstance);
// Is this NotSelectNode in the GlobalSelectList of
// another FilterInstance.
// Remove it from NotSelectList and add it to
// GlobalSelectList for this filter as well.
//
if(pFilterInstance->pGraphNodeInstance-> lstTopologyNodeGlobalSelect.EnumerateList( CTopologyNode::MatchTopologyNode, pTopologyNode) == STATUS_SUCCESS) {
if (NT_SUCCESS(lstTopologyNodeGlobalSelect. AddListDup(pTopologyNode))) {
// Mark the topologyNode for deletion.
pDestroyTopologyNode = pTopologyNode; } else { DPF2(4, "Failed to add TN %X to GNI %X GlobalSelectList", pTopologyNode, this); Trap(); }
fCheck = FALSE; break; }
} END_EACH_LIST_ITEM }
if(fCheck) { if(EnumerateGraphTopology( pStartNode->GetStartInfo(), (TOP_PFN)FindTopologyNode, pTopologyNode) == STATUS_SUCCESS) {
DPF2(80, "IsGraphValid: TN %08x SN %08x found NotSelect", pTopologyNode, pStartNode);
return(FALSE); } }
} END_EACH_LIST_ITEM
if (pDestroyTopologyNode) { DPF2(50, "Removing (2) TN %X %s", pDestroyTopologyNode, pDestroyTopologyNode->pFilterNode->DumpName());
// Remove the topologynode from NotSelect list.
palstTopologyNodeNotSelect[PinId]. RemoveList(pDestroyTopologyNode); } } return(TRUE); }
NTSTATUS CGraphNodeInstance::GetPinInstances( PIRP pIrp, PKSP_PIN pPin, PKSPIN_CINSTANCES pcInstances ) { NTSTATUS Status; ULONG ulPinId = pPin->PinId;
//
// For HW Accelerated pins, send the request to HW filter.
//
if (pulPinFlags[ulPinId]) { PSTART_NODE pStartNode; PPIN_INFO pPinInfo; ULONG BytesReturned; PIO_STACK_LOCATION pIrpStack; PFILTER_NODE_INSTANCE pFilterNodeInstance = NULL;
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
pStartNode = aplstStartNode[ulPinId]->GetListFirstData();
pPinInfo = pStartNode->pPinNode->pPinInfo;
Status = CFilterNodeInstance::Create( &pFilterNodeInstance, pStartNode->pPinNode->pLogicalFilterNode, pGraphNode->pDeviceNode, TRUE);
if(NT_SUCCESS(Status)) { pPin->PinId = pPinInfo->PinId; pPin->Property.Id = KSPROPERTY_PIN_CINSTANCES;
AssertFileObject(pFilterNodeInstance->pFileObject); Status = KsSynchronousIoControlDevice( pFilterNodeInstance->pFileObject, KernelMode, IOCTL_KS_PROPERTY, pPin, pIrpStack->Parameters.DeviceIoControl.InputBufferLength, pcInstances, pIrpStack->Parameters.DeviceIoControl.OutputBufferLength, &BytesReturned);
if(NT_SUCCESS(Status)) { pIrp->IoStatus.Information = BytesReturned; }
if (pFilterNodeInstance) { pFilterNodeInstance->Destroy(); } } else { DPF2(10, "GetPinInstances FAILS %08x %s", Status, pPinInfo->pFilterNode->DumpName()); } } //
// For other pins use the cached instances
//
else { Status = STATUS_SUCCESS; *pcInstances = pacPinInstances[ulPinId]; }
return Status; } // GetPinInstances
BOOL CGraphNodeInstance::IsPinInstances( ULONG ulPinId) { //
// For HW Accelerated pins, always allow further operations.
//
if (pulPinFlags[ulPinId]) { return TRUE; } //
// For other pins check cached instances.
//
else { if(pacPinInstances[ulPinId].CurrentCount >= pacPinInstances[ulPinId].PossibleCount) { return FALSE; } }
return TRUE; } // IsPinInstances
//---------------------------------------------------------------------------
|