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

1246 lines
33 KiB
C++

//---------------------------------------------------------------------------
//
// Module: sni.cpp
//
// Description:
//
// Start Node Instance
//
//@@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"
//---------------------------------------------------------------------------
WAVEFORMATEX aWaveFormatEx[] = {
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
44100, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
44100, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
44100, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
44100, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
48000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
48000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
48000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
48000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
32000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
32000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
32000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
32000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
22050, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
22050, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
22050, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
22050, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
16000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
16000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
16000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
16000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
11025, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
11025, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
11025, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
11025, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
8000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
8000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
16, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
2, // nChannels
8000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
{
WAVE_FORMAT_PCM, // wFormatTag
1, // nChannels
8000, // nSamplesPerSec
0, // nAvgBytesPerSec
0, // nBlockAlign
8, // wBitsPerSample
0, // cbSize
},
};
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
NTSTATUS
CStartNodeInstance::Create(
PPIN_INSTANCE pPinInstance,
PSTART_NODE pStartNode,
PKSPIN_CONNECT pPinConnect,
PWAVEFORMATEX pWaveFormatExRequested,
PWAVEFORMATEX pWaveFormatExRegistry
)
{
PSTART_NODE_INSTANCE pStartNodeInstance = NULL;
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
Assert(pPinInstance);
Assert(pStartNode);
Assert(pStartNode->pPinNode);
DPF3(90, "CSNI::Create SN %08x #%d %s",
pStartNode,
pStartNode->pPinNode->pPinInfo->PinId,
pStartNode->pPinNode->pPinInfo->pFilterNode->DumpName());
#ifdef DEBUG
DumpDataRange(95, (PKSDATARANGE_AUDIO)pStartNode->pPinNode->pDataRange);
#endif
if(!CompareIdentifier(
pStartNode->pPinNode->pMedium,
&pPinConnect->Medium)) {
Trap();
DPF1(90, "CSNI::Create: Medium %08X", pStartNode);
ASSERT(Status == STATUS_INVALID_DEVICE_REQUEST);
goto exit;
}
if(!CompareIdentifier(
pStartNode->pPinNode->pInterface,
&pPinConnect->Interface)) {
DPF1(90, "CSNI::Create: Interface %08X", pStartNode);
ASSERT(Status == STATUS_INVALID_DEVICE_REQUEST);
goto exit;
}
if(!CompareDataRangeGuids(
pStartNode->pPinNode->pDataRange,
(PKSDATARANGE)(pPinConnect + 1))) {
DPF1(90, "CSNI::Create: DataRange GUID %08X", pStartNode);
ASSERT(Status == STATUS_INVALID_DEVICE_REQUEST);
goto exit;
}
//
// VOICE MANAGEMENT and HW ACCELARATION
// For HW accelarated pins we are not relying on local sysaudio
// instance counts. PinCreate request will be sent down to the driver.
// It is upto the driver to reject the request based on its capabilities.
//
if ((pStartNode->pPinNode->pPinInfo->pFilterNode->GetType() & FILTER_TYPE_RENDERER) &&
(KSPIN_DATAFLOW_IN == pStartNode->pPinNode->pPinInfo->DataFlow) &&
(KSPIN_COMMUNICATION_SINK == pStartNode->pPinNode->pPinInfo->Communication)) {
DPF(20,"StartInfo::IsPinInstances return TRUE for HW");
}
else {
if(!pStartNode->IsPinInstances()) {
DPF1(90, "CSNI::Create: no instances SN %08X", pStartNode);
Status = STATUS_DEVICE_BUSY;
goto exit;
}
}
pStartNodeInstance = new START_NODE_INSTANCE(pPinInstance, pStartNode);
if(pStartNodeInstance == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
#ifndef UNDER_NT
//
// Try the format from the registry
//
if(pWaveFormatExRegistry != NULL) {
DPF3(90, "CSNI::Create: Registry SR %d CH %d BPS %d",
pWaveFormatExRegistry->nSamplesPerSec,
pWaveFormatExRegistry->nChannels,
pWaveFormatExRegistry->wBitsPerSample);
Status = pStartNodeInstance->Connect(
pPinInstance->pFilterInstance->GetDeviceNode(),
pPinConnect,
pWaveFormatExRegistry,
NULL);
}
#endif
//
// If capture pin, try some intelligent variations of requested format
//
if(!NT_SUCCESS(Status) &&
pWaveFormatExRequested != NULL &&
pStartNode->pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_OUT) {
DPF(90, "CSNI::Create: IntelligentConnect");
Status = pStartNodeInstance->IntelligentConnect(
pPinInstance->pFilterInstance->GetDeviceNode(),
pPinConnect,
pWaveFormatExRequested);
//
// If the graph contains only splitter and capturer, only the
// requested format can succeed.
// So exit here.
//
if (pStartNodeInstance->pStartNode->IsCaptureFormatStrict()) {
DPF1(50, "CSNI::Create: CaptureFormatStrict Bailing Out: Status %X", Status);
goto exit;
}
}
//
// If capture pin and if aec is included, negotiate format between
// aec and capture device.
//
if(!NT_SUCCESS(Status) &&
pStartNode->IsAecIncluded() &&
pStartNode->pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_OUT) {
PKSPIN_CONNECT pPinConnectDirect = NULL;
DPF(90, "CSNI::Create: AecConnection");
Status = pStartNodeInstance->AecConnectionFormat(
pPinInstance->pFilterInstance->GetDeviceNode(),
&pPinConnectDirect);
//
// Try mono/stereo formats first.
//
if (NT_SUCCESS(Status)) {
for (WORD i = 1; i <= 2; i++) {
ModifyPinConnect(pPinConnectDirect, i);
Status = pStartNodeInstance->Connect(
pPinInstance->pFilterInstance->GetDeviceNode(),
pPinConnect,
NULL,
pPinConnectDirect);
if (NT_SUCCESS(Status)) {
break;
}
}
}
if (pPinConnectDirect) {
delete pPinConnectDirect;
}
}
//
// Try pin data intersection
//
if(!NT_SUCCESS(Status)) {
DPF(90, "CSNI::Create: Data Intersection");
Status = pStartNodeInstance->Connect(
pPinInstance->pFilterInstance->GetDeviceNode(),
pPinConnect,
NULL,
NULL);
}
if(!NT_SUCCESS(Status)) {
int i;
//
// Try each waveformatex limit until success
//
for(i = 0; i < SIZEOF_ARRAY(aWaveFormatEx); i++) {
DPF3(90, "CSNI::Create: Array SR %d CH %d BPS %d",
aWaveFormatEx[i].nSamplesPerSec,
aWaveFormatEx[i].nChannels,
aWaveFormatEx[i].wBitsPerSample);
Status = pStartNodeInstance->Connect(
pPinInstance->pFilterInstance->GetDeviceNode(),
pPinConnect,
&aWaveFormatEx[i],
NULL);
if(NT_SUCCESS(Status)) {
break;
}
}
}
if(!NT_SUCCESS(Status)) {
goto exit;
}
Status = pStartNodeInstance->CreateTopologyTable(
pPinInstance->pFilterInstance->pGraphNodeInstance);
if(!NT_SUCCESS(Status)) {
Trap();
goto exit;
}
ASSERT(pStartNodeInstance->CurrentState == KSSTATE_STOP);
#ifdef DEBUG
pStartNodeInstance->pPinConnect = (PKSPIN_CONNECT)
new BYTE[sizeof(KSPIN_CONNECT) +
((PKSDATARANGE)(pPinConnect + 1))->FormatSize];
if(pStartNodeInstance->pPinConnect != NULL) {
memcpy(
pStartNodeInstance->pPinConnect,
pPinConnect,
sizeof(KSPIN_CONNECT) +
((PKSDATARANGE)(pPinConnect + 1))->FormatSize);
}
#endif
DPF1(90, "CSNI::Create: SUCCESS %08x", pStartNodeInstance);
exit:
if(!NT_SUCCESS(Status)) {
DPF1(90, "CSNI::Create: FAIL %08x", Status);
delete pStartNodeInstance;
}
return(Status);
}
CStartNodeInstance::CStartNodeInstance(
PPIN_INSTANCE pPinInstance,
PSTART_NODE pStartNode
)
{
this->pStartNode = pStartNode;
pStartNode->AddPinInstance();
this->pPinInstance = pPinInstance;
pPinInstance->pStartNodeInstance = this;
AddList(
&pPinInstance->pFilterInstance->pGraphNodeInstance->lstStartNodeInstance);
}
CStartNodeInstance::~CStartNodeInstance(
)
{
PINSTANCE pInstance;
ASSERT(this != NULL);
Assert(this);
Assert(pPinInstance);
DPF1(95, "~CSNI: %08x", this);
RemoveList();
SetState(KSSTATE_STOP, SETSTATE_FLAG_IGNORE_ERROR);
pStartNode->RemovePinInstance();
pPinNodeInstance->Destroy(); // also see CSNI::CleanUp
pFilterNodeInstance->Destroy(); //
delete papFileObjectTopologyTable;
delete pVirtualNodeData;
#ifdef DEBUG
delete pPinConnect;
#endif
pPinInstance->pStartNodeInstance = NULL;
pPinInstance->ParentInstance.Invalidate();
}
VOID
CStartNodeInstance::CleanUp(
)
{
Assert(this);
ASSERT(papFileObjectTopologyTable == NULL);
ASSERT(pVirtualNodeData == NULL);
ASSERT(CurrentState == KSSTATE_STOP);
pPinNodeInstance->Destroy();
pPinNodeInstance = NULL;
pFilterNodeInstance->Destroy();
pFilterNodeInstance = NULL;
lstConnectNodeInstance.DestroyList();
}
NTSTATUS
CStartNodeInstance::IntelligentConnect(
PDEVICE_NODE pDeviceNode,
PKSPIN_CONNECT pPinConnect,
PWAVEFORMATEX pWaveFormatEx
)
{
PWAVEFORMATEXTENSIBLE pWaveFormatExtensible;
NTSTATUS Status;
BOOL Continue;
WORD NumChannels, BitWidth;
PBYTE pWaveFormat = NULL;
ULONG RegionAllocSize, RegionCopySize;
BOOL IsFloat = FALSE;
WORD MaxBitWidth, MinBitWidth, MaxChannels, MinChannels;
//
// First copy the user requested format into a local structure
// (because we will tamper it later for different params)
//
if (pWaveFormatEx->wFormatTag == WAVE_FORMAT_PCM) {
RegionAllocSize = sizeof(WAVEFORMATEX);
RegionCopySize = sizeof(PCMWAVEFORMAT);
}
else {
RegionAllocSize = sizeof(WAVEFORMATEX) + pWaveFormatEx->cbSize;
RegionCopySize = RegionAllocSize;
}
pWaveFormat = new(BYTE[RegionAllocSize]);
if (!pWaveFormat) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
RtlCopyMemory(pWaveFormat, pWaveFormatEx, RegionCopySize);
//
// cast for convenient access
//
pWaveFormatExtensible = (PWAVEFORMATEXTENSIBLE) pWaveFormat;
if (pWaveFormatExtensible->Format.wFormatTag == WAVE_FORMAT_PCM) {
pWaveFormatExtensible->Format.cbSize = 0;
}
DPF3(90, "CSNI::Create: Client SR %d CH %d BPS %d",
pWaveFormatExtensible->Format.nSamplesPerSec,
pWaveFormatExtensible->Format.nChannels,
pWaveFormatExtensible->Format.wBitsPerSample);
//
// and try the requested format first
//
Status = this->Connect(
pDeviceNode,
pPinConnect,
(PWAVEFORMATEX)pWaveFormatEx,
NULL);
//
// If the graph contains only splitter and capturer, only the
// requested format can succeed.
// So exit here.
//
if (pStartNode->IsCaptureFormatStrict()) {
goto exit;
}
if (pWaveFormatExtensible->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
IsFloat = TRUE;
}
if (pWaveFormatExtensible->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
if (IsEqualGUID(&pWaveFormatExtensible->SubFormat,&KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
IsFloat = TRUE;
}
}
if (IsFloat == FALSE) {
if (pWaveFormatExtensible->Format.wFormatTag != WAVE_FORMAT_PCM) {
if (pWaveFormatExtensible->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) {
goto exit;
}
else {
if (!IsEqualGUID(&pWaveFormatExtensible->SubFormat,&KSDATAFORMAT_SUBTYPE_PCM)) {
goto exit;
}
}
}
MaxBitWidth = (pWaveFormatExtensible->Format.wBitsPerSample>16)?pWaveFormatExtensible->Format.wBitsPerSample:16;
MinBitWidth = 8;
}
else {
MaxBitWidth = MinBitWidth = pWaveFormatEx->wBitsPerSample;
}
//
// MaxChannels = (pWaveFormatExtensible->nChannels > 2) ? pWaveFormatExtensible->nChannels:2;
// We can do this, what would be the channle mask for WaveFormatExtensible?
//
MaxChannels = 2;
MinChannels = 1;
//
// If that failed with the same sample rate try different
// combinations of numchannels & bitwidth
//
// Tries 4 combinations of STEREO/MONO & 8/16 bits
// More intelligence can be built based upon device capability
// (also does not check whether we tried a combination earlier)
//
if (!NT_SUCCESS(Status)) {
Continue = TRUE;
for (NumChannels = MaxChannels; (NumChannels >= MinChannels) && Continue; NumChannels--) {
for (BitWidth = MaxBitWidth;
(BitWidth >= MinBitWidth) && Continue;
BitWidth=(BitWidth%8)?((BitWidth/8)*8):(BitWidth-8)) {
pWaveFormatExtensible->Format.nChannels = NumChannels;
pWaveFormatExtensible->Format.wBitsPerSample = BitWidth;
pWaveFormatExtensible->Format.nBlockAlign = (NumChannels * BitWidth)/8;
pWaveFormatExtensible->Format.nAvgBytesPerSec = pWaveFormatExtensible->Format.nSamplesPerSec *
pWaveFormatExtensible->Format.nBlockAlign;
if (pWaveFormatExtensible->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
pWaveFormatExtensible->Samples.wValidBitsPerSample = BitWidth;
if (NumChannels == 1) {
pWaveFormatExtensible->dwChannelMask = SPEAKER_FRONT_CENTER;
}
else {
pWaveFormatExtensible->dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
}
}
DPF3(90, "CSNI::Create: Client SR %d CH %d BPS %d",
pWaveFormatExtensible->Format.nSamplesPerSec,
pWaveFormatExtensible->Format.nChannels,
pWaveFormatExtensible->Format.wBitsPerSample);
Status = this->Connect(pDeviceNode,
pPinConnect,
(PWAVEFORMATEX)pWaveFormatExtensible,
NULL);
if (NT_SUCCESS(Status)) {
Continue = FALSE;
}
}
}
}
exit:
delete [] pWaveFormat;
return(Status);
}
NTSTATUS
CStartNodeInstance::AecConnectionFormat(
PDEVICE_NODE pDeviceNode,
PKSPIN_CONNECT *ppPinConnect)
{
PCLIST_ITEM pListItem;
PCONNECT_NODE_INSTANCE pConnectNodeInstance;
PCONNECT_NODE_INSTANCE pBottomConnection;
PCONNECT_NODE_INSTANCE pAecConnection = NULL;
NTSTATUS Status = STATUS_SUCCESS;
*ppPinConnect = NULL;
Status = CConnectNodeInstance::Create(this, pDeviceNode);
if(!NT_SUCCESS(Status)) {
goto exit;
}
//
// Get Aec Source and Capture Sink pins.
//
pListItem = lstConnectNodeInstance.GetListLast();
pBottomConnection = lstConnectNodeInstance.GetListData(pListItem);
FOR_EACH_LIST_ITEM_BACKWARD(&lstConnectNodeInstance, pConnectNodeInstance) {
if (pConnectNodeInstance->pConnectNode->pPinNodeSource->
pPinInfo->pFilterNode->GetType() & FILTER_TYPE_AEC) {
pAecConnection = pConnectNodeInstance;
break;
}
} END_EACH_LIST_ITEM
if (NULL == pAecConnection || NULL == pBottomConnection) {
DPF(5, "CSNI::AecConnectionFormat: Cannot find Aec or Capture");
Status = STATUS_INVALID_DEVICE_REQUEST;
goto exit;
}
DPF3(20, "Aec : %X %d %s",
pAecConnection,
pAecConnection->pConnectNode->pPinNodeSource->pPinInfo->PinId,
pAecConnection->pConnectNode->pPinNodeSource->pPinInfo->pFilterNode->DumpName());
DPF3(20, "Capture : %X %d %s",
pBottomConnection,
pBottomConnection->pConnectNode->pPinNodeSink->pPinInfo->PinId,
pBottomConnection->pConnectNode->pPinNodeSink->pPinInfo->pFilterNode->DumpName());
//
// Find the intersection between kmixer source and capture sink.
//
Status = CreatePinIntersection(
ppPinConnect,
pBottomConnection->pConnectNode->pPinNodeSink,
pAecConnection->pConnectNode->pPinNodeSource,
pBottomConnection->pFilterNodeInstanceSink,
pAecConnection->pFilterNodeInstanceSource);
if(!NT_SUCCESS(Status)) {
DPF(5, "CSNI::AecConnectionFormat: No intersection found");
Status = STATUS_INVALID_DEVICE_REQUEST;
goto exit;
}
#ifdef DEBUG
DumpDataFormat(20, (PKSDATAFORMAT) (*ppPinConnect + 1));
#endif
exit:
if(!NT_SUCCESS(Status)) {
DPF2(90, "CSNI::AecConnectionFormat: %08x FAIL %08x", this, Status);
if (*ppPinConnect) {
ExFreePool(*ppPinConnect);
*ppPinConnect = NULL;
}
}
CleanUp();
return(Status);
} // AecConnectionFormat
NTSTATUS
CStartNodeInstance::Connect(
PDEVICE_NODE pDeviceNode,
PKSPIN_CONNECT pPinConnect,
PWAVEFORMATEX pWaveFormatEx,
PKSPIN_CONNECT pPinConnectDirect
)
{
PCONNECT_NODE_INSTANCE pConnectNodeInstance;
NTSTATUS Status = STATUS_SUCCESS;
Status = CConnectNodeInstance::Create(this, pDeviceNode);
if(!NT_SUCCESS(Status)) {
goto exit;
}
//
// Do all the bottom up connecting
//
FOR_EACH_LIST_ITEM_BACKWARD(&lstConnectNodeInstance, pConnectNodeInstance) {
if(!pConnectNodeInstance->IsTopDown()) {
//
// For Aec sink pin do intersection, no matter what the format is.
//
if (pConnectNodeInstance->pFilterNodeInstanceSink->
pFilterNode->GetType() & FILTER_TYPE_AEC) {
Status = pConnectNodeInstance->Connect(NULL, NULL);
}
else {
Status = pConnectNodeInstance->Connect(
pWaveFormatEx,
pPinConnectDirect);
}
if(!NT_SUCCESS(Status)) {
goto exit;
}
}
} END_EACH_LIST_ITEM
pPinConnect->PinToHandle = NULL;
Status = CPinNodeInstance::Create(
&pPinNodeInstance,
pFilterNodeInstance,
pStartNode->pPinNode,
pPinConnect,
(pStartNode->fRender)
#ifdef FIX_SOUND_LEAK
,lstConnectNodeInstance.IsLstEmpty()
#endif
);
if(!NT_SUCCESS(Status)) {
goto exit;
}
//
// Do all the top down connecting
//
FOR_EACH_LIST_ITEM(&lstConnectNodeInstance, pConnectNodeInstance) {
if(pConnectNodeInstance->IsTopDown()) {
//
// Rely on DataIntersection for all Topdown connections
//
Status = pConnectNodeInstance->Connect(NULL, NULL);
if(!NT_SUCCESS(Status)) {
goto exit;
}
}
} END_EACH_LIST_ITEM
DPF1(90, "CSNI::Connect: %08x SUCCESS", this);
exit:
if(!NT_SUCCESS(Status)) {
DPF2(90, "CSNI::Connect: %08x FAIL %08x", this, Status);
CleanUp();
}
return(Status);
}
NTSTATUS
CStartNodeInstance::CreateTopologyTable(
PGRAPH_NODE_INSTANCE pGraphNodeInstance
)
{
PCONNECT_NODE_INSTANCE pConnectNodeInstance;
NTSTATUS Status = STATUS_SUCCESS;
PFILTER_NODE pFilterNode = NULL;
ULONG n;
Assert(this);
Assert(pGraphNodeInstance);
if(pGraphNodeInstance->Topology.TopologyNodesCount != 0) {
ASSERT(papFileObjectTopologyTable == NULL);
papFileObjectTopologyTable =
new PFILE_OBJECT[pGraphNodeInstance->Topology.TopologyNodesCount];
if(papFileObjectTopologyTable == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
}
for(n = 0; n < pGraphNodeInstance->Topology.TopologyNodesCount; n++) {
// if filter node is the same as last time, no need to search
if(pFilterNode == pGraphNodeInstance->papTopologyNode[n]->pFilterNode) {
ASSERT(n != 0);
ASSERT(pFilterNode != NULL);
papFileObjectTopologyTable[n] = papFileObjectTopologyTable[n - 1];
continue;
}
pFilterNode = pGraphNodeInstance->papTopologyNode[n]->pFilterNode;
Assert(pFilterNode);
//
// Now find a filter instance and a pin instance in this graph
// instance for this filter node.
//
Assert(pPinNodeInstance);
if(pPinNodeInstance->pPinNode->pPinInfo->pFilterNode == pFilterNode) {
papFileObjectTopologyTable[n] = pPinNodeInstance->pFileObject;
continue;
}
FOR_EACH_LIST_ITEM_BACKWARD( // Top Down
&lstConnectNodeInstance,
pConnectNodeInstance) {
Assert(pConnectNodeInstance);
Assert(pConnectNodeInstance->pPinNodeInstanceSink);
Assert(pConnectNodeInstance->pPinNodeInstanceSink->pPinNode);
Assert(
pConnectNodeInstance->pPinNodeInstanceSink->pPinNode->pPinInfo);
//
// Use the sink pin handle for now. This should be fine until
// Sysaudio supports a spliter.
//
if(pConnectNodeInstance->pPinNodeInstanceSink->
pPinNode->pPinInfo->pFilterNode == pFilterNode) {
papFileObjectTopologyTable[n] =
pConnectNodeInstance->pPinNodeInstanceSink->pFileObject;
break;
}
} END_EACH_LIST_ITEM
}
DPF1(90, "CreatePinInstanceTopologyTable PI: %08x",
papFileObjectTopologyTable);
exit:
return(Status);
}
NTSTATUS
CStartNodeInstance::GetTopologyNodeFileObject(
OUT PFILE_OBJECT *ppFileObject,
IN ULONG NodeId
)
{
PGRAPH_NODE_INSTANCE pGraphNodeInstance;
NTSTATUS Status = STATUS_SUCCESS;
if(this == NULL) {
Status = STATUS_NO_SUCH_DEVICE;
goto exit;
}
Assert(this);
ASSERT(pPinInstance != NULL);
Status = pPinInstance->pFilterInstance->GetGraphNodeInstance(
&pGraphNodeInstance);
if(!NT_SUCCESS(Status)) {
goto exit;
}
Assert(pGraphNodeInstance);
if(NodeId >= pGraphNodeInstance->cTopologyNodes) {
Trap();
Status = STATUS_INVALID_DEVICE_REQUEST;
goto exit;
}
if(papFileObjectTopologyTable == NULL ||
papFileObjectTopologyTable[NodeId] == NULL) {
Status = pGraphNodeInstance->GetTopologyNodeFileObject(
ppFileObject,
NodeId);
if(!NT_SUCCESS(Status)) {
goto exit;
}
}
else {
*ppFileObject = papFileObjectTopologyTable[NodeId];
}
exit:
return(Status);
}
//---------------------------------------------------------------------------
NTSTATUS
CStartNodeInstance::SetState(
KSSTATE NewState,
ULONG ulFlags
)
{
NTSTATUS Status = STATUS_SUCCESS;
LONG State;
Assert(this);
if(NewState < KSSTATE_STOP || NewState >= MAX_STATES) {
Status = STATUS_INVALID_PARAMETER;
goto exit;
}
if(CurrentState == NewState) {
ASSERT(NT_SUCCESS(Status));
goto exit;
}
if(CurrentState < NewState) {
for(State = CurrentState + 1; State <= NewState; State++) {
Status = SetStateTopDown(
(KSSTATE)State,
CurrentState,
ulFlags | SETSTATE_FLAG_SINK | SETSTATE_FLAG_SOURCE);
if(!NT_SUCCESS(Status)) {
goto exit;
}
CurrentState = (KSSTATE)State;
}
}
else {
for(State = CurrentState - 1; State >= NewState; State--) {
Status = SetStateBottomUp(
(KSSTATE)State,
CurrentState,
ulFlags | SETSTATE_FLAG_SINK | SETSTATE_FLAG_SOURCE);
if(!NT_SUCCESS(Status)) {
goto exit;
}
CurrentState = (KSSTATE)State;
}
}
ASSERT(CurrentState == NewState);
exit:
return(Status);
}
NTSTATUS
CStartNodeInstance::SetStateTopDown(
KSSTATE NewState,
KSSTATE PreviousState,
ULONG ulFlags
)
{
PCONNECT_NODE_INSTANCE pConnectNodeInstance;
NTSTATUS Status = STATUS_SUCCESS;
if(this != NULL) {
Assert(this);
if(ulFlags & SETSTATE_FLAG_SINK) {
Status = pPinNodeInstance->SetState(
NewState,
PreviousState,
ulFlags);
if(!NT_SUCCESS(Status)) {
goto exit;
}
}
FOR_EACH_LIST_ITEM(
&lstConnectNodeInstance,
pConnectNodeInstance) {
Status = pConnectNodeInstance->SetStateTopDown(
NewState,
PreviousState,
ulFlags);
if(!NT_SUCCESS(Status)) {
goto exit;
}
} END_EACH_LIST_ITEM
}
exit:
return(Status);
}
NTSTATUS
CStartNodeInstance::SetStateBottomUp(
KSSTATE NewState,
KSSTATE PreviousState,
ULONG ulFlags
)
{
PCONNECT_NODE_INSTANCE pConnectNodeInstance;
NTSTATUS Status = STATUS_SUCCESS;
if(this != NULL) {
Assert(this);
FOR_EACH_LIST_ITEM_BACKWARD(
&lstConnectNodeInstance,
pConnectNodeInstance) {
Status = pConnectNodeInstance->SetStateBottomUp(
NewState,
PreviousState,
ulFlags);
if(!NT_SUCCESS(Status)) {
goto exit;
}
} END_EACH_LIST_ITEM
if(ulFlags & SETSTATE_FLAG_SINK) {
Status = pPinNodeInstance->SetState(
NewState,
PreviousState,
ulFlags);
if(!NT_SUCCESS(Status)) {
goto exit;
}
}
}
exit:
return(Status);
}
//---------------------------------------------------------------------------
#ifdef DEBUG
ENUMFUNC
CStartNodeInstance::Dump(
)
{
PCONNECT_NODE_INSTANCE pConnectNodeInstance;
extern PSZ apszStates[];
if(this == NULL) {
return(STATUS_CONTINUE);
}
if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) {
dprintf("SNI: %08x SN %08x PI %08x FNI %08x VND %08x papFO %08x\n",
this,
pStartNode,
pPinInstance,
pFilterNodeInstance,
pVirtualNodeData,
papFileObjectTopologyTable);
dprintf(" State: %08x %s\n",
CurrentState,
apszStates[CurrentState]);
if(ulDebugFlags & DEBUG_FLAGS_INSTANCE) {
if(pPinNodeInstance != NULL) {
pPinNodeInstance->Dump();
}
}
if(pPinConnect != NULL) {
DumpPinConnect(MAXULONG, pPinConnect);
}
}
else {
dprintf(" To: ");
if(pPinNodeInstance != NULL) {
pPinNodeInstance->Dump();
}
else {
dprintf("NULL\n");
}
}
if(ulDebugFlags & DEBUG_FLAGS_TOPOLOGY) {
PGRAPH_NODE_INSTANCE pGraphNodeInstance;
pGraphNodeInstance = pPinInstance->pFilterInstance->pGraphNodeInstance;
if(pGraphNodeInstance != NULL) {
Assert(pGraphNodeInstance);
for(ULONG i = 0;
i < pGraphNodeInstance->Topology.TopologyNodesCount;
i++) {
if(papFileObjectTopologyTable[i] != NULL) {
dprintf(" %02x FO %08x %s\n",
i,
papFileObjectTopologyTable[i],
pGraphNodeInstance->papTopologyNode[i]->pFilterNode->
DumpName());
}
}
}
}
if(ulDebugFlags & DEBUG_FLAGS_INSTANCE) {
FOR_EACH_LIST_ITEM(&lstConnectNodeInstance, pConnectNodeInstance) {
pConnectNodeInstance->Dump();
} END_EACH_LIST_ITEM
}
dprintf("\n");
return(STATUS_CONTINUE);
}
#endif
//---------------------------------------------------------------------------