Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1191 lines
30 KiB

/*******************************************************************************
Module Name:
bgapp.cpp
Abstract:
Implements class CBridgeApp
Author:
Qianbo Huai (qhuai) Jan 27 2000
*******************************************************************************/
#include "stdafx.h"
#include <bridge.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\
";
WCHAR *SelfAlias = L"Conference";
/*//////////////////////////////////////////////////////////////////////////////
initiates tapi and listens at h323 address
////*/
CBridgeApp::CBridgeApp (HRESULT *phr)
{
ENTER_FUNCTION ("CBridgeApp::CBridgeApp");
LOG ((BG_TRACE, "%s entered", __fxName));
*phr = S_OK;
// init members
m_pTapi = NULL;
m_pH323Addr = NULL;
m_pSDPAddr = NULL;
m_pList = new CBridgeItemList ();
if (NULL == m_pList)
{
*phr = E_FAIL;
return;
}
// create tapi
*phr = CoCreateInstance (
CLSID_TAPI,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITTAPI,
(LPVOID *)&m_pTapi
);
if (FAILED(*phr))
return;
// tapi initiate
*phr = m_pTapi->Initialize ();
if (FAILED(*phr))
return;
// 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)
{
*phr = E_OUTOFMEMORY;
goto Error;
}
// get pointer container from tapi
*phr = m_pTapi->QueryInterface (
IID_IConnectionPointContainer,
(void **)&pContainer
);
if (FAILED(*phr))
goto Error;
// get connection point from container
*phr = pContainer->FindConnectionPoint (
IID_ITTAPIEventNotification,
&pPoint
);
if (FAILED(*phr))
goto Error;
// advise event notification on connection pointer
*phr = pPoint->Advise (
pEventNotif,
&ulTapiEventAdvise
);
if (FAILED(*phr))
goto Error;
// put event filter on tapi
*phr = m_pTapi->put_EventFilter (
TE_CALLNOTIFICATION |
TE_CALLSTATE |
TE_CALLMEDIA |
TE_PRIVATE
);
if (FAILED(*phr))
goto Error;
// find h323 address
bstrAddrName = SysAllocString (L"H323 Line");
*phr = FindAddress (
0,
bstrAddrName,
TAPIMEDIATYPE_AUDIO,
&m_pH323Addr
);
SysFreeString (bstrAddrName);
if (FAILED(*phr))
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;
*phr = m_pH323Addr->QueryInterface(&pIH323LineEx);
if (SUCCEEDED(*phr))
{
*phr = pIH323LineEx->SetExternalT120Address(TRUE, INADDR_ANY, 1503);
H245_CAPABILITY Capabilities[] =
{HC_G711, HC_G723, HC_H263QCIF, HC_H261QCIF};
DWORD Weights[] = {200, 100, 100, 0};
*phr = pIH323LineEx->SetDefaultCapabilityPreferrence(
4, Capabilities, Weights
);
*phr = pIH323LineEx->SetAlias (SelfAlias, wcslen (SelfAlias));
}
// register call notification
*phr = m_pTapi->RegisterCallNotifications (
m_pH323Addr,
VARIANT_TRUE,
VARIANT_TRUE,
m_lH323MediaType,
ulTapiEventAdvise,
&lCallNotif
);
if (FAILED(*phr))
goto Error;
// find sdp address
*phr = FindAddress (
LINEADDRESSTYPE_SDP,
NULL,
TAPIMEDIATYPE_AUDIO,
&m_pSDPAddr
);
if (FAILED(*phr))
goto Error;
// 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 ();
LOG ((BG_TRACE, "%s returns", __fxName));
return;
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;
}
if (m_pList)
{
delete m_pList;
}
goto Cleanup;
}
/*//////////////////////////////////////////////////////////////////////////////
////*/
CBridgeApp::~CBridgeApp ()
{
if (m_pList)
{
// all calls should already been disconnected
delete m_pList;
}
if (m_pSDPAddr)
{
m_pSDPAddr->Release ();
}
if (m_pH323Addr)
{
m_pH323Addr->Release ();
}
if (m_pTapi)
{
m_pTapi->Release ();
}
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::CreateH323Call (IDispatch *pEvent)
{
ENTER_FUNCTION ("CBridgeApp::CreateH323Call");
LOG ((BG_TRACE, "%s entered", __fxName));
HRESULT hr;
BSTR bstrID = NULL;
BSTR bstrName = NULL;
BSTR CallerIDNumber = NULL;
ITCallNotificationEvent *pNotify = NULL;
ITCallInfo *pCallInfo = NULL;
ITBasicCallControl *pCallControl = NULL;
IUnknown *pIUnknown = NULL;
CBridgeItem *pItem = NULL;
// check privilege
CALL_PRIVILEGE privilege;
// 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 Error;
}
// get call info string
hr = pCallInfo->get_CallInfoString(CIS_CALLERIDNAME, &bstrName);
if (FAILED (hr))
goto Error;
hr = pCallInfo->get_CallInfoString(CIS_CALLERIDNUMBER, &CallerIDNumber);
if (FAILED(hr))
goto Error;
// construct the caller id
bstrID = SysAllocStringLen(NULL,
SysStringLen(bstrName) + SysStringLen(CallerIDNumber) + 2);
wsprintfW(bstrID, L"%ws@%ws", bstrName, CallerIDNumber);
hr = pCallInfo->QueryInterface (
IID_ITBasicCallControl,
(void **)&pCallControl
);
if (FAILED(hr))
goto Error;
// check if there is an item with same id
if (FAILED (hr = pCallInfo->QueryInterface (IID_IUnknown, (void**)&pIUnknown)))
goto Error;
pItem = m_pList->FindByH323 (pIUnknown);
pIUnknown->Release ();
pIUnknown = NULL;
if (NULL != pItem)
{
// @@ we are already in a call from the same ID
// @@ should have some debug info and feedback?
hr = pCallControl->Disconnect (DC_REJECTED);
// don't care the return value of diconnect
hr = E_ABORT;
goto Error;
}
// everything is right, store the call
pItem = new CBridgeItem;
if (NULL == pItem)
{
hr = E_OUTOFMEMORY;
goto Error;
}
pItem->bstrID = bstrID;
pItem->bstrName = bstrName;
pItem->pCallH323 = pCallControl;
m_pList->Append (pItem);
Cleanup:
if (pNotify) pNotify->Release ();
if (pCallInfo) pCallInfo->Release();
if (CallerIDNumber) SysFreeString(CallerIDNumber);
LOG ((BG_TRACE, "%s returns, %x", __fxName, hr));
return hr;
Error:
if (bstrID) SysFreeString (bstrID);
if (bstrName) SysFreeString (bstrName);
if (pCallControl) pCallControl->Release ();
goto Cleanup;
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::CreateSDPCall (CBridgeItem *pItem)
{
ENTER_FUNCTION ("CBridgeApp::CreateSDPCall");
LOG ((BG_TRACE, "%s entered", __fxName));
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;
// store the call
pItem->pCallSDP = pCall;
LOG ((BG_TRACE, "%s returns", __fxName));
return hr;
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::BridgeCalls (CBridgeItem *pItem)
{
ENTER_FUNCTION ("CBridgeApp::BridgeCalls");
LOG ((BG_TRACE, "%s entered", __fxName));
HRESULT hr;
hr = SetupParticipantInfo (pItem);
if (FAILED(hr))
return hr;
hr = SetMulticastMode (pItem);
if (FAILED(hr))
return hr;
if (FAILED (hr = CreateBridgeTerminals (pItem)))
return hr;
if (FAILED (hr = GetStreams (pItem)))
return hr;
if (FAILED (hr = SelectBridgeTerminals (pItem)))
return hr;
// connect h323 call
if (FAILED (hr = pItem->pCallH323->Answer ()))
return hr;
// connect sdp call
if (FAILED (hr = pItem->pCallSDP->Connect (VARIANT_TRUE)))
{
pItem->pCallH323->Disconnect (DC_NORMAL);
return hr;
}
LOG ((BG_TRACE, "%s returns", __fxName));
return S_OK;
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::DisconnectCall (CBridgeItem *pItem, DISCONNECT_CODE dc)
{
// disconnect
if (pItem->pCallH323)
pItem->pCallH323->Disconnect (dc);
if (pItem->pCallSDP)
pItem->pCallSDP->Disconnect (dc);
return S_OK;
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::DisconnectAllCalls (DISCONNECT_CODE dc)
{
// i should have a better way to traverse each call
CBridgeItem ** pItemArray;
int num, i;
// out of memory
if (!m_pList->GetAllItems (&pItemArray, &num))
return E_OUTOFMEMORY;
// no calls
if (num == 0)
return S_OK;
for (i=0; i<num; i++)
{
// disconnect each call
if (pItemArray[i]->pCallH323)
pItemArray[i]->pCallH323->Disconnect (dc);
if (pItemArray[i]->pCallSDP)
pItemArray[i]->pCallSDP->Disconnect (dc);
// do not delete item
}
free (pItemArray);
return S_OK;
}
/*//////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::RemoveCall (CBridgeItem *pItem)
{
m_pList->TakeOut (pItem);
return S_OK;
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::HasH323Call (IDispatch *pEvent, CBridgeItem **ppItem)
{
HRESULT hr;
ITCallStateEvent *pState = NULL;
ITCallInfo *pCallInfo = NULL;
IUnknown * pIUnknown = NULL;
// ignore null checking
if (*ppItem)
{
delete *ppItem;
*ppItem = NULL;
}
// get call state event
hr = pEvent->QueryInterface (
IID_ITCallStateEvent,
(void **)&pState
);
if (FAILED(hr))
return hr;
// check privilege
CALL_PRIVILEGE privilege;
// get call event interface
hr = pState->get_Call (&pCallInfo);
if (FAILED(hr))
return hr;
// if we own the call
hr = pCallInfo->get_Privilege (&privilege);
if (FAILED(hr))
goto Error;
if (CP_OWNER != privilege)
{
hr = E_UNEXPECTED;
goto Error;
}
// get IUnknown
if (FAILED (hr = pCallInfo->QueryInterface (IID_IUnknown, (void **)&pIUnknown)))
goto Error;
*ppItem = m_pList->FindByH323 (pIUnknown);
Cleanup:
if (pCallInfo) pCallInfo->Release ();
if (pIUnknown) pIUnknown->Release ();
if (pState) pState->Release ();
return hr;
Error:
goto Cleanup;
}
/*//////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::HasCalls ()
{
if (m_pList->IsEmpty ())
return S_FALSE;
else
return S_OK;
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::CreateBridgeTerminals (CBridgeItem *pItem)
{
HRESULT hr;
IConfBridge *pConfBridge = NULL;
// create CConfBridge
hr = CoCreateInstance (
__uuidof(ConfBridge),
NULL,
CLSCTX_INPROC_SERVER,
IID_IConfBridge,
(LPVOID *)&pConfBridge
);
if (FAILED(hr))
return hr;
// create terminal: video H323->SDP
hr = pConfBridge->CreateBridgeTerminal (
TAPIMEDIATYPE_VIDEO,
&(pItem->pTermHSVid)
);
if (FAILED(hr))
goto Error;
// create terminal: audio H323->SDP
hr = pConfBridge->CreateBridgeTerminal (
TAPIMEDIATYPE_AUDIO,
&(pItem->pTermHSAud)
);
if (FAILED(hr))
goto Error;
// create terminal: video SDP->H323
hr = pConfBridge->CreateBridgeTerminal (
TAPIMEDIATYPE_VIDEO,
&(pItem->pTermSHVid)
);
if (FAILED(hr))
goto Error;
// create terminal: audio SDP->H323
hr = pConfBridge->CreateBridgeTerminal (
TAPIMEDIATYPE_AUDIO,
&(pItem->pTermSHAud)
);
if (FAILED(hr))
goto Error;
Cleanup:
pConfBridge->Release ();
pConfBridge = NULL;
return hr;
Error:
goto Cleanup;
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::GetStreams (CBridgeItem *pItem)
{
ITStreamControl *pStreamControl = NULL;
IEnumStream *pEnumStreams = NULL;
ITStream *pStream = NULL;
// get stream control on H323
HRESULT hr = pItem->pCallH323->QueryInterface (
IID_ITStreamControl,
(void **)&pStreamControl
);
if (FAILED(hr))
return hr;
// get enum stream on H323
hr = pStreamControl->EnumerateStreams (&pEnumStreams);
pStreamControl->Release ();
pStreamControl = NULL;
if (FAILED(hr))
return hr;
// iterate each stream on H323
while (S_OK == pEnumStreams->Next (1, &pStream, NULL))
{
if (IsStream (pStream, TAPIMEDIATYPE_VIDEO, TD_CAPTURE))
pItem->pStreamHVidCap = pStream;
else if (IsStream (pStream, TAPIMEDIATYPE_VIDEO, TD_RENDER))
{
pItem->pStreamHVidRen = pStream;
IKeyFrameControl* pIKeyFrameControl = NULL;
hr = pStream->QueryInterface(&pIKeyFrameControl);
if (SUCCEEDED(hr))
{
hr = pIKeyFrameControl->PeriodicUpdatePicture(TRUE, 5);
pIKeyFrameControl->Release();
}
}
else if (IsStream (pStream, TAPIMEDIATYPE_AUDIO, TD_CAPTURE))
pItem->pStreamHAudCap = pStream;
else if (IsStream (pStream, TAPIMEDIATYPE_AUDIO, TD_RENDER))
pItem->pStreamHAudRen = pStream;
else
{
pEnumStreams->Release ();
// @@ IsStream doesn't return hresult
return E_FAIL;
}
}
// don't release pStream, it's stored in pItem
pEnumStreams->Release ();
pEnumStreams = NULL;
//========================================
// get stream control on SDP
hr = pItem->pCallSDP->QueryInterface (
IID_ITStreamControl,
(void **)&pStreamControl
);
if (FAILED(hr))
return hr;
// get enum stream on SDP
hr = pStreamControl->EnumerateStreams (&pEnumStreams);
pStreamControl->Release ();
pStreamControl = NULL;
if (FAILED(hr))
return hr;
// iterate each stream on SDP
while (S_OK == pEnumStreams->Next (1, &pStream, NULL))
{
if (IsStream (pStream, TAPIMEDIATYPE_VIDEO, TD_CAPTURE))
pItem->pStreamSVidCap = pStream;
else if (IsStream (pStream, TAPIMEDIATYPE_VIDEO, TD_RENDER))
pItem->pStreamSVidRen = pStream;
else if (IsStream (pStream, TAPIMEDIATYPE_AUDIO, TD_CAPTURE))
pItem->pStreamSAudCap = pStream;
else if (IsStream (pStream, TAPIMEDIATYPE_AUDIO, TD_RENDER))
pItem->pStreamSAudRen = pStream;
else
{
pEnumStreams->Release ();
// @@ IsStream doesn't return hresult
return E_FAIL;
}
}
// don't release pStream, it's stored in pItem
pEnumStreams->Release ();
pEnumStreams = NULL;
return S_OK;
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::SelectBridgeTerminals (CBridgeItem *pItem)
{
HRESULT hr;
// sdp->h323 audio pair
if (FAILED (hr = pItem->pStreamHAudCap->SelectTerminal (pItem->pTermSHAud)))
return hr;
if (FAILED (hr = pItem->pStreamSAudRen->SelectTerminal (pItem->pTermSHAud)))
return hr;
// h323->sdp audio pair
if (FAILED (hr = pItem->pStreamSAudCap->SelectTerminal (pItem->pTermHSAud)))
return hr;
if (FAILED (hr = pItem->pStreamHAudRen->SelectTerminal (pItem->pTermHSAud)))
return hr;
// sdp->h323 video pair
if (FAILED (hr = pItem->pStreamHVidCap->SelectTerminal (pItem->pTermSHVid)))
return hr;
if (FAILED (hr = pItem->pStreamSVidRen->SelectTerminal (pItem->pTermSHVid)))
return hr;
// h323->sdp video pair
if (FAILED (hr = pItem->pStreamSVidCap->SelectTerminal (pItem->pTermHSVid)))
return hr;
if (FAILED (hr = pItem->pStreamHVidRen->SelectTerminal (pItem->pTermHSVid)))
return hr;
return S_OK;
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::SetupParticipantInfo (CBridgeItem *pItem)
{
HRESULT hr = S_OK;
ITLocalParticipant *pLocalParticipant = NULL;
// set the CName on the SDP side.
hr = pItem->pCallSDP->QueryInterface(&pLocalParticipant);
if (FAILED(hr)) goto Cleanup;
hr = pLocalParticipant->put_LocalParticipantTypedInfo(
PTI_CANONICALNAME, pItem->bstrID
);
if (FAILED(hr)) goto Cleanup;
hr = pLocalParticipant->put_LocalParticipantTypedInfo(
PTI_NAME, pItem->bstrName
);
if (FAILED(hr)) goto Cleanup;
Cleanup:
if (pLocalParticipant) pLocalParticipant->Release();
return hr;
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::SetMulticastMode (CBridgeItem *pItem)
{
IMulticastControl * pIMulticastControl = NULL;
HRESULT hr = pItem->pCallSDP->QueryInterface(&pIMulticastControl);
if (FAILED(hr)) return hr;
hr = pIMulticastControl->put_LoopbackMode(MM_SELECTIVE_LOOPBACK);
pIMulticastControl->Release();
return hr;
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::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))
{
// @@ should have some debug info here
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))
{
// @@ debug info here
// 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;
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
BOOL
CBridgeApp::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);
}
/*///////////////////////////////////////////////////////////////////////////////
////*/
BOOL
CBridgeApp::IsStream (ITStream *pStream, long lMediaType, TERMINAL_DIRECTION tdDirection)
{
long mediatype;
TERMINAL_DIRECTION direction;
if (FAILED (pStream->get_Direction(&direction)))
return false;
if (FAILED (pStream->get_MediaType(&mediatype)))
return false;
return ((direction == tdDirection) &&
(mediatype == lMediaType));
}
/*//////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::NextSubStream ()
{
HRESULT hr = S_OK;
CBridgeItem **ItemArray = NULL;
int num, i;
ITSubStreamControl *pSubControl = NULL;
IEnumSubStream *pEnumSub = NULL;
ULONG fetched;
ITSubStream *pSubStream = NULL;
BOOL fActive = FALSE; // if active stream found
ITSubStream *pSubInactive = NULL;
ITSubStream *pSubFirstInactive = NULL;
IEnumTerminal *pEnumTerminal = NULL;
ITParticipantSubStreamControl *pSwitcher = NULL;
// get all stored call items
if (FAILED (hr = m_pList->GetAllItems (&ItemArray, &num)))
return hr;
if (num == 0)
return S_OK;
// for each call item
for (i=0; i<num; i++)
{
// get substream control
if (NULL == ItemArray[i]->pStreamSVidRen)
continue;
if (FAILED (hr = ItemArray[i]->pStreamSVidRen->QueryInterface (&pSubControl)))
goto Error;
// get substreams on sdp video render
if (FAILED (hr = pSubControl->EnumerateSubStreams (&pEnumSub)))
goto Error;
pSubControl->Release ();
pSubControl = NULL;
// for each substream, if !(both active & inactive substream stored)
// the algo tries to be as fair as possible in switching.
// it switches the inactive substream just after the active one
// if the active one is the last in the enum, the first inactive one is chosen
while (!pSubInactive &&
(S_OK == (hr = pEnumSub->Next (1, &pSubStream, &fetched)))
)
{
// get terminal enumerator
if (FAILED (hr = pSubStream->EnumerateTerminals (&pEnumTerminal)))
goto Error;
// if the substream active, store the substream
if (S_OK == pEnumTerminal->Skip (1))
{
if (fActive)
;
// printf ("oops, another active substream on SDP video render stream");
else
fActive = TRUE;
}
else
{
// if inactive, store the substream
if (!pSubFirstInactive)
{
// the first inactive substream
pSubFirstInactive = pSubStream;
pSubFirstInactive->AddRef ();
}
else
{
// store the inactive only if the active was found
if (fActive)
{
pSubInactive = pSubStream;
pSubInactive->AddRef ();
}
}
}
// release
pEnumTerminal->Release ();
pEnumTerminal = NULL;
pSubStream->Release ();
pSubStream = NULL;
}
pEnumSub->Release ();
pEnumSub = NULL;
// if only first inactive is found
if (pSubFirstInactive && !pSubInactive)
{
pSubInactive = pSubFirstInactive;
pSubFirstInactive = NULL;
}
// if not found two substreams, do nothing
if (pSubInactive && ItemArray[i]->pStreamSVidRen && ItemArray[i]->pTermSHVid)
{
if (FAILED (hr = ItemArray[i]->pStreamSVidRen->QueryInterface (&pSwitcher)))
goto Error;
// switch terminal on substream
if (FAILED (hr = pSwitcher->SwitchTerminalToSubStream
(ItemArray[i]->pTermSHVid, pSubInactive)))
goto Error;
pSwitcher->Release ();
pSwitcher = NULL;
}
if (pSubFirstInactive)
{
pSubFirstInactive->Release ();
pSubFirstInactive = NULL;
}
if (pSubInactive)
{
pSubInactive->Release ();
pSubInactive = NULL;
}
}
Cleanup:
if (ItemArray) free (ItemArray);
return hr;
Error:
if (pSubControl) pSubControl->Release ();
if (pEnumSub) pEnumSub->Release ();
if (pSubStream) pSubStream->Release ();
if (pSubInactive) pSubInactive->Release ();
if (pSubFirstInactive) pSubFirstInactive->Release ();
if (pEnumTerminal) pEnumTerminal->Release ();
if (pSwitcher) pSwitcher->Release ();
goto Cleanup;
}
/*//////////////////////////////////////////////////////////////////////////////
////*/
HRESULT
CBridgeApp::ShowParticipant (ITBasicCallControl *pSDPCall, ITParticipant *pParticipant)
{
ENTER_FUNCTION ("CBridgeApp::ShowParticipant");
HRESULT hr;
IUnknown *pIUnknown = NULL;
CBridgeItem *pItem = NULL;
ITParticipantSubStreamControl *pSwitcher = NULL;
ITSubStream *pSubStream = NULL;
// get IUnknown
if (FAILED (hr = pSDPCall->QueryInterface (IID_IUnknown, (void**)&pIUnknown)))
{
LOG ((BG_ERROR, "%s failed to query interface IUnknown, %x", __fxName, hr));
return hr;
}
// find the item matches pSDPCall
pItem = m_pList->FindBySDP (pIUnknown);
pIUnknown->Release ();
pIUnknown = NULL;
// oops, no match
if (NULL == pItem)
return S_FALSE;
// get participant substream control interface
if (NULL == pItem->pStreamSVidRen)
return S_OK;
if (FAILED (hr = pItem->pStreamSVidRen->QueryInterface (&pSwitcher)))
{
LOG ((BG_ERROR, "%s failed to query interface ITParticipantSubStreamControl, %x", __fxName, hr));
return hr;
}
// get substream from participant
if (FAILED (hr = pSwitcher->get_SubStreamFromParticipant (pParticipant, &pSubStream)))
{
pSwitcher->Release ();
pSwitcher = NULL;
LOG ((BG_WARN, "%s failed to get substream from participant, %x", __fxName, hr));
// stream from h323 side does not have substream, report false
return S_FALSE;
}
// switch
if (pItem->pTermSHVid)
hr = pSwitcher->SwitchTerminalToSubStream (pItem->pTermSHVid, pSubStream);
pSubStream->Release ();
pSubStream = NULL;
pSwitcher->Release ();
pSwitcher = NULL;
return hr;
}