windows-nt/Source/XPSP1/NT/net/tapi/skywalker/wavemsp/waveaddr.cpp
2020-09-26 16:20:57 +08:00

590 lines
15 KiB
C++

/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
waveaddr.cpp
Abstract:
This module contains implementation of CWaveMSP.
Author:
Zoltan Szilagyi (zoltans) September 7, 1998
--*/
#include "stdafx.h"
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
CWaveMSP::CWaveMSP()
{
LOG((MSP_TRACE, "CWaveMSP::CWaveMSP entered."));
m_fHaveWaveIDs = FALSE;
m_dwWaveInID = 0xfeedface;
m_dwWaveOutID = 0xfeedface;
m_fdSupport = FDS_UNKNOWN;
m_pFilterMapper = NULL;
LOG((MSP_TRACE, "CWaveMSP::CWaveMSP exited."));
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
CWaveMSP::~CWaveMSP()
{
LOG((MSP_TRACE, "CWaveMSP::~CWaveMSP entered."));
if ( m_pFilterMapper )
{
m_pFilterMapper->Release();
}
LOG((MSP_TRACE, "CWaveMSP::~CWaveMSP exited."));
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
ULONG CWaveMSP::MSPAddressAddRef(void)
{
return MSPAddRefHelper(this);
}
ULONG CWaveMSP::MSPAddressRelease(void)
{
return MSPReleaseHelper(this);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
STDMETHODIMP CWaveMSP::CreateMSPCall(
IN MSP_HANDLE htCall,
IN DWORD dwReserved,
IN DWORD dwMediaType,
IN IUnknown * pOuterUnknown,
OUT IUnknown ** ppMSPCall
)
{
LOG((MSP_TRACE, "CWaveMSP::CreateMSPCall - enter"));
CWaveMSPCall * pCWaveMSPCall;
HRESULT hr = CreateMSPCallHelper<CWaveMSPCall>(this,
htCall,
dwReserved,
dwMediaType,
pOuterUnknown,
ppMSPCall,
&pCWaveMSPCall);
//
// pCWaveMSPCall is not addrefed; no need to release.
//
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CWaveMSP::CreateMSPCall - template helper returned"
"0x%08x", hr));
return hr;
}
//
// If we know the wave IDs, tell the call. If we don't know the wave IDs
// or if the setting fails, we still successfully create the call; we will
// just get failure events during streaming.
//
if ( m_fHaveWaveIDs )
{
pCWaveMSPCall->SetWaveIDs( m_dwWaveInID, m_dwWaveOutID );
}
LOG((MSP_TRACE, "CWaveMSP::CreateMSPCall - exit S_OK"));
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
STDMETHODIMP CWaveMSP::ShutdownMSPCall (
IN IUnknown * pMSPCall
)
{
LOG((MSP_TRACE, "CWaveMSP::ShutdownMSPCall - enter"));
CWaveMSPCall * pCWaveMSPCall;
HRESULT hr = ShutdownMSPCallHelper<CWaveMSPCall>(pMSPCall,
&pCWaveMSPCall);
//
// pCWaveMSPCall is not addrefed; no need to release.
//
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CWaveMSP::ShutdownMSPCall - template helper returned"
"0x%08x", hr));
return hr;
}
LOG((MSP_TRACE, "CWaveMSP::ShutdownMSPCall - exit S_OK"));
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// Mandatory CMSPAddress override. This indicates the media types that
// we support.
//
DWORD CWaveMSP::GetCallMediaTypes(void)
{
return (DWORD) TAPIMEDIATYPE_AUDIO;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// Optional CMSPAddress override. Used to find out the wave id's before any
// calls are created, allowing us to exclude our own wave devices from our
// enumeration of static terminals.
//
// We now also use these as the wave ids for all our calls on this address.
// We must get one of these messages before we make any calls -- these
// messages are sent while tapi is initializing the address, and it is
// done synchronously.
//
HRESULT CWaveMSP::ReceiveTSPAddressData(
IN PBYTE pBuffer,
IN DWORD dwSize
)
{
LOG((MSP_TRACE, "CWaveMSP::ReceiveTSPAddressData - enter"));
//
// Check that the buffer is as big as advertised.
//
if ( IsBadWritePtr(pBuffer, sizeof(BYTE) * dwSize) )
{
LOG((MSP_ERROR, "CWaveMSP::ReceiveTSPAddressData - "
"bad buffer - exit E_POINTER"));
return E_POINTER;
}
//
// Check if we have a command DWORD.
//
if ( dwSize < sizeof(DWORD) )
{
LOG((MSP_ERROR, "CWaveMSP::ReceiveTSPAddressData - "
"need a DWORD for command - exit E_INVALIDARG"));
return E_INVALIDARG;
}
int i;
HRESULT hr;
//
// Based on the command, take action:
//
switch ( ((DWORD *) pBuffer) [0] )
{
case 3: // use wave IDs to hide terminals
{
if ( dwSize < 3 * sizeof(DWORD) )
{
LOG((MSP_ERROR, "CWaveMSP::ReceiveTSPAddressData - "
"need 3 DWORDs for SetWaveID command - "
"exit E_INVALIDARG"));
return E_INVALIDARG;
}
m_TerminalDataLock.Lock();
_ASSERTE( m_fTerminalsUpToDate == FALSE );
m_fHaveWaveIDs = TRUE;
m_dwWaveInID = ((DWORD *) pBuffer) [1];
m_dwWaveOutID = ((DWORD *) pBuffer) [2];
m_TerminalDataLock.Unlock();
LOG((MSP_INFO, "CWaveMSP::ReceiveTSPAddressData - "
"setting WaveInID=%d, WaveOutID=%d",
m_dwWaveInID, m_dwWaveOutID));
}
break;
case 4: // don't use wave IDs to hide terminals
{
_ASSERTE( m_fTerminalsUpToDate == FALSE );
LOG((MSP_INFO, "CWaveMSP::ReceiveTSPAddressData - "
"got command 4 - not setting wave IDs"));
// m_fHaveWaveIDs remains FALSE
}
break;
case 8:
{
if ( dwSize < 2 * sizeof(DWORD) )
{
LOG((MSP_INFO, "CWaveMSP::ReceiveTSPAddressData - "
"need 2 DWORDS for set duplex support command - "
"exit E_INVALIDARG"));
return E_INVALIDARG;
}
m_TerminalDataLock.Lock();
if ( 1 == ((DWORD *) pBuffer) [1] )
{
m_fdSupport = FDS_SUPPORTED;
LOG((MSP_INFO, "CWaveMSP::ReceiveTSPAddressData - "
"Full Duplex supported"));
}
else
{
m_fdSupport = FDS_NOTSUPPORTED;
LOG((MSP_INFO, "CWaveMSP::ReceiveTSPAddressData - "
"Full Duplex not supported"));
}
m_TerminalDataLock.Unlock();
}
break;
default:
LOG((MSP_ERROR, "CWaveMSP::ReceiveTSPAddressData - "
"invalid command - exit E_INVALIDARG"));
return E_INVALIDARG;
}
LOG((MSP_TRACE, "CWaveMSP::ReceiveTSPAddressData - exit S_OK"));
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// Optional CMSPAddress override. Used to remove our own wave devices from
// the list of static terminals.
//
HRESULT CWaveMSP::UpdateTerminalList(void)
{
LOG((MSP_TRACE, "CWaveMSP::UpdateTerminalList - enter"));
//
// Call the base class method. This builds up the list of terminals.
//
HRESULT hr = CMSPAddress::UpdateTerminalList();
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CWaveMSP::UpdateTerminalList - "
"base class method failed - exit 0x%08x", hr));
return hr;
}
m_TerminalDataLock.Lock();
if ( m_fHaveWaveIDs )
{
int iSize = m_Terminals.GetSize();
for ( int i = 0; i < iSize; i++ )
{
ITTerminal * pTerminal = m_Terminals[i];
long lMediaType;
if ( SUCCEEDED( pTerminal->get_MediaType( & lMediaType ) ) )
{
if ( lMediaType == TAPIMEDIATYPE_AUDIO )
{
TERMINAL_DIRECTION dir;
if ( SUCCEEDED( pTerminal->get_Direction( & dir ) ) )
{
if ( TerminalHasWaveID( dir == TD_CAPTURE,
pTerminal,
m_dwWaveOutID ) )
{
pTerminal->Release();
m_Terminals.RemoveAt(i);
i--;
iSize--;
}
} // if direction is available
} // if audio
} // if media type is available
} // for each terminal
} // if we have wave ids
m_TerminalDataLock.Unlock();
LOG((MSP_TRACE, "CWaveMSP::UpdateTerminalList - exit S_OK"));
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// Private helpers to check if a terminal has a given wave IDs.
//
BOOL CWaveMSP::TerminalHasWaveID(
IN BOOL fCapture,
IN ITTerminal * pTerminal,
IN DWORD dwWaveID
)
{
LOG((MSP_TRACE, "CWaveMSP::TerminalHasWaveID - enter"));
_ASSERTE( ! IsBadReadPtr(pTerminal, sizeof(ITTerminal) ) );
IMoniker * pMoniker;
//
// Cast to the correct type of terminal and get the moniker.
//
if ( fCapture )
{
CAudioCaptureTerminal * pCaptureTerminal;
pCaptureTerminal = dynamic_cast<CAudioCaptureTerminal *> (pTerminal);
if ( pCaptureTerminal == NULL )
{
LOG((MSP_ERROR, "CWaveMSP::TerminalHasWaveID - "
"dynamic cast (capture) failed - exit FALSE"));
return FALSE;
}
pMoniker = pCaptureTerminal->m_pMoniker;
}
else
{
CAudioRenderTerminal * pRenderTerminal;
pRenderTerminal = dynamic_cast<CAudioRenderTerminal *> (pTerminal);
if ( pRenderTerminal == NULL )
{
LOG((MSP_ERROR, "CWaveMSP::TerminalHasWaveID - "
"dynamic cast (render) failed - exit FALSE"));
return FALSE;
}
pMoniker = pRenderTerminal->m_pMoniker;
}
//
// Check the moniker pointer.
//
if ( IsBadWritePtr( pMoniker, sizeof(IMoniker) ) )
{
LOG((MSP_ERROR, "CWaveMSP::TerminalHasWaveID - "
"bad moniker pointer - exit FALSE"));
return FALSE;
}
//
// Get a property bag from the moniker.
//
IPropertyBag * pBag;
HRESULT hr = pMoniker->BindToStorage(0,
0,
IID_IPropertyBag,
(void **) &pBag);
if (FAILED(hr))
{
LOG((MSP_ERROR, "CWaveMSP::TerminalHasWaveID - "
"can't get property bag - exit FALSE"));
return FALSE;
}
//
// Get the ID from the property bag.
//
WCHAR * pwszWaveID;
if ( fCapture )
{
pwszWaveID = L"WaveInId";
}
else
{
pwszWaveID = L"WaveOutId";
}
VARIANT var;
var.vt = VT_I4;
hr = pBag->Read(pwszWaveID, &var, 0);
pBag->Release();
if (FAILED(hr))
{
LOG((MSP_ERROR, "CWaveMSP::TerminalHasWaveID - "
"can't read wave ID - exit FALSE"));
return FALSE;
}
if ( var.lVal == (long) dwWaveID )
{
LOG((MSP_TRACE, "CWaveMSP::TerminalHasWaveID - "
"matched wave ID (%d) - exit TRUE", var.lVal));
return TRUE;
}
else
{
LOG((MSP_TRACE, "CWaveMSP::TerminalHasWaveID - "
"didn't match wave ID (%d) - exit FALSE", var.lVal));
return FALSE;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// Public method for creating and saving a reference to the DShow filter
// mapper object on an intelligent connect. Called by the stream/call when an
// intelligent connection is attempted. Does nothing if the cache has already
// been created.
//
HRESULT CWaveMSP::CreateFilterMapper(void)
{
LOG((MSP_TRACE, "CWaveMSP::CreateFilterMapper - enter"));
if ( m_pFilterMapper != NULL )
{
LOG((MSP_TRACE, "CWaveMSP::CreateFilterMapper - "
"mapper cache already created - doing nothing"));
}
else
{
//
// Create an extra filter mapper to keep the filter mapper cache around,
// and create the cache up front, This speeds up DShow's performance
// when we do intelligent connects.
//
HRESULT hr;
hr = CoCreateInstance(CLSID_FilterMapper,
NULL,
CLSCTX_INPROC_SERVER,
IID_IFilterMapper,
(void**) & m_pFilterMapper
);
if ( FAILED(hr) )
{
LOG((MSP_WARN, "CWaveMSP::CreateFilterMapper - "
"failed to create filter mapper - 0x%08x - continuing", hr));
m_pFilterMapper = NULL; // just to be safe
}
//
// No need to enumerate filters on the mapper cache, because this is
// called at connection time anyway, so there is nothing to be gained
// that way -- the intelligent connection will just do it.
//
}
LOG((MSP_TRACE, "CWaveMSP::CreateFilterMapper - exit S_OK"));
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// Returns full duplex support on this device
//
HRESULT CWaveMSP::IsFullDuplex( FULLDUPLEX_SUPPORT * pSupport )
{
LOG((MSP_TRACE, "CWaveMSP::IsFullDuplex - enter"));
if (IsBadWritePtr( pSupport, sizeof(FULLDUPLEX_SUPPORT) ))
{
LOG((MSP_TRACE, "CWaveMSP::IsFullDuplex - bad pointer"));
return E_POINTER;
}
m_TerminalDataLock.Lock();
*pSupport = m_fdSupport;
m_TerminalDataLock.Unlock();
LOG((MSP_TRACE, "CWaveMSP::IsFullDuplex - exit S_OK"));
return S_OK;
}
// eof