//--------------------------------------------------------------------------- // // Module: sn.cpp // // Description: // // //@@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" //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- NTSTATUS CStartNode::Create( PPIN_NODE pPinNode, PCONNECT_NODE pConnectNode, PGRAPH_PIN_INFO pGraphPinInfo, ULONG ulFlagsCurrent, ULONG ulOverhead, PGRAPH_NODE pGraphNode ) { PTOPOLOGY_CONNECTION pTopologyConnection; NTSTATUS Status = STATUS_SUCCESS; PSTART_NODE pStartNode = NULL; Assert(pPinNode); Assert(pGraphNode); if((pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_SOURCE)) { ASSERT(NT_SUCCESS(Status)); ASSERT(pStartNode == NULL); goto exit; } if(pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_SINK || pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_BOTH) { // Don't create a sysaudio pin if OUT/RENDER or IN/CAPTURER if(pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_OUT && ulFlagsCurrent & LFN_FLAGS_CONNECT_RENDER) { DPF1(50, "CStartNode::Create PN %08x - out/render", pPinNode); ASSERT(NT_SUCCESS(Status)); ASSERT(pStartNode == NULL); goto exit; } if(pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_IN && ulFlagsCurrent & LFN_FLAGS_CONNECT_CAPTURE) { DPF1(50, "CStartNode::Create PN %08x - in/capturer", pPinNode); ASSERT(NT_SUCCESS(Status)); ASSERT(pStartNode == NULL); goto exit; } } FOR_EACH_LIST_ITEM( &pPinNode->pPinInfo->lstTopologyConnection, pTopologyConnection) { // Only check physical connections if(!IS_CONNECTION_TYPE(pTopologyConnection, PHYSICAL)) { continue; } // If there is one connection that is valid for this GraphNode if(pTopologyConnection->IsTopologyConnectionOnGraphNode(pGraphNode)) { // Don't create a sysaudio pin DPF4(80, "CStartNode::Create %s PN %08x TC %08x GN %08x connected", pPinNode->pPinInfo->pFilterNode->DumpName(), pPinNode, pTopologyConnection, pGraphNode); ASSERT(NT_SUCCESS(Status)); ASSERT(pStartNode == NULL); goto exit; } } END_EACH_LIST_ITEM pStartNode = new START_NODE( pPinNode, pConnectNode, ulOverhead, pGraphNode); if(pStartNode == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } Status = CStartInfo::Create( pStartNode, pConnectNode->GetConnectInfo(), pGraphPinInfo, pGraphNode); if(!NT_SUCCESS(Status)) { Trap(); goto exit; } DPF3(80, "CStartNode::Create %08x PN %08x O %08x", pStartNode, pPinNode, pStartNode->ulOverhead); // // For capture graphs only. // if (pStartNode->pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_OUT) { pStartNode->SetSpecialFlags(); } exit: if(!NT_SUCCESS(Status)) { if (pStartNode) { pStartNode->Destroy(); } } return(Status); } CStartNode::CStartNode( PPIN_NODE pPinNode, PCONNECT_NODE pConnectNode, ULONG ulOverhead, PGRAPH_NODE pGraphNode ) { Assert(pPinNode); Assert(pGraphNode); this->pPinNode = pPinNode; this->ulOverhead = ulOverhead + pPinNode->GetOverhead(); this->pConnectNodeHead = pConnectNode; this->ulFlags = 0; this->fRender = (pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_IN); this->ulSpecialFlags = STARTNODE_SPECIALFLAG_NONE; pConnectNode->AddRef(); if(pPinNode->GetType() & FILTER_TYPE_VIRTUAL) { AddListEnd(&pGraphNode->lstStartNode); } else { AddList(&pGraphNode->lstStartNode); } DPF3(80, "CStartNode: %08x PN %08x O %08x", this, pPinNode, ulOverhead); } CStartNode::~CStartNode( ) { DPF1(80, "~CStartNode: %08x", this); Assert(this); RemoveList(); pStartInfo->Destroy(); pConnectNodeHead->Destroy(); } void CStartNode::SetSpecialFlags() { // // STARTNODE_SPECIALFLAG_STRICT // Get the last ConnectNode in connection list and check if the // source pin is splitter. // Also the first pin should be splitter pin. // // // STARTNODE_SPECIALFLAG_AEC // If the StartNode contains Aec mark the StartNode with this flag. // // // ISSUE-2001/03/09-alpers // In the future two splitters in the graph will not work // with this logic. // We need a way of knowing if a filter does SRC upfront. // if (pConnectNodeHead) { PCONNECT_NODE pConnectNode; for(pConnectNode = pConnectNodeHead; pConnectNode->GetNextConnectNode() != NULL; pConnectNode = pConnectNode->GetNextConnectNode()) { if (pConnectNode->pPinNodeSource->pLogicalFilterNode-> pFilterNode->GetType() & FILTER_TYPE_AEC) { ulSpecialFlags |= STARTNODE_SPECIALFLAG_AEC; } } ulSpecialFlags |= (pConnectNode->pPinNodeSource->pPinInfo-> pFilterNode->GetType() & FILTER_TYPE_SPLITTER) && (pPinNode->pPinInfo->pFilterNode->GetType() & FILTER_TYPE_SPLITTER) ? STARTNODE_SPECIALFLAG_STRICT : STARTNODE_SPECIALFLAG_NONE; } DPF3(50, "CStartNode: %08x %s SpecialFlags %X", this, DbgUnicode2Sz(pPinNode->pPinInfo->pFilterNode->GetFriendlyName()), ulSpecialFlags); } ENUMFUNC CStartNode::RemoveBypassPaths( PVOID pReference ) { PGRAPH_NODE pGraphNode = PGRAPH_NODE(pReference); PLOGICAL_FILTER_NODE pLogicalFilterNode; PCONNECT_NODE pConnectNode; ULONG cLfnNoBypassTotal = 0; ULONG cLfnNoBypass = 0; ULONG ulFlags; ULONG cAecFilterCount = 0; BOOL fDestroy; Assert(this); Assert(pGraphNode); if(pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_NONE || pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_BRIDGE || pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_SOURCE) { return(STATUS_CONTINUE); } if(pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_IN) { ulFlags = LFN_FLAGS_CONNECT_RENDER; DPF(60,"RBP - for Render"); } else { ASSERT(pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_OUT); ulFlags = LFN_FLAGS_CONNECT_CAPTURE; DPF(60,"RBP - for Capture"); } FOR_EACH_LIST_ITEM( &pGraphNode->lstLogicalFilterNodeNoBypass, pLogicalFilterNode) { if(pLogicalFilterNode->GetFlags() & ulFlags) { ++cLfnNoBypassTotal; } } END_EACH_LIST_ITEM DPF1(60,"RBP:NoBypassTotal = %08x", cLfnNoBypassTotal); for(pConnectNode = GetFirstConnectNode(); pConnectNode != NULL; pConnectNode = pConnectNode->GetNextConnectNode()) { Assert(pConnectNode); FOR_EACH_LIST_ITEM( &pGraphNode->lstLogicalFilterNodeNoBypass, pLogicalFilterNode) { if(pLogicalFilterNode->GetFlags() & ulFlags) { Assert(pConnectNode->pPinNodeSource); Assert(pConnectNode->pPinNodeSource->pLogicalFilterNode); if(pConnectNode->pPinNodeSource->pLogicalFilterNode == pLogicalFilterNode) { cLfnNoBypass++; } } } END_EACH_LIST_ITEM DPF1(60,"RBP:FilterInPath = %s", DbgUnicode2Sz(pConnectNode->pPinNodeSource->pLogicalFilterNode->pFilterNode->GetFriendlyName())); // // In capture paths count AEC filters to avoid conflict with GFXes // if((ulFlags & LFN_FLAGS_CONNECT_CAPTURE) && (pConnectNode->pPinNodeSource->pLogicalFilterNode->pFilterNode->GetType() & FILTER_TYPE_AEC)) { ++cAecFilterCount; } } ASSERT(cAecFilterCount < 2); DPF2(60,"RBP:NBPCount=%08x, AECCount=%08x", cLfnNoBypass, cAecFilterCount); // // Mark all the paths with NO Gfx as second pass candidates // We do this to support the following sequence of capture pin creations // 1. Client installs GFX(es) on a capture device // 2. Client creates a pin with AEC // This would result in creating a Capture->Splitter->AEC path // 3. Client tries to create a regular capture pin (with GFX) // In this case we want to create a regular path (but since no GFX // hooked up between capture and splitter. We create a capture->splitter->[kmixer] path // These special paths are marked as secondpass. And we try these paths // only if all the primary start nodes failed to instantiate a pin. // (look in pins.cpp - PinDispatchCreateKP() // if(cLfnNoBypassTotal != 0) { if(cLfnNoBypass == 0) { this->ulFlags |= STARTNODE_FLAGS_SECONDPASS; } } // // Assume that this path is going to be OK // fDestroy = FALSE; if (cAecFilterCount == 0) { // // There is no AEC in this path // We have to make sure that we have all the necessary // GFXs loaded in this path. (Else destroy the path) // if(cLfnNoBypass != cLfnNoBypassTotal) { fDestroy = TRUE; } } else { // // There is an AEC in this path // No GFXs should be there in this path. If there is even one GFX // destroy the path // if ((cLfnNoBypass != 0) || (cAecFilterCount > 1)) { fDestroy = TRUE; } } if ((fDestroy) && ((this->ulFlags & STARTNODE_FLAGS_SECONDPASS) == 0)) { Destroy(); DPF(60,"RBP:PathDestroyed"); } DPF(60,"RBP:Done"); return(STATUS_CONTINUE); } #ifdef DEBUG // // Handy debug routine to dump filters in the path for this StartNode // VOID CStartNode::DumpFilters( ) { PCONNECT_NODE pConnectNode; for(pConnectNode = GetFirstConnectNode(); pConnectNode != NULL; pConnectNode = pConnectNode->GetNextConnectNode()) { Assert(pConnectNode); DPF1(0,"DF:FilterInPath = %s", DbgUnicode2Sz(pConnectNode->pPinNodeSource->pLogicalFilterNode->pFilterNode->GetFriendlyName())); } } #endif ENUMFUNC CStartNode::RemoveConnectedStartNode( PVOID pReference ) { PGRAPH_NODE pGraphNode = PGRAPH_NODE(pReference); PCONNECT_NODE pConnectNode; PSTART_NODE pStartNode; Assert(this); Assert(pGraphNode); FOR_EACH_LIST_ITEM(&pGraphNode->lstStartNode, pStartNode) { if(this == pStartNode) { continue; } for(pConnectNode = pStartNode->GetFirstConnectNode(); pConnectNode != NULL; pConnectNode = pConnectNode->GetNextConnectNode()) { if(this->pPinNode == pConnectNode->pPinNodeSink) { DPF3(50, "CStartNode::RemoveConnectedSN %08x GN %08x %s", this, pGraphNode, pPinNode->pPinInfo->pFilterNode->DumpName()); Destroy(); return(STATUS_CONTINUE); } } } END_EACH_LIST_ITEM return(STATUS_CONTINUE); } //--------------------------------------------------------------------------- #ifdef DEBUG ENUMFUNC CStartNode::Dump( ) { PCONNECT_NODE pConnectNode; Assert(this); dprintf("SN: %08x PN %08x SI %08x O %08x #%d %s\n", this, pPinNode, pStartInfo, ulOverhead, pPinNode->pPinInfo->PinId, pPinNode->pPinInfo->pFilterNode->DumpName()); if(ulDebugFlags & DEBUG_FLAGS_GRAPH) { for(pConnectNode = GetFirstConnectNode(); pConnectNode != NULL; pConnectNode = pConnectNode->GetNextConnectNode()) { pConnectNode->Dump(); } } return(STATUS_CONTINUE); } #endif