8500 lines
197 KiB
C++
8500 lines
197 KiB
C++
/*++
|
|
|
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
call.cpp
|
|
|
|
Abstract:
|
|
|
|
Implements helper functions for call object
|
|
|
|
Author:
|
|
|
|
mquinton - 4/17/97
|
|
|
|
Notes:
|
|
|
|
optional-notes
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
#include "tapievt.h"
|
|
|
|
|
|
extern ULONG_PTR GenerateHandleAndAddToHashTable( ULONG_PTR Element);
|
|
extern void RemoveHandleFromHashTable(ULONG_PTR Handle);
|
|
|
|
extern CHashTable * gpCallHubHashTable;
|
|
extern CHashTable * gpCallHashTable;
|
|
extern CHashTable * gpHandleHashTable;
|
|
extern HANDLE ghAsyncRetryQueueEvent;
|
|
|
|
|
|
DWORD gdwWaitForConnectSleepTime = 100;
|
|
DWORD gdwWaitForConnectWaitIntervals = 600;
|
|
|
|
char *callStateName(CALL_STATE callState);
|
|
|
|
HRESULT
|
|
ProcessNewCallPrivilege(
|
|
DWORD dwPrivilege,
|
|
CALL_PRIVILEGE * pCP
|
|
);
|
|
|
|
HRESULT
|
|
ProcessNewCallState(
|
|
DWORD dwCallState,
|
|
DWORD dwDetail,
|
|
CALL_STATE CurrentCallState,
|
|
CALL_STATE * pCallState,
|
|
CALL_STATE_EVENT_CAUSE * pCallStateCause
|
|
);
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CCall
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// Initialize the call object
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CCall::Initialize(
|
|
CAddress * pAddress,
|
|
PWSTR pszDestAddress,
|
|
long lAddressType,
|
|
long lMediaType,
|
|
CALL_PRIVILEGE cp,
|
|
BOOL bNeedToNotify,
|
|
BOOL bExpose,
|
|
HCALL hCall,
|
|
CEventMasks* pEventMasks
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IUnknown * pUnk = NULL;
|
|
|
|
LOG((TL_TRACE,"Initialize - enter" ));
|
|
LOG((TL_TRACE," pAddress ---------> %p", pAddress ));
|
|
LOG((TL_TRACE," pszDestAddress ---> %p", pszDestAddress ));
|
|
LOG((TL_TRACE," DestAddress is ---> %ls", pszDestAddress ));
|
|
LOG((TL_TRACE," CallPrivilege ----> %d", cp ));
|
|
LOG((TL_TRACE," bNeedToNotify ----> %d", bNeedToNotify ));
|
|
LOG((TL_TRACE," hCall ------------> %lx", hCall ));
|
|
|
|
|
|
//
|
|
// good address object?
|
|
//
|
|
|
|
if (IsBadReadPtr(pAddress, sizeof(CAddress)))
|
|
{
|
|
LOG((TL_ERROR, "Initialize - - bad address pointer"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// copy the destination address
|
|
//
|
|
if (NULL != pszDestAddress)
|
|
{
|
|
m_szDestAddress = (PWSTR) ClientAlloc(
|
|
(lstrlenW(pszDestAddress) + 1) * sizeof (WCHAR)
|
|
);
|
|
if (NULL == m_szDestAddress)
|
|
{
|
|
LOG((TL_ERROR, E_OUTOFMEMORY,"Initialize - exit" ));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
lstrcpyW(
|
|
m_szDestAddress,
|
|
pszDestAddress
|
|
);
|
|
}
|
|
|
|
m_pCallParams = (LINECALLPARAMS *)ClientAlloc( sizeof(LINECALLPARAMS) + 1000 );
|
|
|
|
if ( NULL == m_pCallParams )
|
|
{
|
|
ClientFree( m_szDestAddress );
|
|
|
|
m_szDestAddress = NULL;
|
|
|
|
LOG((TL_ERROR, E_OUTOFMEMORY,"Initialize - exit" ));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
m_pCallParams->dwTotalSize = sizeof(LINECALLPARAMS) + 1000;
|
|
m_dwCallParamsUsedSize = sizeof(LINECALLPARAMS);
|
|
|
|
//
|
|
// set original state
|
|
//
|
|
m_t3Call.hCall = hCall;
|
|
m_t3Call.pCall = this;
|
|
m_hAdditionalCall = NULL;
|
|
m_CallPrivilege = cp;
|
|
m_pAddress = pAddress;
|
|
m_pAddress->AddRef();
|
|
if( m_pAddress->GetAPIVersion() >= TAPI_VERSION3_0 )
|
|
{
|
|
m_pCallParams->dwAddressType = lAddressType;
|
|
}
|
|
m_dwMediaMode = lMediaType;
|
|
|
|
//
|
|
// Read the subevent mask from the
|
|
// address parent object
|
|
//
|
|
pEventMasks->CopyEventMasks( &m_EventMasks);
|
|
|
|
|
|
if (bNeedToNotify)
|
|
{
|
|
m_dwCallFlags |= CALLFLAG_NEEDTONOTIFY;
|
|
}
|
|
|
|
if (!bExpose)
|
|
{
|
|
m_dwCallFlags |= CALLFLAG_DONTEXPOSE;
|
|
}
|
|
|
|
//
|
|
// keep 1 reference for the global hash table
|
|
//
|
|
if ( bNeedToNotify )
|
|
{
|
|
m_dwRef = 3;
|
|
}
|
|
else
|
|
{
|
|
m_dwRef = 2;
|
|
}
|
|
|
|
|
|
//
|
|
// if we are the owner of the call, and the address has msp, attempt to
|
|
// create msp call
|
|
//
|
|
|
|
if ( (CP_OWNER == m_CallPrivilege) && m_pAddress->HasMSP() )
|
|
{
|
|
hr = CreateMSPCall( lMediaType );
|
|
if ( FAILED (hr) )
|
|
{
|
|
// If we fail to create an MSP call we can still use the call
|
|
// for non media call control
|
|
LOG((TL_ERROR, hr, "Initialize - CreateMSPCall failed"));
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// put in global hash table
|
|
//
|
|
if ( NULL != m_t3Call.hCall )
|
|
{
|
|
AddCallToHashTable();
|
|
}
|
|
|
|
LOG((TL_TRACE,S_OK,"Initialize - exit" ));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// ExternalFinalRelease
|
|
// Clean up call object
|
|
//
|
|
// we have this special finalrelease because we keep our own reference
|
|
// to the call. right before the ref count goes to 1 inside of release,
|
|
// we call this. It is possible that the call's ref count could go up
|
|
// again because of a message from tapisrv. So, we lock the hashtable,
|
|
// then verify the refcount again. If we did process a message from
|
|
// tapisrv for the call,the refcount will be increased, and we won't
|
|
// do this finalrelease.
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
BOOL
|
|
CCall::ExternalFinalRelease()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CCallHub * pCallHub = NULL;
|
|
|
|
|
|
LOG((TL_TRACE, "ExternalFinalRelease - enter" ));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// NikhilB: Call object has a reference to Callhub object so its safe to
|
|
// lock the callhub object before locking the call. This is to avoid a
|
|
// deadlock that happens dur to locking the call and the callhub in reverse
|
|
// orders in different functions.
|
|
//
|
|
|
|
if( m_pCallHub != NULL )
|
|
{
|
|
m_pCallHub->AddRef();
|
|
|
|
pCallHub = m_pCallHub;
|
|
|
|
Unlock();
|
|
|
|
// lock the callhub object before locking the call
|
|
pCallHub->Lock();
|
|
Lock();
|
|
|
|
pCallHub->Release();
|
|
}
|
|
|
|
//
|
|
// Check extra t3call used in conference legs
|
|
//
|
|
if (NULL != m_hAdditionalCall)
|
|
{
|
|
LOG((TL_INFO,"ExternalFinalRelease: Deallocating Addditional call"));
|
|
|
|
LineDeallocateCall( m_hAdditionalCall );
|
|
|
|
m_hAdditionalCall = NULL;
|
|
}
|
|
|
|
|
|
if (NULL != m_t3Call.hCall)
|
|
{
|
|
//
|
|
// dealloc call
|
|
//
|
|
LOG((TL_INFO,"Deallocating call"));
|
|
|
|
hr = LineDeallocateCall( m_t3Call.hCall );
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, hr, "ExternalFinalRelease - LineDeallocateCall failed" ));
|
|
}
|
|
|
|
m_t3Call.hCall = NULL;
|
|
}
|
|
|
|
//
|
|
// clean up & release the callhub
|
|
//
|
|
if (NULL != pCallHub)
|
|
{
|
|
|
|
|
|
pCallHub->RemoveCall( this );
|
|
|
|
|
|
|
|
Unlock();
|
|
|
|
|
|
//
|
|
// checkforidle will lock the callhub and then every call that belongs
|
|
// to it. make this call outside call's lock to prevent deadlocks with
|
|
// other threads that can possibly lock a call (which belongs to this
|
|
// callhub) while trying to lock this callhub
|
|
//
|
|
|
|
pCallHub->CheckForIdle();
|
|
|
|
|
|
Lock();
|
|
|
|
|
|
pCallHub->Unlock();
|
|
pCallHub = NULL;
|
|
|
|
//release the refcount that call object has to the callhub.
|
|
if(m_pCallHub != NULL)
|
|
{
|
|
m_pCallHub->Release();
|
|
m_pCallHub = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// close the associated line
|
|
//
|
|
if ( ! ( m_dwCallFlags & CALLFLAG_NOTMYLINE ) )
|
|
{
|
|
m_pAddress->MaybeCloseALine( &m_pAddressLine );
|
|
}
|
|
|
|
//
|
|
// remove the call from the address's list
|
|
//
|
|
m_pAddress->RemoveCall( (ITCallInfo *) this );
|
|
|
|
//
|
|
// free the dest address string
|
|
//
|
|
ClientFree(m_szDestAddress);
|
|
m_szDestAddress = NULL;
|
|
|
|
if ( NULL != m_pCallInfo )
|
|
{
|
|
ClientFree( m_pCallInfo );
|
|
m_pCallInfo = NULL;
|
|
m_dwCallFlags |= CALLFLAG_CALLINFODIRTY;
|
|
}
|
|
|
|
//
|
|
// tell the msp the call is going away
|
|
//
|
|
if ( NULL != m_pMSPCall )
|
|
{
|
|
m_pAddress->ShutdownMSPCall( m_pMSPCall );
|
|
|
|
m_pMSPCall->Release();
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// release the address
|
|
//
|
|
m_pAddress->Release();
|
|
|
|
//
|
|
// release the private object
|
|
//
|
|
if (NULL != m_pPrivate)
|
|
{
|
|
m_pPrivate->Release();
|
|
}
|
|
|
|
//
|
|
//NikhilB:If this was a consultation call and is being dropped before
|
|
//calling Finish on it then we should release the reference it holds to
|
|
//the primary call object through m_pRelatedCall
|
|
//
|
|
if( NULL != m_pRelatedCall )
|
|
{
|
|
m_pRelatedCall->Release();
|
|
|
|
m_pRelatedCall = NULL;
|
|
m_dwCallFlags &= ~CALLFLAG_CONSULTCALL;
|
|
}
|
|
|
|
|
|
//
|
|
// free any call params
|
|
//
|
|
if ( NULL != m_pCallParams )
|
|
{
|
|
ClientFree( m_pCallParams );
|
|
m_pCallParams = NULL;
|
|
}
|
|
|
|
//
|
|
// clean up the gather digits queue
|
|
//
|
|
m_GatherDigitsQueue.Shutdown();
|
|
|
|
Unlock();
|
|
|
|
|
|
LOG((TL_TRACE, "ExternalFinalRelease - exit" ));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CCall::CallOnTapiShutdown()
|
|
{
|
|
LOG((TL_TRACE, "CallOnTapiShutdown - enter" ));
|
|
|
|
|
|
//
|
|
// we need to remove the call from the handle hash table to avoid duplicate
|
|
// entries with the calls that are created later with the same call handle
|
|
// (in case _this_ call object is still referenced by the app and is
|
|
// still around
|
|
//
|
|
|
|
gpCallHashTable->Lock();
|
|
|
|
gpCallHashTable->Remove( (ULONG_PTR)(m_t3Call.hCall) );
|
|
|
|
gpCallHashTable->Unlock();
|
|
|
|
|
|
LOG((TL_TRACE, "CallOnTapiShutdown - exit" ));
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// MyBasicCallControlQI
|
|
// don't give out the basiccallcontrol interface
|
|
// if the application does not own the call
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
WINAPI
|
|
MyBasicCallControlQI(void* pv, REFIID riid, LPVOID* ppv, DWORD_PTR dw)
|
|
{
|
|
LOG((TL_TRACE,"MyBasicCallControlQI - enter"));
|
|
|
|
CALL_PRIVILEGE cp;
|
|
|
|
((CCall *)pv)->get_Privilege( &cp );
|
|
|
|
if (CP_OWNER != cp)
|
|
{
|
|
LOG((TL_WARN,"The application is not the owner of this call"));
|
|
LOG((TL_WARN,"so it cannot access the BCC interface"));
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
//
|
|
// S_FALSE tells atl to continue querying for the interface
|
|
//
|
|
LOG((TL_INFO,"The application owns this call, so it can access the BCC interface"));
|
|
|
|
LOG((TL_TRACE, "MyBasicCallControlQI - exit"));
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// TryToFindACallHub
|
|
//
|
|
// for an incoming call, tries to find an existing callhub.
|
|
// the order of events (LINE_APPNEWCALL and LINE_APPNEWCALLHUB) is
|
|
// not guaranteed.
|
|
//
|
|
// must be called in a Lock()
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CCall::TryToFindACallHub()
|
|
{
|
|
HRESULT hr;
|
|
HCALLHUB hCallHub;
|
|
CCallHub * pCallHub;
|
|
|
|
//
|
|
// do we already have a callhub?
|
|
//
|
|
if ( ( NULL == m_pCallHub ) && (NULL != m_t3Call.hCall ) )
|
|
{
|
|
//
|
|
// no. Ask tapisrv for the hCallHub
|
|
//
|
|
hr = LineGetCallHub(
|
|
m_t3Call.hCall,
|
|
&hCallHub
|
|
);
|
|
|
|
//
|
|
// if it fails, there is no hCallHub,
|
|
// so try to create a fake one
|
|
//
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
hr = CheckAndCreateFakeCallHub();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// if there is, find the correponding CallHub object
|
|
//
|
|
if (FindCallHubObject(
|
|
hCallHub,
|
|
&pCallHub
|
|
))
|
|
{
|
|
//
|
|
// save it in the call
|
|
//
|
|
SetCallHub( pCallHub );
|
|
|
|
//
|
|
// tell it about this call
|
|
// ZoltanS note: the following calls CCall::SetCallHub as well,
|
|
// but this no longer results in an extra reference to the callhub
|
|
// as we now check for that in CCall::SetCallHub.
|
|
//
|
|
pCallHub->AddCall( this );
|
|
|
|
//
|
|
// FindCallHubObject addrefs
|
|
//
|
|
pCallHub->Release();
|
|
}
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// SetRelatedCall
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
void CCall::SetRelatedCall(CCall * pCall, DWORD callFlags)
|
|
{
|
|
Lock();
|
|
|
|
//
|
|
// keep a reference to the related call
|
|
//
|
|
pCall->AddRef();
|
|
|
|
//
|
|
// save it
|
|
//
|
|
m_pRelatedCall = pCall;
|
|
|
|
//
|
|
// save the relavant call flags
|
|
//
|
|
m_dwCallFlags |= callFlags;
|
|
|
|
Unlock();
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// ResetRelatedCall
|
|
//
|
|
// clear out the relate call stuff
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
void CCall::ResetRelatedCall()
|
|
{
|
|
Lock();
|
|
|
|
//
|
|
// release ref
|
|
//
|
|
if( m_pRelatedCall != NULL )
|
|
{
|
|
m_pRelatedCall->Release();
|
|
m_pRelatedCall = NULL;
|
|
}
|
|
|
|
m_dwCallFlags &= ~(CALLFLAG_CONSULTCALL | CALLFLAG_CONFCONSULT | CALLFLAG_TRANSFCONSULT );
|
|
|
|
Unlock();
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// CreateMSPCall
|
|
//
|
|
// tell the msp to create a call based on the give mediatype
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::CreateMSPCall(
|
|
long lMediaType
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
IUnknown * pUnk;
|
|
|
|
LOG((TL_TRACE,"CreateMSPCall - enter"));
|
|
|
|
Lock();
|
|
|
|
hr = _InternalQueryInterface( IID_IUnknown, (void**) &pUnk );
|
|
|
|
if ( !SUCCEEDED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "CreateMSPCall - cant get IUnk - %lx", hr));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Create a context handle to give the MSPCall object & associate it with
|
|
//this object in the global handle hash table
|
|
m_MSPCallHandle = (MSP_HANDLE) GenerateHandleAndAddToHashTable((ULONG_PTR)this);
|
|
|
|
|
|
//
|
|
// create a MSPCall - the address actually calls
|
|
// into the msp for us.
|
|
//
|
|
hr = m_pAddress->CreateMSPCall(
|
|
m_MSPCallHandle,
|
|
0,
|
|
lMediaType,
|
|
pUnk,
|
|
&m_pMSPCall
|
|
);
|
|
|
|
pUnk->Release();
|
|
|
|
Unlock();
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_ERROR, "CreateMSPCall failed, %x", hr ));
|
|
}
|
|
|
|
LOG((TL_TRACE,"CreateMSPCall - exit - returning %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// DialConsultCall
|
|
//
|
|
// bSync - same as connect - should we wait to return until
|
|
// the call is connected or disconnected?
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CCall::DialConsultCall(BOOL bSync)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hEvent;
|
|
|
|
LOG((TL_TRACE, "DialConsultCall - enter" ));
|
|
LOG((TL_TRACE, " bSync ---> %d", bSync ));
|
|
|
|
Lock();
|
|
|
|
// make sure they have selected media terminals
|
|
//
|
|
hr = m_pAddress->FindOrOpenALine(
|
|
m_dwMediaMode,
|
|
&m_pAddressLine
|
|
);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
Unlock();
|
|
|
|
LOG((
|
|
TL_ERROR,
|
|
"DialConsultCall - FindOrOpenALine failed - %lx",
|
|
hr
|
|
));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// dial the call
|
|
//
|
|
hr = LineDial(
|
|
m_t3Call.hCall,
|
|
m_szDestAddress,
|
|
m_dwCountryCode
|
|
);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if (bSync)
|
|
{
|
|
hEvent = CreateConnectedEvent();
|
|
}
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// wait for an async reply
|
|
//
|
|
hr = WaitForReply( hr );
|
|
|
|
Lock();
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "DialConsultCall - LineDial failed - %lx", hr ));
|
|
|
|
ClearConnectedEvent();
|
|
|
|
m_CallState = CS_DISCONNECTED;
|
|
|
|
m_pAddress->MaybeCloseALine( &m_pAddressLine );
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
if (bSync)
|
|
{
|
|
return SyncWait( hEvent );
|
|
}
|
|
|
|
LOG((TL_TRACE, "DialConsultCall - exit - return SUCCESS"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// OnDisconnect
|
|
//
|
|
// called when the call transitions into the disconnected state
|
|
//
|
|
// called in lock
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::OnDisconnect()
|
|
{
|
|
CCallHub * pCallHub = NULL;
|
|
|
|
LOG((TL_ERROR, "OnDisconnect - enter"));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// set the connected event if necessary
|
|
//
|
|
if ( NULL != m_hConnectedEvent )
|
|
{
|
|
SetEvent( m_hConnectedEvent );
|
|
}
|
|
|
|
//
|
|
// special case for wavemsp
|
|
//
|
|
if ( OnWaveMSPCall() )
|
|
{
|
|
StopWaveMSPStream();
|
|
}
|
|
#ifdef USE_PHONEMSP
|
|
else if ( OnPhoneMSPCall() )
|
|
{
|
|
StopPhoneMSPStream();
|
|
}
|
|
#endif USE_PHONEMSP
|
|
|
|
//
|
|
// check to see if the callhub
|
|
// is idle
|
|
//
|
|
pCallHub = m_pCallHub;
|
|
|
|
if ( NULL != pCallHub )
|
|
{
|
|
|
|
pCallHub->AddRef();
|
|
|
|
Unlock();
|
|
|
|
|
|
//
|
|
// unlock the call before calling checkfor idle to prevent deadlocks
|
|
//
|
|
|
|
pCallHub->CheckForIdle();
|
|
|
|
pCallHub->Release();
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
Unlock();
|
|
}
|
|
|
|
LOG((TL_ERROR, "OnDisconnect - finish"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::StartWaveMSPStream
|
|
//
|
|
// need to give it the waveID info and
|
|
// tell it to start streaming
|
|
//
|
|
// the format of the blob given to the wave msp is:
|
|
//
|
|
// First DWORD = Command Second DWORD Third DWORD
|
|
// ------------- ------- ------------ -----------
|
|
// 0 Set wave IDs WaveIn ID WaveOut ID
|
|
// 1 Start streaming <ignored> <ignored>
|
|
// 2 Stop streaming <ignored> <ignored>
|
|
// 3 <per-address, not per-call>
|
|
// 4 <per-address, not per-call>
|
|
// 5 Suspend streaming <ignored> <ignored>
|
|
// 6 Resume streaming <ignored> <ignored>
|
|
// 7 Wave IDs unavailable <ignored> <ignored>
|
|
//
|
|
//
|
|
// called in lock()
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CCall::StartWaveMSPStream()
|
|
{
|
|
//
|
|
// Get the stream control interface.
|
|
//
|
|
|
|
DWORD adwInfo[3];
|
|
ITStreamControl * pStreamControl;
|
|
|
|
pStreamControl = GetStreamControl();
|
|
|
|
if ( NULL == pStreamControl )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Get the per-call waveids, and report the results to the wavemsp.
|
|
//
|
|
|
|
HRESULT hr;
|
|
|
|
hr = CreateWaveInfo(
|
|
NULL,
|
|
0,
|
|
m_t3Call.hCall,
|
|
LINECALLSELECT_CALL,
|
|
m_pAddress->HasFullDuplexWaveDevice(),
|
|
adwInfo
|
|
);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
// 0 = set waveids
|
|
adwInfo[0] = 0;
|
|
// waveids filled in above
|
|
}
|
|
else
|
|
{
|
|
// 7: per-call waveids unavailable
|
|
adwInfo[0] = 7;
|
|
adwInfo[1] = 0;
|
|
adwInfo[2] = 0;
|
|
}
|
|
|
|
m_pAddress->ReceiveTSPData(
|
|
pStreamControl,
|
|
(LPBYTE)adwInfo,
|
|
sizeof(adwInfo)
|
|
);
|
|
|
|
//
|
|
// now tell it to start streaming
|
|
//
|
|
|
|
adwInfo[0] = 1;
|
|
adwInfo[1] = 0;
|
|
adwInfo[2] = 0;
|
|
|
|
m_pAddress->ReceiveTSPData(
|
|
pStreamControl,
|
|
(LPBYTE)adwInfo,
|
|
sizeof(adwInfo)
|
|
);
|
|
|
|
pStreamControl->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::StopWaveMSPStream
|
|
//
|
|
// called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CCall::StopWaveMSPStream()
|
|
{
|
|
DWORD adwInfo[3];
|
|
ITStreamControl * pStreamControl;
|
|
|
|
adwInfo[0] = 2;
|
|
|
|
pStreamControl = GetStreamControl();
|
|
|
|
if ( NULL == pStreamControl )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
m_pAddress->ReceiveTSPData(
|
|
pStreamControl,
|
|
(LPBYTE)adwInfo,
|
|
sizeof(adwInfo)
|
|
);
|
|
|
|
pStreamControl->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::SuspendWaveMSPStream
|
|
//
|
|
// called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CCall::SuspendWaveMSPStream()
|
|
{
|
|
DWORD adwInfo[3];
|
|
ITStreamControl * pStreamControl;
|
|
|
|
adwInfo[0] = 5;
|
|
|
|
pStreamControl = GetStreamControl();
|
|
|
|
if ( NULL == pStreamControl )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
m_pAddress->ReceiveTSPData(
|
|
pStreamControl,
|
|
(LPBYTE)adwInfo,
|
|
sizeof(adwInfo)
|
|
);
|
|
|
|
pStreamControl->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::ResumeWaveMSPStream
|
|
//
|
|
// called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CCall::ResumeWaveMSPStream()
|
|
{
|
|
DWORD adwInfo[3];
|
|
ITStreamControl * pStreamControl;
|
|
|
|
adwInfo[0] = 6;
|
|
|
|
pStreamControl = GetStreamControl();
|
|
|
|
if ( NULL == pStreamControl )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
m_pAddress->ReceiveTSPData(
|
|
pStreamControl,
|
|
(LPBYTE)adwInfo,
|
|
sizeof(adwInfo)
|
|
);
|
|
|
|
pStreamControl->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
#ifdef USE_PHONEMSP
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::StartPhoneMSPStream
|
|
//
|
|
// called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CCall::StartPhoneMSPStream()
|
|
{
|
|
ITStreamControl * pStreamControl;
|
|
DWORD dwControl = 0;
|
|
|
|
|
|
pStreamControl = GetStreamControl();
|
|
|
|
if ( NULL == pStreamControl )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
m_pAddress->ReceiveTSPData(
|
|
pStreamControl,
|
|
(LPBYTE)&dwControl,
|
|
sizeof(DWORD)
|
|
);
|
|
|
|
pStreamControl->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::StopPhoneMSPStream
|
|
//
|
|
// called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CCall::StopPhoneMSPStream()
|
|
{
|
|
ITStreamControl * pStreamControl;
|
|
DWORD dwControl = 1;
|
|
|
|
|
|
pStreamControl = GetStreamControl();
|
|
|
|
if ( NULL == pStreamControl )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
m_pAddress->ReceiveTSPData(
|
|
pStreamControl,
|
|
(LPBYTE)&dwControl,
|
|
sizeof(DWORD)
|
|
);
|
|
|
|
pStreamControl->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
#endif USE_PHONEMSP
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// OnConnect
|
|
//
|
|
// called when the call transitions to the connected state
|
|
//
|
|
// called in lock
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::OnConnect()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// set connected event if it exists
|
|
//
|
|
if ( NULL != m_hConnectedEvent )
|
|
{
|
|
SetEvent( m_hConnectedEvent );
|
|
}
|
|
|
|
//
|
|
// special cases
|
|
//
|
|
if (OnWaveMSPCall())
|
|
{
|
|
StartWaveMSPStream();
|
|
}
|
|
#ifdef USE_PHONEMSP
|
|
else if ( OnPhoneMSPCall() )
|
|
{
|
|
StartPhoneMSPStream();
|
|
}
|
|
#endif USE_PHONEMSP
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCall
|
|
// Method : CreateConference
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::CreateConference(
|
|
CCall * pConsultationCall,
|
|
VARIANT_BOOL bSync
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HCALL hConfCall;
|
|
HCALL hConsultCall;
|
|
DWORD dwCallFeatures;
|
|
CALL_STATE consultationCallState = CS_IDLE;
|
|
|
|
LOG((TL_TRACE, "CreateConference - enter"));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// we must have a hub
|
|
//
|
|
|
|
if (m_pCallHub == NULL)
|
|
{
|
|
|
|
//
|
|
// if this is happening, we have a bug. debug.
|
|
//
|
|
|
|
LOG((TL_ERROR, "CreateConference - no call hub. returning E_UNEXPECTED"));
|
|
|
|
_ASSERTE(FALSE);
|
|
|
|
Unlock();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// Get Call Status to determine what features we can use
|
|
//
|
|
LPLINECALLSTATUS pCallStatus = NULL;
|
|
|
|
hr = LineGetCallStatus( m_t3Call.hCall, &pCallStatus );
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_ERROR, "CreateConference - LineGetCallStatus failed %lx", hr));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
dwCallFeatures = pCallStatus->dwCallFeatures;
|
|
|
|
ClientFree( pCallStatus );
|
|
|
|
#if CHECKCALLSTATUS
|
|
|
|
//
|
|
// Do we support the required call features ?
|
|
//
|
|
if ( !( (dwCallFeatures & LINECALLFEATURE_SETUPCONF) &&
|
|
(dwCallFeatures & LINECALLFEATURE_ADDTOCONF) ) )
|
|
{
|
|
LOG((TL_ERROR, "CreateConference - LineGetCallStatus reports Conference not supported"));
|
|
|
|
Unlock();
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// we support it, so try the Conference
|
|
// Setup & dial the consultation Call
|
|
//
|
|
LOG((TL_INFO, "CreateConference - Trying to setupConference" ));
|
|
|
|
pConsultationCall->Lock();
|
|
|
|
pConsultationCall->FinishCallParams();
|
|
|
|
hr = LineSetupConference(
|
|
m_t3Call.hCall,
|
|
&(m_pAddressLine->t3Line),
|
|
&hConfCall,
|
|
&hConsultCall,
|
|
3,
|
|
m_pCallParams
|
|
);
|
|
|
|
Unlock();
|
|
|
|
pConsultationCall->Unlock();
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
//
|
|
// wait for async reply
|
|
//
|
|
hr = WaitForReply( hr );
|
|
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_INFO, "CreateConference - LineSetupConference failed - %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
LOG((TL_INFO, "CreateConference - LineSetupConference completed OK"));
|
|
|
|
//Check if the call is in connected state.
|
|
pConsultationCall->Lock();
|
|
|
|
pConsultationCall->get_CallState(&consultationCallState);
|
|
|
|
if ( (consultationCallState == CS_CONNECTED) || (consultationCallState == CS_HOLD) )
|
|
{
|
|
//
|
|
// the existing call is in a connected stae so we just need to deallocate
|
|
// hConsultcall and do a finish() to call down to LineAddToConference()
|
|
//
|
|
if ( NULL != hConsultCall )
|
|
{
|
|
HRESULT hr2;
|
|
|
|
hr2 = LineDrop( hConsultCall, NULL, 0 );
|
|
|
|
if ( ((long)hr2) > 0 )
|
|
{
|
|
hr2 = WaitForReply( hr2 ) ;
|
|
}
|
|
|
|
hr = LineDeallocateCall( hConsultCall );
|
|
hConsultCall = NULL;
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_INFO, "CreateConference - lineDeallocateCall failed - %lx", hr));
|
|
}
|
|
else
|
|
{
|
|
pConsultationCall->SetRelatedCall(
|
|
this,
|
|
CALLFLAG_CONFCONSULT|CALLFLAG_CONSULTCALL
|
|
);
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
pConsultationCall->Unlock();
|
|
|
|
Lock();
|
|
//
|
|
// Store the confcontroller in the callhub object
|
|
//
|
|
if (m_pCallHub != NULL)
|
|
{
|
|
m_pCallHub->CreateConferenceControllerCall(
|
|
hConfCall,
|
|
m_pAddress
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we made sure we had the hub when we entered the function
|
|
//
|
|
|
|
LOG((TL_INFO, "CreateConference - No CallHub"));
|
|
_ASSERTE(FALSE);
|
|
}
|
|
|
|
Unlock();
|
|
|
|
}
|
|
else
|
|
{
|
|
pConsultationCall->FinishSettingUpCall( hConsultCall );
|
|
|
|
pConsultationCall->Unlock();
|
|
|
|
Lock();
|
|
//
|
|
// Store the confcontroller in the callhub object
|
|
//
|
|
if (m_pCallHub != NULL)
|
|
{
|
|
m_pCallHub->CreateConferenceControllerCall(
|
|
hConfCall,
|
|
m_pAddress
|
|
);
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "CreateConference - No CallHub"));
|
|
_ASSERTE(FALSE);
|
|
}
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// now do the consulation call
|
|
//
|
|
hr = pConsultationCall->DialAsConsultationCall( this, dwCallFeatures, TRUE, bSync );
|
|
|
|
}
|
|
|
|
LOG((TL_TRACE, hr, "CreateConference - exit"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCall
|
|
// Method : AddToConference
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::AddToConference(
|
|
CCall * pConsultationCall,
|
|
VARIANT_BOOL bSync
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CCall * pConfContCall = NULL;
|
|
HCALL hConfContCall = NULL;
|
|
HCALL hConsultCall = NULL;
|
|
CALL_STATE consultationCallState = CS_IDLE;
|
|
DWORD dwCallFeatures;
|
|
|
|
LOG((TL_TRACE, "AddToConference - enter"));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// we must have a hub
|
|
//
|
|
|
|
if (m_pCallHub == NULL)
|
|
{
|
|
|
|
//
|
|
// if this is happening, we have a bug. debug.
|
|
//
|
|
|
|
LOG((TL_ERROR,
|
|
"AddToConference - no call hub. returning E_UNEXPECTED"));
|
|
|
|
_ASSERTE(FALSE);
|
|
|
|
Unlock();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
{
|
|
//
|
|
// NikhilB: Call object has a reference to Callhub object so its safe to
|
|
// lock the callhub object before locking the call. This is to avoid a
|
|
// deadlock that happens dur to locking the call and the callhub in reverse
|
|
// orders in different functions.
|
|
//
|
|
|
|
m_pCallHub->AddRef();
|
|
AddRef();
|
|
|
|
Unlock();
|
|
|
|
// lock the callhub object before locking the call
|
|
m_pCallHub->Lock();
|
|
Lock();
|
|
|
|
Release();
|
|
m_pCallHub->Release();
|
|
}
|
|
|
|
//
|
|
// we must have conference controller
|
|
//
|
|
|
|
pConfContCall = m_pCallHub->GetConferenceControllerCall();
|
|
m_pCallHub->Unlock();
|
|
|
|
if (NULL == pConfContCall)
|
|
{
|
|
|
|
//
|
|
// if we get here, we have a bug. debug.
|
|
//
|
|
|
|
LOG((TL_ERROR,
|
|
"AddToConference - the callhub does not have a conference controller. E_UNEXPECTED"));
|
|
|
|
_ASSERTE(FALSE);
|
|
|
|
Unlock();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
//
|
|
// ask conference call controller for a conference call handle
|
|
//
|
|
|
|
hConfContCall = pConfContCall->GetHCall();
|
|
|
|
if (NULL == hConfContCall)
|
|
{
|
|
LOG((TL_ERROR,
|
|
"AddToConference - conf controller does not have a valid conf call handle. E_UNEXPECTED"));
|
|
|
|
_ASSERTE(FALSE);
|
|
|
|
Unlock();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// Get Call Status to determine what features we can use
|
|
//
|
|
LPLINECALLSTATUS pCallStatus = NULL;
|
|
|
|
hr = LineGetCallStatus( m_t3Call.hCall, &pCallStatus );
|
|
|
|
if ( !SUCCEEDED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "AddToConference - LineGetCallStatus failed %lx", hr));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
dwCallFeatures = pCallStatus->dwCallFeatures;
|
|
|
|
ClientFree( pCallStatus );
|
|
|
|
#if CHECKCALLSTATUS
|
|
|
|
//
|
|
// Do we support the required call features ?
|
|
//
|
|
if ( !( ( dwCallFeatures & LINECALLFEATURE_PREPAREADDCONF ) &&
|
|
( dwCallFeatures & LINECALLFEATURE_ADDTOCONF ) ) )
|
|
{
|
|
LOG((TL_ERROR, "AddToConference - LineGetCallStatus reports Conference not supported"));
|
|
|
|
Unlock();
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// we support it, so try the Conference
|
|
//
|
|
pConsultationCall->get_CallState(&consultationCallState);
|
|
|
|
if ( (consultationCallState == CS_CONNECTED) || (consultationCallState == CS_HOLD) )
|
|
{
|
|
//
|
|
// the existing call is in a connected stae so we just need to to do a finish()
|
|
// to call down to LineAddToConference()
|
|
//
|
|
pConsultationCall->SetRelatedCall(
|
|
this,
|
|
CALLFLAG_CONFCONSULT|CALLFLAG_CONSULTCALL
|
|
);
|
|
|
|
Unlock();
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// We need to Setup & dial the consultation Call
|
|
//
|
|
//Lock();
|
|
|
|
pConsultationCall->Lock();
|
|
|
|
pConsultationCall->FinishCallParams();
|
|
|
|
|
|
hr = LinePrepareAddToConference(
|
|
hConfContCall,
|
|
&hConsultCall,
|
|
m_pCallParams
|
|
);
|
|
|
|
pConsultationCall->Unlock();
|
|
|
|
Unlock();
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
//
|
|
// wait for async reply
|
|
//
|
|
hr = WaitForReply( hr );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
LONG lCap;
|
|
|
|
LOG((TL_INFO, "AddToConference - LinePrepareAddToConference completed OK"));
|
|
//
|
|
// Update handles in consult call object & insert it in the hash table
|
|
// note - we can miss messages if something comes in between the time time
|
|
// we get the reply, and the time we insert the call
|
|
//
|
|
pConsultationCall->Lock();
|
|
|
|
pConsultationCall->FinishSettingUpCall( hConsultCall );
|
|
|
|
pConsultationCall->Unlock();
|
|
|
|
//
|
|
// now do the consulation call
|
|
//
|
|
hr = pConsultationCall->DialAsConsultationCall( this, dwCallFeatures, TRUE, bSync );
|
|
}
|
|
else // AddToConference async reply failed
|
|
{
|
|
LOG((TL_ERROR, "AddToConference - LinePrepareAddToConference failed async" ));
|
|
}
|
|
}
|
|
else // AddToConference failed
|
|
{
|
|
LOG((TL_ERROR, "AddToConference - LinePrepareAddToConference failed" ));
|
|
}
|
|
|
|
|
|
LOG((TL_TRACE, hr, "AddToConference - exit"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCall
|
|
// Method : WaitForCallState
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CCall::WaitForCallState( CALL_STATE requiredCS )
|
|
{
|
|
DWORD gdwWaitIntervals = 0;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
LOG((TL_TRACE, "WaitForCallState - enter"));
|
|
|
|
while (
|
|
( requiredCS != m_CallState ) &&
|
|
( CS_DISCONNECTED != m_CallState ) &&
|
|
( gdwWaitIntervals < gdwWaitForConnectWaitIntervals )
|
|
)
|
|
{
|
|
LOG((TL_INFO, "WaitForCallState - Waiting for state %d", requiredCS));
|
|
LOG((TL_INFO, " state is currently %d for call %p", m_CallState, this));
|
|
Sleep( gdwWaitForConnectSleepTime );
|
|
gdwWaitIntervals++;
|
|
}
|
|
|
|
if (m_CallState == requiredCS)
|
|
{
|
|
LOG((TL_INFO, "WaitForCallState - Reached required state"));
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "WaitForCallState - Did not reach required state"));
|
|
}
|
|
|
|
LOG((TL_TRACE, hr, "WaitForCallState - exit"));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCall
|
|
// Method : OneStepTransfer
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::OneStepTransfer(
|
|
CCall * pConsultationCall,
|
|
VARIANT_BOOL bSync
|
|
)
|
|
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPLINECALLPARAMS pCallParams;
|
|
DWORD dwDestAddrSize;
|
|
HCALL hCall;
|
|
HANDLE hEvent;
|
|
|
|
|
|
|
|
LOG((TL_TRACE, "OneStepTransfer - enter"));
|
|
|
|
//
|
|
// Setup call params structure for a one step transfer Consultation call
|
|
//
|
|
pConsultationCall->Lock();
|
|
|
|
dwDestAddrSize = (lstrlenW(pConsultationCall->m_szDestAddress) * sizeof(WCHAR)) + sizeof(WCHAR);
|
|
|
|
Lock();
|
|
|
|
hr = ResizeCallParams(dwDestAddrSize);
|
|
|
|
if( !SUCCEEDED(hr) )
|
|
{
|
|
pConsultationCall->Unlock();
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_ERROR, "OneStepTransfer - resizecallparams failed %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Copy the string & set the size, offset etc
|
|
//
|
|
lstrcpyW((PWSTR)(((PBYTE)m_pCallParams) + m_dwCallParamsUsedSize),
|
|
pConsultationCall->m_szDestAddress);
|
|
|
|
if ( m_pAddress->GetAPIVersion() >= TAPI_VERSION2_0 )
|
|
{
|
|
m_pCallParams->dwTargetAddressSize = dwDestAddrSize;
|
|
m_pCallParams->dwTargetAddressOffset = m_dwCallParamsUsedSize;
|
|
}
|
|
|
|
m_dwCallParamsUsedSize += dwDestAddrSize;
|
|
|
|
//
|
|
// Set the one step bit flag
|
|
//
|
|
m_pCallParams->dwCallParamFlags |= LINECALLPARAMFLAGS_ONESTEPTRANSFER ;
|
|
|
|
|
|
FinishCallParams();
|
|
|
|
//
|
|
// Do the transfer
|
|
//
|
|
hr = LineSetupTransfer(
|
|
m_t3Call.hCall,
|
|
&hCall,
|
|
m_pCallParams
|
|
);
|
|
|
|
Unlock();
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hEvent = pConsultationCall->CreateConnectedEvent();
|
|
|
|
pConsultationCall->Unlock();
|
|
|
|
//
|
|
// wait for async reply
|
|
//
|
|
hr = WaitForReply( hr );
|
|
|
|
pConsultationCall->Lock();
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
ClearConnectedEvent();
|
|
|
|
pConsultationCall->Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
LOG((TL_INFO, "OneStepTransfer - LineSetupTransfer completed OK"));
|
|
|
|
pConsultationCall->FinishSettingUpCall( hCall );
|
|
|
|
pConsultationCall->SetRelatedCall(
|
|
this,
|
|
CALLFLAG_TRANSFCONSULT|CALLFLAG_CONSULTCALL
|
|
);
|
|
|
|
pConsultationCall->Unlock();
|
|
|
|
if(bSync)
|
|
{
|
|
//
|
|
// Wait for connect on on our consultation call
|
|
//
|
|
hr = pConsultationCall->SyncWait( hEvent );
|
|
|
|
if( S_OK == hr )
|
|
{
|
|
LOG((TL_INFO, "OneStepTransfer - Consultation call connected" ));
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "OneStepTransfer - Consultation call failed to connect" ));
|
|
|
|
hr = TAPI_E_OPERATIONFAILED;
|
|
}
|
|
}
|
|
|
|
LOG((TL_TRACE, hr, "OneStepTransfer - exit"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// UpdateStateAndPrivilege
|
|
//
|
|
// update the call state and privilege of this call
|
|
// this method is used when a call shows up in Unpark or Pickup
|
|
// and needs to have the correct state and priv
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::UpdateStateAndPrivilege()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LINECALLSTATUS * pCallStatus;
|
|
HCALL hCall;
|
|
|
|
|
|
Lock();
|
|
|
|
hCall = m_t3Call.hCall;
|
|
|
|
hr = LineGetCallStatus(
|
|
hCall,
|
|
&pCallStatus
|
|
);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
CALL_STATE cs;
|
|
CALL_STATE_EVENT_CAUSE csc;
|
|
CALL_PRIVILEGE cp;
|
|
|
|
hr = ProcessNewCallState(
|
|
pCallStatus->dwCallState,
|
|
0,
|
|
m_CallState,
|
|
&cs,
|
|
&csc
|
|
);
|
|
|
|
SetCallState( cs );
|
|
|
|
hr = ProcessNewCallPrivilege(
|
|
pCallStatus->dwCallPrivilege,
|
|
&cp
|
|
);
|
|
|
|
m_CallPrivilege = cp;
|
|
|
|
ClientFree(pCallStatus);
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// ProcessNewCallState
|
|
// given a call state message (dwCallState, dwDetail, dwPriv)
|
|
// create a new tapi 3.0 callstate
|
|
//
|
|
// return S_OK if a new call state was created
|
|
// return S_FALSE if the message can be ignored (duplicate
|
|
// return E_? if bad error
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::ProcessNewCallState(
|
|
DWORD dwCallState,
|
|
DWORD dwDetail,
|
|
CALL_STATE CurrentCallState,
|
|
CALL_STATE * pCallState,
|
|
CALL_STATE_EVENT_CAUSE * pCallStateCause
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CALL_STATE NewCallState = CurrentCallState;
|
|
|
|
LOG((TL_INFO, "ProcessNewCallState"));
|
|
LOG((TL_INFO, " dwCallState----->%lx", dwCallState));
|
|
LOG((TL_INFO, " dwDetail-------->%lx", dwDetail));
|
|
LOG((TL_INFO, " pCallState------>%p", pCallState));
|
|
LOG((TL_INFO, " pCallStateCause->%p", pCallStateCause));
|
|
|
|
*pCallStateCause = CEC_NONE;
|
|
|
|
|
|
switch (dwCallState)
|
|
{
|
|
case LINECALLSTATE_BUSY:
|
|
dwDetail = LINEDISCONNECTMODE_BUSY;
|
|
// fall through
|
|
case LINECALLSTATE_DISCONNECTED:
|
|
case LINECALLSTATE_IDLE:
|
|
{
|
|
|
|
NewCallState = CS_DISCONNECTED;
|
|
|
|
switch (dwDetail)
|
|
{
|
|
case LINEDISCONNECTMODE_REJECT:
|
|
*pCallStateCause = CEC_DISCONNECT_REJECTED;
|
|
break;
|
|
case LINEDISCONNECTMODE_BUSY:
|
|
*pCallStateCause = CEC_DISCONNECT_BUSY;
|
|
break;
|
|
case LINEDISCONNECTMODE_NOANSWER:
|
|
*pCallStateCause = CEC_DISCONNECT_NOANSWER;
|
|
break;
|
|
case LINEDISCONNECTMODE_BLOCKED:
|
|
*pCallStateCause = CEC_DISCONNECT_BLOCKED;
|
|
break;
|
|
case LINEDISCONNECTMODE_CONGESTION:
|
|
case LINEDISCONNECTMODE_INCOMPATIBLE:
|
|
case LINEDISCONNECTMODE_NODIALTONE:
|
|
case LINEDISCONNECTMODE_UNAVAIL:
|
|
case LINEDISCONNECTMODE_NUMBERCHANGED:
|
|
case LINEDISCONNECTMODE_OUTOFORDER:
|
|
case LINEDISCONNECTMODE_TEMPFAILURE:
|
|
case LINEDISCONNECTMODE_QOSUNAVAIL:
|
|
case LINEDISCONNECTMODE_DONOTDISTURB:
|
|
case LINEDISCONNECTMODE_CANCELLED:
|
|
*pCallStateCause = CEC_DISCONNECT_FAILED;
|
|
break;
|
|
case LINEDISCONNECTMODE_UNREACHABLE:
|
|
case LINEDISCONNECTMODE_BADADDRESS:
|
|
*pCallStateCause = CEC_DISCONNECT_BADADDRESS;
|
|
break;
|
|
case LINEDISCONNECTMODE_PICKUP:
|
|
case LINEDISCONNECTMODE_FORWARDED:
|
|
case LINEDISCONNECTMODE_NORMAL:
|
|
case LINEDISCONNECTMODE_UNKNOWN:
|
|
default:
|
|
*pCallStateCause = CEC_DISCONNECT_NORMAL;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LINECALLSTATE_OFFERING:
|
|
{
|
|
switch (CurrentCallState)
|
|
{
|
|
case CS_IDLE:
|
|
|
|
if ( ! ( CALLFLAG_ACCEPTTOALERT & m_dwCallFlags ) )
|
|
{
|
|
NewCallState = CS_OFFERING;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "ProcessNewCallState - ignoring LINECALLSTATE_OFFERING message as this is ISDN & needs a lineAccept"));
|
|
hr = S_FALSE;
|
|
}
|
|
break;
|
|
default:
|
|
LOG((TL_ERROR, "ProcessNewCallState - trying to go to OFFERING from bad state"));
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
case LINECALLSTATE_ACCEPTED:
|
|
{
|
|
switch (CurrentCallState)
|
|
{
|
|
case CS_IDLE:
|
|
|
|
if ( CALLFLAG_ACCEPTTOALERT & m_dwCallFlags )
|
|
{
|
|
NewCallState = CS_OFFERING;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "ProcessNewCallState - ignoring LINECALLSTATE_ACCEPTED message "));
|
|
hr = S_FALSE;
|
|
}
|
|
break;
|
|
default:
|
|
LOG((TL_ERROR, "ProcessNewCallState - trying to go to OFFERING from bad state"));
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case LINECALLSTATE_PROCEEDING:
|
|
case LINECALLSTATE_RINGBACK:
|
|
case LINECALLSTATE_DIALING:
|
|
case LINECALLSTATE_DIALTONE:
|
|
{
|
|
switch(CurrentCallState)
|
|
{
|
|
case CS_IDLE:
|
|
NewCallState = CS_INPROGRESS;
|
|
break;
|
|
case CS_INPROGRESS:
|
|
break;
|
|
default:
|
|
LOG((TL_ERROR, "ProcessNewCallState - trying to go to INPROGRESS from bad state"));
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case LINECALLSTATE_CONFERENCED:
|
|
case LINECALLSTATE_CONNECTED:
|
|
{
|
|
if ( CurrentCallState == CS_DISCONNECTED )
|
|
{
|
|
LOG((TL_ERROR, "ProcessNewCallState - invalid state going to CONNECTED"));
|
|
hr = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
NewCallState = CS_CONNECTED;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case LINECALLSTATE_ONHOLDPENDCONF:
|
|
case LINECALLSTATE_ONHOLD:
|
|
case LINECALLSTATE_ONHOLDPENDTRANSFER:
|
|
{
|
|
switch(CurrentCallState)
|
|
{
|
|
case CS_HOLD:
|
|
break;
|
|
default:
|
|
NewCallState = CS_HOLD;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case LINECALLSTATE_SPECIALINFO:
|
|
{
|
|
LOG((TL_INFO, "ProcessNewCallState - ignoring message"));
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
case LINECALLSTATE_UNKNOWN:
|
|
{
|
|
LOG((TL_INFO, "ProcessNewCallState - LINECALLSTATE_UNKNOWN, so ignoring message"));
|
|
//return a failure as we don't want to processs this further
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
|
|
default:
|
|
break;
|
|
|
|
} // End switch(dwCallState)
|
|
|
|
|
|
|
|
if (NewCallState == CurrentCallState)
|
|
{
|
|
#if DBG
|
|
LOG((TL_INFO, "ProcessNewCallState - No State Change - still in %s",
|
|
callStateName(NewCallState) ));
|
|
#endif
|
|
hr = S_FALSE;
|
|
}
|
|
else // Valid change so update & return S_OK
|
|
{
|
|
#if DBG
|
|
LOG((TL_INFO, "ProcessNewCallState - State Transition %s -> %s",
|
|
callStateName(CurrentCallState),
|
|
callStateName(NewCallState) ));
|
|
#endif
|
|
*pCallState = NewCallState;
|
|
hr = S_OK;
|
|
}
|
|
|
|
|
|
LOG((TL_TRACE, "ProcessNewCallState - exit"));
|
|
LOG((TL_INFO, " *pCallState------->%lx", *pCallState));
|
|
LOG((TL_INFO, " *pCallStateCause-->%lx", *pCallStateCause));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// GetOtherParty()
|
|
//
|
|
// Used to find the other party in a call ie,
|
|
// ___
|
|
// / \
|
|
// [A1]--hCall1--(this)--| CH1 |--(OtherCall)--hCall3--[A2]
|
|
// \___/
|
|
//
|
|
// AddRefs returned call
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
CCall* CCall::GetOtherParty()
|
|
{
|
|
LINECALLLIST * pCallHubList = NULL;
|
|
HCALL * phCalls;
|
|
HRESULT hr;
|
|
CCall * pCall = NULL;
|
|
|
|
//
|
|
// get the list of hcalls
|
|
// related to this call
|
|
//
|
|
hr = LineGetHubRelatedCalls(
|
|
0,
|
|
m_t3Call.hCall,
|
|
&pCallHubList
|
|
);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if (pCallHubList->dwCallsNumEntries >= 3)
|
|
{
|
|
//
|
|
// get to the list of calls
|
|
//
|
|
phCalls = (HCALL *)(((LPBYTE)pCallHubList) + pCallHubList->dwCallsOffset);
|
|
|
|
//
|
|
// the first call is the callhub, we want the third
|
|
//
|
|
FindCallObject(phCalls[2], &pCall);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (pCallHubList)
|
|
{
|
|
ClientFree( pCallHubList );
|
|
}
|
|
|
|
return pCall;
|
|
}
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// FindConferenceControllerCall()
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
CCall * CCall::FindConferenceControllerCall()
|
|
{
|
|
LINECALLLIST * pCallList;
|
|
HCALL * phCalls;
|
|
CCall * pCall = NULL;
|
|
HRESULT hr;
|
|
|
|
|
|
hr = LineGetConfRelatedCalls(
|
|
m_t3Call.hCall,
|
|
&pCallList
|
|
);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
//
|
|
// get to the list of calls
|
|
//
|
|
phCalls = (HCALL *)(((LPBYTE)pCallList) + pCallList->dwCallsOffset);
|
|
|
|
//
|
|
// The first call is the conf controller
|
|
// get its tapi3 call object
|
|
//
|
|
if (FindCallObject(phCalls[0], &pCall))
|
|
{
|
|
LOG((TL_INFO, "FindConferenceControllerCall - controller is %p "
|
|
,pCall));
|
|
}
|
|
else
|
|
{
|
|
pCall = NULL;
|
|
LOG((TL_INFO, "FindConferenceControllerCall - call handle %lx "
|
|
"does not currently exist", phCalls[0]));
|
|
}
|
|
|
|
if(pCallList)
|
|
{
|
|
ClientFree( pCallList );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "FindExistingCalls - LineGetConfRelatedCalls failed "));
|
|
}
|
|
|
|
return pCall;
|
|
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// AddCallToHashTable()
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
void CCall::AddCallToHashTable()
|
|
{
|
|
//
|
|
// put in global hash table
|
|
//
|
|
CTAPI *pTapi = m_pAddress->GetTapi();
|
|
|
|
if ( NULL != m_t3Call.hCall )
|
|
{
|
|
gpCallHashTable->Lock();
|
|
|
|
gpCallHashTable->Insert( (ULONG_PTR)(m_t3Call.hCall), (ULONG_PTR)this, pTapi );
|
|
|
|
gpCallHashTable->Unlock();
|
|
}
|
|
|
|
//
|
|
// Signal the asyncEventThread to wake up & process the retry queue
|
|
// since events may have come in for this call before it
|
|
// was in the hash table
|
|
//
|
|
SetEvent(ghAsyncRetryQueueEvent);
|
|
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// OnConference()
|
|
//
|
|
// called in lock()
|
|
//
|
|
// called when call goes into conferenced state.
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::OnConference()
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
CCall * pCall = NULL;
|
|
CCall * pConfControllerCall = NULL;
|
|
CCall * pCallOtherParty = NULL;
|
|
CCallHub * pConferenceCallHub = NULL;
|
|
|
|
pConfControllerCall = FindConferenceControllerCall();
|
|
|
|
if (pConfControllerCall != NULL)
|
|
{
|
|
pConferenceCallHub = pConfControllerCall->GetCallHub();
|
|
|
|
//
|
|
// try & find this call in the callhub
|
|
//
|
|
if (pConferenceCallHub != NULL)
|
|
{
|
|
pCall = pConferenceCallHub->FindCallByHandle(m_t3Call.hCall);
|
|
|
|
if (pCall == NULL)
|
|
{
|
|
// Not in the same hub so this is the consultation call being added in
|
|
// see if there's a call object for the other party
|
|
//
|
|
// (ConfControllerCall)___
|
|
// \_________________
|
|
// / \
|
|
// [A1]--hCall1--(RelatedCall)--| ConferenceCallHub |--
|
|
// | \_________________/
|
|
// |
|
|
// | ___
|
|
// | / \
|
|
// --hCall2--(this)--| CH1 |--(CallOtherParty)--hCall3--[A3]
|
|
// \___/
|
|
//
|
|
|
|
LOG((TL_INFO, "OnConference - This is the consult call being conferenced " ));
|
|
/*
|
|
if ( NULL != (pCallOtherParty = GetOtherParty()) )
|
|
{
|
|
//
|
|
// Yes there is, so we're going to take this call out of the hash table
|
|
// & give the other call our hCall Handle;
|
|
//
|
|
LOG((TL_INFO, "OnConference - We have the other party , so give him our hCall %x", m_t3Call.hCall));
|
|
|
|
RemoveCallFromHashTable();
|
|
|
|
// release the callhub
|
|
//
|
|
if (NULL != m_pCallHub)
|
|
{
|
|
m_pCallHub->RemoveCall( this );
|
|
|
|
// m_pCallHub->Release();
|
|
}
|
|
|
|
pCallOtherParty->Lock();
|
|
|
|
pCallOtherParty->m_hAdditionalCall = m_t3Call.hCall;
|
|
|
|
pCallOtherParty->Unlock();
|
|
|
|
m_t3Call.hCall = NULL;
|
|
|
|
hr = S_OK;
|
|
}
|
|
*/
|
|
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "OnConference - This is the initial call being conferenced " ));
|
|
pCall->Release(); // FindCallByHandle addRefs
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "OnConference - Couldn't find conference CallHub " ));
|
|
}
|
|
|
|
pConfControllerCall->Release(); // FindConferenceControllerCall addrefs
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "OnConference - Couldn't find conference controller " ));
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// ProcessNewCallPrivilege
|
|
//
|
|
// converts a tapi2 callpriv to a tapi3 call priv.
|
|
//
|
|
// returns S_OK if there was a priv
|
|
// returns S_FALSE if priv was 0 (indicating there was no change)
|
|
// returns E_UNEXPECTED if the priv wasn't recognized
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
ProcessNewCallPrivilege(
|
|
DWORD dwPrivilege,
|
|
CALL_PRIVILEGE * pCP
|
|
)
|
|
{
|
|
if ( 0 == dwPrivilege )
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
if ( LINECALLPRIVILEGE_OWNER == dwPrivilege )
|
|
{
|
|
*pCP = CP_OWNER;
|
|
return S_OK;
|
|
}
|
|
|
|
if ( LINECALLPRIVILEGE_MONITOR == dwPrivilege )
|
|
{
|
|
*pCP = CP_MONITOR;
|
|
S_OK;
|
|
}
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// CallStateEvent
|
|
// process call state events, and queue an event to the app
|
|
// if necessary
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::CallStateEvent(
|
|
PASYNCEVENTMSG pParams
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrCallStateEvent;
|
|
HRESULT hrCallPrivilege;
|
|
BOOL bNeedToNotify;
|
|
CONNECTDATA cd;
|
|
AddressLineStruct * pLine;
|
|
|
|
|
|
CALL_STATE CallState;
|
|
CALL_STATE_EVENT_CAUSE CallStateCause;
|
|
CALL_PRIVILEGE newCP;
|
|
|
|
|
|
LOG((TL_INFO, "CallStateEvent - enter hCall %lx", m_t3Call.hCall));
|
|
|
|
//
|
|
// pParams->OpenContext is the 32-bit handle for AddressLineStruct
|
|
//
|
|
|
|
LOG((TL_INFO, "CallStateEvent: pParams->OpenContext %p", pParams->OpenContext ));
|
|
|
|
|
|
//
|
|
// recover the ptr value of AddressLineStruct from the 32-bit handle
|
|
//
|
|
|
|
pLine = GetAddRefAddressLine(pParams->OpenContext);
|
|
|
|
if ( NULL == pLine )
|
|
{
|
|
//
|
|
// pLine is NULL, the line must have already been closed before we got this event.
|
|
//
|
|
|
|
LOG((TL_WARN, "CallStateEvent - pLine is NULL"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
LOG((TL_INFO, "CallStateEvent: pLine %p", pLine));
|
|
|
|
Lock();
|
|
|
|
if ( NULL == m_pAddressLine )
|
|
{
|
|
m_pAddressLine = pLine;
|
|
m_dwCallFlags |= CALLFLAG_NOTMYLINE;
|
|
}
|
|
|
|
|
|
//
|
|
// keep callback instance for this line
|
|
//
|
|
|
|
long lCallbackInstance = pLine->lCallbackInstance;
|
|
|
|
|
|
|
|
//
|
|
// no longer need address line itself
|
|
//
|
|
|
|
|
|
// (this needs to be done outside call lock)
|
|
|
|
Unlock();
|
|
|
|
|
|
|
|
ReleaseAddressLine(pLine);
|
|
pLine = NULL;
|
|
|
|
|
|
|
|
Lock();
|
|
|
|
|
|
|
|
if (pParams->Param1 == LINECALLSTATE_OFFERING)
|
|
{
|
|
OnOffering();
|
|
}
|
|
else if (pParams->Param1 == LINECALLSTATE_CONFERENCED)
|
|
{
|
|
if( OnConference() == S_OK)
|
|
{
|
|
pParams->Param1 = LINECALLSTATE_IDLE;
|
|
pParams->Param2 = LINEDISCONNECTMODE_UNKNOWN;
|
|
}
|
|
|
|
}
|
|
else if (pParams->Param1 == LINECALLSTATE_ONHOLDPENDCONF)
|
|
{
|
|
//
|
|
// This is a cnf controller call so hide it
|
|
//
|
|
LOG((TL_INFO, "CallStateEvent - This is a conference controller call, so hide it"));
|
|
|
|
m_dwCallFlags |= CALLFLAG_DONTEXPOSE;
|
|
m_dwCallFlags &= ~CALLFLAG_NEEDTONOTIFY;
|
|
}
|
|
|
|
bNeedToNotify = m_dwCallFlags & CALLFLAG_NEEDTONOTIFY;
|
|
|
|
|
|
|
|
//
|
|
// verify and get the new state
|
|
//
|
|
hrCallStateEvent = ProcessNewCallState(
|
|
pParams->Param1,
|
|
pParams->Param2,
|
|
m_CallState,
|
|
&CallState,
|
|
&CallStateCause
|
|
);
|
|
|
|
|
|
hrCallPrivilege = ProcessNewCallPrivilege(
|
|
pParams->Param3,
|
|
&newCP
|
|
);
|
|
|
|
if ( S_OK == hrCallPrivilege )
|
|
{
|
|
if ( m_CallPrivilege != newCP )
|
|
{
|
|
if ( !bNeedToNotify )
|
|
{
|
|
//
|
|
// callpriv changed. send a new call notification event
|
|
//
|
|
|
|
m_CallPrivilege = newCP;
|
|
|
|
CAddress *pAddress = m_pAddress;
|
|
pAddress->AddRef();
|
|
|
|
Unlock();
|
|
|
|
|
|
|
|
CCallInfoChangeEvent::FireEvent(
|
|
this,
|
|
CIC_PRIVILEGE,
|
|
pAddress->GetTapi(),
|
|
lCallbackInstance
|
|
);
|
|
|
|
Lock();
|
|
|
|
pAddress->Release();
|
|
pAddress = NULL;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( FAILED(hrCallStateEvent) ||
|
|
FAILED(hrCallPrivilege) )
|
|
{
|
|
//
|
|
// bad failure
|
|
// We get here if we had LINECALLSTATE_UNKNOWN
|
|
//
|
|
Unlock();
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
//
|
|
// if it's s_ok, then the callstate
|
|
// changed, so do relevant stuff
|
|
//
|
|
else if (S_OK == hrCallStateEvent)
|
|
{
|
|
LOG((TL_ERROR, "CCall::Changing call state :%p", this ));
|
|
|
|
//
|
|
// save the callstate
|
|
//
|
|
SetCallState( CallState );
|
|
|
|
//
|
|
// do relevant processing on call
|
|
//
|
|
if (CS_CONNECTED == m_CallState)
|
|
{
|
|
OnConnect();
|
|
}
|
|
else if (CS_DISCONNECTED == m_CallState)
|
|
{
|
|
LOG((TL_ERROR, "CCall::Changing call state to disconnect:%p", this ));
|
|
|
|
|
|
Unlock();
|
|
|
|
|
|
//
|
|
// do not hold call's lock while calling disconnect , to prevent deadlocks with callhub
|
|
//
|
|
|
|
OnDisconnect();
|
|
|
|
Lock();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// if we are here, ProcessNewCallState returned
|
|
// S_FALSE, indicating we are already in the
|
|
// correct callstate
|
|
// if we don't need to notify the app of the call
|
|
// then we can return right here
|
|
//
|
|
if ( !bNeedToNotify )
|
|
{
|
|
LOG((TL_TRACE, "CallStateEvent - ProcessNewCallState returned %lx - ignoring message", hr ));
|
|
Unlock();
|
|
return S_OK;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// if this is a new call
|
|
// find out the mediamode
|
|
// and tell the app about the
|
|
// new call
|
|
//
|
|
if ( bNeedToNotify )
|
|
{
|
|
LPLINECALLINFO pCallInfo = NULL;
|
|
|
|
TryToFindACallHub();
|
|
|
|
hr = LineGetCallInfo(
|
|
m_t3Call.hCall,
|
|
&pCallInfo
|
|
);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
if (NULL != pCallInfo)
|
|
{
|
|
ClientFree( pCallInfo );
|
|
}
|
|
|
|
LOG((TL_ERROR, "CallStateEvent - LineGetCallInfo returned %lx", hr ));
|
|
LOG((TL_ERROR, "CallStateEvent - can't set new mediamode"));
|
|
//
|
|
// since we could not get media mode, keep media mode that we
|
|
// received on initalization
|
|
//
|
|
}
|
|
else
|
|
{
|
|
SetMediaMode( pCallInfo->dwMediaMode );
|
|
|
|
{
|
|
// get rid of unknown bit
|
|
SetMediaMode( m_dwMediaMode & ~LINEMEDIAMODE_UNKNOWN );
|
|
|
|
}
|
|
|
|
LOG((TL_INFO, "CallStateEvent - new call media modes is %lx", m_dwMediaMode ));
|
|
|
|
ClientFree(pCallInfo);
|
|
}
|
|
|
|
LOG((TL_INFO, "Notifying app of call" ));
|
|
|
|
//
|
|
// now, create and fire the callnotification event
|
|
//
|
|
|
|
CAddress *pAddress = m_pAddress;
|
|
pAddress->AddRef();
|
|
|
|
CALL_NOTIFICATION_EVENT Priveledge = (m_CallPrivilege == CP_OWNER) ? CNE_OWNER : CNE_MONITOR;
|
|
|
|
Unlock();
|
|
|
|
hr = CCallNotificationEvent::FireEvent(
|
|
(ITCallInfo *)this,
|
|
Priveledge,
|
|
pAddress->GetTapi(),
|
|
lCallbackInstance
|
|
);
|
|
|
|
Lock();
|
|
|
|
pAddress->Release();
|
|
pAddress = NULL;
|
|
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_ERROR, "CallNotificationEvent failed %lx", hr));
|
|
}
|
|
|
|
//
|
|
// if it was needtonotify, we had an extra ref
|
|
// count, so get rid of it now
|
|
//
|
|
Release();
|
|
|
|
//
|
|
// just notify of existence once
|
|
//
|
|
m_dwCallFlags = m_dwCallFlags & ~CALLFLAG_NEEDTONOTIFY;
|
|
}
|
|
|
|
if ( S_OK == hrCallStateEvent )
|
|
{
|
|
//
|
|
// create the call state event object
|
|
//
|
|
LOG((TL_INFO, "Firing CallStateEvent"));
|
|
|
|
|
|
CAddress *pAddress = m_pAddress;
|
|
pAddress->AddRef();
|
|
|
|
Unlock();
|
|
|
|
hr = CCallStateEvent::FireEvent(
|
|
(ITCallInfo *)this,
|
|
CallState,
|
|
CallStateCause,
|
|
pAddress->GetTapi(),
|
|
lCallbackInstance
|
|
);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_ERROR, "CallStateEvent - fire event failed %lx", hr));
|
|
}
|
|
|
|
//
|
|
// Go through the phones and call our event hooks
|
|
//
|
|
|
|
ITPhone * pPhone;
|
|
CPhone * pCPhone;
|
|
int iPhoneCount;
|
|
PhoneArray PhoneArray;
|
|
|
|
//
|
|
// Get a copy of the phone array from tapi. This copy will contain
|
|
// references to all the phone objects.
|
|
//
|
|
|
|
pAddress->GetTapi()->GetPhoneArray( &PhoneArray );
|
|
|
|
pAddress->Release();
|
|
pAddress = NULL;
|
|
|
|
|
|
//
|
|
// stay unlocked while we are messing with the phone objects, otherwise
|
|
// we risk deadlock if a phone object would try to access call methods.
|
|
//
|
|
|
|
for(iPhoneCount = 0; iPhoneCount < PhoneArray.GetSize(); iPhoneCount++)
|
|
{
|
|
pPhone = PhoneArray[iPhoneCount];
|
|
|
|
pCPhone = dynamic_cast<CPhone *>(pPhone);
|
|
|
|
pCPhone->Automation_CallState( (ITCallInfo *)this, CallState, CallStateCause );
|
|
}
|
|
|
|
//
|
|
// Release all the phone objects.
|
|
//
|
|
|
|
PhoneArray.Shutdown();
|
|
|
|
Lock();
|
|
}
|
|
|
|
LOG((TL_TRACE, "CallStateEvent - exit - return SUCCESS" ));
|
|
|
|
Unlock();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
AddressLineStruct *CCall::GetAddRefMyAddressLine()
|
|
{
|
|
|
|
LOG((TL_INFO, "GetAddRefMyAddressLine - enter."));
|
|
|
|
|
|
Lock();
|
|
|
|
|
|
//
|
|
// have address line?
|
|
//
|
|
|
|
if ( NULL == m_pAddressLine )
|
|
{
|
|
LOG((TL_WARN, "GetAddRefMyAddressLine - no address line"));
|
|
|
|
Unlock();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// get address
|
|
//
|
|
|
|
if (NULL == m_pAddress)
|
|
{
|
|
LOG((TL_ERROR, "GetAddRefMyAddressLine - no address"));
|
|
|
|
Unlock();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// get the address line
|
|
//
|
|
|
|
AddressLineStruct *pLine = m_pAddressLine;
|
|
|
|
|
|
//
|
|
// keep a reference to the address for after we unlock the call
|
|
//
|
|
|
|
CAddress *pAddress = m_pAddress;
|
|
pAddress->AddRef();
|
|
|
|
|
|
//
|
|
// unlock
|
|
//
|
|
|
|
Unlock();
|
|
|
|
|
|
//
|
|
// lock the address (so address line does not go away before we addref it)
|
|
//
|
|
|
|
pAddress->Lock();
|
|
|
|
|
|
//
|
|
// does our address manage this line? if so, get a refcount on that line.
|
|
//
|
|
|
|
if (!pAddress->IsValidAddressLine(pLine, TRUE))
|
|
{
|
|
LOG((TL_ERROR, "GetAddRefMyAddressLine - not one of the address' lines"));
|
|
|
|
|
|
//
|
|
// assume this line is plain bad. in which case there is no need to
|
|
// undo the addref (we cannot do it anyway, since we don't have the
|
|
// address which the line belongs to so we cannot maybeclosealine it.)
|
|
//
|
|
|
|
|
|
//
|
|
// unlock and release the address
|
|
//
|
|
|
|
pAddress->Unlock();
|
|
pAddress->Release();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// unlock the address
|
|
//
|
|
|
|
pAddress->Unlock();
|
|
|
|
|
|
//
|
|
// no need to keep the reference to the address anymore
|
|
//
|
|
|
|
pAddress->Release();
|
|
|
|
|
|
//
|
|
// all done. return pLine.
|
|
//
|
|
|
|
LOG((TL_INFO, "GetAddRefMyAddressLine - finish. pLine = %p", pLine));
|
|
|
|
return pLine;
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CCall::GetAddRefAddressLine()
|
|
//
|
|
// this function returns a pointer to an addreff'ed address line on success
|
|
// or NULL on failure
|
|
//
|
|
// this function should be called OUTSIDE call lock to prevent deadlocks
|
|
//
|
|
|
|
AddressLineStruct *CCall::GetAddRefAddressLine(DWORD dwAddressLineHandle)
|
|
{
|
|
|
|
LOG((TL_INFO, "GetAddRefAddressLine - enter. dwAddressLineHandle[0x%lx]",
|
|
dwAddressLineHandle));
|
|
|
|
|
|
Lock();
|
|
|
|
|
|
//
|
|
// get address
|
|
//
|
|
|
|
if (NULL == m_pAddress)
|
|
{
|
|
LOG((TL_ERROR, "GetAddRefAddressLine - no address"));
|
|
|
|
Unlock();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// keep a reference to the address for after we unlock the call
|
|
//
|
|
|
|
CAddress *pAddress = m_pAddress;
|
|
pAddress->AddRef();
|
|
|
|
|
|
//
|
|
// unlock
|
|
//
|
|
|
|
Unlock();
|
|
|
|
|
|
//
|
|
// lock the address (so address line does not go away before we addref it)
|
|
//
|
|
|
|
pAddress->Lock();
|
|
|
|
|
|
//
|
|
// get address line
|
|
//
|
|
|
|
AddressLineStruct *pLine =
|
|
(AddressLineStruct *)GetHandleTableEntry(dwAddressLineHandle);
|
|
|
|
|
|
//
|
|
// handle table entry exists?
|
|
//
|
|
|
|
if (NULL == pLine)
|
|
{
|
|
LOG((TL_ERROR, "GetAddRefAddressLine - no address line"));
|
|
|
|
|
|
//
|
|
// unlock and release the address
|
|
//
|
|
|
|
pAddress->Unlock();
|
|
pAddress->Release();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// does our address manage this line?
|
|
//
|
|
|
|
if (!pAddress->IsValidAddressLine(pLine, TRUE))
|
|
{
|
|
LOG((TL_ERROR, "GetAddRefAddressLine - not one of the address' lines"));
|
|
|
|
|
|
//
|
|
// so there is no confusion in the future, remove this so-called "line"
|
|
// from handle table
|
|
//
|
|
|
|
DeleteHandleTableEntry(dwAddressLineHandle);
|
|
|
|
|
|
//
|
|
// unlock and release the address
|
|
//
|
|
|
|
pAddress->Unlock();
|
|
pAddress->Release();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// unlock the address
|
|
//
|
|
|
|
pAddress->Unlock();
|
|
|
|
|
|
//
|
|
// no need to keep the reference to the address anymore
|
|
//
|
|
|
|
pAddress->Release();
|
|
|
|
|
|
//
|
|
// all done. return pLine.
|
|
//
|
|
|
|
LOG((TL_INFO, "GetAddRefAddressLine - finish. pLine = %p", pLine));
|
|
|
|
return pLine;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CCall::ReleaseAddressLine()
|
|
//
|
|
// this function takes a pointer to an line and attempts to free it if needed
|
|
//
|
|
// this function should be called OUTSIDE call lock to prevent deadlocks
|
|
//
|
|
|
|
HRESULT CCall::ReleaseAddressLine(AddressLineStruct *pLine)
|
|
{
|
|
|
|
LOG((TL_INFO, "ReleaseAddressLine - enter. pLine[%p]", pLine));
|
|
|
|
|
|
//
|
|
// lock
|
|
//
|
|
|
|
Lock();
|
|
|
|
|
|
//
|
|
// get address
|
|
//
|
|
|
|
if (NULL == m_pAddress)
|
|
{
|
|
LOG((TL_ERROR, "ReleaseAddressLine - no address"));
|
|
|
|
Unlock();
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
//
|
|
// keep a reference to the address for after we unlock the call
|
|
//
|
|
|
|
CAddress *pAddress = m_pAddress;
|
|
pAddress->AddRef();
|
|
|
|
|
|
//
|
|
// unlock
|
|
//
|
|
|
|
Unlock();
|
|
|
|
|
|
//
|
|
// close address line
|
|
//
|
|
|
|
AddressLineStruct *pAddressLine = pLine;
|
|
|
|
HRESULT hr = pAddress->MaybeCloseALine(&pAddressLine);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
|
|
LOG((TL_ERROR, "ReleaseAddressLine - MaybeCloseALine failed. hr = %lx", hr));
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// no need to keep the reference to the address anymore
|
|
//
|
|
|
|
pAddress->Release();
|
|
|
|
|
|
//
|
|
// all done.
|
|
//
|
|
|
|
LOG((TL_INFO, "ReleaseAddressLine - finish. hr = %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CCall::GetCallBackInstance
|
|
//
|
|
// return lCallbackInstance from the address line referred to by the handle
|
|
//
|
|
|
|
HRESULT
|
|
CCall::GetCallBackInstance(IN DWORD dwAddressLineHandle,
|
|
OUT long *plCallbackInstance)
|
|
{
|
|
|
|
LOG((TL_INFO, "GetCallBackInstance - enter. dwAddressLineHandle = 0x%lx",
|
|
dwAddressLineHandle));
|
|
|
|
|
|
//
|
|
// got a good pointer?
|
|
//
|
|
|
|
if (IsBadWritePtr(plCallbackInstance, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "GetCallBackInstance - bad pointer[%p]",
|
|
plCallbackInstance));
|
|
|
|
_ASSERTE(FALSE);
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
//
|
|
// get an address line from the handle
|
|
//
|
|
|
|
AddressLineStruct *pLine = GetAddRefAddressLine(dwAddressLineHandle);
|
|
|
|
if ( NULL == pLine )
|
|
{
|
|
//
|
|
// pLine is NULL, the line must have already been closed before we got this event.
|
|
//
|
|
|
|
LOG((TL_WARN, "HandleMonitorToneMessage - pLine is NULL"));
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
LOG((TL_INFO, "HandleMonitorToneMessage: pLine %p", pLine));
|
|
|
|
|
|
//
|
|
// try to get callbackinstance from pline
|
|
//
|
|
|
|
long lCBInstance = 0;
|
|
|
|
try
|
|
{
|
|
|
|
lCBInstance = pLine->lCallbackInstance;
|
|
}
|
|
catch(...)
|
|
{
|
|
|
|
LOG((TL_ERROR,
|
|
"HandleMonitorToneMessage - exception while accessing pLine[%p]",
|
|
pLine));
|
|
|
|
|
|
//
|
|
// pline memory got released somehow. this should not happen so debug to see why
|
|
//
|
|
|
|
_ASSERTE(FALSE);
|
|
}
|
|
|
|
|
|
//
|
|
// release address line
|
|
//
|
|
|
|
HRESULT hr = ReleaseAddressLine(pLine);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR,
|
|
"HandleMonitorToneMessage - ReleaseAddressLine failed. hr = %lx",
|
|
hr));
|
|
}
|
|
|
|
|
|
*plCallbackInstance = lCBInstance;
|
|
|
|
|
|
LOG((TL_INFO, "ReleaseAddressLine - finish. lCallbackInstance[0x%lx]", *plCallbackInstance));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// MediaModeEvent
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::MediaModeEvent(
|
|
PASYNCEVENTMSG pParams
|
|
)
|
|
{
|
|
LOG((TL_INFO, "MediaModeEvent - enter. pParams->OpenContext %lx", pParams->OpenContext ));
|
|
|
|
|
|
//
|
|
// pParams->OpenContext is the 32-bit handle for AddressLineStruct
|
|
//
|
|
|
|
|
|
//
|
|
// get the callback instance thatcorresponds to this address line structure
|
|
//
|
|
|
|
long lCallBackInstance = 0;
|
|
|
|
HRESULT hr = GetCallBackInstance(pParams->OpenContext, &lCallBackInstance);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
//
|
|
// failed to get callback instance
|
|
//
|
|
|
|
LOG((TL_WARN, "MediaModeEvent - GetCallBackInstance failed. hr = %lx", hr));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
Lock(); // using m_pAddress below -- therefore need to lock?
|
|
|
|
|
|
//
|
|
// fire the event
|
|
//
|
|
|
|
CCallInfoChangeEvent::FireEvent(
|
|
this,
|
|
CIC_MEDIATYPE,
|
|
m_pAddress->GetTapi(),
|
|
lCallBackInstance
|
|
);
|
|
|
|
Unlock();
|
|
|
|
|
|
LOG((TL_INFO, "MediaModeEvent - exit. hr = %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// CheckAndCreateFakeCallHub
|
|
//
|
|
// we need to create a fake callhub object if the address doesn't support
|
|
// call hubs.
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::CheckAndCreateFakeCallHub()
|
|
{
|
|
Lock();
|
|
|
|
if (NULL == m_pCallHub)
|
|
{
|
|
DWORD dwRet;
|
|
HRESULT hr;
|
|
|
|
//
|
|
// if it doesn't support callhubs, then
|
|
// create one
|
|
//
|
|
// if it does, then we should get notified from
|
|
// tapisrv, and the callhub will be filled in during
|
|
// the LINE_APPNEWCALLHUB handling
|
|
//
|
|
dwRet = m_pAddress->DoesThisAddressSupportCallHubs( this );
|
|
|
|
if ( CALLHUBSUPPORT_NONE == dwRet )
|
|
{
|
|
hr = CCallHub::CreateFakeCallHub(
|
|
m_pAddress->GetTapi(),
|
|
this,
|
|
&m_pCallHub
|
|
);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_ERROR, "CheckAndCreateFakeCallHub - "
|
|
"could not creat callhub %lx", hr));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Unlock();
|
|
|
|
return E_PENDING;
|
|
}
|
|
|
|
}
|
|
|
|
LOG((TL_ERROR, "CCall::m_pCallHub -created:%p:%p", this, m_pCallHub ));
|
|
|
|
Unlock();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// SetCallHub
|
|
//
|
|
// sets the callhub member
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
void
|
|
CCall::SetCallHub(
|
|
CCallHub * pCallHub
|
|
)
|
|
{
|
|
CCallHub* temp_pCallHub;
|
|
|
|
Lock();
|
|
|
|
LOG((TL_ERROR, "CCall::SetCallhub:%p:%p", this, pCallHub ));
|
|
|
|
// only process if they've changed 3/3/1999 - bug 300914
|
|
if (pCallHub != m_pCallHub)
|
|
{
|
|
//NikhilB: These cahnges are to solve a hang and an AV.
|
|
|
|
temp_pCallHub = m_pCallHub; //store the old value
|
|
m_pCallHub = pCallHub; //assign the new value
|
|
LOG((TL_ERROR, "CCall::m_pCallHub -set:%p:%p", this, m_pCallHub ));
|
|
|
|
if (temp_pCallHub != NULL) //release the old reference
|
|
{
|
|
LOG((TL_INFO, "SetCallHub - call %p changing hub from %p to %p"
|
|
, this, temp_pCallHub, pCallHub));
|
|
|
|
//NikhilB:remove this Call from previous CallHub's m_CallArray otherwise
|
|
//this call will be present in two call hubs.
|
|
temp_pCallHub->RemoveCall( this );
|
|
|
|
temp_pCallHub->Release(); // ZoltanS fix 11-12-98
|
|
}
|
|
|
|
//addref to the new reference
|
|
if ( NULL != pCallHub )
|
|
{
|
|
pCallHub->AddRef();
|
|
}
|
|
|
|
}
|
|
|
|
Unlock();
|
|
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// LINE_CALLSTATE handler
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT HandleCallStateMessage( PASYNCEVENTMSG pParams )
|
|
{
|
|
CCall * pCall;
|
|
BOOL bSuccess;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
bSuccess = FindCallObject(
|
|
(HCALL)(pParams->hDevice),
|
|
&pCall
|
|
);
|
|
|
|
if (bSuccess)
|
|
{
|
|
// fire the event
|
|
pCall->CallStateEvent(
|
|
pParams
|
|
);
|
|
|
|
// find call object addrefs the
|
|
// call, so release it
|
|
pCall->Release();
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "HandleCallStateMessage - failed to find Call Object %lx", pParams->hDevice));
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
HandleCallIDChange(
|
|
PASYNCEVENTMSG pParams,
|
|
CCall * pCall
|
|
)
|
|
{
|
|
LINECALLLIST * pCallHubList;
|
|
HCALL * phCalls;
|
|
HCALLHUB hNewCallHub = 0;
|
|
HCALLHUB hCurrentCallHub = 0;
|
|
CCallHub * pCallHub = NULL;
|
|
HRESULT hr;
|
|
|
|
//
|
|
// find the current callhub handle
|
|
//
|
|
pCallHub = pCall->GetCallHub();
|
|
|
|
if(pCallHub != NULL)
|
|
{
|
|
hCurrentCallHub = pCallHub->GetCallHub();
|
|
}
|
|
|
|
|
|
//
|
|
// Now get the callhub handle from TAPI (based on hCall)
|
|
//
|
|
hr = LineGetHubRelatedCalls(
|
|
0,
|
|
(HCALL)(pParams->hDevice),
|
|
&pCallHubList
|
|
);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
// get to the list of calls
|
|
phCalls = (HCALL *)(((LPBYTE)pCallHubList) + pCallHubList->dwCallsOffset);
|
|
|
|
// the first handle is the callhub
|
|
hNewCallHub = (HCALLHUB)(phCalls[0]);
|
|
|
|
// have they changed ?
|
|
if (hNewCallHub != hCurrentCallHub )
|
|
{
|
|
//
|
|
// Yes so we've moved hubs
|
|
//
|
|
LOG((TL_INFO, "HandleCallInfoMessage - LINECALLINFOSTATE_CALLID callhub change"));
|
|
LOG((TL_INFO, "HandleCallInfoMessage - Call %p > old Hub handle:%lx > new handle:%lx",
|
|
pCall, hCurrentCallHub, hNewCallHub ));
|
|
|
|
|
|
// remove call from current hub.
|
|
if(pCallHub != NULL)
|
|
{
|
|
pCallHub->RemoveCall(pCall);
|
|
pCallHub->CheckForIdle();
|
|
}
|
|
|
|
// Add it to new hub.
|
|
if(FindCallHubObject(hNewCallHub, &pCallHub) )
|
|
{
|
|
pCallHub->AddCall(pCall);
|
|
|
|
// FindCallHubObject AddRefs, so release
|
|
pCallHub->Release();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "HandleCallInfoMessage - LINECALLINFOSTATE_CALLID callhub not changed"));
|
|
}
|
|
|
|
ClientFree( pCallHubList );
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "HandleCallInfoMessage - LINECALLINFOSTATE_CALLID LineGetHubRelatedCalls "
|
|
"failed %lx", hr));
|
|
}
|
|
|
|
pCall->CallInfoChangeEvent( CIC_CALLID );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// LINE_CALLINFO handler
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT HandleCallInfoMessage( PASYNCEVENTMSG pParams )
|
|
{
|
|
BOOL bSuccess;
|
|
HRESULT hr = S_OK;
|
|
CALLINFOCHANGE_CAUSE cic;
|
|
CCall * pCall;
|
|
DWORD dw;
|
|
|
|
bSuccess = FindCallObject(
|
|
(HCALL)(pParams->hDevice),
|
|
&pCall
|
|
);
|
|
|
|
if ( !bSuccess )
|
|
{
|
|
LOG((TL_INFO, "HandleCallInfoMessage - failed to find Call Object %lx", pParams->hDevice));
|
|
return E_FAIL;
|
|
}
|
|
|
|
pCall->SetCallInfoDirty();
|
|
|
|
dw = pParams->Param1;
|
|
|
|
if (dw & LINECALLINFOSTATE_MEDIAMODE)
|
|
{
|
|
pCall->MediaModeEvent(pParams);
|
|
}
|
|
|
|
if (dw & LINECALLINFOSTATE_CALLID)
|
|
{
|
|
HandleCallIDChange( pParams, pCall );
|
|
}
|
|
|
|
if (dw & LINECALLINFOSTATE_OTHER)
|
|
pCall->CallInfoChangeEvent( CIC_OTHER );
|
|
if (dw & LINECALLINFOSTATE_DEVSPECIFIC)
|
|
pCall->CallInfoChangeEvent( CIC_DEVSPECIFIC );
|
|
if (dw & LINECALLINFOSTATE_BEARERMODE)
|
|
pCall->CallInfoChangeEvent( CIC_BEARERMODE );
|
|
if (dw & LINECALLINFOSTATE_RATE)
|
|
pCall->CallInfoChangeEvent( CIC_RATE );
|
|
if (dw & LINECALLINFOSTATE_APPSPECIFIC)
|
|
pCall->CallInfoChangeEvent( CIC_APPSPECIFIC );
|
|
if (dw & LINECALLINFOSTATE_RELATEDCALLID)
|
|
pCall->CallInfoChangeEvent( CIC_RELATEDCALLID );
|
|
if (dw & LINECALLINFOSTATE_ORIGIN)
|
|
pCall->CallInfoChangeEvent( CIC_ORIGIN );
|
|
if (dw & LINECALLINFOSTATE_REASON)
|
|
pCall->CallInfoChangeEvent( CIC_REASON );
|
|
if (dw & LINECALLINFOSTATE_COMPLETIONID)
|
|
pCall->CallInfoChangeEvent( CIC_COMPLETIONID );
|
|
if (dw & LINECALLINFOSTATE_NUMOWNERINCR)
|
|
pCall->CallInfoChangeEvent( CIC_NUMOWNERINCR );
|
|
if (dw & LINECALLINFOSTATE_NUMOWNERDECR)
|
|
pCall->CallInfoChangeEvent( CIC_NUMOWNERDECR );
|
|
if (dw & LINECALLINFOSTATE_NUMMONITORS)
|
|
pCall->CallInfoChangeEvent( CIC_NUMMONITORS );
|
|
if (dw & LINECALLINFOSTATE_TRUNK)
|
|
pCall->CallInfoChangeEvent( CIC_TRUNK );
|
|
if (dw & LINECALLINFOSTATE_CALLERID)
|
|
pCall->CallInfoChangeEvent( CIC_CALLERID );
|
|
if (dw & LINECALLINFOSTATE_CALLEDID)
|
|
pCall->CallInfoChangeEvent( CIC_CALLEDID );
|
|
if (dw & LINECALLINFOSTATE_CONNECTEDID)
|
|
pCall->CallInfoChangeEvent( CIC_CONNECTEDID );
|
|
if (dw & LINECALLINFOSTATE_REDIRECTIONID)
|
|
pCall->CallInfoChangeEvent( CIC_REDIRECTIONID );
|
|
if (dw & LINECALLINFOSTATE_REDIRECTINGID)
|
|
pCall->CallInfoChangeEvent( CIC_REDIRECTINGID );
|
|
if (dw & LINECALLINFOSTATE_USERUSERINFO)
|
|
pCall->CallInfoChangeEvent( CIC_USERUSERINFO );
|
|
if (dw & LINECALLINFOSTATE_HIGHLEVELCOMP)
|
|
pCall->CallInfoChangeEvent( CIC_HIGHLEVELCOMP );
|
|
if (dw & LINECALLINFOSTATE_LOWLEVELCOMP)
|
|
pCall->CallInfoChangeEvent( CIC_LOWLEVELCOMP );
|
|
if (dw & LINECALLINFOSTATE_CHARGINGINFO)
|
|
pCall->CallInfoChangeEvent( CIC_CHARGINGINFO );
|
|
if (dw & LINECALLINFOSTATE_TREATMENT)
|
|
pCall->CallInfoChangeEvent( CIC_TREATMENT );
|
|
if (dw & LINECALLINFOSTATE_CALLDATA)
|
|
pCall->CallInfoChangeEvent( CIC_CALLDATA );
|
|
|
|
if (dw & LINECALLINFOSTATE_QOS)
|
|
{
|
|
LOG((TL_WARN, "Unhandled LINECALLINFOSTATE_QOS message"));
|
|
}
|
|
if (dw & LINECALLINFOSTATE_MONITORMODES)
|
|
{
|
|
LOG((TL_WARN, "Unhandled LINECALLINFOSTATE_MONITORMODES message"));
|
|
}
|
|
if (dw & LINECALLINFOSTATE_DIALPARAMS)
|
|
{
|
|
LOG((TL_WARN, "Unhandled LINECALLINFOSTATE_DIALPARAMS message"));
|
|
}
|
|
if (dw & LINECALLINFOSTATE_TERMINAL)
|
|
{
|
|
LOG((TL_WARN, "Unhandled LINECALLINFOSTATE_TERMINAL message"));
|
|
}
|
|
if (dw & LINECALLINFOSTATE_DISPLAY)
|
|
{
|
|
LOG((TL_WARN, "Unhandled LINECALLINFOSTATE_DISPLAY message"));
|
|
}
|
|
|
|
|
|
// find call object addrefs the call
|
|
// so release it.
|
|
pCall->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// LINE_MONITORDIGIT handler
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT HandleMonitorDigitsMessage( PASYNCEVENTMSG pParams )
|
|
{
|
|
|
|
LOG((TL_INFO, "HandleMonitorDigitsMessage - enter"));
|
|
|
|
|
|
BOOL bSuccess;
|
|
CCall * pCall = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
//
|
|
// get the call object
|
|
//
|
|
bSuccess = FindCallObject(
|
|
(HCALL)(pParams->hDevice),
|
|
&pCall
|
|
);
|
|
|
|
if (bSuccess)
|
|
{
|
|
AddressLineStruct * pLine;
|
|
CAddress * pAddress;
|
|
|
|
pAddress = pCall->GetCAddress();
|
|
|
|
|
|
//
|
|
// pParams->OpenContext is the 32-bit handle for AddressLineStruct
|
|
//
|
|
|
|
LOG((TL_INFO, "HandleMonitorDigitsMessage: pParams->OpenContext %lx", pParams->OpenContext ));
|
|
|
|
|
|
//
|
|
// recover the callback instance value corresponding to this AddressLineStruct
|
|
//
|
|
|
|
long lCallbackInstance = 0;
|
|
|
|
hr = pCall->GetCallBackInstance(pParams->OpenContext, &lCallbackInstance);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
//
|
|
// failed to get callback instance
|
|
//
|
|
|
|
LOG((TL_WARN, "HandleMonitorDigitsMessage - GetCallBackInstance failed. hr = %lx", hr));
|
|
|
|
pCall->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
LOG((TL_INFO, "HandleMonitorDigitsMessage - callbackinstance[%lx]", lCallbackInstance));
|
|
|
|
|
|
//
|
|
// fire the event
|
|
//
|
|
|
|
CDigitDetectionEvent::FireEvent(
|
|
pCall,
|
|
(long)(pParams->Param1),
|
|
(TAPI_DIGITMODE)(pParams->Param2),
|
|
(long)(pParams->Param3),
|
|
pAddress->GetTapi(),
|
|
lCallbackInstance
|
|
);
|
|
//
|
|
// release the call
|
|
//
|
|
pCall->Release();
|
|
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "HandleMonitorDigitsMessage - failed to find Call Object %lx", pParams->hDevice));
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// LINE_MONITORTONE handler
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT HandleMonitorToneMessage( PASYNCEVENTMSG pParams )
|
|
{
|
|
BOOL bSuccess;
|
|
CCall * pCall;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// get the call object
|
|
//
|
|
bSuccess = FindCallObject(
|
|
(HCALL)(pParams->hDevice),
|
|
&pCall
|
|
);
|
|
|
|
if (bSuccess)
|
|
{
|
|
AddressLineStruct * pLine;
|
|
CAddress * pAddress;
|
|
|
|
pAddress = pCall->GetCAddress();
|
|
|
|
|
|
//
|
|
// pParams->OpenContext is the 32-bit handle for AddressLineStruct
|
|
//
|
|
|
|
LOG((TL_INFO, "HandleMonitorToneMessage: pParams->OpenContext %lx", pParams->OpenContext ));
|
|
|
|
|
|
//
|
|
// recover the callback instance corresponding to this AddressLineStruct
|
|
//
|
|
|
|
long lCallbackInstance = 0;
|
|
|
|
hr = pCall->GetCallBackInstance(pParams->OpenContext, &lCallbackInstance);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
|
|
LOG((TL_WARN, "HandleMonitorToneMessage - GetCallBackInstance failed. hr = %lx", hr));
|
|
|
|
pCall->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
LOG((TL_INFO, "HandleMonitorToneMessage - lCallbackInstance 0x%lx", lCallbackInstance));
|
|
|
|
|
|
//
|
|
// fire the event
|
|
//
|
|
|
|
CToneDetectionEvent::FireEvent(
|
|
pCall,
|
|
(long)(pParams->Param1),
|
|
(long)(pParams->Param3),
|
|
lCallbackInstance,
|
|
pAddress->GetTapi()
|
|
);
|
|
|
|
|
|
//
|
|
// release the call
|
|
//
|
|
pCall->Release();
|
|
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "HandleMonitorDigitsMessage - failed to find Call Object %lx", pParams->hDevice));
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// LINE_MONITORMEDIA handler
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void HandleMonitorMediaMessage( PASYNCEVENTMSG pParams )
|
|
{
|
|
BOOL bSuccess;
|
|
CCall * pCall;
|
|
|
|
//
|
|
// get the call object
|
|
//
|
|
|
|
bSuccess = FindCallObject(
|
|
(HCALL)(pParams->hDevice),
|
|
&pCall
|
|
);
|
|
|
|
if (bSuccess)
|
|
{
|
|
//
|
|
// Retrieve relevant info about the event:
|
|
//
|
|
// (long) (pParams->Param1) is the media type
|
|
// (DWORD?) (pParams->Param3) is the tick count (which we ignore)
|
|
//
|
|
|
|
long lMediaType = (long) (pParams->Param1);
|
|
|
|
HRESULT hr;
|
|
|
|
//
|
|
// This event means the TSP signaled a new media type that it
|
|
// detected. Try to set this on the call. The setting will
|
|
// trigger another event (LINE_CALLINFO) to inform the app
|
|
// that the media type actually changed, and that we will
|
|
// propagate to the app.
|
|
//
|
|
|
|
hr = pCall->SetMediaType( lMediaType );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_INFO, "HandleMonitorMediaMessage - "
|
|
"failed SetMediaType 0x%08x", hr));
|
|
}
|
|
|
|
//
|
|
// release the call because FindCallObject AddRefed it
|
|
//
|
|
|
|
pCall->Release();
|
|
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "HandleMonitorMediaMessage - "
|
|
"failed to find Call Object %lx", pParams->hDevice));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// HandleLineGenerateMessage
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT HandleLineGenerateMessage( PASYNCEVENTMSG pParams )
|
|
{
|
|
BOOL bSuccess;
|
|
CCall * pCall;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// get the call object
|
|
//
|
|
bSuccess = FindCallObject(
|
|
(HCALL)(pParams->hDevice),
|
|
&pCall
|
|
);
|
|
|
|
if (bSuccess)
|
|
{
|
|
|
|
//
|
|
// get call's address
|
|
//
|
|
|
|
CAddress *pAddress = pCall->GetCAddress();
|
|
|
|
|
|
//
|
|
// pParams->OpenContext is the 32-bit handle for AddressLineStruct
|
|
//
|
|
|
|
LOG((TL_INFO, "HandleLineGenerateMessage: pParams->OpenContext %lx", pParams->OpenContext ));
|
|
|
|
|
|
//
|
|
// get the callback instance corresponding to this AddressLineStruct handle
|
|
//
|
|
|
|
long lCallbackInstance = 0;
|
|
|
|
hr = pCall->GetCallBackInstance(pParams->OpenContext, &lCallbackInstance);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
//
|
|
// it is possible the line had been closed before we got this event.
|
|
//
|
|
|
|
LOG((TL_WARN, "HandleLineGenerateMessage - GetCallBackInstance failed. hr = %lx", hr));
|
|
|
|
pCall->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
LOG((TL_INFO, "HandleLineGenerateMessage - lCallbackInstance %lx", lCallbackInstance ));
|
|
|
|
//
|
|
// fire the event
|
|
//
|
|
CDigitGenerationEvent::FireEvent(
|
|
pCall,
|
|
(long)(pParams->Param1),
|
|
(long)(pParams->Param3),
|
|
lCallbackInstance,
|
|
pAddress->GetTapi()
|
|
);
|
|
|
|
|
|
|
|
//
|
|
// special case for wavemsp
|
|
// LineGenerateDigits or LineGenerateTones has completed, so we are
|
|
// now ready to resume...
|
|
// resume the stream so the wave devices are reopened after the
|
|
// tapi function has completed
|
|
//
|
|
// param1 is LINEGENERATETERM_DONE or LINEGENERATETERM_CANCEL
|
|
// (either way we need to resume the stream)
|
|
//
|
|
|
|
if ( pCall->OnWaveMSPCall() )
|
|
{
|
|
pCall->ResumeWaveMSPStream();
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// release the call
|
|
//
|
|
pCall->Release();
|
|
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "HandleLineGenerateMessage - failed to find Call Object %lx", pParams->hDevice));
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// LINE_GATHERDIGIT handler
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT HandleGatherDigitsMessage( PASYNCEVENTMSG pParams )
|
|
{
|
|
BOOL bSuccess;
|
|
CCall * pCall;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// get the call object
|
|
//
|
|
bSuccess = FindCallObject(
|
|
(HCALL)(pParams->hDevice),
|
|
&pCall
|
|
);
|
|
|
|
if (bSuccess)
|
|
{
|
|
pCall->GatherDigitsEvent( pParams );
|
|
|
|
//
|
|
// release the call
|
|
//
|
|
pCall->Release();
|
|
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "HandleGatherDigitsMessage - failed to find Call Object %lx", pParams->hDevice));
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// GatherDigitsEvent
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT CCall::GatherDigitsEvent( PASYNCEVENTMSG pParams )
|
|
{
|
|
|
|
LOG((TL_INFO, "GatherDigitsEvent - enter. pParams->OpenContext[%lx]",
|
|
pParams->OpenContext ));
|
|
|
|
|
|
//
|
|
// pParams->OpenContext is the 32-bit handle for AddressLineStruct
|
|
//
|
|
|
|
|
|
//
|
|
// recover the callback instance associated with thisAddressLineStruct
|
|
//
|
|
|
|
long lCallbackInstance = 0;
|
|
|
|
HRESULT hr = GetCallBackInstance(pParams->OpenContext, &lCallbackInstance);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
|
|
LOG((TL_WARN, "GatherDigitsEvent - failed to get callback instance"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
LOG((TL_INFO, "GatherDigitsEvent - lCallbackInstance %lx", lCallbackInstance));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Check to make sure the queue isn't empty
|
|
//
|
|
|
|
if ( m_GatherDigitsQueue.GetSize() == 0 )
|
|
{
|
|
LOG((TL_ERROR, "GatherDigitsEvent - GatherDigitsQueue is empty"));
|
|
|
|
Unlock();
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
LPWSTR pDigits;
|
|
BSTR bstrDigits;
|
|
|
|
//
|
|
// Get the digit string from the queue
|
|
//
|
|
|
|
pDigits = m_GatherDigitsQueue[0];
|
|
m_GatherDigitsQueue.RemoveAt(0);
|
|
|
|
if ( IsBadStringPtrW(pDigits, -1) )
|
|
{
|
|
LOG((TL_ERROR, "GatherDigitsEvent - bad digits string"));
|
|
|
|
Unlock();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
bstrDigits = SysAllocString(pDigits);
|
|
|
|
ClientFree(pDigits);
|
|
pDigits = NULL;
|
|
|
|
//
|
|
// fire the event
|
|
//
|
|
|
|
CDigitsGatheredEvent::FireEvent(
|
|
this,
|
|
bstrDigits,
|
|
(TAPI_GATHERTERM)(pParams->Param1),
|
|
(long)(pParams->Param3),
|
|
lCallbackInstance,
|
|
m_pAddress->GetTapi()
|
|
);
|
|
|
|
Unlock();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// RefreshCallInfo
|
|
//
|
|
// Assume called in lock
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::RefreshCallInfo()
|
|
{
|
|
LINECALLINFO * pCallInfo;
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
//
|
|
// do we need to update?
|
|
//
|
|
if ( CS_IDLE == m_CallState )
|
|
{
|
|
LOG((TL_ERROR, "Can't get callinfo while in idle state"));
|
|
|
|
return TAPI_E_INVALCALLSTATE;
|
|
}
|
|
|
|
if ( CALLFLAG_CALLINFODIRTY & m_dwCallFlags )
|
|
{
|
|
hr = LineGetCallInfo(
|
|
m_t3Call.hCall,
|
|
&pCallInfo
|
|
);
|
|
|
|
if ( !SUCCEEDED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "RefreshCallInfo - linegetcallinfo failed - %lx", hr));
|
|
|
|
if ( NULL != m_pCallInfo )
|
|
{
|
|
//
|
|
// use cached struct
|
|
//
|
|
// don't clear bit
|
|
//
|
|
return S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// clear bit
|
|
//
|
|
m_dwCallFlags &= ~CALLFLAG_CALLINFODIRTY;
|
|
|
|
//
|
|
// free
|
|
//
|
|
if ( NULL != m_pCallInfo )
|
|
{
|
|
ClientFree( m_pCallInfo );
|
|
}
|
|
|
|
//
|
|
// save
|
|
//
|
|
m_pCallInfo = pCallInfo;
|
|
}
|
|
|
|
if( NULL == m_pCallInfo )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// CCall::FinishCallParams()
|
|
//
|
|
// called in lock
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
void
|
|
CCall::FinishCallParams()
|
|
{
|
|
if(m_pCallParams != NULL)
|
|
{
|
|
|
|
Lock();
|
|
|
|
m_pCallParams->dwAddressMode = LINEADDRESSMODE_ADDRESSID;
|
|
m_pCallParams->dwAddressID = m_pAddress->GetAddressID();
|
|
|
|
if (m_dwMediaMode & AUDIOMEDIAMODES)
|
|
{
|
|
m_dwMediaMode &= ~AUDIOMEDIAMODES;
|
|
|
|
m_dwMediaMode |= (AUDIOMEDIAMODES & m_pAddress->GetMediaModes());
|
|
}
|
|
|
|
|
|
//
|
|
// if we're < tapi3, multiple media modes can't be handled
|
|
//
|
|
if ( m_pAddress->GetAPIVersion() < TAPI_VERSION3_0 )
|
|
{
|
|
if ( (m_dwMediaMode & AUDIOMEDIAMODES) == AUDIOMEDIAMODES )
|
|
{
|
|
m_dwMediaMode &= ~LINEMEDIAMODE_INTERACTIVEVOICE;
|
|
}
|
|
}
|
|
|
|
m_pCallParams->dwMediaMode = m_dwMediaMode;
|
|
|
|
Unlock();
|
|
}
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// ResizeCallParams
|
|
//
|
|
// assumed called in lock
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::ResizeCallParams( DWORD dwSize )
|
|
{
|
|
LOG((TL_TRACE, "ResizeCallParams - enter"));
|
|
|
|
DWORD dwNewSize;
|
|
LINECALLPARAMS * pCallParams;
|
|
|
|
|
|
if ( NULL == m_pCallParams )
|
|
{
|
|
LOG((TL_WARN,
|
|
"ResizeCallParams - finish. no call params. invalid state for this function call"));
|
|
|
|
return TAPI_E_INVALCALLSTATE;
|
|
}
|
|
|
|
|
|
dwSize += m_dwCallParamsUsedSize;
|
|
|
|
if ( dwSize <= m_pCallParams->dwTotalSize )
|
|
{
|
|
LOG((TL_TRACE, "ResizeCallParams - finish. sufficient size"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
dwNewSize = m_pCallParams->dwTotalSize;
|
|
|
|
while ( dwNewSize < dwSize )
|
|
{
|
|
dwNewSize *= 2;
|
|
}
|
|
|
|
pCallParams = (LINECALLPARAMS *) ClientAlloc (dwNewSize);
|
|
|
|
if ( NULL == pCallParams )
|
|
{
|
|
LOG((TL_ERROR, "ResizeCallParams - alloc failed"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
CopyMemory(
|
|
pCallParams,
|
|
m_pCallParams,
|
|
m_dwCallParamsUsedSize
|
|
);
|
|
|
|
ClientFree( m_pCallParams );
|
|
|
|
m_pCallParams = pCallParams;
|
|
|
|
m_pCallParams->dwTotalSize = dwNewSize;
|
|
|
|
LOG((TL_TRACE, "ResizeCallParams - finish."));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// SendUserUserInfo
|
|
//
|
|
// Not called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CCall::SendUserUserInfo(
|
|
HCALL hCall,
|
|
long lSize,
|
|
BYTE * pBuffer
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( IsBadReadPtr( pBuffer, lSize ) )
|
|
{
|
|
LOG((TL_ERROR, "SendUserUserInfo - invalid buffer"));
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
hr = LineSendUserUserInfo(
|
|
hCall,
|
|
(LPCSTR)pBuffer,
|
|
lSize
|
|
);
|
|
|
|
if (((LONG)hr) < 0)
|
|
{
|
|
LOG((TL_ERROR, "LineSendUserUserInfo failed - %lx", hr));
|
|
return hr;
|
|
}
|
|
|
|
hr = WaitForReply( hr );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// SaveUserUserInfo
|
|
//
|
|
// called in Lock()
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CCall::SaveUserUserInfo(
|
|
long lSize,
|
|
BYTE * pBuffer
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
if ( IsBadReadPtr( pBuffer, lSize ) )
|
|
{
|
|
LOG((TL_ERROR, "SaveUserUserInfo - invalid buffer"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
hr = ResizeCallParams( lSize );
|
|
|
|
if ( !SUCCEEDED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "SaveUserUserInfo - can't resize call params - %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
CopyMemory(
|
|
((PBYTE)m_pCallParams) + m_dwCallParamsUsedSize,
|
|
pBuffer,
|
|
lSize
|
|
);
|
|
|
|
m_pCallParams->dwUserUserInfoSize = lSize;
|
|
m_pCallParams->dwUserUserInfoOffset = m_dwCallParamsUsedSize;
|
|
m_dwCallParamsUsedSize += lSize;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// MakeBufferFromVariant
|
|
//
|
|
// this function copies the data from a VARIANT with a safearray
|
|
// of bytes to a byte buffer. the caller must clientfee the
|
|
// buffer allocated.
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
MakeBufferFromVariant(
|
|
VARIANT var,
|
|
DWORD * pdwSize,
|
|
BYTE ** ppBuffer
|
|
)
|
|
{
|
|
long lDims;
|
|
long lUpper;
|
|
long lLower;
|
|
BYTE * pArray;
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSize;
|
|
|
|
|
|
if ( ( ! (var.vt & VT_ARRAY) ) ||
|
|
( ! (var.vt & VT_UI1) ) )
|
|
{
|
|
LOG((TL_ERROR, "MakeBufferFromVariant - Variant not array or not byte"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
lDims = SafeArrayGetDim( var.parray );
|
|
|
|
if ( 1 != lDims )
|
|
{
|
|
LOG((TL_ERROR, "MakeBufferFromVariant - Variant dims != 1 - %d", lDims));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( !(SUCCEEDED(SafeArrayGetLBound(var.parray, 1, &lLower)) ) ||
|
|
!(SUCCEEDED(SafeArrayGetUBound(var.parray, 1, &lUpper)) ) )
|
|
{
|
|
LOG((TL_ERROR, "MakeBufferFromVariant - get bound failed"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( lLower >= lUpper )
|
|
{
|
|
LOG((TL_ERROR, "MakeBufferFromVariant - bounds invalid"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
dwSize = lUpper - lLower + 1;
|
|
|
|
*ppBuffer = (BYTE *)ClientAlloc( dwSize );
|
|
|
|
if ( NULL == *ppBuffer )
|
|
{
|
|
LOG((TL_ERROR, "MakeBufferFromVariant - Alloc failed"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
SafeArrayAccessData( var.parray, (void**)&pArray );
|
|
|
|
CopyMemory(
|
|
*ppBuffer,
|
|
pArray,
|
|
dwSize
|
|
);
|
|
|
|
SafeArrayUnaccessData( var.parray );
|
|
|
|
*pdwSize = dwSize;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// FillVariantFromBuffer
|
|
//
|
|
// create a safearray of bytes, copy the buffer into the safearray,
|
|
// and save the safearray in the variant
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
FillVariantFromBuffer(
|
|
DWORD dw,
|
|
BYTE * pBuffer,
|
|
VARIANT * pVar
|
|
)
|
|
{
|
|
SAFEARRAY * psa;
|
|
SAFEARRAYBOUND sabound[1];
|
|
BYTE * pArray;
|
|
|
|
|
|
sabound[0].lLbound = 0;
|
|
sabound[0].cElements = dw;
|
|
|
|
psa = SafeArrayCreate(VT_UI1, 1, sabound);
|
|
|
|
if ( NULL == psa )
|
|
{
|
|
LOG((TL_ERROR, "FillVariantFromBuffer - failed to allocate safearray"));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if ( 0 != dw )
|
|
{
|
|
SafeArrayAccessData( psa, (void **) &pArray );
|
|
|
|
CopyMemory(
|
|
pArray,
|
|
pBuffer,
|
|
dw
|
|
);
|
|
|
|
SafeArrayUnaccessData( psa );
|
|
}
|
|
|
|
pVar->vt = VT_ARRAY | VT_UI1;
|
|
pVar->parray = psa;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// HandleLineQOSInfoMessage
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT HandleLineQOSInfoMessage(
|
|
PASYNCEVENTMSG pParams
|
|
)
|
|
{
|
|
CCall * pCall;
|
|
BOOL bSuccess;
|
|
HRESULT hr = S_OK;
|
|
|
|
bSuccess = FindCallObject(
|
|
(HCALL)(pParams->hDevice),
|
|
&pCall
|
|
);
|
|
|
|
if (bSuccess)
|
|
{
|
|
ITCallHub * pCallHub;
|
|
CCallHub * pCCallHub;
|
|
|
|
hr = pCall->get_CallHub( &pCallHub );
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pCCallHub = dynamic_cast<CCallHub *>(pCallHub);
|
|
|
|
CQOSEvent::FireEvent(
|
|
pCall,
|
|
(QOS_EVENT)pParams->Param1,
|
|
(long)pParams->Param2,
|
|
pCCallHub->GetTapi() // no addref
|
|
);
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
//
|
|
// release the call
|
|
//
|
|
pCall->Release();
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "HandleLineQOSInfoMessage - failed to find Call Object %lx", pParams->hDevice));
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
AddressLineStruct *
|
|
CCall::GetPAddressLine()
|
|
{
|
|
AddressLineStruct * pAddressLine;
|
|
|
|
Lock();
|
|
|
|
pAddressLine = m_pAddressLine;
|
|
|
|
Unlock();
|
|
|
|
return pAddressLine;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HCALL
|
|
CCall::GetHCall()
|
|
{
|
|
HCALL hCall;
|
|
|
|
Lock();
|
|
|
|
hCall = m_t3Call.hCall;
|
|
|
|
Unlock();
|
|
|
|
return hCall;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
BOOL
|
|
CCall::DontExpose()
|
|
{
|
|
BOOL bReturn;
|
|
|
|
Lock();
|
|
|
|
bReturn = (m_dwCallFlags & CALLFLAG_DONTEXPOSE)?TRUE:FALSE;
|
|
|
|
Unlock();
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
CCallHub *
|
|
CCall::GetCallHub()
|
|
{
|
|
CCallHub * pCallHub;
|
|
|
|
Lock();
|
|
|
|
pCallHub = m_pCallHub;
|
|
|
|
Unlock();
|
|
|
|
return pCallHub;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CCall::ResetCallParams()
|
|
{
|
|
LOG((TL_TRACE, "ResetCallParams - enter."));
|
|
|
|
ClientFree( m_pCallParams );
|
|
|
|
m_pCallParams = NULL;
|
|
|
|
m_dwCallParamsUsedSize = 0;
|
|
|
|
LOG((TL_TRACE, "ResetCallParams - finish."));
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CCall::FinishSettingUpCall( HCALL hCall )
|
|
{
|
|
LOG((TL_TRACE, "FinishSettingUpCall - enter"));
|
|
|
|
if(m_t3Call.hCall != NULL)
|
|
{
|
|
LOG((TL_ERROR, "FinishSettingUpCall - m_t3Call.hCall != NULL"));
|
|
#ifdef DBG
|
|
DebugBreak();
|
|
#endif
|
|
}
|
|
|
|
m_t3Call.hCall = hCall;
|
|
|
|
//
|
|
// Set filter events for this call
|
|
//
|
|
m_EventMasks.SetTapiSrvCallEventMask( m_t3Call.hCall );
|
|
|
|
//
|
|
// note - we can miss messages if something comes in between the time time
|
|
// we get the reply, and the time we insert the call
|
|
//
|
|
AddCallToHashTable();
|
|
|
|
CheckAndCreateFakeCallHub();
|
|
|
|
ResetCallParams();
|
|
|
|
LOG((TL_TRACE, "FinishSettingUpCall - finish"));
|
|
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// not called in Lock()
|
|
//
|
|
// returns S_OK if gets to connected
|
|
// S_FALSE otherwise
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CCall::SyncWait( HANDLE hEvent )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// wait for connected event
|
|
//
|
|
extern DWORD gdwTapi3SyncWaitTimeOut;
|
|
|
|
WaitForSingleObject(
|
|
hEvent,
|
|
gdwTapi3SyncWaitTimeOut
|
|
);
|
|
|
|
Lock();
|
|
|
|
//
|
|
// get rid of event
|
|
//
|
|
ClearConnectedEvent();
|
|
|
|
//
|
|
// it it is connected
|
|
// return S_OK
|
|
//
|
|
if (m_CallState == CS_CONNECTED)
|
|
{
|
|
LOG((TL_INFO, "Connect - reached connected state"));
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "Connect - exit bSync - return SUCCESS"));
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
//
|
|
// if it is disconnect or times out
|
|
// return S_FALSE;
|
|
//
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "Connect - did not reach connected state"));
|
|
|
|
//
|
|
// if it isn't disconnected (it timed out), make it disconnect
|
|
//
|
|
if (m_CallState != CS_DISCONNECTED)
|
|
{
|
|
if ( m_t3Call.hCall != NULL )
|
|
{
|
|
LONG lResult;
|
|
|
|
lResult = LineDrop(
|
|
m_t3Call.hCall,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if ( lResult < 0 )
|
|
{
|
|
LOG((TL_ERROR, "Connect - LineDrop failed %lx", lResult ));
|
|
|
|
m_CallState = CS_DISCONNECTED;
|
|
}
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "Connect - exit bSync - return S_FALSE"));
|
|
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// this must be created inside the same
|
|
// Lock() as the call to tapisrv
|
|
// otherwise, the connected message
|
|
// may appear before the event
|
|
// exists
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HANDLE
|
|
CCall::CreateConnectedEvent()
|
|
{
|
|
m_hConnectedEvent = CreateEvent(
|
|
NULL,
|
|
FALSE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
return m_hConnectedEvent;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// ClearConnectedEvent
|
|
// called in Lock()
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CCall::ClearConnectedEvent()
|
|
{
|
|
if ( NULL != m_hConnectedEvent )
|
|
{
|
|
CloseHandle( m_hConnectedEvent );
|
|
|
|
m_hConnectedEvent = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// DialAsConsultationCall
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CCall::DialAsConsultationCall(
|
|
CCall * pRelatedCall,
|
|
DWORD dwCallFeatures,
|
|
BOOL bConference,
|
|
BOOL bSync
|
|
)
|
|
{
|
|
//
|
|
// do we support Linedial or makeCall for creating our consultation call ?
|
|
//
|
|
LONG lCap;
|
|
BOOL bCap;
|
|
DWORD dwConsultFlags;
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
m_pAddress->get_AddressCapability( AC_ADDRESSCAPFLAGS, &lCap );
|
|
|
|
if (bConference)
|
|
{
|
|
bCap = lCap & LINEADDRCAPFLAGS_CONFERENCEMAKE;
|
|
dwConsultFlags = CALLFLAG_CONFCONSULT|CALLFLAG_CONSULTCALL;
|
|
}
|
|
else
|
|
{
|
|
bCap = lCap & LINEADDRCAPFLAGS_TRANSFERMAKE;
|
|
dwConsultFlags = CALLFLAG_TRANSFCONSULT|CALLFLAG_CONSULTCALL;
|
|
}
|
|
|
|
if ( !(dwCallFeatures & LINECALLFEATURE_DIAL) &&
|
|
(bCap) )
|
|
{
|
|
//
|
|
// We need to do a makecall to create a consultation call
|
|
// lose the consulation call handle created by lineSetupConference
|
|
//
|
|
hr = Disconnect(DC_NORMAL);
|
|
|
|
//
|
|
// Make the new call
|
|
//
|
|
hr = Connect((BOOL)bSync);
|
|
|
|
if(SUCCEEDED(hr) )
|
|
{
|
|
SetRelatedCall(
|
|
pRelatedCall,
|
|
dwConsultFlags
|
|
);
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "DialAsConsultationCall - Consultation makeCall failed"));
|
|
}
|
|
}
|
|
else // We can linedial our consultaion call
|
|
{
|
|
//
|
|
// Wait for dialtone or equivalent
|
|
//
|
|
hr = WaitForCallState(CS_INPROGRESS);
|
|
|
|
if(SUCCEEDED(hr) )
|
|
{
|
|
hr = DialConsultCall(bSync);
|
|
|
|
if(SUCCEEDED(hr) )
|
|
{
|
|
SetRelatedCall(
|
|
pRelatedCall,
|
|
dwConsultFlags
|
|
);
|
|
}
|
|
else // LineDial failed
|
|
{
|
|
LOG((TL_ERROR, "DialAsConsultationCall - DialConsultCall failed" ));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "DialAsConsultationCall - Failed to get to CS_INPROGRESS (dialtone) on consult call"));
|
|
}
|
|
|
|
} // Endif - Linedial or make call for consultation ?
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// SetCallInfoDirty
|
|
//
|
|
// not called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CCall::SetCallInfoDirty()
|
|
{
|
|
Lock();
|
|
|
|
m_dwCallFlags |= CALLFLAG_CALLINFODIRTY;
|
|
|
|
Unlock();
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// SetMediaMode
|
|
//
|
|
// called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CCall::SetMediaMode( DWORD dwMediaMode )
|
|
{
|
|
m_dwMediaMode = dwMediaMode;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// SetCallState
|
|
//
|
|
// called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CCall::SetCallState( CALL_STATE cs )
|
|
{
|
|
m_CallState = cs;
|
|
|
|
if ( CS_OFFERING == cs )
|
|
{
|
|
m_dwCallFlags |= CALLFLAG_INCOMING;
|
|
}
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// OnWaveMSPCall
|
|
//
|
|
// called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
BOOL
|
|
CCall::OnWaveMSPCall()
|
|
{
|
|
Lock();
|
|
|
|
BOOL bWaveMSPCall = ( ( NULL != m_pMSPCall ) && m_pAddress->HasWaveDevice() );
|
|
|
|
Unlock();
|
|
|
|
return bWaveMSPCall;
|
|
}
|
|
|
|
#ifdef USE_PHONEMSP
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// OnPhoneMSPCall
|
|
//
|
|
// called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
BOOL
|
|
CCall::OnPhoneMSPCall()
|
|
{
|
|
return ( ( NULL != m_pMSPCall ) && m_pAddress->HasPhoneDevice() );
|
|
}
|
|
#endif USE_PHONEMSP
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
CAddress *
|
|
CCall::GetCAddress()
|
|
{
|
|
return m_pAddress;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// GetStreamControl
|
|
//
|
|
// called in lock
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
ITStreamControl *
|
|
CCall::GetStreamControl()
|
|
{
|
|
HRESULT hr;
|
|
ITStreamControl * pStreamControl;
|
|
|
|
// +++ FIXBUG 90668 +++
|
|
if( NULL == m_pMSPCall )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
hr = m_pMSPCall->QueryInterface(
|
|
IID_ITStreamControl,
|
|
(void**)&pStreamControl
|
|
);
|
|
|
|
if ( !SUCCEEDED(hr) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return pStreamControl;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// GetMSPCall()
|
|
//
|
|
// not called in lock
|
|
//
|
|
//
|
|
// returns the IUnknown of the msp call (the object we are
|
|
// aggregating)
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
IUnknown *
|
|
CCall::GetMSPCall()
|
|
{
|
|
IUnknown * pUnk;
|
|
|
|
Lock();
|
|
|
|
pUnk = m_pMSPCall;
|
|
|
|
Unlock();
|
|
|
|
if ( NULL != pUnk )
|
|
{
|
|
pUnk->AddRef();
|
|
}
|
|
|
|
return pUnk;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::DetectDigits
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::DetectDigits(TAPI_DIGITMODE DigitMode)
|
|
{
|
|
HRESULT hr;
|
|
HCALL hCall;
|
|
|
|
LOG((TL_TRACE, "DetectDigits - enter"));
|
|
|
|
Lock();
|
|
|
|
hCall = m_t3Call.hCall;
|
|
|
|
Unlock();
|
|
|
|
if ( NULL == hCall )
|
|
{
|
|
LOG((TL_TRACE, "DetectDigits - need a call first"));
|
|
|
|
return TAPI_E_INVALCALLSTATE;
|
|
}
|
|
|
|
hr = LineMonitorDigits(
|
|
hCall,
|
|
DigitMode
|
|
);
|
|
|
|
LOG((TL_TRACE, "DetectDigits - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::GenerateDigits
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::GenerateDigits(
|
|
BSTR pDigits,
|
|
TAPI_DIGITMODE DigitMode
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "GenerateDigits - enter"));
|
|
|
|
hr = GenerateDigits2(pDigits, DigitMode, 0);
|
|
|
|
LOG((TL_TRACE, "GenerateDigits - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::GenerateDigits2
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::GenerateDigits2(
|
|
BSTR pDigits,
|
|
TAPI_DIGITMODE DigitMode,
|
|
long lDuration
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
HCALL hCall;
|
|
|
|
LOG((TL_TRACE, "GenerateDigits2 - enter"));
|
|
|
|
// It is alright for pDigits to be NULL
|
|
if ( ( pDigits != NULL ) && IsBadStringPtrW( pDigits, -1 ) )
|
|
{
|
|
LOG((TL_TRACE, "GenerateDigits2 - bad string"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
hCall = m_t3Call.hCall;
|
|
|
|
Unlock();
|
|
|
|
if ( NULL == hCall )
|
|
{
|
|
LOG((TL_TRACE, "GenerateDigits2 - need call first"));
|
|
|
|
return TAPI_E_INVALCALLSTATE;
|
|
}
|
|
|
|
//
|
|
// special case for wavemsp
|
|
// suspend the stream so the wave devices are closed before the
|
|
// tapi function starts. SuspendWaveMSPStream is a synchronous
|
|
// call.
|
|
//
|
|
// But if pDigits is NULL, then we do not suspend the stream, as
|
|
// this call is only intended to cancel an already-pending
|
|
// LineGenerateDigits. Only one event will be fired in this case,
|
|
// and the specifics of the event will indicate whether the digit
|
|
// generation was completed or aborted -- the LGD(NULL) itself
|
|
// never results in a separate event being fired.
|
|
//
|
|
|
|
if ( OnWaveMSPCall() && ( pDigits != NULL ) )
|
|
{
|
|
SuspendWaveMSPStream();
|
|
}
|
|
|
|
hr = LineGenerateDigits(
|
|
hCall,
|
|
DigitMode,
|
|
pDigits,
|
|
lDuration
|
|
);
|
|
|
|
//
|
|
// For a wavemsp call, we will tell the wavemsp to resume the stream when
|
|
// we receive the digit completion event from tapisrv. However, if the
|
|
// LineGenerateDigits failed synchronously, then we will never receive
|
|
// such an event, so we must resume the stream now.
|
|
//
|
|
// Also see above -- we didn't suspend the stream if the digit string
|
|
// is NULL.
|
|
//
|
|
|
|
if ( OnWaveMSPCall() && ( pDigits != NULL ) && FAILED(hr) )
|
|
{
|
|
ResumeWaveMSPStream();
|
|
}
|
|
|
|
LOG((TL_TRACE, "GenerateDigits2 - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::GatherDigits
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::GatherDigits(
|
|
TAPI_DIGITMODE DigitMode,
|
|
long lNumDigits,
|
|
BSTR pTerminationDigits,
|
|
long lFirstDigitTimeout,
|
|
long lInterDigitTimeout
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
HCALL hCall;
|
|
LPWSTR pDigitBuffer;
|
|
BOOL fResult;
|
|
|
|
LOG((TL_TRACE, "GatherDigits - enter"));
|
|
|
|
// It is alright for pTerminationDigits to be NULL
|
|
if ( ( pTerminationDigits != NULL ) && IsBadStringPtrW( pTerminationDigits, -1 ) )
|
|
{
|
|
LOG((TL_TRACE, "GatherDigits - bad string"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
hCall = m_t3Call.hCall;
|
|
|
|
Unlock();
|
|
|
|
if ( NULL == hCall )
|
|
{
|
|
LOG((TL_TRACE, "GatherDigits - need a call first"));
|
|
|
|
return TAPI_E_INVALCALLSTATE;
|
|
}
|
|
|
|
if (lNumDigits)
|
|
{
|
|
//
|
|
// Allocate the digit string
|
|
//
|
|
|
|
pDigitBuffer = (LPWSTR)ClientAlloc( (lNumDigits + 1)*sizeof(WCHAR) );
|
|
|
|
if (NULL == pDigitBuffer)
|
|
{
|
|
LOG((TL_TRACE, "GatherDigits - out of memory"));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
ZeroMemory(pDigitBuffer, (lNumDigits + 1)*sizeof(WCHAR) );
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Add digit string to the queue
|
|
//
|
|
|
|
fResult = m_GatherDigitsQueue.Add(pDigitBuffer);
|
|
|
|
|
|
|
|
if (FALSE == fResult)
|
|
{
|
|
LOG((TL_TRACE, "GatherDigits - unable to add to queue"));
|
|
|
|
ClientFree( pDigitBuffer );
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = LineGatherDigits(
|
|
hCall,
|
|
DigitMode,
|
|
pDigitBuffer,
|
|
lNumDigits,
|
|
pTerminationDigits,
|
|
lFirstDigitTimeout,
|
|
lInterDigitTimeout
|
|
);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
fResult = m_GatherDigitsQueue.Remove(pDigitBuffer);
|
|
|
|
if (TRUE == fResult)
|
|
{
|
|
ClientFree( pDigitBuffer );
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_TRACE, "GatherDigits - unable to remove from queue"));
|
|
|
|
// This shouldn't happen
|
|
_ASSERTE(FALSE);
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// lNumDigits == 0 means cancel the gather digits
|
|
//
|
|
|
|
hr = LineGatherDigits(
|
|
hCall,
|
|
DigitMode,
|
|
NULL,
|
|
0,
|
|
pTerminationDigits,
|
|
lFirstDigitTimeout,
|
|
lInterDigitTimeout
|
|
);
|
|
}
|
|
|
|
LOG((TL_TRACE, "GatherDigits - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::DetectTones
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::DetectTones(
|
|
TAPI_DETECTTONE * pToneList,
|
|
long lNumTones
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
HCALL hCall;
|
|
|
|
LOG((TL_TRACE, "DetectTones - enter"));
|
|
|
|
//
|
|
// pToneList == NULL is ok, it means cancel tone detection
|
|
//
|
|
|
|
if ( (pToneList != NULL) && IsBadReadPtr( pToneList, lNumTones * sizeof(TAPI_DETECTTONE) ))
|
|
{
|
|
LOG((TL_TRACE, "DetectTones - invalid pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
hCall = m_t3Call.hCall;
|
|
|
|
Unlock();
|
|
|
|
if ( NULL == hCall )
|
|
{
|
|
LOG((TL_TRACE, "DetectTones - need a call first"));
|
|
|
|
return TAPI_E_INVALCALLSTATE;
|
|
}
|
|
|
|
hr = LineMonitorTones(
|
|
hCall,
|
|
(LPLINEMONITORTONE)pToneList,
|
|
lNumTones
|
|
);
|
|
|
|
LOG((TL_TRACE, "DetectTones - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::DetectTonesByCollection
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::DetectTonesByCollection(
|
|
ITCollection2 * pDetectToneCollection
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
TAPI_DETECTTONE * pToneList = NULL;
|
|
long lNumTones = 0;
|
|
long lCount;
|
|
|
|
LOG((TL_TRACE, "DetectTonesByCollection - enter"));
|
|
|
|
//
|
|
// pDetectToneCollection == NULL is ok, it means cancel tone detection
|
|
//
|
|
|
|
if ( (pDetectToneCollection != NULL) && IsBadReadPtr( pDetectToneCollection, sizeof(ITCollection2) ) )
|
|
{
|
|
LOG((TL_ERROR, "DetectTonesByCollection - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ( pDetectToneCollection != NULL )
|
|
{
|
|
//
|
|
// Find out how many items are in the collection and allocate an appropriately
|
|
// sized data structure
|
|
//
|
|
|
|
hr = pDetectToneCollection->get_Count(&lCount);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "DetectTonesByCollection - get_Count failed - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
pToneList = (TAPI_DETECTTONE *)ClientAlloc( lCount * sizeof(TAPI_DETECTTONE) );
|
|
|
|
if ( NULL == pToneList )
|
|
{
|
|
LOG((TL_ERROR, "DetectTonesByCollection - out of memory"));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Go through collection
|
|
//
|
|
|
|
for ( int i = 1; i <= lCount; i++ )
|
|
{
|
|
ITDetectTone * pDetectTone;
|
|
IDispatch * pDisp;
|
|
VARIANT var;
|
|
|
|
hr = pDetectToneCollection->get_Item(i, &var);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_WARN, "DetectTonesByCollection - get_Item failed - %lx", hr));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// get the IDispatch pointer out of the variant
|
|
//
|
|
|
|
try
|
|
{
|
|
if ( var.vt != VT_DISPATCH )
|
|
{
|
|
LOG((TL_WARN, "DetectTonesByCollection - expected VT_DISPATCH"));
|
|
|
|
continue;
|
|
}
|
|
|
|
pDisp = V_DISPATCH(&var);
|
|
}
|
|
catch(...)
|
|
{
|
|
LOG((TL_WARN, "DetectTonesByCollection - bad variant"));
|
|
|
|
continue;
|
|
}
|
|
|
|
if ( IsBadReadPtr( pDisp, sizeof(IDispatch) ) )
|
|
{
|
|
LOG((TL_WARN, "DetectTonesByCollection - bad pointer"));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Query for the ITDetectTone interface
|
|
//
|
|
|
|
hr = pDisp->QueryInterface( IID_ITDetectTone, (void **) &pDetectTone );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_WARN, "DetectTonesByCollection - QI failed - %lx", hr));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Fill in the data structure with information from ITDetectTone
|
|
//
|
|
|
|
pDetectTone->get_AppSpecific((long *)&pToneList[lNumTones].dwAppSpecific);
|
|
pDetectTone->get_Duration((long *)&pToneList[lNumTones].dwDuration);
|
|
pDetectTone->get_Frequency(1, (long *)&pToneList[lNumTones].dwFrequency1);
|
|
pDetectTone->get_Frequency(2, (long *)&pToneList[lNumTones].dwFrequency2);
|
|
pDetectTone->get_Frequency(3, (long *)&pToneList[lNumTones].dwFrequency3);
|
|
|
|
LOG((TL_INFO, "DetectTonesByCollection - **** Tone %d ****", lNumTones));
|
|
LOG((TL_INFO, "DetectTonesByCollection - AppSpecific %d", pToneList[lNumTones].dwAppSpecific));
|
|
LOG((TL_INFO, "DetectTonesByCollection - Duration %d", pToneList[lNumTones].dwDuration));
|
|
LOG((TL_INFO, "DetectTonesByCollection - Frequency1 %d", pToneList[lNumTones].dwFrequency1));
|
|
LOG((TL_INFO, "DetectTonesByCollection - Frequency2 %d", pToneList[lNumTones].dwFrequency2));
|
|
LOG((TL_INFO, "DetectTonesByCollection - Frequency3 %d", pToneList[lNumTones].dwFrequency3));
|
|
|
|
lNumTones++;
|
|
|
|
pDetectTone->Release();
|
|
}
|
|
}
|
|
|
|
hr = DetectTones( pToneList, lNumTones );
|
|
|
|
LOG((TL_TRACE, "DetectTonesByCollection - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::GenerateTone
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::GenerateTone(
|
|
TAPI_TONEMODE ToneMode,
|
|
long lDuration
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
HCALL hCall;
|
|
|
|
LOG((TL_TRACE, "GenerateTone - enter"));
|
|
|
|
Lock();
|
|
|
|
hCall = m_t3Call.hCall;
|
|
|
|
Unlock();
|
|
|
|
if ( NULL == hCall )
|
|
{
|
|
LOG((TL_TRACE, "GenerateTone - need call first"));
|
|
|
|
return TAPI_E_INVALCALLSTATE;
|
|
}
|
|
|
|
if ( ToneMode == (TAPI_TONEMODE)LINETONEMODE_CUSTOM ) // no custom tones
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// special case for wavemsp
|
|
// suspend the stream so the wave devices are closed before the
|
|
// tapi function starts. SuspendWaveMSPStream is a synchronous
|
|
// call.
|
|
//
|
|
// But if ToneMode is 0, then we do not suspend the stream, as
|
|
// this call is only intended to cancel an already-pending
|
|
// LineGenerateTone. Only one event will be fired in this case,
|
|
// and the specifics of the event will indicate whether the tone
|
|
// generation was completed or aborted -- the LGT(0) itself
|
|
// never results in a separate event being fired.
|
|
//
|
|
|
|
if ( OnWaveMSPCall() && ( ToneMode != (TAPI_TONEMODE)0 ) )
|
|
{
|
|
SuspendWaveMSPStream();
|
|
}
|
|
|
|
hr = LineGenerateTone(
|
|
hCall,
|
|
ToneMode,
|
|
lDuration,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// For a wavemsp call, we will tell the wavemsp to resume the stream when
|
|
// we receive the digit completion event from tapisrv. However, if the
|
|
// LineGenerateTone failed synchronously, then we will never receive
|
|
// such an event, so we must resume the stream now.
|
|
//
|
|
// Also see above -- we didn't suspend the stream if the ToneMode
|
|
// is 0.
|
|
//
|
|
|
|
if ( OnWaveMSPCall() && ( ToneMode != (TAPI_TONEMODE)0 ) && FAILED(hr) )
|
|
{
|
|
ResumeWaveMSPStream();
|
|
}
|
|
|
|
LOG((TL_TRACE, "GenerateTone - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::GenerateCustomTones
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::GenerateCustomTones(
|
|
TAPI_CUSTOMTONE * pToneList,
|
|
long lNumTones,
|
|
long lDuration
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
HCALL hCall;
|
|
|
|
LOG((TL_TRACE, "GenerateCustomTones - enter"));
|
|
|
|
if ( IsBadReadPtr( pToneList, lNumTones * sizeof(TAPI_CUSTOMTONE) ) )
|
|
{
|
|
LOG((TL_TRACE, "GenerateCustomTones - invalid pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
hCall = m_t3Call.hCall;
|
|
|
|
Unlock();
|
|
|
|
if ( NULL == hCall )
|
|
{
|
|
LOG((TL_TRACE, "GenerateCustomTones - need call first"));
|
|
|
|
return TAPI_E_INVALCALLSTATE;
|
|
}
|
|
|
|
//
|
|
// special case for wavemsp
|
|
// suspend the stream so the wave devices are closed before the
|
|
// tapi function starts. SuspendWaveMSPStream is a synchronous
|
|
// call.
|
|
//
|
|
|
|
if ( OnWaveMSPCall() )
|
|
{
|
|
SuspendWaveMSPStream();
|
|
}
|
|
|
|
hr = LineGenerateTone(
|
|
hCall,
|
|
LINETONEMODE_CUSTOM,
|
|
lDuration,
|
|
lNumTones,
|
|
(LPLINEGENERATETONE)pToneList
|
|
);
|
|
|
|
//
|
|
// For a wavemsp call, we will tell the wavemsp to resume the stream when
|
|
// we receive the digit completion event from tapisrv. However, if the
|
|
// LineGenerateTone failed synchronously, then we will never receive
|
|
// such an event, so we must resume the stream now.
|
|
//
|
|
|
|
if ( OnWaveMSPCall() && FAILED(hr) )
|
|
{
|
|
ResumeWaveMSPStream();
|
|
}
|
|
|
|
LOG((TL_TRACE, "GenerateCustomTones - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::GenerateCustomTonesByCollection
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::GenerateCustomTonesByCollection(
|
|
ITCollection2 * pCustomToneCollection,
|
|
long lDuration
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
TAPI_CUSTOMTONE * pToneList = NULL;
|
|
long lNumTones = 0;
|
|
long lCount;
|
|
|
|
LOG((TL_TRACE, "GenerateCustomTonesByCollection - enter"));
|
|
|
|
if ( IsBadReadPtr( pCustomToneCollection, sizeof(ITCollection2) ) )
|
|
{
|
|
LOG((TL_ERROR, "GenerateCustomTonesByCollection - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Find out how many items are in the collection and allocate an appropriately
|
|
// sized data structure
|
|
//
|
|
|
|
hr = pCustomToneCollection->get_Count(&lCount);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "GenerateCustomTonesByCollection - get_Count failed - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
pToneList = (TAPI_CUSTOMTONE *)ClientAlloc( lCount * sizeof(TAPI_CUSTOMTONE) );
|
|
|
|
if ( NULL == pToneList )
|
|
{
|
|
LOG((TL_ERROR, "GenerateCustomTonesByCollection - out of memory"));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Go through collection
|
|
//
|
|
|
|
for ( int i = 1; i <= lCount; i++ )
|
|
{
|
|
ITCustomTone * pCustomTone;
|
|
IDispatch * pDisp;
|
|
VARIANT var;
|
|
|
|
hr = pCustomToneCollection->get_Item(i, &var);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_WARN, "GenerateCustomTonesByCollection - get_Item failed - %lx", hr));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// get the IDispatch pointer out of the variant
|
|
//
|
|
|
|
try
|
|
{
|
|
if ( var.vt != VT_DISPATCH )
|
|
{
|
|
LOG((TL_WARN, "GenerateCustomTonesByCollection - expected VT_DISPATCH"));
|
|
|
|
continue;
|
|
}
|
|
|
|
pDisp = V_DISPATCH(&var);
|
|
}
|
|
catch(...)
|
|
{
|
|
LOG((TL_WARN, "GenerateCustomTonesByCollection - bad variant"));
|
|
|
|
continue;
|
|
}
|
|
|
|
if ( IsBadReadPtr( pDisp, sizeof(IDispatch) ) )
|
|
{
|
|
LOG((TL_WARN, "GenerateCustomTonesByCollection - bad pointer"));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Query for the ITDetectTone interface
|
|
//
|
|
|
|
hr = pDisp->QueryInterface( IID_ITCustomTone, (void **) &pCustomTone );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_WARN, "GenerateCustomTonesByCollection - QI failed - %lx", hr));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Fill in the data structure with information from ITDetectTone
|
|
//
|
|
|
|
pCustomTone->get_CadenceOff((long *)&pToneList[lNumTones].dwCadenceOff);
|
|
pCustomTone->get_CadenceOn((long *)&pToneList[lNumTones].dwCadenceOn);
|
|
pCustomTone->get_Frequency((long *)&pToneList[lNumTones].dwFrequency);
|
|
pCustomTone->get_Volume((long *)&pToneList[lNumTones].dwVolume);
|
|
|
|
LOG((TL_INFO, "GenerateCustomTonesByCollection - **** Tone %d ****", lNumTones));
|
|
LOG((TL_INFO, "GenerateCustomTonesByCollection - CadenceOff %d", pToneList[lNumTones].dwCadenceOff));
|
|
LOG((TL_INFO, "GenerateCustomTonesByCollection - CadenceOn %d", pToneList[lNumTones].dwCadenceOn));
|
|
LOG((TL_INFO, "GenerateCustomTonesByCollection - Frequency %d", pToneList[lNumTones].dwFrequency));
|
|
LOG((TL_INFO, "GenerateCustomTonesByCollection - Volume %d", pToneList[lNumTones].dwVolume));
|
|
|
|
lNumTones++;
|
|
|
|
pCustomTone->Release();
|
|
}
|
|
|
|
hr = GenerateCustomTones( pToneList, lNumTones, lDuration );
|
|
|
|
LOG((TL_TRACE, "GenerateCustomTonesByCollection - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::CreateDetectToneObject
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::CreateDetectToneObject(
|
|
ITDetectTone ** ppDetectTone
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "CreateDetectToneObject enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( ppDetectTone, sizeof( ITDetectTone * ) ) )
|
|
{
|
|
LOG((TL_ERROR, "CreateDetectToneObject - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
// Initialize the return value in case we fail
|
|
*ppDetectTone = NULL;
|
|
|
|
CComObject< CDetectTone > * p;
|
|
hr = CComObject< CDetectTone >::CreateInstance( &p );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
LOG((TL_ERROR, "CreateDetectToneObject - could not create CDetectTone" ));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// get the ITDetectTone interface
|
|
hr = p->QueryInterface( IID_ITDetectTone, (void **) ppDetectTone );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "CreateDetectToneObject - could not get IDispatch interface" ));
|
|
|
|
delete p;
|
|
return hr;
|
|
}
|
|
|
|
LOG((TL_TRACE, "CreateDetectToneObject - exit - return %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::CreateCustomToneObject
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::CreateCustomToneObject(
|
|
ITCustomTone ** ppCustomTone
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "CreateCustomToneObject enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( ppCustomTone, sizeof( ITCustomTone * ) ) )
|
|
{
|
|
LOG((TL_ERROR, "CreateCustomToneObject - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
// Initialize the return value in case we fail
|
|
*ppCustomTone = NULL;
|
|
|
|
CComObject< CCustomTone > * p;
|
|
hr = CComObject< CCustomTone >::CreateInstance( &p );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
LOG((TL_ERROR, "CreateCustomToneObject - could not create CCustomTone" ));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// get the ITCustomTone interface
|
|
hr = p->QueryInterface( IID_ITCustomTone, (void **) ppCustomTone );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "CreateCustomToneObject - could not get ITCustomTone interface" ));
|
|
|
|
delete p;
|
|
return hr;
|
|
}
|
|
|
|
LOG((TL_TRACE, "CreateCustomToneObject - exit - return %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::GetID
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::GetID(
|
|
BSTR pDeviceClass,
|
|
DWORD * pdwSize,
|
|
BYTE ** ppDeviceID
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPVARSTRING pVarString = NULL;
|
|
|
|
LOG((TL_TRACE, "GetID - enter"));
|
|
|
|
if ( IsBadStringPtrW( pDeviceClass, -1 ) )
|
|
{
|
|
LOG((TL_ERROR, "GetID - bad string"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ( TAPIIsBadWritePtr( pdwSize, sizeof(DWORD)))
|
|
{
|
|
LOG((TL_ERROR, "GetID - bad size"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ( TAPIIsBadWritePtr( ppDeviceID, sizeof(BYTE *) ) )
|
|
{
|
|
LOG((TL_ERROR, "GetID - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if( m_t3Call.hCall == NULL )
|
|
{
|
|
if( m_CallState == CS_IDLE )
|
|
{
|
|
LOG((TL_ERROR, "GetID - idle call, invalid call state"));
|
|
|
|
return TAPI_E_INVALCALLSTATE;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "GetID - weird call state!!!"));
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
}
|
|
|
|
hr = LineGetID(
|
|
NULL,
|
|
0,
|
|
m_t3Call.hCall,
|
|
LINECALLSELECT_CALL,
|
|
&pVarString,
|
|
pDeviceClass
|
|
);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
*ppDeviceID = (BYTE *)CoTaskMemAlloc( pVarString->dwUsedSize );
|
|
|
|
if (NULL != *ppDeviceID)
|
|
{
|
|
CopyMemory(
|
|
*ppDeviceID,
|
|
((LPBYTE)pVarString)+pVarString->dwStringOffset,
|
|
pVarString->dwStringSize
|
|
);
|
|
|
|
*pdwSize = pVarString->dwStringSize;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Check LineGetID to see if it can succeed w/o setting pVarString
|
|
ClientFree (pVarString);
|
|
}
|
|
|
|
LOG((TL_TRACE, "GetID - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::GetIDAsVariant
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP CCall::GetIDAsVariant( IN BSTR bstrDeviceClass,
|
|
OUT VARIANT *pVarDeviceID )
|
|
{
|
|
LOG((TL_TRACE, "GetIDAsVariant - enter"));
|
|
|
|
|
|
//
|
|
// did we get a good string?
|
|
//
|
|
|
|
if ( IsBadStringPtrW( bstrDeviceClass, -1 ) )
|
|
{
|
|
LOG((TL_ERROR, "GetIDAsVariant - bad string"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
//
|
|
// did we get a good variant?
|
|
//
|
|
|
|
if ( IsBadWritePtr( pVarDeviceID, sizeof(VARIANT) ) )
|
|
{
|
|
LOG((TL_ERROR, "GetIDAsVariant - bad variant pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
//
|
|
// initialize the variant
|
|
//
|
|
|
|
VariantInit(pVarDeviceID);
|
|
|
|
|
|
//
|
|
// get the buffer containing ID
|
|
//
|
|
|
|
|
|
DWORD dwDeviceIDBufferSize = 0;
|
|
|
|
BYTE *pDeviceIDBuffer = NULL;
|
|
|
|
HRESULT hr = GetID(bstrDeviceClass,
|
|
&dwDeviceIDBufferSize,
|
|
&pDeviceIDBuffer);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "GetIDAsVariant - failed to get device id. hr = %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// place device id buffer into the variant
|
|
//
|
|
|
|
hr = FillVariantFromBuffer(dwDeviceIDBufferSize,
|
|
pDeviceIDBuffer,
|
|
pVarDeviceID);
|
|
|
|
|
|
//
|
|
// succeeded, or failed, we no longer need the buffer
|
|
//
|
|
|
|
CoTaskMemFree(pDeviceIDBuffer);
|
|
pDeviceIDBuffer = NULL;
|
|
|
|
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "GetIDAsVariant - failed to put device id into a variant. hr = %lx"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// done. returning the variant that is array of bytes that contains device id.
|
|
//
|
|
|
|
LOG((TL_TRACE, "GetIDAsVariant - exit"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::SetMediaType
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::SetMediaType(long lMediaType)
|
|
{
|
|
LOG((TL_TRACE, "SetMediaType - enter"));
|
|
|
|
HRESULT hr;
|
|
|
|
Lock();
|
|
|
|
HCALL hCall = m_t3Call.hCall;
|
|
|
|
Unlock();
|
|
|
|
if ( hCall == NULL )
|
|
{
|
|
LOG((TL_ERROR, "SetMediaType - invalid hCall"));
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
hr = LineSetMediaMode( hCall, lMediaType );
|
|
|
|
LOG((TL_TRACE, "SetMediaType - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::MonitorMedia
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CCall::MonitorMedia(long lMediaType)
|
|
{
|
|
LOG((TL_TRACE, "MonitorMedia - enter"));
|
|
|
|
HRESULT hr;
|
|
|
|
Lock();
|
|
|
|
HCALL hCall = m_t3Call.hCall;
|
|
|
|
Unlock();
|
|
|
|
if ( hCall == NULL )
|
|
{
|
|
LOG((TL_ERROR, "MonitorMedia - invalid hCall"));
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
hr = lineMonitorMedia( hCall, lMediaType );
|
|
|
|
LOG((TL_TRACE, "MonitorMedia - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IDispatch implementation
|
|
//
|
|
typedef IDispatchImpl<ITCallInfo2Vtbl<CCall>, &IID_ITCallInfo2, &LIBID_TAPI3Lib> CallInfoType;
|
|
typedef IDispatchImpl<ITBasicCallControl2Vtbl<CCall>, &IID_ITBasicCallControl2, &LIBID_TAPI3Lib> BasicCallControlType;
|
|
typedef IDispatchImpl<ITLegacyCallMediaControl2Vtbl<CCall>, &IID_ITLegacyCallMediaControl2, &LIBID_TAPI3Lib> LegacyCallMediaControlType;
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::GetIDsOfNames
|
|
//
|
|
// Overide if IDispatch method
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP CCall::GetIDsOfNames(REFIID riid,
|
|
LPOLESTR* rgszNames,
|
|
UINT cNames,
|
|
LCID lcid,
|
|
DISPID* rgdispid
|
|
)
|
|
{
|
|
HRESULT hr = DISP_E_UNKNOWNNAME;
|
|
|
|
|
|
// See if the requsted method belongs to the default interface
|
|
hr = CallInfoType::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_INFO, "GetIDsOfNames - found %S on ITCallInfo", *rgszNames));
|
|
rgdispid[0] |= IDISPCALLINFO;
|
|
return hr;
|
|
}
|
|
|
|
// If not, then try the Basic Call control interface
|
|
hr = BasicCallControlType::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_INFO, "GetIDsOfNames - found %S on ITBasicCallControl", *rgszNames));
|
|
rgdispid[0] |= IDISPBASICCALLCONTROL;
|
|
return hr;
|
|
}
|
|
|
|
|
|
// If not, then try the Legacy CAll Media Control interface
|
|
hr = LegacyCallMediaControlType::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_INFO, "GetIDsOfNames - found %S on ITLegacyCallMediaControl", *rgszNames));
|
|
rgdispid[0] |= IDISPLEGACYCALLMEDIACONTROL;
|
|
return hr;
|
|
}
|
|
|
|
// If not, then try the aggregated MSP Call object
|
|
if (m_pMSPCall != NULL)
|
|
{
|
|
IDispatch *pIDispatchMSPAggCall;
|
|
|
|
m_pMSPCall->QueryInterface(IID_IDispatch, (void**)&pIDispatchMSPAggCall);
|
|
|
|
hr = pIDispatchMSPAggCall->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pIDispatchMSPAggCall->Release();
|
|
LOG((TL_INFO, "GetIDsOfNames - found %S on our aggregated MSP Call", *rgszNames));
|
|
rgdispid[0] |= IDISPAGGREGATEDMSPCALLOBJ;
|
|
return hr;
|
|
}
|
|
pIDispatchMSPAggCall->Release();
|
|
}
|
|
|
|
LOG((TL_INFO, "GetIDsOfNames - Didn't find %S on our iterfaces", *rgszNames));
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CCall::Invoke
|
|
//
|
|
// Overide if IDispatch method
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP CCall::Invoke(DISPID dispidMember,
|
|
REFIID riid,
|
|
LCID lcid,
|
|
WORD wFlags,
|
|
DISPPARAMS* pdispparams,
|
|
VARIANT* pvarResult,
|
|
EXCEPINFO* pexcepinfo,
|
|
UINT* puArgErr
|
|
)
|
|
{
|
|
HRESULT hr = DISP_E_MEMBERNOTFOUND;
|
|
DWORD dwInterface = (dispidMember & INTERFACEMASK);
|
|
|
|
|
|
LOG((TL_TRACE, "Invoke - dispidMember %X", dispidMember));
|
|
|
|
// Call invoke for the required interface
|
|
switch (dwInterface)
|
|
{
|
|
case IDISPCALLINFO:
|
|
{
|
|
hr = CallInfoType::Invoke(dispidMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
break;
|
|
}
|
|
case IDISPBASICCALLCONTROL:
|
|
{
|
|
hr = BasicCallControlType::Invoke(dispidMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
break;
|
|
}
|
|
case IDISPLEGACYCALLMEDIACONTROL:
|
|
{
|
|
hr = LegacyCallMediaControlType::Invoke(dispidMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
break;
|
|
}
|
|
case IDISPAGGREGATEDMSPCALLOBJ:
|
|
{
|
|
IDispatch *pIDispatchMSPAggCall = NULL;
|
|
|
|
if (m_pMSPCall != NULL)
|
|
{
|
|
m_pMSPCall->QueryInterface(IID_IDispatch, (void**)&pIDispatchMSPAggCall);
|
|
|
|
hr = pIDispatchMSPAggCall->Invoke(dispidMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
|
|
pIDispatchMSPAggCall->Release();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
} // end switch (dwInterface)
|
|
|
|
|
|
LOG((TL_TRACE, hr, "Invoke - exit" ));
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// HandleAcceptToAlert
|
|
//
|
|
// Handler for PRIVATE_ISDN__ACCEPTTOALERT message
|
|
// This is processed on the callback thread to do a lineAccept on an offering
|
|
// ISDN call that requires Accept before it will ring. Bug 335566
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void HandleAcceptToAlert( PASYNCEVENTMSG pParams )
|
|
{
|
|
HRESULT hr;
|
|
HCALL hCall = (HCALL) pParams->hDevice;
|
|
|
|
|
|
hr = LineAccept( hCall, NULL, 0 );
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = WaitForReply(hr);
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_INFO, hr, "HandleAcceptToAlert - lineAccept failed async"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, hr, "HandleAcceptToAlert - lineAccept failed sync"));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// OnOffering()
|
|
//
|
|
// If it's an offering call & the TSP requires a lineAccept to start ringing
|
|
// (typically an ISDN feature) then we queue a message to the callback thread
|
|
// to do the lineAccept. We can't do it here because this is processed on
|
|
// the async thread & as lineAccept is an async fucion we would deadlock
|
|
// while waiting for the async reply. Bug 335566
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::OnOffering()
|
|
{
|
|
LOG((TL_TRACE, "OnOffering - enter" ));
|
|
|
|
HRESULT hr = S_FALSE;
|
|
LONG lCap;
|
|
ASYNCEVENTMSG Msg;
|
|
|
|
if (m_pAddress != NULL)
|
|
{
|
|
hr = m_pAddress->get_AddressCapability( AC_ADDRESSCAPFLAGS, &lCap );
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if ( (lCap & LINEADDRCAPFLAGS_ACCEPTTOALERT) && (CP_OWNER == m_CallPrivilege) )
|
|
{
|
|
|
|
LOG((TL_TRACE, "OnOffering - queueing PRIVATE_ISDN__ACCEPTTOALERT message."));
|
|
|
|
|
|
// Build an msg to queue to the callback thread
|
|
Msg.Msg = PRIVATE_ISDN__ACCEPTTOALERT;
|
|
Msg.TotalSize = sizeof (ASYNCEVENTMSG);
|
|
Msg.hDevice = (ULONG_PTR) m_t3Call.hCall;
|
|
Msg.Param1 = 0;
|
|
Msg.Param2 = 0;
|
|
Msg.Param3 = 0;
|
|
|
|
QueueCallbackEvent( &Msg );
|
|
|
|
// Set the Call flag
|
|
m_dwCallFlags |= CALLFLAG_ACCEPTTOALERT;
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
LOG((TL_TRACE, "OnOffering - exit. hr = %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// CObjectSafeImpl. since we have aggregates, implement this method
|
|
//
|
|
// return non delegating iunkown of the first aggregated object
|
|
// that supports the interface
|
|
//
|
|
|
|
HRESULT CCall::QIOnAggregates(REFIID riid, IUnknown **ppNonDelegatingUnknown)
|
|
{
|
|
|
|
//
|
|
// argument check
|
|
//
|
|
|
|
if ( TAPIIsBadWritePtr(ppNonDelegatingUnknown, sizeof(IUnknown*)) )
|
|
{
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// if we fail, at least return consistent values
|
|
//
|
|
|
|
*ppNonDelegatingUnknown = NULL;
|
|
|
|
|
|
//
|
|
// see if mspcall or private support the interface riid
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
Lock();
|
|
|
|
if (m_pMSPCall)
|
|
{
|
|
|
|
//
|
|
// does mspcall expose this interface?
|
|
//
|
|
|
|
IUnknown *pUnk = NULL;
|
|
|
|
hr = m_pMSPCall->QueryInterface(riid, (void**)&pUnk);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
pUnk->Release();
|
|
pUnk = NULL;
|
|
|
|
//
|
|
// return the mspcall's non-delegating unknown
|
|
//
|
|
|
|
*ppNonDelegatingUnknown = m_pMSPCall;
|
|
(*ppNonDelegatingUnknown)->AddRef();
|
|
}
|
|
}
|
|
|
|
if ( FAILED(hr) && m_pPrivate )
|
|
{
|
|
|
|
//
|
|
// bad luck with mspcall? still have a chance with private
|
|
//
|
|
|
|
IUnknown *pUnk = NULL;
|
|
|
|
hr = m_pPrivate->QueryInterface(riid, (void**)&pUnk);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pUnk->Release();
|
|
pUnk = NULL;
|
|
|
|
*ppNonDelegatingUnknown = m_pPrivate;
|
|
(*ppNonDelegatingUnknown)->AddRef();
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
// ITBasicCallControl2
|
|
|
|
/*++
|
|
RequestTerminal
|
|
|
|
ITBasicCallControl2::CreateTerminal() method
|
|
|
|
If bstrTerminalClassGUID is CLSID_NULL then
|
|
we'll try to create the default dynamic terminals
|
|
--*/
|
|
STDMETHODIMP CCall::RequestTerminal(
|
|
IN BSTR bstrTerminalClassGUID,
|
|
IN long lMediaType,
|
|
IN TERMINAL_DIRECTION Direction,
|
|
OUT ITTerminal** ppTerminal
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "RequestTerminal - enter" ));
|
|
|
|
//
|
|
// Validates arguments
|
|
//
|
|
|
|
if( IsBadStringPtrW( bstrTerminalClassGUID, (UINT)-1) )
|
|
{
|
|
LOG((TL_ERROR, "RequestTerminal - exit "
|
|
" bstrTerminalClassGUID invalid, returns E_INVALIDARG"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if( TAPIIsBadWritePtr( ppTerminal, sizeof(ITTerminal*)) )
|
|
{
|
|
LOG((TL_ERROR, "RequestTerminal - exit "
|
|
" ppTerminal invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Determines if is a static terminal or a dynamic one
|
|
// For static terminal bstrTerminalClassGUID should have one
|
|
// of the following values
|
|
// CLSID_NULL {00000000-0000-0000-0000-000000000000}
|
|
// CLSID_MicrophoneTerminal
|
|
// CLSID_SpeakersTerminal
|
|
// CLSID_VideoInputTerminal
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if( IsStaticGUID( bstrTerminalClassGUID ))
|
|
{
|
|
// Create a static terminal
|
|
LOG((TL_INFO, "RequestTerminal -> StaticTerminal" ));
|
|
|
|
hr = CreateStaticTerminal(
|
|
bstrTerminalClassGUID,
|
|
Direction,
|
|
lMediaType,
|
|
ppTerminal);
|
|
}
|
|
else
|
|
{
|
|
// Create a dynamic terminal
|
|
LOG((TL_INFO, "RequestTerminal -> DynamicTerminal" ));
|
|
hr = CreateDynamicTerminal(
|
|
bstrTerminalClassGUID,
|
|
Direction,
|
|
lMediaType,
|
|
ppTerminal);
|
|
}
|
|
|
|
//
|
|
// Return value
|
|
//
|
|
|
|
LOG((TL_TRACE, "RequestTerminal - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CCall::SelectTerminalOnCall(
|
|
IN ITTerminal *pTerminal
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "SelectTerminalOnCall - enter" ));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if( IsBadReadPtr( pTerminal, sizeof(ITTerminal)) )
|
|
{
|
|
LOG((TL_ERROR, "SelectTerminalOnCall - exit "
|
|
" pTerminal invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Just a HRESULT
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//
|
|
// Is a single or multi track terminal
|
|
//
|
|
|
|
ITMultiTrackTerminal* pMultiTrack = NULL;
|
|
hr = pTerminal->QueryInterface(
|
|
IID_ITMultiTrackTerminal,
|
|
(void**)&pMultiTrack);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
//
|
|
// SingleTrack terminal
|
|
//
|
|
|
|
LOG((TL_TRACE, "SelectTerminalOnCall - SingleTrack terminal" ));
|
|
|
|
long lMediaType = 0;
|
|
TERMINAL_DIRECTION Direction =TD_NONE;
|
|
|
|
hr = SelectSingleTerminalOnCall(
|
|
pTerminal,
|
|
&lMediaType,
|
|
&Direction);
|
|
|
|
LOG((TL_TRACE, "SelectTerminalOnCall - "
|
|
"SelectSingleTerminalOnCall exit with 0x%08x", hr));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Multitrack terminal
|
|
//
|
|
|
|
|
|
hr = SelectMultiTerminalOnCall(
|
|
pMultiTrack);
|
|
|
|
LOG((TL_TRACE, "SelectTerminalOnCall - "
|
|
"SelectMultiTerminalOnCall failed"));
|
|
}
|
|
|
|
//
|
|
// Clean-up
|
|
//
|
|
|
|
if( pMultiTrack )
|
|
{
|
|
pMultiTrack->Release();
|
|
}
|
|
|
|
LOG((TL_TRACE, "SelectTerminalOnCall - exit 0x%08x", hr ));
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CCall::UnselectTerminalOnCall(
|
|
IN ITTerminal *pTerminal
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "UnselectTerminalOnCall - enter" ));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if( IsBadReadPtr( pTerminal, sizeof(ITTerminal)) )
|
|
{
|
|
LOG((TL_ERROR, "UnselectTerminalOnCall - exit "
|
|
" pTerminal invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Just a HRESULT
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//
|
|
// Is a single or multi track terminal
|
|
//
|
|
|
|
ITMultiTrackTerminal* pMultiTrack = NULL;
|
|
hr = pTerminal->QueryInterface(
|
|
IID_ITMultiTrackTerminal,
|
|
(void**)&pMultiTrack);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
//
|
|
// SingleTrack terminal
|
|
//
|
|
|
|
LOG((TL_INFO, "UnselectTerminalOnCall - SingleTrack terminal" ));
|
|
|
|
hr = UnSelectSingleTerminalFromCall(
|
|
pTerminal);
|
|
|
|
LOG((TL_INFO, "UnselectTerminalOnCall - "
|
|
"UnSelectSingleTerminalFromCall exit 0x%08x", hr));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Multitrack terminal
|
|
//
|
|
|
|
LOG((TL_INFO, "UnselectTerminalOnCall - MultiTrack terminal" ));
|
|
|
|
hr = UnSelectMultiTerminalFromCall(
|
|
pMultiTrack);
|
|
|
|
LOG((TL_INFO, "UnselectTerminalOnCall - "
|
|
"UnSelectMultiTerminalOnCall exit 0x%08x", hr));
|
|
}
|
|
|
|
//
|
|
// Clean-up
|
|
//
|
|
|
|
if( pMultiTrack )
|
|
{
|
|
pMultiTrack->Release();
|
|
}
|
|
|
|
LOG((TL_TRACE, "UnselectTerminalOnCall - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*++
|
|
SelectSingleTerminalOnCall
|
|
|
|
Select pTerminal on a right stream
|
|
pMediaType - if *pMediatype is 0 the we have just to return the media type
|
|
pDirection - if pDirection is TD_NONE we have just to return the direction
|
|
--*/
|
|
HRESULT CCall::SelectSingleTerminalOnCall(
|
|
IN ITTerminal* pTerminal,
|
|
OUT long* pMediaType,
|
|
OUT TERMINAL_DIRECTION* pDirection)
|
|
{
|
|
LOG((TL_TRACE, "SelectSingleTerminalOnCall - Enter" ));
|
|
|
|
//
|
|
// Validate terminal pointer
|
|
//
|
|
|
|
if( IsBadReadPtr( pTerminal, sizeof(ITTerminal)))
|
|
{
|
|
LOG((TL_ERROR, "SelectSingleTerminalOnCall - exit "
|
|
"pTerminal invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Is terminal in use?
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
TERMINAL_STATE state = TS_INUSE;
|
|
pTerminal->get_State( &state );
|
|
|
|
if( TS_INUSE == state )
|
|
{
|
|
LOG((TL_ERROR, "SelectSingleTerminalOnCall - exit "
|
|
"terminal IN USE, returns E_UNEXPECTED"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// Get ITStreamControl interface
|
|
//
|
|
|
|
ITStreamControl* pStreamControl = NULL;
|
|
pStreamControl = GetStreamControl();
|
|
|
|
if( NULL == pStreamControl )
|
|
{
|
|
LOG((TL_ERROR, "SelectSingleTerminalOnCall - exit "
|
|
" GetStreamControl failed, returns E_UNEXPECTED"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// Get streams
|
|
//
|
|
|
|
IEnumStream * pEnumStreams = NULL;
|
|
|
|
hr = pStreamControl->EnumerateStreams(&pEnumStreams);
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
|
|
pStreamControl->Release();
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "SelectSingleTerminalOnCall - exit "
|
|
" EnumerateStreams failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Find the right stream
|
|
//
|
|
|
|
ITStream * pStream = NULL;
|
|
hr = E_FAIL;
|
|
|
|
while ( S_OK == pEnumStreams->Next(1, &pStream, NULL) )
|
|
{
|
|
//
|
|
// Find out the media type and direction of this stream,
|
|
// and compare with pTerminal.
|
|
//
|
|
|
|
hr = IsRightStream(
|
|
pStream,
|
|
pTerminal,
|
|
pMediaType,
|
|
pDirection
|
|
);
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
hr = pStream->SelectTerminal( pTerminal );
|
|
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_TRACE, "SelectSingleTerminalOnCall - "
|
|
"pStream->SelectTerminal failed. 0x%08x",hr));
|
|
|
|
// Clean-up
|
|
pStream->Release();
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Clean-up
|
|
pStream->Release();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clean-up
|
|
//
|
|
|
|
pStream->Release();
|
|
}
|
|
|
|
//
|
|
// Clean-up
|
|
//
|
|
|
|
pEnumStreams->Release();
|
|
|
|
LOG((TL_TRACE, "SelectSingleTerminalOnCall - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
SelectMultiTerminalOnCall
|
|
|
|
It's a complict algorithm to describe it here
|
|
See specs
|
|
--*/
|
|
HRESULT CCall::SelectMultiTerminalOnCall(
|
|
IN ITMultiTrackTerminal* pMultiTerminal)
|
|
{
|
|
LOG((TL_TRACE, "SelectMultiTerminalOnCall - enter" ));
|
|
|
|
//
|
|
// Get tracks
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
IEnumTerminal* pEnumTerminals = NULL;
|
|
hr = pMultiTerminal->EnumerateTrackTerminals(&pEnumTerminals);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "SelectMultiTerminalOnCall - exit "
|
|
"EnumerateTrackTerminals failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
ITTerminal* pTerm = NULL;
|
|
hr = pMultiTerminal->QueryInterface(
|
|
IID_ITTerminal,
|
|
(void**)&pTerm);
|
|
if( FAILED(hr) )
|
|
{
|
|
//Clean-up
|
|
pEnumTerminals->Release();
|
|
|
|
LOG((TL_ERROR, "SelectMultiTerminalOnCall - exit "
|
|
"QI for Terminal failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
long nTermMediaTypes = 0;
|
|
hr = pTerm->get_MediaType( &nTermMediaTypes );
|
|
if( FAILED(hr) )
|
|
{
|
|
//Clean-up
|
|
pEnumTerminals->Release();
|
|
pTerm->Release();
|
|
|
|
LOG((TL_ERROR, "SelectMultiTerminalOnCall - exit "
|
|
"get_MediaType failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
pTerm->Release();
|
|
|
|
//
|
|
// Inner struct
|
|
//
|
|
|
|
typedef struct tagSTREAMINFO
|
|
{
|
|
TERMINAL_DIRECTION Direction;
|
|
long lMediaType;
|
|
BOOL bSelected;
|
|
} STREAMINFO;
|
|
|
|
//
|
|
// Find tracks unused and select them
|
|
// on the right stream
|
|
|
|
ITTerminal * pTerminal = NULL;
|
|
STREAMINFO StreamsInfo[4] = {
|
|
{TD_RENDER, TAPIMEDIATYPE_AUDIO, FALSE},
|
|
{TD_RENDER, TAPIMEDIATYPE_VIDEO, FALSE},
|
|
{TD_CAPTURE, TAPIMEDIATYPE_AUDIO, FALSE},
|
|
{TD_CAPTURE, TAPIMEDIATYPE_VIDEO, FALSE}
|
|
};
|
|
|
|
//
|
|
// +++ FIXBUG 92559 +++
|
|
//
|
|
|
|
BOOL bSelectAtLeastOne = FALSE;
|
|
LOG((TL_INFO, "SelectMultiTerminalOnCall - FIRST LOOP ENTER"));
|
|
while ( S_OK == pEnumTerminals->Next(1, &pTerminal, NULL) )
|
|
{
|
|
//
|
|
// Select track on the right stream
|
|
//
|
|
|
|
long lMediaType = 0;
|
|
TERMINAL_DIRECTION Direction = TD_NONE;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
LOG((TL_INFO, "SelectMultiTerminalOnCall - FIRST LOOP IN"));
|
|
hr = SelectSingleTerminalOnCall(
|
|
pTerminal,
|
|
&lMediaType,
|
|
&Direction);
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
LOG((TL_TRACE, "SelectMultiTerminalOnCall - "
|
|
"select terminal on stream (%ld, %ld)", lMediaType, Direction));
|
|
|
|
int nIndex = GetStreamIndex(
|
|
lMediaType,
|
|
Direction);
|
|
|
|
if( nIndex != STREAM_NONE )
|
|
{
|
|
StreamsInfo[nIndex].bSelected = TRUE;
|
|
}
|
|
|
|
bSelectAtLeastOne = TRUE;
|
|
}
|
|
|
|
// Clean-up
|
|
pTerminal->Release();
|
|
}
|
|
LOG((TL_INFO, "SelectMultiTerminalOnCall - FIRST LOOP EXIT"));
|
|
|
|
//
|
|
// Clean-up
|
|
//
|
|
pEnumTerminals->Release();
|
|
|
|
BOOL bCreateAtLeastOne = FALSE;
|
|
|
|
//
|
|
// Let's create a terminal for unselected streams
|
|
//
|
|
|
|
LOG((TL_INFO, "SelectMultiTerminalOnCall - SECOND LOOP ENTER"));
|
|
for(int nStream = STREAM_RENDERAUDIO; nStream < STREAM_NONE; nStream++)
|
|
{
|
|
LOG((TL_INFO, "SelectMultiTerminalOnCall - SECOND LOOP IN"));
|
|
|
|
if( StreamsInfo[ nStream ].bSelected)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( (StreamsInfo[ nStream ].lMediaType & nTermMediaTypes)==0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Unselected stream
|
|
//
|
|
|
|
LOG((TL_INFO, "SelectMultiTerminalOnCall - SECOND LOOP REALYIN"));
|
|
|
|
HRESULT hr = E_FAIL;
|
|
ITTerminal* pTerminal = NULL;
|
|
hr = pMultiTerminal->CreateTrackTerminal(
|
|
StreamsInfo[ nStream ].lMediaType,
|
|
StreamsInfo[ nStream ].Direction,
|
|
&pTerminal);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "SelectMultiTerminalOnCall - "
|
|
"create terminal on stream (%ld, %ld) failed",
|
|
StreamsInfo[ nStream ].lMediaType,
|
|
StreamsInfo[ nStream ].Direction));
|
|
}
|
|
else
|
|
{
|
|
long lMediaType = StreamsInfo[ nStream ].lMediaType;
|
|
TERMINAL_DIRECTION Direction = StreamsInfo[ nStream ].Direction;
|
|
hr = SelectSingleTerminalOnCall(
|
|
pTerminal,
|
|
&lMediaType,
|
|
&Direction);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_INFO, "SelectMultiTerminalOnCall - "
|
|
"select terminal on stream (%ld, %ld) failed",
|
|
StreamsInfo[ nStream ].lMediaType,
|
|
StreamsInfo[ nStream ].Direction));
|
|
|
|
pMultiTerminal->RemoveTrackTerminal( pTerminal );
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "SelectMultiTerminalOnCall - SelectSingleTerminal SUCCEEDED"));
|
|
bCreateAtLeastOne = TRUE;
|
|
}
|
|
|
|
// Clean-up
|
|
pTerminal->Release();
|
|
}
|
|
}
|
|
LOG((TL_INFO, "SelectMultiTerminalOnCall - SECOND LOOP EXIT"));
|
|
|
|
if( bSelectAtLeastOne )
|
|
{
|
|
LOG((TL_INFO, "SelectMultiTerminalOnCall - "
|
|
"Select at least one existing track terminal"));
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
if( bCreateAtLeastOne )
|
|
{
|
|
LOG((TL_ERROR, "SelectMultiTerminalOnCall - "
|
|
"Create and select at least one track terminal"));
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "SelectMultiTerminalOnCall - "
|
|
"Create and/or select no track terminal"));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
LOG((TL_TRACE, "SelectMultiTerminalOnCall - exit 0X%08X", hr ));
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CCall::IsRightStream(
|
|
IN ITStream* pStream,
|
|
IN ITTerminal* pTerminal,
|
|
OUT long* pMediaType/*= NULL*/,
|
|
OUT TERMINAL_DIRECTION* pDirection/*=NULL*/)
|
|
{
|
|
LOG((TL_TRACE, "IsRightStream - enter" ));
|
|
|
|
if( NULL == pStream )
|
|
{
|
|
LOG((TL_ERROR, "IsRightStream - exit "
|
|
"pStream failed, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
HRESULT hr = E_FAIL;
|
|
long lMediaStream, lMediaTerminal;
|
|
TERMINAL_DIRECTION DirStream, DirTerminal;
|
|
|
|
//
|
|
// Determine the media type and direction of this stream.
|
|
//
|
|
|
|
hr = pStream->get_MediaType( &lMediaStream );
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "IsRightStream - exit "
|
|
"IStream::get_MediaType failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
hr = pStream->get_Direction( &DirStream );
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "IsRightStream - exit "
|
|
"IStream::get_Direction failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Determine the media type and direction of this terminal.
|
|
//
|
|
|
|
hr = pTerminal->get_MediaType( &lMediaTerminal );
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "IsRightStream - exit "
|
|
"ITTerminal::get_MediaType failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
hr = pTerminal->get_Direction( &DirTerminal );
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "IsRightStream - exit "
|
|
"ITTerminal::get_Direction failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Compare the media types supported
|
|
//
|
|
|
|
if ( (0 == (lMediaTerminal & lMediaStream)) /*||
|
|
(*pMediaType != 0 && *pMediaType != lMediaStream)*/ )
|
|
{
|
|
LOG((TL_ERROR, "IsRightStream - exit "
|
|
"media types unmatched, returns E_FAIL (S=0x%08x,T=0x%08x)",
|
|
lMediaStream, lMediaTerminal));
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Compare directions
|
|
//
|
|
|
|
if( ( DirTerminal != DirStream) /*||
|
|
( *pDirection != TD_NONE && *pDirection != DirStream)*/)
|
|
{
|
|
LOG((TL_ERROR, "IsRightStream - exit "
|
|
"directions unmatched, returns E_FAIL (S=0x%08x,T=0x%08x)",
|
|
DirStream,DirTerminal));
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// The wants to know the media type & direction?
|
|
//
|
|
*pMediaType = lMediaStream;
|
|
*pDirection = DirStream;
|
|
|
|
LOG((TL_TRACE, "IsRightStream - exit, matched (M=0x%08x, D=0x%08x)",
|
|
*pMediaType, *pDirection));
|
|
return S_OK;
|
|
}
|
|
|
|
/*++
|
|
GetStreamIndex
|
|
--*/
|
|
int CCall::GetStreamIndex(
|
|
IN long lMediaType,
|
|
IN TERMINAL_DIRECTION Direction)
|
|
{
|
|
int nIndex = STREAM_NONE;
|
|
LOG((TL_TRACE, "GetStreamIndex - enter (%ld, %ld)", lMediaType, Direction));
|
|
|
|
if(Direction == TD_RENDER )
|
|
{
|
|
if( lMediaType == TAPIMEDIATYPE_AUDIO )
|
|
{
|
|
nIndex = STREAM_RENDERAUDIO;
|
|
}
|
|
else
|
|
{
|
|
nIndex = STREAM_RENDERVIDEO;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( lMediaType == TAPIMEDIATYPE_AUDIO )
|
|
{
|
|
nIndex = STREAM_CAPTUREAUDIO;
|
|
}
|
|
else
|
|
{
|
|
nIndex = STREAM_CAPTUREVIDEO;
|
|
}
|
|
}
|
|
|
|
LOG((TL_TRACE, "GetStreamIndex - exit %d", nIndex));
|
|
return nIndex;
|
|
}
|
|
|
|
/*++
|
|
UnSelectSingleTerminalFromCall
|
|
--*/
|
|
HRESULT CCall::UnSelectSingleTerminalFromCall(
|
|
IN ITTerminal* pTerminal)
|
|
{
|
|
LOG((TL_TRACE, "UnSelectSingleTerminalFromCall - enter" ));
|
|
|
|
//
|
|
// Get ITStreamControl interface
|
|
//
|
|
|
|
ITStreamControl* pStreamControl = NULL;
|
|
pStreamControl = GetStreamControl();
|
|
|
|
if( NULL == pStreamControl )
|
|
{
|
|
LOG((TL_ERROR, "UnSelectSingleTerminalFromCall - exit "
|
|
" GetStreamControl failed, returns E_UNEXPECTED"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// Get streams
|
|
//
|
|
|
|
IEnumStream * pEnumStreams = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
hr = pStreamControl->EnumerateStreams(&pEnumStreams);
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
|
|
pStreamControl->Release();
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "UnSelectSingleTerminalFromCall - exit "
|
|
"EnumerateStreams failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Find the right stream
|
|
//
|
|
|
|
ITStream * pStream = NULL;
|
|
hr = TAPI_E_INVALIDTERMINAL;
|
|
|
|
while ( S_OK == pEnumStreams->Next(1, &pStream, NULL) )
|
|
{
|
|
//
|
|
// Unselect terminal
|
|
//
|
|
|
|
hr = pStream->UnselectTerminal(
|
|
pTerminal);
|
|
|
|
//
|
|
// Clean-up
|
|
//
|
|
|
|
pStream->Release();
|
|
|
|
LOG((TL_INFO, "UnSelectSingleTerminalFromCall - "
|
|
"pStream->UnselectTerminal returns 0x%08x", hr));
|
|
|
|
if( hr == S_OK)
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Clean-up
|
|
//
|
|
|
|
pEnumStreams->Release();
|
|
|
|
LOG((TL_TRACE, "UnSelectSingleTerminalFromCall - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
UnSelectMultiTerminalFromCall
|
|
--*/
|
|
HRESULT CCall::UnSelectMultiTerminalFromCall(
|
|
IN ITMultiTrackTerminal* pMultiTerminal)
|
|
{
|
|
LOG((TL_TRACE, "UnSelectMultiTerminalFromCall - enter" ));
|
|
|
|
//
|
|
// Get tracks
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
IEnumTerminal* pEnumTerminals = NULL;
|
|
hr = pMultiTerminal->EnumerateTrackTerminals(&pEnumTerminals);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "UnSelectMultiTerminalFromCall - exit "
|
|
"EnumerateTrackTerminals failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Find tracks and unselect them
|
|
//
|
|
|
|
ITTerminal * pTerminal = NULL;
|
|
HRESULT hrUnselect = S_OK; // The return HR
|
|
BOOL bOnStream = FALSE; // If we have a track on stream
|
|
|
|
while ( S_OK == pEnumTerminals->Next(1, &pTerminal, NULL) )
|
|
{
|
|
LOG((TL_INFO, "UnSelectMultiTerminalFromCall - NextTerminalBegin "));
|
|
|
|
//
|
|
// Try to find out if the terminal
|
|
// was selected on a stream
|
|
//
|
|
|
|
BOOL bSelected = FALSE;
|
|
HRESULT hr = IsTerminalSelected(
|
|
pTerminal,
|
|
&bSelected
|
|
);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
hrUnselect = hr;
|
|
pTerminal->Release();
|
|
|
|
LOG((TL_INFO, "UnSelectMultiTerminalFromCall - "
|
|
"IsTerminalSelected failed all method will failed hrUnselect=0x%08x",
|
|
hrUnselect));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// The terminal wasn't selected?
|
|
//
|
|
|
|
if( !bSelected )
|
|
{
|
|
//
|
|
// The terminal wasn't selected
|
|
// goto the next terminal
|
|
//
|
|
|
|
LOG((TL_INFO, "UnSelectMultiTerminalFromCall - "
|
|
"the terminal wasn't selected on a stream, "
|
|
"goto the next terminal hrUnselect=0x%08x",
|
|
hrUnselect));
|
|
|
|
pTerminal->Release();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We have an terminal on stream
|
|
//
|
|
|
|
bOnStream = TRUE;
|
|
|
|
//
|
|
// The terminal was selected on stream
|
|
// try to unselect terminal
|
|
//
|
|
|
|
hr = UnSelectSingleTerminalFromCall(
|
|
pTerminal
|
|
);
|
|
|
|
//
|
|
// Unselection failed?
|
|
//
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
//
|
|
// Event this unselection failed
|
|
// try to unselect the other terminals
|
|
// so go to the next terminal
|
|
//
|
|
|
|
hrUnselect = hr;
|
|
|
|
LOG((TL_INFO, "UnSelectMultiTerminalFromCall - "
|
|
"the terminal wasn't unselected from the stream, "
|
|
"goto the next terminal hrUnselect=0x%08x",
|
|
hrUnselect));
|
|
|
|
pTerminal->Release();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Unselection succeded
|
|
// Leave the hrUnselected as it was before
|
|
// we start the loop with hrUnselect=S_OK
|
|
// if a previous terminal failed
|
|
// we already have setted on FAIL the hrUnselect
|
|
// Goto the next terminal
|
|
//
|
|
|
|
pTerminal->Release();
|
|
|
|
LOG((TL_INFO, "UnSelectMultiTerminalFromCall - NextTerminalEnd hrUnselect=0x%08x", hrUnselect));
|
|
}
|
|
|
|
//
|
|
// Clean-up
|
|
//
|
|
pEnumTerminals->Release();
|
|
|
|
//
|
|
// If we don't have track on streams
|
|
// this is realy bad
|
|
//
|
|
if( !bOnStream )
|
|
{
|
|
hrUnselect = E_FAIL;
|
|
}
|
|
|
|
hr = hrUnselect;
|
|
|
|
LOG((TL_TRACE, "UnSelectMultiTerminalFromCall - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
IsStaticGUID
|
|
|
|
Is caleled by RequestTerminal
|
|
Determines if the GUID represents a static terminal
|
|
or a dynamic one
|
|
--*/
|
|
BOOL CCall::IsStaticGUID(
|
|
BSTR bstrTerminalGUID)
|
|
{
|
|
LOG((TL_TRACE, "IsStaticGUID - enter" ));
|
|
|
|
BOOL bStatic = FALSE;
|
|
|
|
//
|
|
// Get the CLSID from bstrTerminalGUID
|
|
//
|
|
|
|
CLSID clsidTerminal;
|
|
HRESULT hr = E_FAIL;
|
|
hr = CLSIDFromString( bstrTerminalGUID, &clsidTerminal );
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "IsStaticGUID - exit "
|
|
"CLSIDFromString failed, returns FALSE"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Is clsidTerminal a 'static terminal' CLSID?
|
|
//
|
|
|
|
if( (clsidTerminal == CLSID_NULL) ||
|
|
(clsidTerminal == CLSID_MicrophoneTerminal) ||
|
|
(clsidTerminal == CLSID_SpeakersTerminal) ||
|
|
(clsidTerminal == CLSID_VideoInputTerminal))
|
|
{
|
|
bStatic = TRUE;
|
|
}
|
|
|
|
LOG((TL_TRACE, "IsStaticGUID - exit (%d)", bStatic));
|
|
return bStatic;
|
|
}
|
|
|
|
/*++
|
|
CreateStaticTerminal
|
|
|
|
Called by RequestTerminal
|
|
--*/
|
|
HRESULT CCall::CreateStaticTerminal(
|
|
IN BSTR bstrTerminalClassGUID,
|
|
IN TERMINAL_DIRECTION Direction,
|
|
IN long lMediaType,
|
|
OUT ITTerminal** ppTerminal
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "CreateStaticTerminal - enter"));
|
|
|
|
//
|
|
// Helper method, the argument should be valid
|
|
//
|
|
|
|
_ASSERTE( bstrTerminalClassGUID );
|
|
_ASSERTE( *pTerminal );
|
|
|
|
//
|
|
// Get ITTerminalSupport interface
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
ITTerminalSupport* pSupport = NULL;
|
|
|
|
hr = m_pAddress->QueryInterface(
|
|
IID_ITTerminalSupport,
|
|
(void**)&pSupport);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "CreateStaticTerminal - exit"
|
|
"QueryInterface for ITTerminalSupport failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get terminal CLSID from BSTR
|
|
//
|
|
|
|
CLSID clsidTerminal = CLSID_NULL;
|
|
hr = CLSIDFromString( bstrTerminalClassGUID, &clsidTerminal );
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
// Cleanup
|
|
pSupport->Release();
|
|
|
|
LOG((TL_ERROR, "CreateStaticTerminal - exit"
|
|
"CLSIDFromString failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Is CLSID matching with lMediaType and Direction?
|
|
//
|
|
|
|
if( clsidTerminal != CLSID_NULL )
|
|
{
|
|
if( clsidTerminal == CLSID_MicrophoneTerminal &&
|
|
((lMediaType != TAPIMEDIATYPE_AUDIO) || (Direction != TD_CAPTURE)))
|
|
{
|
|
// Cleanup
|
|
pSupport->Release();
|
|
|
|
LOG((TL_ERROR, "CreateStaticTerminal - exit"
|
|
"CLSID_MicrophoneTerminal unmatched, returns E_UNEXPECTED"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
if( clsidTerminal == CLSID_SpeakersTerminal &&
|
|
((lMediaType != TAPIMEDIATYPE_AUDIO) || (Direction != TD_RENDER)))
|
|
{
|
|
// Cleanup
|
|
pSupport->Release();
|
|
|
|
LOG((TL_ERROR, "CreateStaticTerminal - exit"
|
|
"CLSID_SpeakersTerminal unmatched, returns E_UNEXPECTED"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
if( clsidTerminal == CLSID_VideoInputTerminal &&
|
|
((lMediaType != TAPIMEDIATYPE_VIDEO) || (Direction != TD_CAPTURE)))
|
|
{
|
|
// Cleanup
|
|
pSupport->Release();
|
|
|
|
LOG((TL_ERROR, "CreateStaticTerminal - exit"
|
|
"CLSID_VideoInputTerminal unmatched, returns E_UNEXPECTED"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Shouldn't be the Dynamic terminal media type and direction
|
|
if((lMediaType == TAPIMEDIATYPE_VIDEO) && (Direction == TD_RENDER))
|
|
{
|
|
// Cleanup
|
|
pSupport->Release();
|
|
|
|
LOG((TL_ERROR, "CreateStaticTerminal - exit"
|
|
"try to create a dynamic terminal, returns E_UNEXPECTED"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Cool, let's create the terminal
|
|
//
|
|
|
|
LOG((TL_INFO, "CreateStaticTerminal -> "
|
|
"ITterminalSupport::GetDefaultStaticTerminal"));
|
|
|
|
hr = pSupport->GetDefaultStaticTerminal(
|
|
lMediaType,
|
|
Direction,
|
|
ppTerminal);
|
|
|
|
//
|
|
// Clean-up ITTerminalSupport interface
|
|
//
|
|
|
|
pSupport->Release();
|
|
|
|
LOG((TL_TRACE, "CreateStaticTerminal - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
CreateDynamicTerminal
|
|
|
|
Called by RequestTerminal
|
|
--*/
|
|
HRESULT CCall::CreateDynamicTerminal(
|
|
IN BSTR bstrTerminalClassGUID,
|
|
IN TERMINAL_DIRECTION Direction,
|
|
IN long lMediaType,
|
|
OUT ITTerminal** ppTerminal
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "CreateDynamicTerminal - enter"));
|
|
|
|
//
|
|
// Helper method, the argument should be valid
|
|
//
|
|
|
|
_ASSERTE( bstrTerminalClassGUID );
|
|
_ASSERTE( *pTerminal );
|
|
|
|
//
|
|
// Get ITTerminalSupport interface
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
ITTerminalSupport* pSupport = NULL;
|
|
|
|
hr = m_pAddress->QueryInterface(
|
|
IID_ITTerminalSupport,
|
|
(void**)&pSupport);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "CreateDynamicTerminal - exit"
|
|
"QueryInterface for ITTerminalSupport failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Create dynamic terminal
|
|
//
|
|
|
|
LOG((TL_INFO, "CreateDynamicTerminal -> "
|
|
"ITTerminalSupport::CreateTerminal"));
|
|
|
|
hr = pSupport->CreateTerminal(
|
|
bstrTerminalClassGUID,
|
|
lMediaType,
|
|
Direction,
|
|
ppTerminal);
|
|
|
|
//
|
|
// Clean-up ITTerminalSupport interface
|
|
//
|
|
|
|
pSupport->Release();
|
|
|
|
LOG((TL_TRACE, "CreateDynamicTerminal - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCall
|
|
// Interface : ITCallInfo2
|
|
// Method : put_FilterEvent
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::put_EventFilter(
|
|
TAPI_EVENT TapiEvent,
|
|
long lSubEvent,
|
|
VARIANT_BOOL bEnable
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "put_EventFilter - enter"));
|
|
|
|
// Enter critical section
|
|
Lock();
|
|
|
|
//
|
|
// Validates the pair TapiEvent - lSubEvent
|
|
// Accept 'allsubevents'
|
|
//
|
|
if( !m_EventMasks.IsSubEventValid( TapiEvent, lSubEvent, TRUE, TRUE) )
|
|
{
|
|
LOG((TL_ERROR, "put_EventFilter - "
|
|
"This event can't be set: %x, return E_INVALIDARG", TapiEvent ));
|
|
|
|
// Leave critical section
|
|
Unlock();
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// Let's set the flag
|
|
HRESULT hr = E_FAIL;
|
|
hr = SetSubEventFlag(
|
|
TapiEvent,
|
|
lSubEvent,
|
|
(bEnable == VARIANT_TRUE)
|
|
);
|
|
|
|
// Leave critical section
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_EventFilter - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCall
|
|
// Interface : ITCallInfo2
|
|
// Method : get_FilterEvent
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CCall::get_EventFilter(
|
|
TAPI_EVENT TapiEvent,
|
|
long lSubEvent,
|
|
VARIANT_BOOL* pEnable
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_EventFilter - enter"));
|
|
|
|
//
|
|
// Validates output argument
|
|
//
|
|
if( IsBadReadPtr(pEnable, sizeof(VARIANT_BOOL)) )
|
|
{
|
|
LOG((TL_ERROR, "get_EventFilter - "
|
|
"invalid VARIANT_BOOL pointer , return E_POINTER" ));
|
|
return E_POINTER;
|
|
}
|
|
|
|
// Enter critical section
|
|
Lock();
|
|
|
|
//
|
|
// Validates the pair TapiEvent - lSubEvent
|
|
// Don't accept 'allsubevents'
|
|
//
|
|
|
|
if( !m_EventMasks.IsSubEventValid( TapiEvent, lSubEvent, FALSE, TRUE) )
|
|
{
|
|
LOG((TL_ERROR, "get_EventFilter - "
|
|
"This event can't be set: %x, return E_INVALIDARG", TapiEvent ));
|
|
|
|
// Leave critical section
|
|
Unlock();
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Get the subevent mask for that (event, subevent) pair
|
|
//
|
|
|
|
BOOL bEnable = FALSE;
|
|
HRESULT hr = GetSubEventFlag(
|
|
TapiEvent,
|
|
(DWORD)lSubEvent,
|
|
&bEnable);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_EventFilter - "
|
|
"GetSubEventFlag failed, return 0x%08x", hr ));
|
|
|
|
// Leave critical section
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Set the output argument
|
|
//
|
|
|
|
*pEnable = bEnable ? VARIANT_TRUE : VARIANT_FALSE;
|
|
|
|
// Leave critical section
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_EventFilter - exit S_OK"));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// SetSubEventFlag
|
|
// It is calle by CAddress::SetSubEventFlagToCalls()
|
|
// Sets the subevent flag
|
|
//
|
|
|
|
HRESULT CCall::SetSubEventFlag(
|
|
IN TAPI_EVENT TapiEvent,
|
|
IN DWORD dwSubEvent,
|
|
IN BOOL bEnable
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "SetSubEventFlag - enter"));
|
|
|
|
//
|
|
// Set the flag for that (event,subevent) pair
|
|
//
|
|
HRESULT hr = E_FAIL;
|
|
hr = m_EventMasks.SetSubEventFlag(
|
|
TapiEvent,
|
|
dwSubEvent,
|
|
bEnable);
|
|
|
|
LOG((TL_TRACE, "SetSubEventFlag - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
GetSubEventFlag
|
|
|
|
It is called by get_EventFilter() method
|
|
--*/
|
|
HRESULT CCall::GetSubEventFlag(
|
|
TAPI_EVENT TapiEvent,
|
|
DWORD dwSubEvent,
|
|
BOOL* pEnable
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "GetSubEventFlag enter" ));
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//
|
|
// Get the subevent falg
|
|
//
|
|
hr = m_EventMasks.GetSubEventFlag(
|
|
TapiEvent,
|
|
dwSubEvent,
|
|
pEnable
|
|
);
|
|
|
|
LOG((TL_TRACE, "GetSubEventFlag exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
GetSubEventsMask
|
|
--*/
|
|
DWORD CCall::GetSubEventsMask(
|
|
IN TAPI_EVENT TapiEvent
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "GetSubEventsMask - enter"));
|
|
|
|
DWORD dwSubEventFlag = m_EventMasks.GetSubEventMask(
|
|
TapiEvent
|
|
);
|
|
|
|
LOG((TL_TRACE, "GetSubEventsMask - exit %ld", dwSubEventFlag));
|
|
return dwSubEventFlag;
|
|
}
|
|
|
|
|
|
HRESULT CCall::IsTerminalSelected(
|
|
IN ITTerminal* pTerminal,
|
|
OUT BOOL* pSelected
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "IsTerminalSelected - enter"));
|
|
|
|
// Initialize
|
|
*pSelected = FALSE;
|
|
HRESULT hr = E_FAIL;
|
|
long nMTTerminal = TAPIMEDIATYPE_AUDIO;
|
|
TERMINAL_DIRECTION DirTerminal = TD_CAPTURE;
|
|
|
|
// Get media type
|
|
hr = pTerminal->get_MediaType(&nMTTerminal);
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "IsTerminalSelected - get_MediaType failed. Exit 0x%08x, %d", hr, *pSelected));
|
|
return hr;
|
|
}
|
|
|
|
// Get direction
|
|
hr = pTerminal->get_Direction(&DirTerminal);
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "IsTerminalSelected - get_Direction failed. Exit %0x%08x, %d", hr, *pSelected));
|
|
return hr;
|
|
}
|
|
|
|
LOG((TL_INFO, "IsTerminalSelected - MT=%d, Dir=%d",
|
|
nMTTerminal, DirTerminal));
|
|
|
|
// Get stream control
|
|
ITStreamControl* pStreamControl = NULL;
|
|
pStreamControl = GetStreamControl();
|
|
|
|
if( NULL == pStreamControl )
|
|
{
|
|
LOG((TL_ERROR, "IsTerminalSelected - exit "
|
|
" GetStreamControl failed, returns E_UNEXPECTED, %d", *pSelected));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//Enumerate streams
|
|
IEnumStream* pStreams = NULL;
|
|
hr = pStreamControl->EnumerateStreams(&pStreams);
|
|
pStreamControl->Release();
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "IsTerminalSelected - exit "
|
|
" EnumerateStreams failed, returns 0x%08x, %d",hr, *pSelected));
|
|
return hr;
|
|
}
|
|
|
|
// Parse the enumeration
|
|
ITStream* pStream = NULL;
|
|
ULONG ulFetched = 0;
|
|
while( S_OK == pStreams->Next(1, &pStream, &ulFetched))
|
|
{
|
|
// Get media type for the stream
|
|
long nMTStream = TAPIMEDIATYPE_AUDIO;
|
|
hr = pStream->get_MediaType(&nMTStream);
|
|
if( FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "IsTerminalSelected - exit "
|
|
" get_MediaType failed, returns 0x%08x, %d",hr, *pSelected));
|
|
return hr;
|
|
}
|
|
|
|
// Get direction for stream
|
|
TERMINAL_DIRECTION DirStream = TD_CAPTURE;
|
|
hr = pStream->get_Direction(&DirStream);
|
|
if( FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "IsTerminalSelected - exit "
|
|
" get_MediaType failed, returns 0x%08x, %d",hr, *pSelected));
|
|
|
|
pStream->Release();
|
|
pStreams->Release();
|
|
return hr;
|
|
}
|
|
|
|
// The stream is matching with the terminal?
|
|
if( (nMTTerminal!=nMTStream) || (DirTerminal!=DirStream) )
|
|
{
|
|
pStream->Release();
|
|
continue; //Go to the next stream
|
|
}
|
|
|
|
// We are on the right stream
|
|
// enumerate the terminals
|
|
IEnumTerminal* pTerminals = NULL;
|
|
hr = pStream->EnumerateTerminals( &pTerminals);
|
|
if( FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "IsTerminalSelected - exit "
|
|
" EnumerateTerminals failed, returns 0x%08x, %d",hr, *pSelected));
|
|
|
|
pStream->Release();
|
|
pStreams->Release();
|
|
return hr;
|
|
}
|
|
|
|
// Clean-up
|
|
pStream->Release();
|
|
|
|
// Parse the terminals
|
|
ITTerminal* pTerminalStream = NULL;
|
|
ULONG ulTerminal = 0;
|
|
while(S_OK==pTerminals->Next(1, &pTerminalStream, &ulTerminal))
|
|
{
|
|
if( pTerminal == pTerminalStream)
|
|
{
|
|
*pSelected = TRUE;
|
|
pTerminalStream->Release();
|
|
break;
|
|
}
|
|
|
|
pTerminalStream->Release();
|
|
}
|
|
|
|
// Clean-up
|
|
pTerminals->Release();
|
|
break;
|
|
}
|
|
|
|
// Clean-up streams
|
|
pStreams->Release();
|
|
|
|
LOG((TL_TRACE, "IsTerminalSelected - exit S_OK Selected=%d", *pSelected));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
Method:
|
|
GetConfControlCall
|
|
|
|
Parameters:
|
|
None.
|
|
|
|
Return Value:
|
|
Conference controller call object associated with this call.
|
|
|
|
Remarks:
|
|
None.
|
|
|
|
--*/
|
|
|
|
CCall*
|
|
CCall::GetConfControlCall(void)
|
|
{
|
|
CCall* pConfContCall = NULL;
|
|
|
|
Lock();
|
|
|
|
//
|
|
// NikhilB: Call object has a reference to Callhub object so its safe to
|
|
// lock the callhub object before locking the call. This is to avoid a
|
|
// deadlock that happens dur to locking the call and the callhub in reverse
|
|
// orders in different functions.
|
|
//
|
|
|
|
if( m_pCallHub != NULL )
|
|
{
|
|
m_pCallHub->AddRef();
|
|
AddRef();
|
|
|
|
Unlock();
|
|
|
|
// lock the callhub object before locking the call
|
|
m_pCallHub->Lock();
|
|
Lock();
|
|
|
|
Release();
|
|
m_pCallHub->Release();
|
|
|
|
pConfContCall = m_pCallHub ->GetConferenceControllerCall();
|
|
|
|
m_pCallHub->Unlock();
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return pConfContCall;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CDetectTone
|
|
// Interface : ITDetectTone
|
|
// Method : put_AppSpecific
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CDetectTone::put_AppSpecific( long lAppSpecific )
|
|
{
|
|
LOG((TL_TRACE, "put_AppSpecific - enter"));
|
|
|
|
Lock();
|
|
|
|
m_lAppSpecific = lAppSpecific;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_AppSpecific - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CDetectTone
|
|
// Interface : ITDetectTone
|
|
// Method : get_AppSpecific
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CDetectTone::get_AppSpecific( long * plAppSpecific )
|
|
{
|
|
LOG((TL_TRACE, "get_AppSpecific - enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( plAppSpecific, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_AppSpecific - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
*plAppSpecific = m_lAppSpecific;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_AppSpecific - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CDetectTone
|
|
// Interface : ITDetectTone
|
|
// Method : put_Duration
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CDetectTone::put_Duration( long lDuration )
|
|
{
|
|
LOG((TL_TRACE, "put_Duration - enter"));
|
|
|
|
Lock();
|
|
|
|
m_lDuration = lDuration;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_Duration - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CDetectTone
|
|
// Interface : ITDetectTone
|
|
// Method : get_Duration
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CDetectTone::get_Duration( long * plDuration )
|
|
{
|
|
LOG((TL_TRACE, "get_Duration - enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( plDuration, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Duration - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
*plDuration = m_lDuration;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_Duration - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CDetectTone
|
|
// Interface : ITDetectTone
|
|
// Method : put_Frequency
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CDetectTone::put_Frequency(
|
|
long Index,
|
|
long lFrequency
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "put_Frequency - enter"));
|
|
|
|
if ( (Index < 1) || (Index > 3))
|
|
{
|
|
LOG((TL_ERROR, "put_Frequency - invalid index"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Lock();
|
|
|
|
m_lFrequency[Index - 1] = lFrequency;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_Frequency - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CDetectTone
|
|
// Interface : ITDetectTone
|
|
// Method : get_Frequency
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CDetectTone::get_Frequency(
|
|
long Index,
|
|
long * plFrequency
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_Frequency - enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( plFrequency, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Frequency - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ( (Index < 1) || (Index > 3))
|
|
{
|
|
LOG((TL_ERROR, "get_Frequency - invalid index"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Lock();
|
|
|
|
*plFrequency = m_lFrequency[Index - 1];
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_Frequency - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCustomTone
|
|
// Interface : ITCustomTone
|
|
// Method : put_Frequency
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CCustomTone::put_Frequency( long lFrequency )
|
|
{
|
|
LOG((TL_TRACE, "put_Frequency - enter"));
|
|
|
|
Lock();
|
|
|
|
m_lFrequency = lFrequency;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_Frequency - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCustomTone
|
|
// Interface : ITCustomTone
|
|
// Method : get_Frequency
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CCustomTone::get_Frequency( long * plFrequency )
|
|
{
|
|
LOG((TL_TRACE, "get_Frequency - enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( plFrequency, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Frequency - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
*plFrequency = m_lFrequency;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_Frequency - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCustomTone
|
|
// Interface : ITCustomTone
|
|
// Method : put_CadenceOn
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CCustomTone::put_CadenceOn( long lCadenceOn )
|
|
{
|
|
LOG((TL_TRACE, "put_CadenceOn - enter"));
|
|
|
|
Lock();
|
|
|
|
m_lCadenceOn = lCadenceOn;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_CadenceOn - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCustomTone
|
|
// Interface : ITCustomTone
|
|
// Method : get_CadenceOn
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CCustomTone::get_CadenceOn( long * plCadenceOn )
|
|
{
|
|
LOG((TL_TRACE, "get_CadenceOn - enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( plCadenceOn, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_CadenceOn - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
*plCadenceOn = m_lCadenceOn;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_CadenceOn - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCustomTone
|
|
// Interface : ITCustomTone
|
|
// Method : put_CadenceOff
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CCustomTone::put_CadenceOff( long lCadenceOff )
|
|
{
|
|
LOG((TL_TRACE, "put_CadenceOff - enter"));
|
|
|
|
Lock();
|
|
|
|
m_lCadenceOff = lCadenceOff;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_CadenceOff - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCustomTone
|
|
// Interface : ITCustomTone
|
|
// Method : get_CadenceOff
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CCustomTone::get_CadenceOff( long * plCadenceOff )
|
|
{
|
|
LOG((TL_TRACE, "get_CadenceOff - enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( plCadenceOff, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_CadenceOff - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
*plCadenceOff = m_lCadenceOff;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_CadenceOff - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCustomTone
|
|
// Interface : ITCustomTone
|
|
// Method : put_Volume
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CCustomTone::put_Volume( long lVolume )
|
|
{
|
|
LOG((TL_TRACE, "put_Volume - enter"));
|
|
|
|
Lock();
|
|
|
|
m_lVolume = lVolume;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_Volume - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CCustomTone
|
|
// Interface : ITCustomTone
|
|
// Method : get_CadenceOff
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT CCustomTone::get_Volume( long * plVolume )
|
|
{
|
|
LOG((TL_TRACE, "get_Volume - enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( plVolume, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Volume - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
*plVolume = m_lVolume;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_Volume - exit - S_OK"));
|
|
|
|
return S_OK;
|
|
}
|