490 lines
13 KiB
C++
490 lines
13 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1998-1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
rcacall.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module contains implementation of CRCAMSPCall.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Zoltan Szilagyi (zoltans) September 7, 1998
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
CRCAMSPCall::CRCAMSPCall() : CMSPCallMultiGraph()
|
||
|
{
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::CRCAMSPCall entered."));
|
||
|
|
||
|
m_pRenderStream = NULL;
|
||
|
m_pCaptureStream = NULL;
|
||
|
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::CRCAMSPCall exited."));
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
CRCAMSPCall::~CRCAMSPCall()
|
||
|
{
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::~CRCAMSPCall entered."));
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::~CRCAMSPCall exited."));
|
||
|
}
|
||
|
|
||
|
ULONG CRCAMSPCall::MSPCallAddRef(void)
|
||
|
{
|
||
|
return MSPAddRefHelper(this);
|
||
|
}
|
||
|
|
||
|
ULONG CRCAMSPCall::MSPCallRelease(void)
|
||
|
{
|
||
|
return MSPReleaseHelper(this);
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
HRESULT CRCAMSPCall::Init(
|
||
|
IN CMSPAddress * pMSPAddress,
|
||
|
IN MSP_HANDLE htCall,
|
||
|
IN DWORD dwReserved,
|
||
|
IN DWORD dwMediaType
|
||
|
)
|
||
|
{
|
||
|
// No need to acquire locks on this call because it is called only
|
||
|
// once when the object is created. No other calls can be made on
|
||
|
// this object at this point.
|
||
|
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::Init - enter"));
|
||
|
|
||
|
//
|
||
|
// First do the base class method. We are adding to the functionality,
|
||
|
// not replacing it.
|
||
|
//
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = CMSPCallMultiGraph::Init(pMSPAddress,
|
||
|
htCall,
|
||
|
dwReserved,
|
||
|
dwMediaType);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::Init - "
|
||
|
"base class method failed: %x", hr));
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Our calls always come with two streams. Create them now. Use the base class
|
||
|
// methods, as our overriden methods (exposed to the user) purposely fail in order
|
||
|
// to keep the user from creating or removing streams themselves.
|
||
|
// These methods return a pointer to the ITStream. They get saved in our list of
|
||
|
// ITStreams, and we also save them here as CRCAMSPStream pointers.
|
||
|
//
|
||
|
|
||
|
ITStream * pStream;
|
||
|
|
||
|
//
|
||
|
// Create the capture stream.
|
||
|
//
|
||
|
|
||
|
hr = InternalCreateStream (dwMediaType,
|
||
|
TD_CAPTURE,
|
||
|
&pStream);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::Init - "
|
||
|
"couldn't create capture stream: %x", hr));
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
m_pCaptureStream = dynamic_cast<CRCAMSPStream *> (pStream);
|
||
|
|
||
|
if ( m_pCaptureStream == NULL )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::Init - "
|
||
|
"couldn't dynamic_cast capture stream - exit E_FAIL"));
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
pStream->Release();
|
||
|
|
||
|
//
|
||
|
// Create the render stream.
|
||
|
//
|
||
|
|
||
|
hr = InternalCreateStream (dwMediaType,
|
||
|
TD_RENDER,
|
||
|
&pStream);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::Init - "
|
||
|
"couldn't create capture stream: %x", hr));
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
m_pRenderStream = dynamic_cast<CRCAMSPStream *> (pStream);
|
||
|
|
||
|
if ( m_pRenderStream == NULL )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::Init - "
|
||
|
"couldn't dynamic_cast render stream - exit E_FAIL"));
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
pStream->Release();
|
||
|
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::Init - exit S_OK"));
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// We override this to make sure the number of
|
||
|
// streams we have is constant.
|
||
|
//
|
||
|
|
||
|
STDMETHODIMP CRCAMSPCall::CreateStream (
|
||
|
IN long lMediaType,
|
||
|
IN TERMINAL_DIRECTION Direction,
|
||
|
IN OUT ITStream ** ppStream
|
||
|
)
|
||
|
{
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::CreateStream entered."));
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::CreateStream - "
|
||
|
"we have a fixed set of streams - exit TAPI_E_MAXSTREAMS"));
|
||
|
|
||
|
return TAPI_E_MAXSTREAMS;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// We override this to make sure the number of
|
||
|
// streams we have is constant.
|
||
|
//
|
||
|
|
||
|
STDMETHODIMP CRCAMSPCall::RemoveStream (
|
||
|
IN ITStream * pStream
|
||
|
)
|
||
|
{
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::RemoveStream entered."));
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::RemoveStream - "
|
||
|
"we have a fixed set of streams - exit TAPI_E_NOTSUPPORTED"));
|
||
|
|
||
|
return TAPI_E_NOTSUPPORTED;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// This is our override to create the right kind of stream on stream creation.
|
||
|
// The base class checks the arguments for us.
|
||
|
//
|
||
|
|
||
|
HRESULT CRCAMSPCall::CreateStreamObject(
|
||
|
IN DWORD dwMediaType,
|
||
|
IN TERMINAL_DIRECTION Direction,
|
||
|
IN IMediaEvent * pGraph,
|
||
|
IN ITStream ** ppStream
|
||
|
)
|
||
|
{
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::CreateStreamObject - enter"));
|
||
|
|
||
|
HRESULT hr;
|
||
|
CMSPComObject<CRCAMSPStream> * pStream;
|
||
|
|
||
|
hr = CMSPComObject<CRCAMSPStream>::CreateInstance( &pStream );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::CreateStreamObject - "
|
||
|
"can't create stream object - 0x%08x", hr));
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
hr = pStream->_InternalQueryInterface( IID_ITStream,
|
||
|
(void **) ppStream );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::CreateStreamObject - "
|
||
|
"can't get ITStream interface - 0x%08x", hr));
|
||
|
|
||
|
delete pStream;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
hr = pStream->Init( (MSP_HANDLE) m_pMSPAddress,
|
||
|
this,
|
||
|
pGraph,
|
||
|
dwMediaType,
|
||
|
Direction);
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::CreateStreamObject - "
|
||
|
"can't Init stream object - 0x%08x", hr));
|
||
|
|
||
|
(*ppStream)->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::CreateStreamObject - exit S_OK"));
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// First DWORD = Command Second DWORD Reply needed?
|
||
|
// ------------- ------- ------------ -------------
|
||
|
// 0 Set VC handle VC handle no
|
||
|
// 1 Start streaming <ignored> no
|
||
|
// 2 Stop streaming <ignored> no
|
||
|
// 3 Are you there? <ignored> yes
|
||
|
//
|
||
|
// The method returns S_OK even if an individual stream failed to
|
||
|
// start, stop, or initialize. We generate events to note these
|
||
|
// failures.
|
||
|
//
|
||
|
|
||
|
HRESULT CRCAMSPCall::ReceiveTSPCallData(
|
||
|
IN PBYTE pBuffer,
|
||
|
IN DWORD dwSize
|
||
|
)
|
||
|
{
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::ReceiveTSPCallData - enter"));
|
||
|
|
||
|
//
|
||
|
// Check that the buffer is as big as advertised.
|
||
|
//
|
||
|
|
||
|
if ( IsBadWritePtr(pBuffer, sizeof(BYTE) * dwSize) )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::ReceiveTSPCallData - "
|
||
|
"bad buffer - exit E_POINTER"));
|
||
|
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check if we have a command DWORD.
|
||
|
//
|
||
|
|
||
|
if ( dwSize < sizeof(DWORD) )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::ReceiveTSPCallData - "
|
||
|
"need a DWORD for command - exit E_INVALIDARG"));
|
||
|
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We are going to access the streams lists -- grab the lock
|
||
|
//
|
||
|
|
||
|
CLock lock(m_lock);
|
||
|
|
||
|
_ASSERTE( m_Streams.GetSize() == 2 );
|
||
|
|
||
|
int i;
|
||
|
HRESULT hr;
|
||
|
|
||
|
//
|
||
|
// Based on the command, take action:
|
||
|
//
|
||
|
|
||
|
switch ( ((DWORD *) pBuffer) [0] )
|
||
|
{
|
||
|
case 0: // set the VC handle
|
||
|
{
|
||
|
if ( dwSize < 2 * sizeof(DWORD) )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::ReceiveTSPCallData - "
|
||
|
"need another DWORD for VC handle - exit E_INVALIDARG"));
|
||
|
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
LOG((MSP_INFO, "CRCAMSPCall::ReceiveTSPCallData - "
|
||
|
"setting VCHandle=%d", ((DWORD *) pBuffer) [1]));
|
||
|
|
||
|
//
|
||
|
// Use our saved class pointers to access the private method,
|
||
|
// and also to conveniently differentiate between render and
|
||
|
// capture. Note that the capture stream is the one with a
|
||
|
// capture terminal, and thus we need to give it the wave out id,
|
||
|
// and we need to give the render terminal the wave in ID.
|
||
|
//
|
||
|
|
||
|
hr = m_pRenderStream ->SetVCHandle( ((DWORD *) pBuffer) [1] );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::ReceiveTSPCallData - "
|
||
|
"render stream SetVCHandle failed 0x%08x - "
|
||
|
"firing CALL_STREAM_FAIL", hr));
|
||
|
|
||
|
m_pRenderStream->FireEvent(CALL_STREAM_FAIL, hr, CALL_CAUSE_UNKNOWN);
|
||
|
}
|
||
|
|
||
|
hr = m_pCaptureStream->SetVCHandle( ((DWORD *) pBuffer) [1] );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::ReceiveTSPCallData - "
|
||
|
"capture stream SetVCHandle failed 0x%08x - "
|
||
|
"firing CALL_STREAM_FAIL", hr));
|
||
|
|
||
|
m_pCaptureStream->FireEvent(CALL_STREAM_FAIL, hr, CALL_CAUSE_UNKNOWN);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 1: // start streaming
|
||
|
{
|
||
|
for ( i = 0; i < m_Streams.GetSize(); i++ )
|
||
|
{
|
||
|
hr = m_Streams[i]->StartStream();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 2: // stop streaming
|
||
|
{
|
||
|
for ( i = 0; i < m_Streams.GetSize(); i++ )
|
||
|
{
|
||
|
hr = m_Streams[i]->StopStream();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 3: // Are you there?
|
||
|
{
|
||
|
//
|
||
|
// "Are you there?" Must reply to indicate we are here.
|
||
|
// Create the event structure.
|
||
|
|
||
|
//
|
||
|
// Note:
|
||
|
//
|
||
|
// the size of the allocated memory =
|
||
|
//
|
||
|
// sizeof(LIST_ENTRY)
|
||
|
//
|
||
|
// +
|
||
|
//
|
||
|
// sizeof(MSP_EVENT_INFO) (LIST_ENTRY and MSP_EVENT_INFO make a
|
||
|
// MSPEVENTITEM structure)
|
||
|
// +
|
||
|
//
|
||
|
// sizeof(DWORD) (for the one-DWORD buffer following the
|
||
|
// variable-size MSP_EVENT_INFO structure)
|
||
|
//
|
||
|
|
||
|
MSPEVENTITEM * pEventItem = AllocateEventItem( sizeof(DWORD) );
|
||
|
|
||
|
if ( pEventItem == NULL )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::ReceiveTSPCallData - "
|
||
|
"can't create MSPEVENTITEM structure - exit E_OUTOFMEMORY"));
|
||
|
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Fill in the necessary fields for the event structure.
|
||
|
// Messages we send to our TSP consist of at least a single DWORD
|
||
|
// for the opcode. (Similar to tsp->msp messages.) In this case
|
||
|
// we just have the opcode zero and no other data.
|
||
|
//
|
||
|
|
||
|
// please send to tsp
|
||
|
pEventItem->MSPEventInfo.Event = ME_TSP_DATA;
|
||
|
|
||
|
// pertains to this call handle
|
||
|
pEventItem->MSPEventInfo.hCall = m_htCall;
|
||
|
|
||
|
// size of event structure
|
||
|
pEventItem->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO) +
|
||
|
sizeof(DWORD);
|
||
|
|
||
|
// size of opaque buffer within event structure
|
||
|
pEventItem->MSPEventInfo.MSP_TSP_DATA.dwBufferSize = sizeof(DWORD);
|
||
|
|
||
|
// contents of opaque buffer within event structure
|
||
|
((DWORD *) pEventItem->MSPEventInfo.MSP_TSP_DATA.pBuffer)[0] = 0;
|
||
|
|
||
|
//
|
||
|
// Send the event to the TSP.
|
||
|
//
|
||
|
|
||
|
hr = m_pMSPAddress->PostEvent(pEventItem);
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::ReceiveTSPCallData - "
|
||
|
"PostEvent failed - returning 0x%08x", hr));
|
||
|
|
||
|
FreeEventItem(pEventItem);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
LOG((MSP_ERROR, "CRCAMSPCall::ReceiveTSPCallData - "
|
||
|
"invalid command - exit E_INVALIDARG"));
|
||
|
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
}
|
||
|
|
||
|
LOG((MSP_TRACE, "CRCAMSPCall::ReceiveTSPCallData - exit S_OK"));
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// UseMulaw
|
||
|
//
|
||
|
// Helper function called when we need to decide if to use Mulaw or Alaw.
|
||
|
// This is simply delegated to the address.
|
||
|
//
|
||
|
|
||
|
BOOL CRCAMSPCall::UseMulaw( void )
|
||
|
{
|
||
|
return ( (CRCAMSP *) m_pMSPAddress )->UseMulaw();
|
||
|
}
|
||
|
|
||
|
// eof
|