windows-nt/Source/XPSP1/NT/drivers/wdm/audio/sysaudio/lfn.cpp

656 lines
15 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//---------------------------------------------------------------------------
//
// 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();
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);
}
//---------------------------------------------------------------------------
#ifdef DEBUG
ULONG nLogicalFilter = 0;
ENUMFUNC
CLogicalFilterNode::Dump(
)
{
Assert(this);
// .slv
if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) {
dprintf("LFN: %08x FN %08x fulType %08x ulOrder %08x ulOverhead %08x\n",
this,
pFilterNode,
pFilterNode->GetType(),
ulOrder,
ulOverhead);
dprintf(" %s\n", pFilterNode->DumpName());
dprintf(" fulType: ");
DumpfulType(GetType());
dprintf("\n ulFlags: ");
if(ulFlags & LFN_FLAGS_CONNECT_CAPTURE) {
dprintf("CAPTURE ");
}
if(ulFlags & LFN_FLAGS_CONNECT_RENDER) {
dprintf("RENDER ");
}
if(ulFlags & LFN_FLAGS_CONNECT_NORMAL_TOPOLOGY) {
dprintf("NORMAL_TOPOLOGY ");
}
if(ulFlags & LFN_FLAGS_CONNECT_MIXER_TOPOLOGY) {
dprintf("MIXER_TOPOLOGY ");
}
if(ulFlags & LFN_FLAGS_TOP_DOWN) {
dprintf("TOP_DOWN ");
}
if(ulFlags & LFN_FLAGS_NO_BYPASS) {
dprintf("NO_BYPASS ");
}
if(ulFlags & LFN_FLAGS_NOT_SELECT) {
dprintf("NOT_SELECT ");
}
if(ulFlags & LFN_FLAGS_REFLECT_DATARANGE) {
dprintf("REFLECT_DATARANGE ");
}
dprintf("\n");
// .slvx
if(ulDebugFlags & DEBUG_FLAGS_DETAILS) {
dprintf(" lstPN: ");
lstPinNode.DumpAddress();
dprintf("\n lstTN: ");
lstTopologyNode.DumpAddress();
dprintf("\n lstTC: ");
lstTopologyConnection.DumpAddress();
dprintf("\n lstFNI: ");
lstFilterNodeInstance.DumpAddress();
dprintf("\n");
}
}
// .slp
if(ulDebugFlags & DEBUG_FLAGS_PIN) {
lstPinNode.Dump();
}
// .slt
if(ulDebugFlags & DEBUG_FLAGS_TOPOLOGY) {
lstTopologyNode.Dump();
// .sltx
if(ulDebugFlags & DEBUG_FLAGS_DETAILS) {
lstTopologyConnection.Dump();
}
}
if(ulDebugFlags &
(DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_PIN | DEBUG_FLAGS_TOPOLOGY)) {
dprintf("\n");
}
return(STATUS_CONTINUE);
}
#endif