|
|
//---------------------------------------------------------------------------
//
// 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 ) { 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
//
// First few checks compare the StartNode datarange to pPinConnect
// datarange.
//
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; }
//
// 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; }
//
// Now all the pins in the graph are connected successfully.
// Create the topology table.
//
Status = pStartNodeInstance->CreateTopologyTable( pPinInstance->pFilterInstance->pGraphNodeInstance);
if(!NT_SUCCESS(Status)) { Trap(); goto exit; } ASSERT(pStartNodeInstance->CurrentState == KSSTATE_STOP);
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();
if (pPinNodeInstance) { pPinNodeInstance->Destroy(); // also see CSNI::CleanUp
}
if (pFilterNodeInstance) { pFilterNodeInstance->Destroy(); }
delete [] papFileObjectTopologyTable; delete pVirtualNodeData; pPinInstance->pStartNodeInstance = NULL; pPinInstance->ParentInstance.Invalidate(); }
VOID CStartNodeInstance::CleanUp( ) { Assert(this); ASSERT(papFileObjectTopologyTable == NULL); ASSERT(pVirtualNodeData == NULL); ASSERT(CurrentState == KSSTATE_STOP);
if (pPinNodeInstance) { pPinNodeInstance->Destroy(); pPinNodeInstance = NULL; } if (pFilterNodeInstance) { 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; }
//
// ISSUE: 02/20/02 ALPERS
// The channel logic might not work with micarrays which have more than
// two channels.
//
//
// MaxChannels = (pWaveFormatExtensible->nChannels > 2) ? pWaveFormatExtensible->nChannels:2;
// We can do this, what would be the channel 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;
ASSERT(ppPinConnect);
*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);
delete [] *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); }
//=============================================================================
// Create an array which holds FileObject of the pin for each topology node
// in this graph.
// This array is later used as a lookup table for node communication.
//
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;
//
// ISSUE: 04/23/2002 ALPERS
// Until we have the parameter validation layer, this function
// is unprotected.
//
Assert(this); 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); }
|