You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
589 lines
16 KiB
589 lines
16 KiB
/*++
|
|
|
|
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
|