windows-nt/Source/XPSP1/NT/enduser/netmeeting/ui/conf/nmconference.cpp
2020-09-26 16:20:57 +08:00

1860 lines
38 KiB
C++

#include "precomp.h"
#include "wbguid.h"
#include "confroom.h"
// SDK Includes
#include "NmEnum.h"
#include "SDKInternal.h"
#include "NmManager.h"
#include "NmConference.h"
#include "NmMember.h"
#include "NmCall.h"
#include "SDKWindow.h"
#include "NmChannelData.h"
#include "NmChannelFt.h"
#include "NmChannelAudio.h"
#include "NmChannelVideo.h"
#include "NmChannelAppShare.h"
#include "NmSharableApp.h"
#include "FtHook.h"
extern INmManager2* g_pInternalNmManager;
/////////////////////////////////////////////////////////
// Construction/destruction
/////////////////////////////////////////////////////////
CNmConferenceObj::CNmConferenceObj()
: m_dwInternalINmConferenceAdvise( 0 ),
m_State(NM_CONFERENCE_IDLE),
m_bFTHookedUp(false)
{
DBGENTRY(CNmConferenceObj::CNmConferenceObj);
DBGEXIT(CNmConferenceObj::CNmConferenceObj);
}
CNmConferenceObj::~CNmConferenceObj()
{
DBGENTRY(CNmConferenceObj::~CNmConferenceObj);
CFt::UnAdvise(this);
m_bFTHookedUp = false;
// this will protect us form re-deleting ourselves
++m_dwRef;
_FreeInternalStuff();
// We don't have to release because we didn't addref
// This is safe because our lifetime is contianed in the CNmManageObj's lifetime
m_pManagerObj = NULL;
DBGEXIT(CNmConferenceObj::~CNmConferenceObj);
}
HRESULT CNmConferenceObj::FinalConstruct()
{
DBGENTRY(CNmConferenceObj::FinalConstruct);
HRESULT hr = S_OK;
if(m_spInternalINmConference)
{
hr = AtlAdvise(m_spInternalINmConference, GetUnknown(), IID_INmConferenceNotify2, &m_dwInternalINmConferenceAdvise);
}
else
{
hr = E_UNEXPECTED;
}
DBGEXIT_HR(CNmConferenceObj::FinalConstruct,hr);
return hr;
}
ULONG CNmConferenceObj::InternalRelease()
{
ATLASSERT(m_dwRef > 0);
--m_dwRef;
if((1 == m_dwRef) && m_dwInternalINmConferenceAdvise)
{
++m_dwRef;
DWORD dwAdvise = m_dwInternalINmConferenceAdvise;
CComPtr<INmConference> spConf = m_spInternalINmConference;
m_spInternalINmConference = NULL;
// This keeps us from getting here twice!
m_dwInternalINmConferenceAdvise = 0;
AtlUnadvise(spConf, IID_INmConferenceNotify2, dwAdvise);
--m_dwRef;
}
return m_dwRef;
}
/*static*/ HRESULT CNmConferenceObj::InitSDK()
{
DBGENTRY(CNmConferenceObj::InitSDK);
HRESULT hr = S_OK;
DBGEXIT_HR(CNmConferenceObj::InitSDK,hr);
return hr;
}
/*static*/void CNmConferenceObj::CleanupSDK()
{
DBGENTRY(CNmConferenceObj::CleanupSDK);
DBGEXIT(CNmConferenceObj::CleanupSDK);
}
/*static*/
HRESULT CNmConferenceObj::CreateInstance(CNmManagerObj* pManagerObj, INmConference* pInternalINmConferenece, INmConference** ppConference)
{
DBGENTRY(CNmConferenceObj::CreateInstance);
HRESULT hr = S_OK;
CComObject<CNmConferenceObj>* p = NULL;
p = new CComObject<CNmConferenceObj>(NULL);
if (p != NULL)
{
if(SUCCEEDED(hr))
{
CNmConferenceObj* pThis = static_cast<CNmConferenceObj*>(p);
pThis->m_spInternalINmConference = pInternalINmConferenece;
if(pInternalINmConferenece)
{
pInternalINmConferenece->GetState(&pThis->m_State);
}
// We don't have to RefCount this because our lifetime is
// contained in the CNMManageuObj's lifetime
pThis->m_pManagerObj = pManagerObj;
}
hr = _CreateInstanceGuts(p, ppConference);
}
DBGEXIT_HR(CNmConferenceObj::CreateInstance,hr);
return hr;
}
/*static*/
HRESULT CNmConferenceObj::_CreateInstanceGuts(CComObject<CNmConferenceObj> *p, INmConference** ppConference)
{
DBGENTRY(CNmConferenceObj::_CreateInstanceGuts);
HRESULT hr = S_OK;
if(ppConference)
{
if(p != NULL)
{
p->SetVoid(NULL);
// We do this so that we don't accidentally Release out of memory
++p->m_dwRef;
hr = p->FinalConstruct();
--p->m_dwRef;
if(hr == S_OK)
hr = p->QueryInterface(IID_INmConference, reinterpret_cast<void**>(ppConference));
if(FAILED(hr))
{ *ppConference = NULL;
delete p;
}
}
else
{
hr = E_UNEXPECTED;
}
}
else
{
hr = E_POINTER;
}
DBGEXIT_HR(CNmConferenceObj::_CreateInstanceGuts,hr);
return hr;
}
/////////////////////////////////////////////////////////
// INmConference methods
/////////////////////////////////////////////////////////
STDMETHODIMP CNmConferenceObj::GetName(BSTR *pbstrName)
{
DBGENTRY(CNmConferenceObj::GetName);
HRESULT hr = S_OK;
if(m_spInternalINmConference)
{
hr = m_spInternalINmConference->GetName(pbstrName);
}
else
{
hr = E_UNEXPECTED;
}
return hr;
}
STDMETHODIMP CNmConferenceObj::GetID(ULONG * puID)
{
HRESULT hr = S_OK;
if(m_spInternalINmConference)
{
hr = m_spInternalINmConference->GetID(puID);
}
else
{
hr = E_UNEXPECTED;
}
return hr;
}
STDMETHODIMP CNmConferenceObj::GetState(NM_CONFERENCE_STATE *pState)
{
DBGENTRY(CNmConferenceObj::GetState);
HRESULT hr = S_OK;
if(m_spInternalINmConference)
{
hr = m_spInternalINmConference->GetState(pState);
}
else
{
hr = E_UNEXPECTED;
}
DBGEXIT_HR(CNmConferenceObj::GetState,hr);
return hr;
}
STDMETHODIMP CNmConferenceObj::GetNmchCaps(ULONG *puchCaps)
{
HRESULT hr = S_OK;
if(m_spInternalINmConference)
{
hr = m_spInternalINmConference->GetNmchCaps(puchCaps);
}
else
{
hr = E_UNEXPECTED;
}
return hr;
}
STDMETHODIMP CNmConferenceObj::GetTopProvider(INmMember **ppMember)
{
HRESULT hr = E_FAIL;
if(ppMember)
{ *ppMember = NULL;
if(m_spInternalINmConference)
{
INmMember* pInternalMember;
if(SUCCEEDED(m_spInternalINmConference->GetTopProvider(&pInternalMember)))
{
*ppMember = GetSDKMemberFromInternalMember(pInternalMember);
if(*ppMember)
{
(*ppMember)->AddRef();
hr = S_OK;
}
// This is commented out for clairity.
// the GetTopProvider method in nmcom does not
// actually addref the pointer (!)
//pInternalMember->Release
}
}
}
else
{
hr = E_POINTER;
}
return hr;
}
STDMETHODIMP CNmConferenceObj::EnumMember(IEnumNmMember **ppEnum)
{
DBGENTRY(CNmConferenceObj::EnumMember);
HRESULT hr = S_OK;
if(ppEnum)
{
hr = CreateEnumFromSimpleAryOfInterface<IEnumNmMember, INmMember>(m_SDKMemberObjs, ppEnum);
}
else
{
hr = E_POINTER;
}
DBGEXIT_HR(CNmConferenceObj::EnumMember,hr);
return hr;
}
STDMETHODIMP CNmConferenceObj::GetMemberCount(ULONG *puCount)
{
DBGENTRY(CNmConferenceObj::GetMemberCount);
HRESULT hr = S_OK;
if(puCount)
{
*puCount = m_SDKMemberObjs.GetSize();
}
else
{
hr = E_POINTER;
}
DBGEXIT_HR(CNmConferenceObj::GetMemberCount,hr);
return hr;
}
STDMETHODIMP CNmConferenceObj::CreateChannel(INmChannel **ppChannel, ULONG uNmCh, INmMember *pMember)
{
ATLTRACENOTIMPL(_T("CNmConferenceObj::GetName"));
}
STDMETHODIMP CNmConferenceObj::EnumChannel(IEnumNmChannel **ppEnum)
{
DBGENTRY(CNmConferenceObj::EnumChannel);
HRESULT hr = E_NOTIMPL;
if(ppEnum)
{
hr = CreateEnumFromSimpleAryOfInterface<IEnumNmChannel, INmChannel>(m_SDKChannelObjs, ppEnum);
}
else
{
hr = E_POINTER;
}
DBGEXIT_HR(CNmConferenceObj::EnumChannel,hr);
return hr;
}
STDMETHODIMP CNmConferenceObj::GetChannelCount(ULONG *puCount)
{
DBGENTRY(CNmConferenceObj::GetChannelCount);
HRESULT hr = S_OK;
if(puCount)
{
*puCount = m_SDKChannelObjs.GetSize();
}
else
{
hr = E_POINTER;
}
DBGEXIT_HR(CNmConferenceObj::GetChannelCount,hr);
return hr;
}
// NetMeeting 2.0 chat guid: {340F3A60-7067-11D0-A041-444553540000}
const GUID g_guidNM2Chat =
{ 0x340f3a60, 0x7067, 0x11d0, { 0xa0, 0x41, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0 } };
STDMETHODIMP CNmConferenceObj::CreateDataChannel(INmChannelData **ppChannel, REFGUID rguid)
{
HRESULT hr = S_OK;
if(m_spInternalINmConference)
{
if(!InlineIsEqualGUID(rguid, g_guidNM2Chat))
{
GUID g = rguid;
if(!_IsGuidInDataChannelList(g))
{
m_DataChannelGUIDList.Add(g);
}
CComPtr<INmChannelData> spInternalDataChannel;
hr = m_spInternalINmConference->CreateDataChannel(&spInternalDataChannel, rguid);
if(SUCCEEDED(hr))
{
INmChannel* pSDKChannel = GetSDKChannelFromInternalChannel(spInternalDataChannel);
if(pSDKChannel && ppChannel)
{
*ppChannel = com_cast<INmChannelData>(pSDKChannel);
if(*ppChannel)
{
(*ppChannel)->AddRef();
}
else
{
hr = E_UNEXPECTED;
}
}
}
else
{
m_DataChannelGUIDList.Remove(g);
}
}
else
{
hr = NM_E_CHANNEL_ALREADY_EXISTS;
}
}
else
{
hr = NM_E_NO_T120_CONFERENCE;
}
return hr;
}
STDMETHODIMP CNmConferenceObj::Host(void)
{
HRESULT hr = S_OK;
if(m_spInternalINmConference)
{
hr = m_spInternalINmConference->Host();
}
else
{
hr = E_UNEXPECTED;
}
return hr;
}
STDMETHODIMP CNmConferenceObj::Leave(void)
{
DBGENTRY(CNmConferenceObj::Leave);
HRESULT hr = S_OK;
if(m_spInternalINmConference)
{
hr = m_spInternalINmConference->Leave();
_FreeInternalStuff();
if(!m_pManagerObj->OfficeMode())
{
StateChanged(NM_CONFERENCE_IDLE);
}
}
else
{
hr = E_UNEXPECTED;
}
DBGEXIT_HR(CNmConferenceObj::Leave,hr);
return hr;
}
STDMETHODIMP CNmConferenceObj::IsHosting(void)
{
HRESULT hr = E_UNEXPECTED;
if(m_spInternalINmConference)
{
hr = m_spInternalINmConference->IsHosting();
}
return hr;
}
STDMETHODIMP CNmConferenceObj::LaunchRemote(REFGUID rguid, INmMember *pMember)
{
HRESULT hr = E_UNEXPECTED;
if(m_spInternalINmConference)
{
CComPtr<INmMember> spInternalMember;
if(pMember)
{
CComPtr<IInternalMemberObj> spObj = com_cast<IInternalMemberObj>(pMember);
ASSERT(spObj);
spObj->GetInternalINmMember(&spInternalMember);
}
hr = m_spInternalINmConference->LaunchRemote(rguid, spInternalMember);
}
return hr;
}
/////////////////////////////////////////////////
// INmConferenceNotify2 methods:
/////////////////////////////////////////////////
STDMETHODIMP CNmConferenceObj::NmUI(CONFN uNotify)
{
DBGENTRY(CNmConferenceObj::NmUI);
HRESULT hr = S_OK;
hr = Fire_NmUI(uNotify);
DBGEXIT_HR(CNmConferenceObj::NmUI,hr);
return hr;
}
void CNmConferenceObj::_EnsureSentConferenceCreatedNotification()
{
if(m_pManagerObj && !m_pManagerObj->m_bSentConferenceCreated)
{
// If we have not sent conference created, send it now!
CComQIPtr<INmConference> spConf(GetUnknown());
m_pManagerObj->Fire_ConferenceCreated(spConf);
}
}
STDMETHODIMP CNmConferenceObj::StateChanged(NM_CONFERENCE_STATE uState)
{
DBGENTRY(CNmConferenceObj::StateChanged);
HRESULT hr = S_OK;
if(m_State != uState)
{
m_State = uState;
if(m_State == NM_CONFERENCE_IDLE)
{
if(m_bFTHookedUp)
{
CFt::UnAdvise(this);
m_bFTHookedUp = false;
}
if(m_pManagerObj)
{
m_pManagerObj->m_bSentConferenceCreated = false;
}
_FreeInternalStuff();
}
else if(NM_CONFERENCE_ACTIVE == m_State)
{
EnsureFTChannel();
}
hr = Fire_StateChanged(uState);
if(NM_CONFERENCE_WAITING == m_State)
{
_EnsureSentConferenceCreatedNotification();
}
}
DBGEXIT_HR(CNmConferenceObj::StateChanged,hr);
return hr;
}
void CNmConferenceObj::AddMemberToAsChannel(INmMember* pSDKMember)
{
INmChannel* pChannel = _GetAppSharingChannel();
if(pChannel)
{
com_cast<IInternalChannelObj>(pChannel)->SDKMemberAdded(pSDKMember);
}
}
void CNmConferenceObj::RemoveMemberFromAsChannel(INmMember* pSDKMember)
{
INmChannel* pChannel = _GetAppSharingChannel();
if(pChannel)
{
com_cast<IInternalChannelObj>(pChannel)->SDKMemberRemoved(pSDKMember);
}
}
void CNmConferenceObj::AddMemberToFtChannel(INmMember* pSDKMember)
{
INmChannel* pChannel = _GetFtChannel();
if(pChannel)
{
com_cast<IInternalChannelObj>(pChannel)->SDKMemberAdded(pSDKMember);
}
}
void CNmConferenceObj::RemoveMemberFromFtChannel(INmMember* pSDKMember)
{
INmChannel* pChannel = _GetFtChannel();
if(pChannel)
{
com_cast<IInternalChannelObj>(pChannel)->SDKMemberRemoved(pSDKMember);
}
}
STDMETHODIMP CNmConferenceObj::MemberChanged(NM_MEMBER_NOTIFY uNotify, INmMember *pInternalMember)
{
DBGENTRY(CNmConferenceObj::MemberChanged);
HRESULT hr = S_OK;
if(pInternalMember)
{
CComPtr<INmMember> spMember;
if(NM_MEMBER_ADDED == uNotify)
{
if(NULL == _GetAppSharingChannel())
{
// We don't get notified of this channel, so
// we have to add it manually
_AddAppShareChannel();
}
// We actually get this notification multiple times, so just check to make sure...
if(!GetSDKMemberFromInternalMember(pInternalMember))
{
hr = CNmMemberObj::CreateInstance(this, pInternalMember, &spMember);
if(SUCCEEDED(hr))
{
spMember.p->AddRef();
m_SDKMemberObjs.Add(spMember.p);
}
}
}
CComPtr<INmMember> spSDKMember = GetSDKMemberFromInternalMember(pInternalMember);
if(NM_MEMBER_REMOVED == uNotify)
{
_RemoveMember(pInternalMember);
}
Fire_MemberChanged(uNotify, spSDKMember);
if((NM_MEMBER_ADDED == uNotify) || (NM_MEMBER_UPDATED == uNotify))
{
// Add the member to the AS Channel iff they have NMCH_DATA
ASSERT(spSDKMember);
ULONG uchCaps = 0;
if(SUCCEEDED(spSDKMember->GetNmchCaps(&uchCaps)))
{
if(NMCH_DATA & uchCaps)
{
// This method will handle being called multiple times for the same member
AddMemberToAsChannel(spSDKMember);
}
}
}
if(SUCCEEDED(hr) && (uNotify != NM_MEMBER_REMOVED))
{
ULONG ulGCCid;
if(SUCCEEDED(spSDKMember->GetID(&ulGCCid)))
{
if(CFt::IsMemberInFtSession(static_cast<T120NodeID>(ulGCCid)))
{
// Make sure that the user is in the channel
AddMemberToFtChannel(spSDKMember);
}
}
_EnsureMemberHasAVChannelsIfNeeded(spSDKMember);
}
}
else
{
WARNING_OUT(("Why are we pased a NULL member?"));
}
DBGEXIT_HR(CNmConferenceObj::MemberChanged,hr);
return hr;
}
STDMETHODIMP CNmConferenceObj::FireNotificationsToSyncState()
{
// this is no longer used...
ASSERT(0);
return S_OK;
}
STDMETHODIMP CNmConferenceObj::EnsureFTChannel()
{
if(m_pManagerObj && m_pManagerObj->FileTransferNotifications())
{
if(!m_bFTHookedUp)
{
// When the conference is active, we should add ourselves
CFt::Advise(this);
_EnsureFtChannelAdded();
m_bFTHookedUp = true;
if(CFt::IsFtActive())
{
// This means that the channel is Active
INmChannel* pChannel = _GetFtChannel();
if(pChannel)
{
com_cast<IInternalChannelObj>(pChannel)->Activate(true);
Fire_ChannelChanged(NM_CHANNEL_UPDATED, pChannel);
}
}
}
}
return S_OK;
}
STDMETHODIMP CNmConferenceObj::AudioChannelActiveState(BOOL bActive, BOOL bIsIncoming)
{
INmChannel* pChannel = _GetAudioChannel(bIsIncoming);
if(pChannel && ((pChannel->IsActive() == S_OK) != bActive))
{
com_cast<IInternalChannelObj>(pChannel)->Activate(bActive);
Fire_ChannelChanged(NM_CHANNEL_UPDATED, pChannel);
}
return S_OK;
}
STDMETHODIMP CNmConferenceObj::VideoChannelActiveState(BOOL bActive, BOOL bIsIncoming)
{
INmChannel* pChannel = _GetVideoChannel(bIsIncoming);
if(pChannel && ((pChannel->IsActive() == S_OK) != bActive))
{
com_cast<IInternalChannelObj>(pChannel)->Activate(bActive);
Fire_ChannelChanged(NM_CHANNEL_UPDATED, pChannel);
}
return S_OK;
}
STDMETHODIMP CNmConferenceObj::VideoChannelPropChanged(DWORD dwProp, BOOL bIsIncoming)
{
INmChannel* pChannel = _GetVideoChannel(bIsIncoming);
if(pChannel)
{
com_cast<INmChannelVideoNotify>(pChannel)->PropertyChanged(dwProp);
}
return S_OK;
}
STDMETHODIMP CNmConferenceObj::VideoChannelStateChanged(NM_VIDEO_STATE uState, BOOL bIsIncoming)
{
INmChannel* pChannel = _GetVideoChannel(bIsIncoming);
if(pChannel)
{
com_cast<INmChannelVideoNotify>(pChannel)->StateChanged(uState);
}
return S_OK;
}
STDMETHODIMP CNmConferenceObj::ChannelChanged(NM_CHANNEL_NOTIFY uNotify, INmChannel *pInternalChannel)
{
DBGENTRY(CNmConferenceObj::ChannelChanged);
HRESULT hr = S_OK;
if(pInternalChannel)
{
if(NM_CHANNEL_ADDED == uNotify)
{
ULONG ulCh = NMCH_NONE;
hr = pInternalChannel->GetNmch(&ulCh);
if(SUCCEEDED(hr))
{
CComPtr<INmChannel> spChannel;
hr = E_UNEXPECTED;
switch(ulCh)
{
case NMCH_VIDEO:
// this means that the channel is "Active"
{
BOOL bIncoming = (S_OK == com_cast<INmChannelVideo>(pInternalChannel)->IsIncoming());
INmChannel* pVidChannel = _GetVideoChannel(bIncoming);
if(pVidChannel)
{
com_cast<IInternalChannelObj>(pVidChannel)->Activate(true);
}
else
{
if(bIncoming)
{
m_bRemoteVideoActive = true;
}
else
{
m_bLocalVideoActive = true;
}
}
}
break;
case NMCH_AUDIO:
// this means that the channel is "Active"
{
BOOL bIncoming = (S_OK == com_cast<INmChannelAudio>(pInternalChannel)->IsIncoming());
INmChannel* pAudioChannel = _GetAudioChannel(bIncoming);
if(pAudioChannel)
{
com_cast<IInternalChannelObj>(pAudioChannel)->Activate(true);
}
}
break;
case NMCH_DATA:
if(m_pManagerObj && m_pManagerObj->DataNotifications())
{
if(pInternalChannel)
{
CComPtr<INmChannelData> spDataChannel = com_cast<INmChannelData>(pInternalChannel);
GUID g;
if(spDataChannel && SUCCEEDED(spDataChannel->GetGuid(&g)))
{
if(_IsGuidInDataChannelList(g))
{
// We only do this if this GUID is in our list
hr = CNmChannelDataObj::CreateInstance(this, pInternalChannel, &spChannel);
}
}
}
}
break;
case NMCH_FT:
break;
case NMCH_SHARE:
// Currently, we don't get notified of the App Sharing "channel"
default:
ERROR_OUT(("Unknown channel type"));
break;
}
if(SUCCEEDED(hr))
{
spChannel.p->AddRef();
m_SDKChannelObjs.Add(spChannel.p);
Fire_ChannelChanged(NM_CHANNEL_ADDED, spChannel);
// Add all the members from the internal channel
CComPtr<IEnumNmMember> spEnumMember;
if(SUCCEEDED(pInternalChannel->EnumMember(&spEnumMember)))
{
INmMember* pMember = NULL;
ULONG ulFetched = 0;
while(S_OK == spEnumMember->Next(1, &pMember, &ulFetched))
{
CComPtr<INmMember> spSDKMember = GetSDKMemberFromInternalMember(pMember);
if(spSDKMember)
{
com_cast<IInternalChannelObj>(spChannel)->SDKMemberAdded(spSDKMember);
}
else
{
ERROR_OUT(("We should not have members of a channel before they are in the conference"));
}
pMember->Release();
pMember = NULL;
}
}
}
}
}
else
{
INmChannel* pChannel = GetSDKChannelFromInternalChannel(pInternalChannel);
if(SUCCEEDED(hr) && pChannel)
{
if(NM_CHANNEL_REMOVED == uNotify)
{
_RemoveChannel(pChannel);
}
else
{
Fire_ChannelChanged(uNotify, pChannel);
}
}
}
}
else
{
hr = E_UNEXPECTED;
ERROR_OUT(("ChannelChanged was passed a NULL INmChannel"));
}
DBGEXIT_HR(CNmConferenceObj::ChannelChanged,hr);
return hr;
}
STDMETHODIMP CNmConferenceObj::StreamEvent(NM_STREAMEVENT uEvent, UINT uSubCode, INmChannel *pInternalChannel)
{
DBGENTRY(CNmConferenceObj::StreamEvent);
HRESULT hr = S_OK;
DBGEXIT_HR(CNmConferenceObj::StreamEvent,hr);
return hr;
}
// IMbftEvent Interface
STDMETHODIMP CNmConferenceObj::OnInitializeComplete(void)
{
// This means that the channel is Active
INmChannel* pChannel = _GetFtChannel();
if(pChannel)
{
com_cast<IInternalChannelObj>(pChannel)->Activate(true);
Fire_ChannelChanged(NM_CHANNEL_UPDATED, pChannel);
}
return S_OK;
}
STDMETHODIMP CNmConferenceObj::OnPeerAdded(MBFT_PEER_INFO *pInfo)
{
CComPtr<INmMember> spMember;
HRESULT hr = E_FAIL;
if(CFt::IsMemberInFtSession(pInfo->NodeID))
{
hr = GetMemberFromNodeID(pInfo->NodeID, &spMember);
if(SUCCEEDED(hr))
{
AddMemberToFtChannel(spMember);
}
}
return hr;
}
STDMETHODIMP CNmConferenceObj::OnPeerRemoved(MBFT_PEER_INFO *pInfo)
{
CComPtr<INmMember> spMember;
HRESULT hr = GetMemberFromNodeID(pInfo->NodeID, &spMember);
if(SUCCEEDED(hr))
{
RemoveMemberFromFtChannel(spMember);
}
return S_OK;
}
STDMETHODIMP CNmConferenceObj::OnFileOffer(MBFT_FILE_OFFER *pOffer)
{
// The FT Channel and FT Object will handle this
return S_OK;
}
STDMETHODIMP CNmConferenceObj::OnFileProgress(MBFT_FILE_PROGRESS *pProgress)
{
// The FT Channel and FT Object will handle this
return S_OK;
}
STDMETHODIMP CNmConferenceObj::OnFileEnd(MBFTFILEHANDLE hFile)
{
// The FT Channel and FT Object will handle this
return S_OK;
}
STDMETHODIMP CNmConferenceObj::OnFileError(MBFT_EVENT_ERROR *pEvent)
{
// The FT Channel and FT Object will handle this
return S_OK;
}
STDMETHODIMP CNmConferenceObj::OnFileEventEnd(MBFTEVENTHANDLE hEvent)
{
// The FT Channel and FT Object will handle this
return S_OK;
}
STDMETHODIMP CNmConferenceObj::OnSessionEnd(void)
{
// This means that the channel is Active
INmChannel* pChannel = _GetFtChannel();
if(pChannel)
{
com_cast<IInternalChannelObj>(pChannel)->Activate(false);
Fire_ChannelChanged(NM_CHANNEL_UPDATED, pChannel);
_RemoveChannel(pChannel);
}
CFt::UnAdvise(this);
m_bFTHookedUp = false;
return S_OK;
}
////////////////////////////////////////////////////////////////////////
//IInternalConferenceObj
////////////////////////////////////////////////////////////////////////
STDMETHODIMP CNmConferenceObj::GetInternalINmConference(INmConference** ppConference)
{
DBGENTRY(CNmConferenceObj::GetInternalINmConference);
HRESULT hr = S_OK;
ASSERT(ppConference);
*ppConference = m_spInternalINmConference;
if(*ppConference)
{
(*ppConference)->AddRef();
}
DBGEXIT_HR(CNmConferenceObj::GetInternalINmConference,hr);
return hr;
}
STDMETHODIMP CNmConferenceObj::GetMemberFromNodeID(DWORD dwNodeID, INmMember** ppMember)
{
HRESULT hr = E_POINTER;
if(ppMember)
{
hr = E_FAIL;
for(int i = 0; i < m_SDKMemberObjs.GetSize(); ++i)
{
DWORD dwGCCID;
HRESULT hrRes;
if(SUCCEEDED(hrRes = m_SDKMemberObjs[i]->GetID(&dwGCCID)))
{
if(dwGCCID == dwNodeID)
{
*ppMember = m_SDKMemberObjs[i];
(*ppMember)->AddRef();
hr = S_OK;
}
}
else hr = hrRes;
}
}
return hr;
}
STDMETHODIMP CNmConferenceObj::RemoveAllMembersAndChannels()
{
HRESULT hr = S_OK;
_FreeInternalStuff();
return hr;
}
STDMETHODIMP CNmConferenceObj::AppSharingChannelChanged()
{
HRESULT hr = E_UNEXPECTED;
INmChannel* pChannel = _GetAppSharingChannel();
if(pChannel)
{
Fire_ChannelChanged(NM_CHANNEL_UPDATED, pChannel);
}
return hr;
}
STDMETHODIMP CNmConferenceObj::FireNotificationsToSyncToInternalObject()
{
if(m_spInternalINmConference)
{
// Add all the members from the internal conference
CComPtr<IEnumNmMember> spEnumMember;
if(SUCCEEDED(m_spInternalINmConference->EnumMember(&spEnumMember)))
{
INmMember* pMember = NULL;
ULONG ulFetched = 0;
while(S_OK == spEnumMember->Next(1, &pMember, &ulFetched))
{
MemberChanged(NM_MEMBER_ADDED, pMember);
pMember->Release();
pMember = NULL;
}
}
// Fire the CHANNEL_ADDED notifications
for(int i = 0; i < m_SDKChannelObjs.GetSize(); ++i)
{
Fire_ChannelChanged(NM_CHANNEL_ADDED, m_SDKChannelObjs[i]);
// Tell the channel to fire the MEMBER_ADDED notificaitnos, etc.
com_cast<IInternalChannelObj>(m_SDKChannelObjs[i])->FireNotificationsToSyncState();
}
if(0 != m_SDKMemberObjs.GetSize())
{
if(NULL == _GetAppSharingChannel())
{
// We don't get notified of this channel, so
// we have to add it manually
_AddAppShareChannel();
}
EnsureFTChannel();
for(i = 0; i < m_SDKMemberObjs.GetSize(); ++i)
{
ULONG uchCaps = 0;
if(SUCCEEDED(m_SDKMemberObjs[i]->GetNmchCaps(&uchCaps)))
{
if(NMCH_DATA & uchCaps)
{
// This method will handle being called multiple times for the same member
AddMemberToAsChannel(m_SDKMemberObjs[i]);
}
}
ULONG ulGCCid;
if(SUCCEEDED(m_SDKMemberObjs[i]->GetID(&ulGCCid)))
{
if(CFt::IsMemberInFtSession(static_cast<T120NodeID>(ulGCCid)))
{
// Make sure that the user is in the channel
AddMemberToFtChannel(m_SDKMemberObjs[i]);
}
}
}
}
}
return S_OK;
}
STDMETHODIMP CNmConferenceObj::AppSharingStateChanged(BOOL bActive)
{
HRESULT hr = E_UNEXPECTED;
INmChannel* pChannel = _GetAppSharingChannel();
if(pChannel)
{
com_cast<IInternalChannelObj>(pChannel)->Activate(bActive);
Fire_ChannelChanged(NM_CHANNEL_UPDATED, pChannel);
}
return hr;
}
INmChannel* CNmConferenceObj::_GetAppSharingChannel()
{
INmChannel* pChannel = NULL;
for(int i = 0; i < m_SDKChannelObjs.GetSize(); ++i)
{
ULONG ulch;
if(SUCCEEDED(m_SDKChannelObjs[i]->GetNmch(&ulch)))
{
if(NMCH_SHARE == ulch)
{
pChannel = m_SDKChannelObjs[i];
break;
}
}
}
return pChannel;
}
INmChannel* CNmConferenceObj::_GetFtChannel()
{
INmChannel* pChannel = NULL;
for(int i = 0; i < m_SDKChannelObjs.GetSize(); ++i)
{
ULONG ulch;
if(SUCCEEDED(m_SDKChannelObjs[i]->GetNmch(&ulch)))
{
if(NMCH_FT == ulch)
{
pChannel = m_SDKChannelObjs[i];
break;
}
}
}
return pChannel;
}
INmChannel* CNmConferenceObj::_GetAudioChannel(BOOL bIncoming)
{
INmChannel* pChannel = NULL;
for(int i = 0; i < m_SDKChannelObjs.GetSize(); ++i)
{
ULONG ulch;
if(SUCCEEDED(m_SDKChannelObjs[i]->GetNmch(&ulch)))
{
if((NMCH_AUDIO == ulch) && ((S_OK == com_cast<INmChannelAudio>(m_SDKChannelObjs[i])->IsIncoming()) == bIncoming))
{
pChannel = m_SDKChannelObjs[i];
break;
}
}
}
return pChannel;
}
INmChannel* CNmConferenceObj::_GetVideoChannel(BOOL bIncoming)
{
INmChannel* pChannel = NULL;
for(int i = 0; i < m_SDKChannelObjs.GetSize(); ++i)
{
ULONG ulch;
if(SUCCEEDED(m_SDKChannelObjs[i]->GetNmch(&ulch)))
{
if((NMCH_VIDEO == ulch) && ((S_OK == com_cast<INmChannelVideo>(m_SDKChannelObjs[i])->IsIncoming()) == bIncoming))
{
pChannel = m_SDKChannelObjs[i];
break;
}
}
}
return pChannel;
}
STDMETHODIMP CNmConferenceObj::SharableAppStateChanged(HWND hWnd, NM_SHAPP_STATE state)
{
INmChannel* pChannelAs = _GetAppSharingChannel();
HRESULT hr = S_OK;
if(pChannelAs)
{
CComPtr<INmSharableApp> spSharableApp;
TCHAR szName[MAX_PATH];
hr = CNmChannelAppShareObj::GetSharableAppName(hWnd, szName, CCHMAX(szName));
if(SUCCEEDED(hr))
{
hr = CNmSharableAppObj::CreateInstance(hWnd, szName, &spSharableApp);
if(SUCCEEDED(hr))
{
com_cast<INmChannelAppShareNotify>(pChannelAs)->StateChanged(state, spSharableApp);
}
}
}
return hr;
}
STDMETHODIMP CNmConferenceObj::ASLocalMemberChanged()
{
return _ASMemberChanged(GetLocalSDKMember());
}
STDMETHODIMP CNmConferenceObj::ASMemberChanged(UINT gccID)
{
CComPtr<INmMember> spMember;
HRESULT hr = GetMemberFromNodeID(gccID, &spMember);
if(SUCCEEDED(hr))
{
hr = _ASMemberChanged(spMember);
}
return hr;
}
HRESULT CNmConferenceObj::_ASMemberChanged(INmMember *pSDKMember)
{
if(pSDKMember)
{
Fire_MemberChanged(NM_MEMBER_UPDATED, pSDKMember);
INmChannel* pChannel = _GetAppSharingChannel();
if(pChannel)
{
com_cast<IInternalChannelObj>(pChannel)->SDKMemberChanged(pSDKMember);
}
}
else
{
return E_UNEXPECTED;
}
return S_OK;
}
////////////////////////////////////////////////////////////////////////
// Notifications
////////////////////////////////////////////////////////////////////////
HRESULT CNmConferenceObj::Fire_NmUI(CONFN uNotify)
{
DBGENTRY(CNmConferenceObj::Fire_NmUI)
HRESULT hr = S_OK;
if(!g_bSDKPostNotifications)
{
/////////////////////////////////////////////////////
// INmConferenceNotify
/////////////////////////////////////////////////////
IConnectionPointImpl<CNmConferenceObj, &IID_INmConferenceNotify, CComDynamicUnkArray>* pCP = this;
for(int i = 0; i < pCP->m_vec.GetSize(); ++i )
{
INmConferenceNotify* pNotify = reinterpret_cast<INmConferenceNotify*>(pCP->m_vec.GetAt(i));
if(pNotify)
{
pNotify->NmUI(uNotify);
}
}
}
else
{
CSDKWindow::PostConferenceNmUI(this, uNotify);
}
DBGEXIT_HR(CNmConferenceObj::Fire_NmUI,hr);
return hr;
}
HRESULT CNmConferenceObj::Fire_StateChanged(NM_CONFERENCE_STATE uState)
{
DBGENTRY(CNmConferenceObj::Fire_StateChanged)
HRESULT hr = S_OK;
if(!g_bSDKPostNotifications)
{
/////////////////////////////////////////////////////
// INmConferenceNotify
/////////////////////////////////////////////////////
IConnectionPointImpl<CNmConferenceObj, &IID_INmConferenceNotify, CComDynamicUnkArray>* pCP = this;
for(int i = 0; i < pCP->m_vec.GetSize(); ++i )
{
INmConferenceNotify* pNotify = reinterpret_cast<INmConferenceNotify*>(pCP->m_vec.GetAt(i));
if(pNotify)
{
pNotify->StateChanged(uState);
}
}
}
else
{
CSDKWindow::PostConferenceStateChanged(this, uState);
}
DBGEXIT_HR(CNmConferenceObj::Fire_StateChanged,hr);
return hr;
}
extern bool g_bOfficeModeSuspendNotifications;
HRESULT CNmConferenceObj::Fire_MemberChanged(NM_MEMBER_NOTIFY uNotify, INmMember *pMember)
{
DBGENTRY(CNmConferenceObj::Fire_MemberChanged);
HRESULT hr = S_OK;
if(m_pManagerObj->OfficeMode() && g_bOfficeModeSuspendNotifications)
{
// We don't have to notify anyone at all...
return S_OK;
}
if(!g_bSDKPostNotifications)
{
/////////////////////////////////////////////////////
// INmConferenceNotify
/////////////////////////////////////////////////////
IConnectionPointImpl<CNmConferenceObj, &IID_INmConferenceNotify, CComDynamicUnkArray>* pCP = this;
for(int i = 0; i < pCP->m_vec.GetSize(); ++i )
{
INmConferenceNotify* pNotify = reinterpret_cast<INmConferenceNotify*>(pCP->m_vec.GetAt(i));
if(pNotify)
{
pNotify->MemberChanged(uNotify, pMember);
}
}
}
else
{
CSDKWindow::PostConferenceMemberChanged(this, uNotify, pMember);
}
DBGEXIT_HR(CNmConferenceObj::Fire_MemberChanged,hr);
return hr;
}
HRESULT CNmConferenceObj::Fire_ChannelChanged(NM_CHANNEL_NOTIFY uNotify, INmChannel *pChannel)
{
DBGENTRY(CNmConferenceObj::Fire_ChannelChanged);
HRESULT hr = S_OK;
if(!g_bSDKPostNotifications)
{
/////////////////////////////////////////////////////
// INmConferenceNotify
/////////////////////////////////////////////////////
IConnectionPointImpl<CNmConferenceObj, &IID_INmConferenceNotify, CComDynamicUnkArray>* pCP = this;
for(int i = 0; i < pCP->m_vec.GetSize(); ++i )
{
INmConferenceNotify* pNotify = reinterpret_cast<INmConferenceNotify*>(pCP->m_vec.GetAt(i));
if(pNotify)
{
pNotify->ChannelChanged(uNotify, pChannel);
}
}
}
else
{
CSDKWindow::PostConferenceChannelChanged(this, uNotify, pChannel);
}
DBGEXIT_HR(CNmConferenceObj::Fire_ChannelChanged,hr);
return hr;
}
/////////////////////////////////////////////////
// helper Fns
/////////////////////////////////////////////////
INmChannel* CNmConferenceObj::GetSDKChannelFromInternalChannel(INmChannel* pInternalChannel)
{
DBGENTRY(CNmConferenceObj::GetSDKChannelFromInternalChannel);
INmChannel* pRet = NULL;
for( int i = 0; i < m_SDKChannelObjs.GetSize(); ++i)
{
CComQIPtr<IInternalChannelObj> spInternal = m_SDKChannelObjs[i];
if(spInternal)
{
CComPtr<INmChannel> spChannel;
if(SUCCEEDED(spInternal->GetInternalINmChannel(&spChannel)))
{
if(spChannel.IsEqualObject(pInternalChannel))
{
pRet = m_SDKChannelObjs[i];
break;
}
}
}
}
DBGEXIT(CNmConferenceObj::GetSDKChannelFromInternalChannel);
return pRet;
}
INmMember* CNmConferenceObj::GetSDKMemberFromInternalMember(INmMember* pInternalMember)
{
DBGENTRY(CNmConferenceObj::GetSDKMemberFromInternalMember);
INmMember* pRet = NULL;
for( int i = 0; i < m_SDKMemberObjs.GetSize(); ++i)
{
CComQIPtr<IInternalMemberObj> spInternal = m_SDKMemberObjs[i];
if(spInternal)
{
CComPtr<INmMember> spMember;
if(SUCCEEDED(spInternal->GetInternalINmMember(&spMember)))
{
if(spMember.IsEqualObject(pInternalMember))
{
pRet = m_SDKMemberObjs[i];
break;
}
}
}
}
DBGEXIT(CNmConferenceObj::GetSDKMemberFromInternalMember);
return pRet;
}
INmMember* CNmConferenceObj::GetLocalSDKMember()
{
INmMember* pRet = NULL;
for( int i = 0; i < m_SDKMemberObjs.GetSize(); ++i)
{
if(S_OK == m_SDKMemberObjs[i]->IsSelf())
{
pRet = m_SDKMemberObjs[i];
break;
}
}
return pRet;
}
HRESULT CNmConferenceObj::_RemoveMember(INmMember* pInternalMember)
{
HRESULT hr = S_OK;
for( int i = 0; i < m_SDKMemberObjs.GetSize(); ++i)
{
CComPtr<INmMember> spSDKMember = m_SDKMemberObjs[i];
CComQIPtr<IInternalMemberObj> spMemberObj = spSDKMember;
CComPtr<INmMember> spInternal;
if(SUCCEEDED(spMemberObj->GetInternalINmMember(&spInternal)))
{
if(spInternal.IsEqualObject(pInternalMember))
{
// Remove the member from each of the channels
for(int iChan = 0; iChan < m_SDKChannelObjs.GetSize(); ++iChan)
{
com_cast<IInternalChannelObj>(m_SDKChannelObjs[iChan])->SDKMemberRemoved(m_SDKMemberObjs[i]);
}
// Remove our reference to the member
m_SDKMemberObjs.RemoveAt(i);
spSDKMember.p->Release();
break;
}
}
}
return hr;
}
HRESULT CNmConferenceObj::_RemoveChannel(INmChannel* pSDKChannel)
{
HRESULT hr = S_OK;
for( int i = 0; i < m_SDKChannelObjs.GetSize(); ++i)
{
CComPtr<INmChannel> spChannel = m_SDKChannelObjs[i];
if(spChannel.IsEqualObject(pSDKChannel))
{
m_SDKChannelObjs.RemoveAt(i);
com_cast<IInternalChannelObj>(spChannel)->ChannelRemoved();
spChannel.p->Release();
break;
}
}
return hr;
}
void CNmConferenceObj::_EnsureFtChannelAdded()
{
if(NULL == _GetFtChannel())
{
_AddFileTransferChannel();
}
}
HRESULT CNmConferenceObj::_AddFileTransferChannel()
{
HRESULT hr = S_OK;
if(m_pManagerObj && m_pManagerObj->FileTransferNotifications())
{
CComPtr<INmChannel> spChannel;
hr = CNmChannelFtObj::CreateInstance(this, &spChannel);
if(SUCCEEDED(hr))
{
// Add the channel to our list
spChannel.p->AddRef();
m_SDKChannelObjs.Add(spChannel.p);
// Fire the notification
Fire_ChannelChanged(NM_CHANNEL_ADDED, spChannel);
}
}
return hr;
}
HRESULT CNmConferenceObj::_AddAppShareChannel()
{
HRESULT hr = S_OK;
if(m_pManagerObj && m_pManagerObj->AppSharingNotifications())
{
CComPtr<INmChannel> spChannel;
hr = CNmChannelAppShareObj::CreateInstance(this, &spChannel);
if(SUCCEEDED(hr))
{
// Add the channel to our list
spChannel.p->AddRef();
m_SDKChannelObjs.Add(spChannel.p);
// Fire the notification
Fire_ChannelChanged(NM_CHANNEL_ADDED, spChannel);
// If app sharing is arleady active, send the notification
CConfRoom* pcr = GetConfRoom();
if(pcr && pcr->FCanShare())
{
AppSharingStateChanged(true);
}
}
}
return hr;
}
void CNmConferenceObj::_FreeInternalStuff()
{
if(m_dwInternalINmConferenceAdvise)
{
AtlUnadvise(m_spInternalINmConference, IID_INmConferenceNotify2, m_dwInternalINmConferenceAdvise);
m_dwInternalINmConferenceAdvise = 0;
}
m_spInternalINmConference = NULL;
while(m_SDKChannelObjs.GetSize())
{
CComPtr<INmChannel> spChannel = m_SDKChannelObjs[0];
m_SDKChannelObjs[0]->Release();
m_SDKChannelObjs.RemoveAt(0);
CComPtr<IInternalChannelObj> spChanObj = com_cast<IInternalChannelObj>(spChannel);
ASSERT(spChanObj);
spChanObj->Activate(FALSE);
Fire_ChannelChanged(NM_CHANNEL_UPDATED, spChannel);
com_cast<IInternalChannelObj>(spChannel)->ChannelRemoved();
}
// Free our Member objects
while(m_SDKMemberObjs.GetSize())
{
INmMember* pMember = m_SDKMemberObjs[0];
m_SDKMemberObjs.RemoveAt(0);
Fire_MemberChanged(NM_MEMBER_REMOVED, pMember);
pMember->Release();
}
m_SDKMemberObjs.RemoveAll();
if(m_pManagerObj)
{
m_pManagerObj->RemoveConference(com_cast<INmConference>(GetUnknown()));
}
}
bool CNmConferenceObj::_IsGuidInDataChannelList(GUID& rg)
{
return -1 != m_DataChannelGUIDList.Find(rg);
}
void CNmConferenceObj::_EnsureMemberHasAVChannelsIfNeeded(INmMember* pSDKMember)
{
ULONG ulCaps = 0;
BOOL bIsSelf = (S_OK == pSDKMember->IsSelf());
if(bIsSelf || SUCCEEDED(pSDKMember->GetNmchCaps(&ulCaps)))
{
if(bIsSelf || (NMCH_AUDIO & ulCaps))
{
_EnsureMemberHasAVChannel(NMCH_AUDIO, pSDKMember);
}
if(bIsSelf || (NMCH_VIDEO & ulCaps))
{
_EnsureMemberHasAVChannel(NMCH_VIDEO, pSDKMember);
}
}
}
void CNmConferenceObj::_EnsureMemberHasAVChannel(ULONG ulch, INmMember* pSDKMember)
{
INmChannel* pChannel = NULL;
// First we have to check to see if the user has this channel
for(int i = 0; i < m_SDKChannelObjs.GetSize(); ++i)
{
ULONG ulchChannel;
if(SUCCEEDED(m_SDKChannelObjs[i]->GetNmch(&ulchChannel)))
{
if(ulch == ulchChannel)
{
INmMember *pChannelMember = NULL;
CComPtr<IEnumNmMember> spEnum;
if(SUCCEEDED(m_SDKChannelObjs[i]->EnumMember(&spEnum)))
{
ULONG cFetched = 0;
if(S_OK == spEnum->Next(1, &pChannelMember, &cFetched))
{
if(CComPtr<INmMember>(pSDKMember).IsEqualObject(pChannelMember))
{
// This means that we already have this member in a channel
pChannelMember->Release();
return;
}
pChannelMember->Release();
}
}
}
}
}
CComPtr<INmChannel> spChannel;
// Now we have to add the channel
if(NMCH_AUDIO == ulch)
{
if(m_pManagerObj && m_pManagerObj->AudioNotifications())
{
CNmChannelAudioObj::CreateInstance(this, &spChannel, S_FALSE == pSDKMember->IsSelf());
// Add the channel to our list
spChannel.p->AddRef();
m_SDKChannelObjs.Add(spChannel.p);
Fire_ChannelChanged(NM_CHANNEL_ADDED, spChannel);
// Add the member to the channel
com_cast<IInternalChannelObj>(spChannel)->SDKMemberAdded(pSDKMember);
spChannel = NULL;
}
}
if(NMCH_VIDEO == ulch)
{
if(m_pManagerObj && m_pManagerObj->VideoNotifications())
{
CNmChannelVideoObj::CreateInstance(this, &spChannel, S_FALSE == pSDKMember->IsSelf());
// Add the channel to our list
spChannel.p->AddRef();
m_SDKChannelObjs.Add(spChannel.p);
Fire_ChannelChanged(NM_CHANNEL_ADDED, spChannel);
// Add the member to the channel
com_cast<IInternalChannelObj>(spChannel)->SDKMemberAdded(pSDKMember);
}
}
// We activate the video channels if the m_bXXXVideoActive flags are set
if(spChannel && (NMCH_VIDEO == ulch))
{
if(S_OK == pSDKMember->IsSelf())
{
if(m_bLocalVideoActive)
{
// Add the member to the channel
com_cast<IInternalChannelObj>(spChannel)->Activate(true);
Fire_ChannelChanged(NM_CHANNEL_UPDATED, spChannel);
}
}
else
{
if(m_bRemoteVideoActive)
{
// Add the member to the channel
com_cast<IInternalChannelObj>(spChannel)->Activate(true);
Fire_ChannelChanged(NM_CHANNEL_UPDATED, spChannel);
}
}
}
}