454 lines
12 KiB
C++
454 lines
12 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// 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
|