You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
531 lines
12 KiB
531 lines
12 KiB
/*******************************************************************************
|
|
|
|
Module: bridge.cpp
|
|
|
|
Author: Qianbo Huai
|
|
|
|
Abstract:
|
|
|
|
implements the class CBridge
|
|
|
|
*******************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
#include "work.h"
|
|
|
|
extern LPSTR glpCmdLine;
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
hard coded SDP
|
|
////*/
|
|
const WCHAR * const MySDP = L"\
|
|
v=0\n\
|
|
o=qhuai 0 0 IN IP4 157.55.89.115\n\
|
|
s=BridgeTestConf\n\
|
|
c=IN IP4 239.9.20.26/15\n\
|
|
t=0 0\n\
|
|
m=video 20000 RTP/AVP 34 31\n\
|
|
m=audio 20040 RTP/AVP 0 4\n\
|
|
";
|
|
|
|
const WCHAR * const MySDP2 = L"\
|
|
v=0\n\
|
|
o=qhuai 0 0 IN IP4 157.55.89.115\n\
|
|
s=BridgeTestConf2\n\
|
|
c=IN IP4 239.9.20.26/15\n\
|
|
t=0 0\n\
|
|
m=video 20000 RTP/AVP 34 31\n\
|
|
m=audio 20040 RTP/AVP 3\n\
|
|
";
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
initiates tapi and listens at h323 address
|
|
////*/
|
|
HRESULT
|
|
CBridge::InitTapi ()
|
|
{
|
|
HRESULT hr;
|
|
|
|
// init members
|
|
m_pTapi = NULL;
|
|
m_pH323Addr = NULL;
|
|
m_pSDPAddr = NULL;
|
|
m_pBridgeCall = new CBridgeCall (this);
|
|
|
|
// create tapi
|
|
hr = CoCreateInstance (
|
|
CLSID_TAPI,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ITTAPI,
|
|
(LPVOID *)&m_pTapi
|
|
);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// tapi initiate
|
|
hr = m_pTapi->Initialize ();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// associate event with listener
|
|
CTAPIEventNotification *pEventNotif = NULL;
|
|
IConnectionPointContainer *pContainer = NULL;
|
|
IConnectionPoint *pPoint = NULL;
|
|
IH323LineEx *pIH323LineEx = NULL;
|
|
ULONG ulTapiEventAdvise;
|
|
long lCallNotif;
|
|
BSTR bstrAddrName = NULL;
|
|
|
|
// create event notification
|
|
pEventNotif = new CTAPIEventNotification;
|
|
if (!pEventNotif)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
}
|
|
|
|
// get pointer container from tapi
|
|
hr = m_pTapi->QueryInterface (
|
|
IID_IConnectionPointContainer,
|
|
(void **)&pContainer
|
|
);
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
// get connection point from container
|
|
hr = pContainer->FindConnectionPoint (
|
|
IID_ITTAPIEventNotification,
|
|
&pPoint
|
|
);
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
// advise event notification on connection pointer
|
|
hr = pPoint->Advise (
|
|
pEventNotif,
|
|
&ulTapiEventAdvise
|
|
);
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
// put event filter on tapi
|
|
hr = m_pTapi->put_EventFilter (
|
|
TE_CALLNOTIFICATION |
|
|
TE_CALLSTATE |
|
|
TE_CALLMEDIA |
|
|
TE_PRIVATE
|
|
);
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
// find h323 address
|
|
bstrAddrName = SysAllocString (L"H323 Line");
|
|
hr = FindAddress (
|
|
0,
|
|
bstrAddrName,
|
|
TAPIMEDIATYPE_AUDIO,
|
|
&m_pH323Addr
|
|
);
|
|
SysFreeString (bstrAddrName);
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
// check if it supports video
|
|
BOOL fSupportsVideo;
|
|
|
|
if (AddressSupportsMediaType (m_pH323Addr, TAPIMEDIATYPE_VIDEO))
|
|
m_lH323MediaType = TAPIMEDIATYPE_AUDIO | TAPIMEDIATYPE_VIDEO;
|
|
else
|
|
m_lH323MediaType = TAPIMEDIATYPE_AUDIO;
|
|
|
|
hr = m_pH323Addr->QueryInterface(&pIH323LineEx);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pIH323LineEx->SetExternalT120Address(TRUE, INADDR_ANY, 1503);
|
|
|
|
H245_CAPABILITY Capabilities[] =
|
|
{HC_G711, HC_G723, HC_H263QCIF, HC_H261QCIF};
|
|
DWORD Weights[] = {200, 100, 100, 0};
|
|
|
|
hr = pIH323LineEx->SetDefaultCapabilityPreferrence(
|
|
4, Capabilities, Weights
|
|
);
|
|
}
|
|
|
|
// register call notification
|
|
hr = m_pTapi->RegisterCallNotifications (
|
|
m_pH323Addr,
|
|
VARIANT_TRUE,
|
|
VARIANT_TRUE,
|
|
m_lH323MediaType,
|
|
ulTapiEventAdvise,
|
|
&lCallNotif
|
|
);
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
// find sdp address
|
|
hr = FindAddress (
|
|
LINEADDRESSTYPE_SDP,
|
|
NULL,
|
|
TAPIMEDIATYPE_AUDIO,
|
|
&m_pSDPAddr
|
|
);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// check if it supports video
|
|
if (AddressSupportsMediaType (m_pSDPAddr, TAPIMEDIATYPE_VIDEO))
|
|
m_lSDPMediaType = TAPIMEDIATYPE_AUDIO | TAPIMEDIATYPE_VIDEO;
|
|
else
|
|
m_lSDPMediaType = TAPIMEDIATYPE_AUDIO;
|
|
|
|
Cleanup:
|
|
if (pEventNotif)
|
|
pEventNotif->Release ();
|
|
if (pPoint)
|
|
pPoint->Release ();
|
|
if (pContainer)
|
|
pContainer->Release ();
|
|
if (pIH323LineEx)
|
|
pIH323LineEx->Release ();
|
|
|
|
return hr;
|
|
|
|
Error:
|
|
if (m_pH323Addr)
|
|
{
|
|
m_pH323Addr->Release ();
|
|
m_pH323Addr = NULL;
|
|
}
|
|
if (m_pSDPAddr)
|
|
{
|
|
m_pSDPAddr->Release ();
|
|
m_pSDPAddr = NULL;
|
|
}
|
|
if (m_pTapi)
|
|
{
|
|
m_pTapi->Release ();
|
|
m_pTapi = NULL;
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
////*/
|
|
void
|
|
CBridge::ShutdownTapi ()
|
|
{
|
|
if (m_pBridgeCall)
|
|
{
|
|
delete m_pBridgeCall;
|
|
m_pBridgeCall = NULL;
|
|
}
|
|
|
|
if (m_pSDPAddr)
|
|
{
|
|
m_pSDPAddr->Release ();
|
|
m_pSDPAddr = NULL;
|
|
}
|
|
if (m_pH323Addr)
|
|
{
|
|
m_pH323Addr->Release ();
|
|
m_pH323Addr = NULL;
|
|
}
|
|
if (m_pTapi)
|
|
{
|
|
m_pTapi->Release ();
|
|
m_pTapi = NULL;
|
|
}
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
create h323 call from event
|
|
////*/
|
|
HRESULT
|
|
CBridge::CreateH323Call (IDispatch *pEvent)
|
|
{
|
|
HRESULT hr;
|
|
|
|
ITCallNotificationEvent *pNotify = NULL;
|
|
CALL_PRIVILEGE privilege;
|
|
ITCallInfo *pCallInfo = NULL;
|
|
ITBasicCallControl *pCall = NULL;
|
|
|
|
// get call event interface
|
|
hr = pEvent->QueryInterface (
|
|
IID_ITCallNotificationEvent,
|
|
(void **)&pNotify
|
|
);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// get call info
|
|
hr = pNotify->get_Call (&pCallInfo);
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
// if we own the call
|
|
hr = pCallInfo->get_Privilege (&privilege);
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
if (CP_OWNER!=privilege)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// get basic call control
|
|
hr = pCallInfo->QueryInterface (
|
|
IID_ITBasicCallControl,
|
|
(void **)&pCall
|
|
);
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
m_pBridgeCall->SetH323Call (pCall);
|
|
|
|
Cleanup:
|
|
if (pCall)
|
|
{
|
|
pCall->Release ();
|
|
pCall = NULL;
|
|
}
|
|
if (pCallInfo)
|
|
{
|
|
pCallInfo->Release ();
|
|
pCallInfo = NULL;
|
|
}
|
|
if (pNotify)
|
|
{
|
|
pNotify->Release ();
|
|
pNotify = NULL;
|
|
}
|
|
return hr;
|
|
|
|
Error:
|
|
goto Cleanup;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
////*/
|
|
BOOL
|
|
CBridge::HasH323Call ()
|
|
{
|
|
return m_pBridgeCall->HasH323Call ();
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
iterates through tapi, find an address and create a sdp call
|
|
////*/
|
|
HRESULT
|
|
CBridge::CreateSDPCall ()
|
|
{
|
|
HRESULT hr;
|
|
|
|
// create call, ignore bstrDestAddr, hardcode it here
|
|
ITBasicCallControl *pCall = NULL;
|
|
BSTR bstrFixedDest;
|
|
|
|
if (glpCmdLine[0] == '\0')
|
|
bstrFixedDest = SysAllocString (MySDP);
|
|
else
|
|
bstrFixedDest = SysAllocString (MySDP2);
|
|
|
|
hr = m_pSDPAddr->CreateCall (
|
|
bstrFixedDest, // bstrDestAddr,
|
|
LINEADDRESSTYPE_SDP,
|
|
m_lSDPMediaType,
|
|
&pCall
|
|
);
|
|
SysFreeString (bstrFixedDest);
|
|
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
m_pBridgeCall->SetSDPCall (pCall);
|
|
pCall->Release ();
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
bridges h323 and sdp calls
|
|
////*/
|
|
HRESULT
|
|
CBridge::BridgeCalls ()
|
|
{
|
|
HRESULT hr;
|
|
|
|
return m_pBridgeCall->BridgeCalls ();
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
returns to same state as just initializing tapi
|
|
////*/
|
|
void
|
|
CBridge::Clear ()
|
|
{
|
|
m_pBridgeCall->Clear ();
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
if the address type is given, find an address based on
|
|
address type and media type
|
|
else if address name is given, find an address based on
|
|
address name and media type
|
|
else
|
|
return E_FAIL
|
|
////*/
|
|
HRESULT
|
|
CBridge::FindAddress (
|
|
long dwAddrType,
|
|
BSTR bstrAddrName,
|
|
long lMediaType,
|
|
ITAddress **ppAddr
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
IEnumAddress *pEnumAddr = NULL;
|
|
ITAddress *pAddr = NULL;
|
|
ITAddressCapabilities *pAddrCaps = NULL;
|
|
|
|
BOOL fFound = false;
|
|
long lTypeFound;
|
|
BSTR bstrAddrNameFound = NULL;
|
|
|
|
// clear output address
|
|
if ((*ppAddr))
|
|
{
|
|
(*ppAddr)->Release ();
|
|
(*ppAddr) = NULL;
|
|
}
|
|
|
|
// enumerate the address
|
|
hr = m_pTapi->EnumerateAddresses (&pEnumAddr);
|
|
if (FAILED(hr))
|
|
{
|
|
DoMessage (L"Failed to enumerate address");
|
|
goto Error;
|
|
}
|
|
// loop to find the right address
|
|
while (!fFound)
|
|
{
|
|
// next address
|
|
if (pAddr)
|
|
{
|
|
pAddr->Release ();
|
|
pAddr = NULL;
|
|
}
|
|
hr = pEnumAddr->Next (1, &pAddr, NULL);
|
|
if (S_OK != hr)
|
|
break;
|
|
|
|
if (dwAddrType != 0)
|
|
{
|
|
// addr type is valid, ignore addr name
|
|
if (pAddrCaps)
|
|
{
|
|
pAddrCaps->Release ();
|
|
pAddrCaps = NULL;
|
|
}
|
|
hr = pAddr->QueryInterface (
|
|
IID_ITAddressCapabilities,
|
|
(void **)&pAddrCaps
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
DoMessage (L"Failed to retrieve address capabilities");
|
|
goto Error;
|
|
}
|
|
|
|
// find address type supported
|
|
hr = pAddrCaps->get_AddressCapability (AC_ADDRESSTYPES, &lTypeFound);
|
|
if (FAILED(hr))
|
|
{
|
|
DoMessage (L"Failed to get address type");
|
|
goto Error;
|
|
}
|
|
|
|
// check if the type we wanted
|
|
if (dwAddrType != lTypeFound)
|
|
continue;
|
|
}
|
|
else if (bstrAddrName != NULL)
|
|
{
|
|
hr = pAddr->get_AddressName (&bstrAddrNameFound);
|
|
if (FAILED(hr))
|
|
{
|
|
DoMessage (L"Failed to get address name");
|
|
goto Error;
|
|
}
|
|
if (wcscmp(bstrAddrName, bstrAddrNameFound) != 0)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
DoMessage (L"Both address type and name are null. Internal error");
|
|
hr = E_UNEXPECTED;
|
|
goto Error;
|
|
}
|
|
|
|
// now check media type
|
|
if (AddressSupportsMediaType (pAddr, lMediaType))
|
|
fFound = true;
|
|
} // end of while (!fFound)
|
|
|
|
if (fFound)
|
|
{
|
|
(*ppAddr) = pAddr;
|
|
(*ppAddr)->AddRef ();
|
|
}
|
|
|
|
Cleanup:
|
|
if (pAddrCaps)
|
|
pAddrCaps->Release ();
|
|
if (pAddr)
|
|
pAddr->Release ();
|
|
if (pEnumAddr)
|
|
pEnumAddr->Release ();
|
|
return hr;
|
|
|
|
Error:
|
|
goto Cleanup;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
checks if the address supports the media type
|
|
////*/
|
|
BOOL
|
|
CBridge::AddressSupportsMediaType (ITAddress *pAddr, long lMediaType)
|
|
{
|
|
VARIANT_BOOL vbSupport = VARIANT_FALSE;
|
|
ITMediaSupport * pMediaSupport;
|
|
|
|
if (SUCCEEDED(pAddr->QueryInterface (IID_ITMediaSupport, (void**)&pMediaSupport)))
|
|
{
|
|
pMediaSupport->QueryMediaType (lMediaType, &vbSupport);
|
|
pMediaSupport->Release ();
|
|
}
|
|
return (vbSupport==VARIANT_TRUE);
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
////*/
|
|
HRESULT
|
|
CBridge::GetSDPAddress (ITAddress **ppAddress)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (*ppAddress)
|
|
{
|
|
(*ppAddress)->Release ();
|
|
*ppAddress = NULL;
|
|
}
|
|
|
|
*ppAddress = m_pSDPAddr;
|
|
m_pSDPAddr->AddRef ();
|
|
return S_OK;
|
|
}
|