/*++ 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(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(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 (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 (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