windows-nt/Source/XPSP1/NT/drivers/wdm/audio/sysaudio/sn.cpp
2020-09-26 16:20:57 +08:00

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