|
|
//---------------------------------------------------------------------------
//
// Module: pni.cpp
//
// Description:
//
// Pin 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"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
CPinNodeInstance::~CPinNodeInstance( ) { DPF1(90, "~CPinNodeInstance: %08x", this); Assert(this);
if(pFileObject != NULL) { AssertFileObject(pFileObject); ObDereferenceObject(pFileObject); } if(hPin != NULL) { AssertStatus(ZwClose(hPin)); } pFilterNodeInstance->Destroy(); }
NTSTATUS CPinNodeInstance::Create( PPIN_NODE_INSTANCE *ppPinNodeInstance, PFILTER_NODE_INSTANCE pFilterNodeInstance, PPIN_NODE pPinNode, PKSPIN_CONNECT pPinConnect, BOOL fRender #ifdef FIX_SOUND_LEAK
,BOOL fDirectConnection #endif
) { PPIN_NODE_INSTANCE pPinNodeInstance = NULL; NTSTATUS Status = STATUS_SUCCESS;
Assert(pPinNode); Assert(pPinNode->pPinInfo); Assert(pFilterNodeInstance);
pPinConnect->PinId = pPinNode->pPinInfo->PinId; pPinNodeInstance = new PIN_NODE_INSTANCE(); if(pPinNodeInstance == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } pPinNodeInstance->pPinNode = pPinNode; pPinNodeInstance->pFilterNodeInstance = pFilterNodeInstance; ASSERT(pPinNodeInstance->CurrentState == KSSTATE_STOP); pFilterNodeInstance->AddRef(); pPinNodeInstance->fRender = fRender; #ifdef FIX_SOUND_LEAK
pPinNodeInstance->fDirectConnection = fDirectConnection; pPinNodeInstance->ForceRun = FALSE; #endif
#ifdef DEBUG
DPF3(90, "CPNI::Create PN %08x #%d %s", pPinNode, pPinNode->pPinInfo->PinId, pPinNode->pPinInfo->pFilterNode->DumpName()); DumpPinConnect(90, pPinConnect); #endif
if (pFilterNodeInstance->hFilter == NULL) { //
// If it is a GFX we have to attach to the AddGfx() context
// to create the pin
//
Status = pFilterNodeInstance->pFilterNode->CreatePin(pPinConnect, GENERIC_WRITE, &pPinNodeInstance->hPin); } else { Status = KsCreatePin( pFilterNodeInstance->hFilter, pPinConnect, GENERIC_WRITE | OBJ_KERNEL_HANDLE, &pPinNodeInstance->hPin); }
if(!NT_SUCCESS(Status)) { #ifdef DEBUG
DPF4(90, "CPNI::Create PN %08x #%d %s KsCreatePin FAILED: %08x", pPinNode, pPinNode->pPinInfo->PinId, pPinNode->pPinInfo->pFilterNode->DumpName(), Status); #endif
pPinNodeInstance->hPin = NULL; goto exit; } Status = ObReferenceObjectByHandle( pPinNodeInstance->hPin, GENERIC_READ | GENERIC_WRITE, NULL, KernelMode, (PVOID*)&pPinNodeInstance->pFileObject, NULL);
if(!NT_SUCCESS(Status)) { pPinNodeInstance->pFileObject = NULL; goto exit; } AssertFileObject(pPinNodeInstance->pFileObject);
DPF2(90, "CPNI::Create SUCCESS %08x PN %08x", pPinNodeInstance, pPinNode); exit: if(!NT_SUCCESS(Status)) { if (pPinNodeInstance) { pPinNodeInstance->Destroy(); } pPinNodeInstance = NULL; }
*ppPinNodeInstance = pPinNodeInstance; return(Status); }
#ifdef DEBUG
PSZ apszStates[] = { "STOP", "ACQUIRE", "PAUSE", "RUN" }; #endif
NTSTATUS CPinNodeInstance::SetState( KSSTATE NewState, KSSTATE PreviousState, ULONG ulFlags ) { NTSTATUS Status = STATUS_SUCCESS; LONG State;
if(this == NULL) { goto exit; } Assert(this);
DPF9(DBG_STATE, "SetState %s to %s cR %d cP %d cA %d cS %d P# %d %s %s", apszStates[PreviousState], apszStates[NewState], cState[KSSTATE_RUN], cState[KSSTATE_PAUSE], cState[KSSTATE_ACQUIRE], cState[KSSTATE_STOP], pPinNode->pPinInfo->PinId, apszStates[CurrentState], pPinNode->pPinInfo->pFilterNode->DumpName());
cState[PreviousState]--; cState[NewState]++;
for(State = KSSTATE_RUN; State > KSSTATE_STOP; State--) { if(cState[State] > 0) { break; } }
// ISSUE-2001/04/09-alpers
// The proper fix would be to propagate the reset to the entire audio stack.
// But it is considered as being to risky for now (after Beta2 of Windows XP).
// This should be one of the first things we should address in Blackcomb.
//
#ifdef FIX_SOUND_LEAK
// FIX_SOUND_LEAK is to prevent the audio stack from play/recording the last
// portion of data when a new stream is started.
// This temporary fix keeps the pins below splitter/kmixer sink pin in
// RUNNING state.
//
if (fRender) { // For render pins
// The criteria for keeping the pin in RUN state:
// If the pin is going to PAUSE from RUN.
// If the filter is below kmixer.
// If the pin is not kmixer sink pin.
//
if ( (!fDirectConnection) && (State == KSSTATE_PAUSE) && (PreviousState == KSSTATE_RUN) && (pFilterNodeInstance->pFilterNode->GetOrder() <= ORDER_MIXER) && !(pFilterNodeInstance->pFilterNode->GetOrder() == ORDER_MIXER && pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_SINK) ) { ForceRun = TRUE; } } else { // For capture pins
// The criteria for keeping the pin in RUN state:
// If the pin is going to PAUSE from RUN.
// There are more than one pins in PAUSE.
//
if ( (State == KSSTATE_PAUSE) && (PreviousState == KSSTATE_RUN) && (cState[KSSTATE_PAUSE] > 1) ) { DPF(DBG_STATE, "SetState: CAPTURE forcing KSSTATE_RUN"); State = KSSTATE_RUN; } }
if (ForceRun) { DPF(DBG_STATE, "SetState: RENDER IN FORCE KSSTATE_RUN state"); State = KSSTATE_RUN; }
#else
for(State = KSSTATE_RUN; cState[State] <= 0; State--) { if(State == KSSTATE_STOP) { break; } } #endif
#ifdef FIX_SOUND_LEAK
// If the pin is forced to be in RUN state, we should go back to
// regular state scheme, if and only if there are no pins in RUN state.
// To prevent RUN-ACQUIRE first go to PAUSE.
//
if (ForceRun && (0 == cState[KSSTATE_PAUSE]) && (0 == cState[KSSTATE_RUN])) { KSSTATE TempState = KSSTATE_PAUSE;
DPF(DBG_STATE, "SetState: Exiting FORCE KSSTATE_RUN state"); DPF1(DBG_STATE, "SetState: PinConnectionProperty(%s)", apszStates[TempState]);
Status = PinConnectionProperty( pFileObject, KSPROPERTY_CONNECTION_STATE, KSPROPERTY_TYPE_SET, sizeof(TempState), &TempState); if (!NT_SUCCESS(Status)) { if(ulFlags & SETSTATE_FLAG_IGNORE_ERROR) { Status = STATUS_SUCCESS; } else { //
// Go back to previous state if failure
//
cState[PreviousState]++; cState[NewState]--; goto exit; } }
// Exiting the FORCE_RUN state.
//
CurrentState = KSSTATE_PAUSE; State = KSSTATE_ACQUIRE; ForceRun = FALSE; } #endif
if(CurrentState != State) { DPF1(DBG_STATE, "SetState: PinConnectionProperty(%s)", apszStates[State]); ASSERT(State == CurrentState + 1 || State == CurrentState - 1);
Status = PinConnectionProperty( pFileObject, KSPROPERTY_CONNECTION_STATE, KSPROPERTY_TYPE_SET, sizeof(State), &State);
if(!NT_SUCCESS(Status)) { DPF1(5, "SetState: PinConnectionProperty FAILED %08x", Status);
if(ulFlags & SETSTATE_FLAG_IGNORE_ERROR) { Status = STATUS_SUCCESS; } else { //
// Go back to previous state if failure
//
cState[PreviousState]++; cState[NewState]--; goto exit; } }
CurrentState = (KSSTATE)State; } exit: return(Status); }
//---------------------------------------------------------------------------
|