|
|
/*******************************************************************************
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; }
|