You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
577 lines
17 KiB
577 lines
17 KiB
//---------------------------------------------------------------------------
|
|
//
|
|
// Module: lfn.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"
|
|
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
|
|
ULONG gcMixers = 0;
|
|
ULONG gcSplitters = 0;
|
|
ULONG gcLogicalFilterNodes = 0;
|
|
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
CLogicalFilterNode::Create(
|
|
OUT PLOGICAL_FILTER_NODE *ppLogicalFilterNode,
|
|
IN PFILTER_NODE pFilterNode
|
|
)
|
|
{
|
|
PLOGICAL_FILTER_NODE pLogicalFilterNode;
|
|
NTSTATUS Status;
|
|
|
|
pLogicalFilterNode = new LOGICAL_FILTER_NODE(pFilterNode);
|
|
if(pLogicalFilterNode == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
Status = pLogicalFilterNode->AddList(&pFilterNode->lstLogicalFilterNode);
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
delete pLogicalFilterNode;
|
|
pLogicalFilterNode = NULL;
|
|
goto exit;
|
|
}
|
|
if(pLogicalFilterNode->GetType() & FILTER_TYPE_LOGICAL_FILTER) {
|
|
Status = pLogicalFilterNode->AddListOrdered(
|
|
gplstLogicalFilterNode,
|
|
FIELD_OFFSET(LOGICAL_FILTER_NODE, ulOrder));
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
}
|
|
exit:
|
|
*ppLogicalFilterNode = pLogicalFilterNode;
|
|
return(Status);
|
|
}
|
|
|
|
CLogicalFilterNode::CLogicalFilterNode(
|
|
PFILTER_NODE pFilterNode
|
|
)
|
|
{
|
|
Assert(pFilterNode);
|
|
this->pFilterNode = pFilterNode;
|
|
|
|
// The type/order is the same as filter node
|
|
SetType(pFilterNode->GetType());
|
|
|
|
// Determine the overhead here, default to software (higher)
|
|
ulOverhead = OVERHEAD_SOFTWARE;
|
|
if(GetType() & FILTER_TYPE_ENDPOINT) {
|
|
ulOverhead = OVERHEAD_HARDWARE;
|
|
}
|
|
|
|
// Count the mixers, splitters and lfns
|
|
if(GetType() & FILTER_TYPE_MIXER) {
|
|
++gcMixers;
|
|
}
|
|
if(GetType() & FILTER_TYPE_SPLITTER) {
|
|
++gcSplitters;
|
|
}
|
|
++gcLogicalFilterNodes;
|
|
|
|
DPF3(60, "CLogicalFilterNode: %08x FN: %08x %s",
|
|
this,
|
|
pFilterNode,
|
|
pFilterNode->DumpName());
|
|
}
|
|
|
|
CLogicalFilterNode::~CLogicalFilterNode(
|
|
)
|
|
{
|
|
PLOGICAL_FILTER_NODE pLogicalFilterNode;
|
|
PDEVICE_NODE pDeviceNode;
|
|
PGRAPH_NODE pGraphNode;
|
|
PPIN_NODE pPinNode;
|
|
BOOL fDestroy;
|
|
|
|
Assert(this);
|
|
DPF2(60, "~CLogicalFilterNode: %08x %s", this, pFilterNode->DumpName());
|
|
//
|
|
// Need to NULL the pPinNode's LFN field because it is used in AddPinNodes
|
|
// to indicate that this PN hasn't been assigned a LFN yet.
|
|
//
|
|
FOR_EACH_LIST_ITEM(&lstPinNode, pPinNode) {
|
|
|
|
Assert(pPinNode);
|
|
if(pPinNode->pLogicalFilterNode == this) {
|
|
pPinNode->pLogicalFilterNode = NULL;
|
|
}
|
|
|
|
} END_EACH_LIST_ITEM
|
|
|
|
FOR_EACH_LIST_ITEM(gplstDeviceNode, pDeviceNode) {
|
|
|
|
fDestroy = FALSE;
|
|
|
|
FOR_EACH_LIST_ITEM(
|
|
&pDeviceNode->lstLogicalFilterNode,
|
|
pLogicalFilterNode) {
|
|
|
|
if(pLogicalFilterNode == this) {
|
|
DPF2(50, "~CLogicalFilterNode: %08x GN %08x Destroy",
|
|
pLogicalFilterNode,
|
|
pGraphNode);
|
|
fDestroy = TRUE;
|
|
break;
|
|
}
|
|
|
|
} END_EACH_LIST_ITEM
|
|
|
|
if(!fDestroy) {
|
|
FOR_EACH_LIST_ITEM(&pDeviceNode->lstGraphNode, pGraphNode) {
|
|
|
|
FOR_EACH_LIST_ITEM(
|
|
&pGraphNode->lstLogicalFilterNode,
|
|
pLogicalFilterNode) {
|
|
|
|
if(pLogicalFilterNode == this) {
|
|
DPF2(50, "~CLogicalFilterNode: %08x GN %08x Destroy",
|
|
pLogicalFilterNode,
|
|
pGraphNode);
|
|
fDestroy = TRUE;
|
|
break;
|
|
}
|
|
|
|
} END_EACH_LIST_ITEM
|
|
|
|
} END_EACH_LIST_ITEM
|
|
}
|
|
|
|
if(fDestroy) {
|
|
pDeviceNode->lstGraphNode.DestroyList();
|
|
}
|
|
|
|
} END_EACH_LIST_ITEM
|
|
|
|
if(GetType() & FILTER_TYPE_MIXER) {
|
|
--gcMixers;
|
|
}
|
|
if(GetType() & FILTER_TYPE_SPLITTER) {
|
|
--gcSplitters;
|
|
}
|
|
--gcLogicalFilterNodes;
|
|
}
|
|
|
|
VOID
|
|
CLogicalFilterNode::SetType(
|
|
ULONG fulType
|
|
)
|
|
{
|
|
pFilterNode->SetType(fulType);
|
|
SetOrder(pFilterNode->GetOrder());
|
|
|
|
ulFlags = 0;
|
|
if(GetType() & FILTER_TYPE_RENDER) {
|
|
ulFlags |= LFN_FLAGS_CONNECT_RENDER;
|
|
}
|
|
if(GetType() & FILTER_TYPE_CAPTURE) {
|
|
ulFlags |= LFN_FLAGS_CONNECT_CAPTURE;
|
|
}
|
|
if(GetType() & FILTER_TYPE_NORMAL_TOPOLOGY) {
|
|
ulFlags |= LFN_FLAGS_CONNECT_NORMAL_TOPOLOGY;
|
|
}
|
|
if(GetType() & FILTER_TYPE_MIXER_TOPOLOGY) {
|
|
ulFlags |= LFN_FLAGS_CONNECT_MIXER_TOPOLOGY;
|
|
}
|
|
if(GetType() & FILTER_TYPE_NO_BYPASS) {
|
|
ulFlags |= LFN_FLAGS_NO_BYPASS;
|
|
}
|
|
if(GetType() & FILTER_TYPE_NOT_SELECT) {
|
|
ulFlags |= LFN_FLAGS_NOT_SELECT;
|
|
}
|
|
if(pFilterNode->GetFlags() & FN_FLAGS_RENDER) {
|
|
ulFlags |= LFN_FLAGS_CONNECT_RENDER;
|
|
}
|
|
if(pFilterNode->GetFlags() & FN_FLAGS_NO_RENDER) {
|
|
ulFlags &= ~LFN_FLAGS_CONNECT_RENDER;
|
|
}
|
|
if(pFilterNode->GetFlags() & FN_FLAGS_CAPTURE) {
|
|
ulFlags |= LFN_FLAGS_CONNECT_CAPTURE;
|
|
}
|
|
if(pFilterNode->GetFlags() & FN_FLAGS_NO_CAPTURE) {
|
|
ulFlags &= ~LFN_FLAGS_CONNECT_CAPTURE;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SwitchLogicalFilterNodes(
|
|
IN PLOGICAL_FILTER_NODE pLogicalFilterNode,
|
|
IN OUT PLOGICAL_FILTER_NODE *ppLogicalFilterNode
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PTOPOLOGY_NODE pTopologyNode;
|
|
PPIN_NODE pPinNode;
|
|
|
|
Assert(pLogicalFilterNode);
|
|
Assert(*ppLogicalFilterNode);
|
|
if(pLogicalFilterNode != *ppLogicalFilterNode) {
|
|
|
|
FOR_EACH_LIST_ITEM(&(*ppLogicalFilterNode)->lstPinNode, pPinNode) {
|
|
Assert(pPinNode);
|
|
pPinNode->pLogicalFilterNode = pLogicalFilterNode;
|
|
} END_EACH_LIST_ITEM
|
|
|
|
pLogicalFilterNode->lstPinNode.JoinList(
|
|
&(*ppLogicalFilterNode)->lstPinNode);
|
|
|
|
FOR_EACH_LIST_ITEM(
|
|
&(*ppLogicalFilterNode)->lstTopologyNode,
|
|
pTopologyNode) {
|
|
Assert(pTopologyNode);
|
|
|
|
(*ppLogicalFilterNode)->RemoveList(
|
|
&pTopologyNode->lstLogicalFilterNode);
|
|
|
|
Status = pLogicalFilterNode->AddList(
|
|
&pTopologyNode->lstLogicalFilterNode);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
Status = pLogicalFilterNode->lstTopologyNode.AddList(pTopologyNode);
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
|
|
} END_EACH_LIST_ITEM
|
|
|
|
pLogicalFilterNode->lstTopologyConnection.JoinList(
|
|
&(*ppLogicalFilterNode)->lstTopologyConnection);
|
|
|
|
delete *ppLogicalFilterNode;
|
|
*ppLogicalFilterNode = pLogicalFilterNode;
|
|
}
|
|
exit:
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
AddPinNodes(
|
|
IN PPIN_INFO pPinInfo,
|
|
IN OUT PLOGICAL_FILTER_NODE *ppLogicalFilterNode
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PPIN_NODE pPinNode;
|
|
|
|
Assert(pPinInfo);
|
|
Assert(*ppLogicalFilterNode);
|
|
|
|
FOR_EACH_LIST_ITEM(&pPinInfo->lstPinNode, pPinNode) {
|
|
|
|
if(pPinNode->pLogicalFilterNode == NULL) {
|
|
pPinNode->pLogicalFilterNode = *ppLogicalFilterNode;
|
|
}
|
|
else {
|
|
Status = SwitchLogicalFilterNodes(
|
|
pPinNode->pLogicalFilterNode,
|
|
ppLogicalFilterNode);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
}
|
|
Status = (*ppLogicalFilterNode)->lstPinNode.AddList(pPinNode);
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
DPF2(100, "AddPinNodes: add PN %08x LFN %08x",
|
|
pPinNode,
|
|
*ppLogicalFilterNode);
|
|
|
|
} END_EACH_LIST_ITEM
|
|
exit:
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
CLogicalFilterNode::EnumerateFilterTopology(
|
|
IN PTOPOLOGY_CONNECTION pTopologyConnection,
|
|
IN BOOL fToDirection,
|
|
IN OUT PLOGICAL_FILTER_NODE *ppLogicalFilterNode
|
|
)
|
|
{
|
|
PTOPOLOGY_NODE pTopologyNode;
|
|
NTSTATUS Status;
|
|
|
|
Assert(pTopologyConnection);
|
|
DPF5(100, "EFT: PIF %08x PIT %08x TPF %08x TPT %08x f %x",
|
|
pTopologyConnection->pPinInfoFrom,
|
|
pTopologyConnection->pPinInfoTo,
|
|
pTopologyConnection->pTopologyPinFrom,
|
|
pTopologyConnection->pTopologyPinTo,
|
|
fToDirection);
|
|
|
|
if(!fToDirection) {
|
|
Status = STATUS_DEAD_END;
|
|
goto exit;
|
|
}
|
|
if(IS_CONNECTION_TYPE(pTopologyConnection, FILTER)) {
|
|
|
|
if(pTopologyConnection->pPinInfoFrom != NULL) {
|
|
Assert(pTopologyConnection->pPinInfoFrom);
|
|
|
|
if(*ppLogicalFilterNode == NULL) {
|
|
|
|
Status = CLogicalFilterNode::Create(
|
|
ppLogicalFilterNode,
|
|
pTopologyConnection->pPinInfoFrom->pFilterNode);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
Status = AddPinNodes(
|
|
pTopologyConnection->pPinInfoFrom,
|
|
ppLogicalFilterNode);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
DPF2(100, "EFT: add from PI %08x LFN %08x",
|
|
pTopologyConnection->pPinInfoFrom,
|
|
*ppLogicalFilterNode);
|
|
}
|
|
ASSERT(*ppLogicalFilterNode != NULL);
|
|
Assert(*ppLogicalFilterNode);
|
|
|
|
if(pTopologyConnection->pPinInfoTo != NULL) {
|
|
|
|
Status = AddPinNodes(
|
|
pTopologyConnection->pPinInfoTo,
|
|
ppLogicalFilterNode);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
DPF2(100, "EFT: add to PI %08x LFN %08x",
|
|
pTopologyConnection->pPinInfoTo,
|
|
*ppLogicalFilterNode);
|
|
}
|
|
|
|
if(pTopologyConnection->pTopologyPinTo != NULL) {
|
|
Assert(pTopologyConnection->pTopologyPinTo);
|
|
pTopologyNode = pTopologyConnection->pTopologyPinTo->pTopologyNode;
|
|
Assert(pTopologyNode);
|
|
|
|
Status = (*ppLogicalFilterNode)->lstTopologyNode.AddList(
|
|
pTopologyNode);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
|
|
if(IsEqualGUID(
|
|
&KSNODETYPE_ACOUSTIC_ECHO_CANCEL,
|
|
pTopologyNode->pguidType)) {
|
|
|
|
Assert(*ppLogicalFilterNode);
|
|
(*ppLogicalFilterNode)->SetType(FILTER_TYPE_AEC);
|
|
if(pTopologyConnection->pTopologyPinTo->ulPinNumber ==
|
|
KSNODEPIN_AEC_RENDER_IN) {
|
|
(*ppLogicalFilterNode)->SetRenderOnly();
|
|
}
|
|
else {
|
|
ASSERT(
|
|
pTopologyConnection->pTopologyPinTo->ulPinNumber ==
|
|
KSNODEPIN_AEC_CAPTURE_IN);
|
|
(*ppLogicalFilterNode)->SetCaptureOnly();
|
|
}
|
|
Status = (*ppLogicalFilterNode)->AddList(
|
|
&pTopologyNode->lstLogicalFilterNode);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
}
|
|
else {
|
|
if(pTopologyNode->lstLogicalFilterNode.IsLstEmpty()) {
|
|
Assert(*ppLogicalFilterNode);
|
|
|
|
Status = (*ppLogicalFilterNode)->AddList(
|
|
&pTopologyNode->lstLogicalFilterNode);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
}
|
|
else {
|
|
Status = SwitchLogicalFilterNodes(
|
|
(PLOGICAL_FILTER_NODE)
|
|
pTopologyNode->lstLogicalFilterNode.GetListFirstData(),
|
|
ppLogicalFilterNode);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
DPF2(100, "EFT: add to PI %08x LFN %08x",
|
|
pTopologyConnection->pPinInfoTo,
|
|
*ppLogicalFilterNode);
|
|
}
|
|
}
|
|
Status = pTopologyConnection->AddList(
|
|
&(*ppLogicalFilterNode)->lstTopologyConnection);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
|
|
if(IS_CONNECTION_TYPE(pTopologyConnection, FILTER)) {
|
|
Status = STATUS_CONTINUE;
|
|
}
|
|
else {
|
|
Status = STATUS_DEAD_END;
|
|
}
|
|
exit:
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
CLogicalFilterNode::CreateAll(
|
|
PFILTER_NODE pFilterNode
|
|
)
|
|
{
|
|
PLOGICAL_FILTER_NODE pLogicalFilterNode;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PPIN_INFO pPinInfo;
|
|
PPIN_NODE pPinNode;
|
|
|
|
DPF2(100, "CLFN::CreateAll: FN %08x %s",
|
|
pFilterNode,
|
|
pFilterNode->DumpName());
|
|
|
|
//
|
|
// Split up the filter into logical filter nodes.
|
|
//
|
|
FOR_EACH_LIST_ITEM(&pFilterNode->lstPinInfo, pPinInfo) {
|
|
|
|
pLogicalFilterNode = NULL;
|
|
Status = EnumerateTopology(
|
|
pPinInfo,
|
|
(TOP_PFN)EnumerateFilterTopology,
|
|
&pLogicalFilterNode);
|
|
|
|
if(Status == STATUS_CONTINUE) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
if(!NT_SUCCESS(Status)) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
} END_EACH_LIST_ITEM
|
|
|
|
//
|
|
// Look at the pins of each LFN and determine if it could possibly
|
|
// be a capture or render filter (or both).
|
|
//
|
|
FOR_EACH_LIST_ITEM(
|
|
&pFilterNode->lstLogicalFilterNode,
|
|
pLogicalFilterNode) {
|
|
ULONG ulPossibleFlags;
|
|
|
|
ulPossibleFlags = 0;
|
|
pLogicalFilterNode->ulFlags |= LFN_FLAGS_REFLECT_DATARANGE;
|
|
FOR_EACH_LIST_ITEM(&pLogicalFilterNode->lstPinNode, pPinNode) {
|
|
|
|
// Don't care about the major format
|
|
if(!IsEqualGUID(
|
|
&pPinNode->pDataRange->SubFormat,
|
|
&KSDATAFORMAT_SUBTYPE_WILDCARD) ||
|
|
|
|
!IsEqualGUID(
|
|
&pPinNode->pDataRange->Specifier,
|
|
&KSDATAFORMAT_SPECIFIER_WILDCARD)) {
|
|
pLogicalFilterNode->ulFlags &= ~LFN_FLAGS_REFLECT_DATARANGE;
|
|
}
|
|
|
|
switch(pPinNode->pPinInfo->Communication) {
|
|
case KSPIN_COMMUNICATION_BOTH:
|
|
ulPossibleFlags |=
|
|
LFN_FLAGS_CONNECT_CAPTURE | LFN_FLAGS_CONNECT_RENDER;
|
|
break;
|
|
case KSPIN_COMMUNICATION_SOURCE:
|
|
switch(pPinNode->pPinInfo->DataFlow) {
|
|
case KSPIN_DATAFLOW_IN:
|
|
ulPossibleFlags |= LFN_FLAGS_CONNECT_CAPTURE;
|
|
break;
|
|
case KSPIN_DATAFLOW_OUT:
|
|
ulPossibleFlags |= LFN_FLAGS_CONNECT_RENDER;
|
|
break;
|
|
}
|
|
break;
|
|
case KSPIN_COMMUNICATION_SINK:
|
|
switch(pPinNode->pPinInfo->DataFlow) {
|
|
case KSPIN_DATAFLOW_IN:
|
|
ulPossibleFlags |= LFN_FLAGS_CONNECT_RENDER;
|
|
break;
|
|
case KSPIN_DATAFLOW_OUT:
|
|
ulPossibleFlags |= LFN_FLAGS_CONNECT_CAPTURE;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
if(ulPossibleFlags ==
|
|
(LFN_FLAGS_CONNECT_CAPTURE | LFN_FLAGS_CONNECT_RENDER)) {
|
|
break;
|
|
}
|
|
|
|
} END_EACH_LIST_ITEM
|
|
|
|
pLogicalFilterNode->ulFlags =
|
|
(ulPossibleFlags & pLogicalFilterNode->GetFlags()) |
|
|
(pLogicalFilterNode->GetFlags() &
|
|
~(LFN_FLAGS_CONNECT_CAPTURE | LFN_FLAGS_CONNECT_RENDER));
|
|
|
|
} END_EACH_LIST_ITEM
|
|
exit:
|
|
return(Status);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|