|
|
// File: iconf.cpp
#include "precomp.h"
#include "version.h"
#include "ichnlaud.h"
#include "ichnlvid.h"
#include "ichnldat.h"
#include "rostinfo.h"
#include "imanager.h"
#include "isysinfo.h"
#include "imstream.h"
#include "medialst.h"
#include <tsecctrl.h>
typedef CEnumNmX<IEnumNmChannel, &IID_IEnumNmChannel, INmChannel, INmChannel> CEnumNmChannel;
// BUGBUG:
// This is defined as 128 because the RNC_ROSTER structure has the
// same limitation. Investigate what the appropriate number is.
const int MAX_CALLER_NAME = 128;
static const WCHAR _szConferenceNameDefault[] = L"Personal Conference";
static HRESULT OnNotifyStateChanged(IUnknown *pConfNotify, PVOID pv, REFIID riid); static HRESULT OnNotifyMemberAdded(IUnknown *pConfNotify, PVOID pv, REFIID riid); static HRESULT OnNotifyMemberUpdated(IUnknown *pConfNotify, PVOID pv, REFIID riid); static HRESULT OnNotifyMemberRemoved(IUnknown *pConfNotify, PVOID pv, REFIID riid); static HRESULT OnNotifyChannelAdded(IUnknown *pConfNotify, PVOID pv, REFIID riid); static HRESULT OnNotifyChannelUpdated(IUnknown *pConfNotify, PVOID pv, REFIID riid); static HRESULT OnNotifyChannelRemoved(IUnknown *pConfNotify, PVOID pv, REFIID riid); static HRESULT OnNotifyNmUI(IUnknown *pConfNotify, PVOID pv, REFIID riid); static HRESULT OnNotifyStreamEvent(IUnknown *pConfNotify, PVOID pv, REFIID riid);
static DWORD PF_VER_FromDw(DWORD dw); static DWORD PF_VER_FromUserData(ROSTER_DATA_HANDLE hUserData);
static const IID * g_apiidCP[] = { {&IID_INmConferenceNotify}, {&IID_INmConferenceNotify2} };
struct StreamEventInfo { INmChannel *pChannel; NM_STREAMEVENT uEventCode; UINT uSubCode; };
class CUserDataOut { private: int m_nEntries; PUSERDATAINFO m_pudi; CRosterInfo m_ri; PBYTE m_pbSecurity;
public: CUserDataOut(BOOL fSecure, BSTR bstrUserString); ~CUserDataOut() { delete [] m_pbSecurity; delete [] m_pudi; }
PUSERDATAINFO Data() { return m_pudi; } int Entries() { return m_nEntries; } };
CUserDataOut::CUserDataOut(BOOL fSecure, BSTR bstrUserString) : m_nEntries(0), m_pudi(NULL), m_pbSecurity(NULL) { COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance(); if (NULL != pOprahNCUI) { BOOL fULSNameValid = FALSE;
ULONG cbSecurity = 0; ULONG cbUserString = 0;
if (fULSNameValid = pOprahNCUI->GetULSName(&m_ri)) m_nEntries++;
DWORD dwResult; if ( fSecure ) { if (cbSecurity = pOprahNCUI->GetAuthenticatedName(&m_pbSecurity)) { m_nEntries++; } } if (bstrUserString) { if (cbUserString = SysStringByteLen(bstrUserString)) { m_nEntries++; } }
// only add the LocalNodeId to the call user data if H323 is enabled
if (pOprahNCUI->IsH323Enabled()) { m_nEntries++; }
m_pudi = new USERDATAINFO[m_nEntries];
if (m_pudi != NULL) { m_nEntries = 0;
if (fULSNameValid) { m_pudi[m_nEntries].pData = NULL; m_pudi[m_nEntries].pGUID = (PGUID) &g_csguidRostInfo; m_ri.Save(&(m_pudi[m_nEntries].pData), &(m_pudi[m_nEntries].cbData)); m_nEntries++;
}
if (cbSecurity > 0) { m_pudi[m_nEntries].pData = m_pbSecurity; m_pudi[m_nEntries].cbData = cbSecurity; m_pudi[m_nEntries].pGUID = (PGUID) &g_csguidSecurity; m_nEntries++; }
if (cbUserString > 0) { m_pudi[m_nEntries].pData = bstrUserString; m_pudi[m_nEntries].cbData = cbUserString; m_pudi[m_nEntries].pGUID = (PGUID) &g_csguidUserString; m_nEntries++; }
// only add the LocalNodeId to the call user data if H323 is enabled
if (pOprahNCUI->IsH323Enabled()) { m_pudi[m_nEntries].pData = &g_guidLocalNodeId; m_pudi[m_nEntries].cbData = sizeof(g_guidLocalNodeId); m_pudi[m_nEntries].pGUID = (PGUID) &g_csguidNodeIdTag; m_nEntries++; } } } }
CConfObject::CConfObject() : CConnectionPointContainer(g_apiidCP, ARRAY_ELEMENTS(g_apiidCP)), m_hConf (NULL), m_csState (CS_UNINITIALIZED), m_fConferenceCreated(FALSE), m_bstrConfName (NULL), m_bstrConfPassword (NULL), m_pbConfHashedPassword (NULL), m_cbConfHashedPassword (0), m_fServerMode (FALSE), m_uDataMembers (0), m_uMembers (0), m_uH323Endpoints (0), m_ourNodeID (0), m_pMemberLocal (NULL), m_uGCCConferenceID (0), m_pChannelAudioLocal(NULL), m_pChannelVideoLocal(NULL), m_pChannelAudioRemote(NULL), m_pChannelVideoRemote(NULL), m_fSecure (FALSE), m_attendeePermissions (NM_PERMIT_ALL), m_maxParticipants (-1), m_cRef (1) { DebugEntry(CConfObject::CConfObject);
DebugExitVOID(CConfObject::CConfObject); }
CConfObject::~CConfObject() { DebugEntry(CConfObject::~CConfObject);
// Empty the participant list:
while (!m_MemberList.IsEmpty()) { CNmMember * pMember = (CNmMember *) m_MemberList.RemoveHead(); // Shouldn't have any NULL entries:
ASSERT(pMember); pMember->Release(); }
_EraseDataChannelGUIDS();
SysFreeString(m_bstrConfName); SysFreeString(m_bstrConfPassword); delete []m_pbConfHashedPassword;
DebugExitVOID(CConfObject::~CConfObject); }
VOID CConfObject::SetConfName(BSTR bstr) { SysFreeString(m_bstrConfName); m_bstrConfName = SysAllocString(bstr); }
VOID CConfObject::SetConfPassword(BSTR bstr) { ASSERT (NULL == m_pbConfHashedPassword); SysFreeString(m_bstrConfPassword); m_bstrConfPassword = SysAllocString(bstr); }
VOID CConfObject::SetConfHashedPassword(BSTR bstr) { int cch = 0;
ASSERT (NULL == m_bstrConfPassword); delete []m_pbConfHashedPassword; m_pbConfHashedPassword = NULL; if (NULL == bstr) return; cch = SysStringByteLen(bstr); m_pbConfHashedPassword = (PBYTE) new BYTE[cch]; if (NULL == m_pbConfHashedPassword) { ERROR_OUT(("CConfObject::SetConfHashedPassword() - Out of merory.")); return; } memcpy(m_pbConfHashedPassword, bstr, cch); m_cbConfHashedPassword = cch; }
VOID CConfObject::SetConfSecurity(BOOL fSecure) { NM_CONFERENCE_STATE NmState;
m_fSecure = fSecure;
// Force update of the status icon to reflect security
GetState(&NmState); NotifySink((PVOID) NmState, OnNotifyStateChanged); }
VOID CConfObject::SetConfAttendeePermissions(NM30_MTG_PERMISSIONS attendeePermissions) { m_attendeePermissions = attendeePermissions; }
VOID CConfObject::SetConfMaxParticipants(UINT maxParticipants) { m_maxParticipants = maxParticipants; }
HRESULT CConfObject::CreateConference(void) { DebugEntry(CConfObject::CreateConference); HRESULT nsRet = E_FAIL;
switch (m_csState) { case CS_UNINITIALIZED: case CS_TERMINATED: { if ((NULL == m_bstrConfName) || (0 == *m_bstrConfName)) { m_bstrConfName = SysAllocString(_szConferenceNameDefault); } TRACE_OUT(("CConfObject:CreateConference [%ls]", m_bstrConfName)); ASSERT(g_pNodeController); ASSERT(NULL == m_hConf); nsRet = g_pNodeController->CreateConference( m_bstrConfName, m_bstrConfPassword, m_pbConfHashedPassword, m_cbConfHashedPassword, m_fSecure, &m_hConf); if (0 == nsRet) { SetT120State(CS_CREATING); } else { m_hConf = NULL; } break; }
default: { WARNING_OUT(("CConfObject: Can't create - bad state")); nsRet = E_FAIL; } } DebugExitINT(CConfObject::CreateConference, nsRet); return nsRet; }
HRESULT CConfObject::JoinConference( LPCWSTR pcwszConferenceName, LPCWSTR pcwszPassword, LPCSTR pcszAddress, BSTR bstrUserString, BOOL fRetry) { DebugEntry(CConfObject::JoinConference); HRESULT nsRet = E_FAIL;
switch (m_csState) { case CS_COMING_UP: { if (!fRetry) { break; } // fall through if this is another attempt to join
} case CS_UNINITIALIZED: case CS_TERMINATED: { TRACE_OUT(("CConfObject: Joining conference...")); CUserDataOut userData(m_fSecure, bstrUserString);
ASSERT(g_pNodeController); nsRet = g_pNodeController->JoinConference(pcwszConferenceName, pcwszPassword, pcszAddress, m_fSecure, userData.Data(), userData.Entries(), &m_hConf); if (0 == nsRet) { SetT120State(CS_COMING_UP); } else { m_hConf = NULL; } break; }
case CS_GOING_DOWN: default: { WARNING_OUT(("CConfObject: Can't join - bad state")); // BUGBUG: define return values
nsRet = S_FALSE; } } DebugExitINT(CConfObject::JoinConference, nsRet);
return nsRet; }
HRESULT CConfObject::InviteConference( LPCSTR Address, BSTR bstrUserString, REQUEST_HANDLE *phRequest ) { DebugEntry(CConfObject::InviteConference); HRESULT nsRet = E_FAIL; ASSERT(phRequest);
switch (m_csState) { case CS_RUNNING: { TRACE_OUT(("CConfObject: Inviting conference...")); CUserDataOut userData(m_fSecure, bstrUserString);
ASSERT(g_pNodeController); ASSERT(m_hConf); m_hConf->SetSecurity(m_fSecure); nsRet = m_hConf->Invite(Address, userData.Data(), userData.Entries(), phRequest); break; }
default: { WARNING_OUT(("CConfObject: Can't invite - bad state")); nsRet = E_FAIL; } } DebugExitINT(CConfObject::InviteConference, nsRet); return nsRet; } HRESULT CConfObject::LeaveConference(BOOL fForceLeave) { DebugEntry(CConfObject::LeaveConference); HRESULT nsRet = E_FAIL; REQUEST_HANDLE hReq = NULL;
switch (m_csState) { case CS_GOING_DOWN: { // we're already going down
nsRet = S_OK; break; } case CS_COMING_UP: case CS_RUNNING: { if (FALSE == fForceLeave) { COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance(); if (NULL != pOprahNCUI) { int nNodes = pOprahNCUI->GetOutgoingCallCount();
if (m_fServerMode || (nNodes > 1) || (m_uDataMembers > 1)) { // We are either in the process of calling another node
// or we have other people in our conference roster
TRACE_OUT(("CConfObject: Not leaving (there are other nodes)")); break; } } } TRACE_OUT(("CConfObject: Leaving conference...")); ASSERT(g_pNodeController); ASSERT(m_hConf); SetT120State(CS_GOING_DOWN); nsRet = m_hConf->Leave(); break; }
default: { WARNING_OUT(("CConfObject: Can't leave - bad state")); break; } } DebugExitINT(CConfObject::LeaveConference, nsRet); return nsRet; }
BOOL CConfObject::OnT120Invite(CONF_HANDLE hConference, BOOL fSecure) { DebugEntry(CConfObject::OnT120Invite);
BOOL bRet = FALSE;
switch (m_csState) { case CS_UNINITIALIZED: case CS_TERMINATED: { TRACE_OUT(("CConfObject: Accepting a conference invitation...")); ASSERT(g_pNodeController); ASSERT(NULL == m_hConf); m_hConf = hConference;
m_fSecure = fSecure; hConference->SetSecurity(m_fSecure);
// WORKITEM need to issue INmManagerNotify::ConferenceCreated()
SetT120State(CS_COMING_UP);
bRet = TRUE; break; }
default: { WARNING_OUT(("CConfObject: Can't accept invite - bad state")); } } DebugExitBOOL(CConfObject::OnT120Invite, bRet); return bRet; }
BOOL CConfObject::OnRosterChanged(PNC_ROSTER pRoster) { DebugEntry(CConfObject::OnRosterChanged);
BOOL bRet = TRUE; int i;
// REVIEW: Could these be done more efficiently?
if (NULL != pRoster) { #ifdef DEBUG
TRACE_OUT(("Data Roster Dump: for conference ID = %d", pRoster->uConferenceID)); for (i = 0; i < (int) pRoster->uNumNodes; i++) { TRACE_OUT(( "\tID:%d\tName:%ls", pRoster->nodes[i].uNodeID, pRoster->nodes[i].pwszNodeName));
ASSERT(g_pNodeController); UINT cbData; PVOID pData; if (NOERROR == g_pNodeController->GetUserData( pRoster->nodes[i].hUserData, (GUID*) &g_csguidRostInfo, &cbData, &pData)) { CRosterInfo ri; ri.Load(pData); ri.Dump(); } } #endif // DEBUG
UINT nExistingParts = 0; // Allocate an array of markers:
UINT uRosterNodes = pRoster->uNumNodes; LPBOOL pMarkArray = new BOOL[uRosterNodes];
m_ourNodeID = pRoster->uLocalNodeID; m_uGCCConferenceID = pRoster->uConferenceID;
if (NULL != pRoster->pwszConferenceName) { SysFreeString(m_bstrConfName); m_bstrConfName = SysAllocString(pRoster->pwszConferenceName); } if (NULL != pMarkArray) { // Zero out the array:
for (UINT iNode = 0; iNode < uRosterNodes; iNode++) { pMarkArray[iNode] = FALSE; } // For all participants still in the roster,
// clear out the reserved flags and
// copy in new UserInfo
POSITION pos = m_MemberList.GetHeadPosition(); // lous: Preserve previous pos so we can check list integrity
POSITION prevpos = pos; while (NULL != pos) { CNmMember * pMember = (CNmMember *) m_MemberList.GetNext(pos); ASSERT(pMember); pMember->RemovePf(PF_RESERVED); UINT uNodeID = INVALID_GCCID; if (PF_T120 & pMember->GetDwFlags()) { uNodeID = pMember->GetGCCID(); } for (UINT uNode = 0; uNode < uRosterNodes; uNode++) { if (uNodeID == pRoster->nodes[uNode].uNodeID) { nExistingParts++; pMarkArray[uNode] = TRUE; // mark this node as "existing member"
ResetDataMember(pMember, pRoster->nodes[uNode].hUserData); // lou: Check pos to make sure we didn't just wipe out the end of
// the list in ResetDataMember.
if (NULL == prevpos->pNext) { pos = NULL; } break; } } // lou: Store previous pos so we can check list integrity.
prevpos = pos; } RemoveOldDataMembers(m_uDataMembers - nExistingParts);
if (pRoster->uNumNodes > nExistingParts) { #ifdef _DEBUG
UINT nAdded = 0; #endif // _DEBUG
// At least one participant joined:
// find the new participant(s)
for (UINT uNode = 0; uNode < uRosterNodes; uNode++) { if (FALSE == pMarkArray[uNode]) // a new participant?
{ BOOL fLocal = FALSE; CNmMember * pMember = NULL; PVOID pvUserInfo; UINT cbUserInfo; ASSERT(g_pNodeController); if (NOERROR != g_pNodeController->GetUserData( pRoster->nodes[uNode].hUserData, (GUID*) &g_csguidRostInfo, &cbUserInfo, &pvUserInfo)) { pvUserInfo = NULL; cbUserInfo = 0; } UINT uCaps; UINT cbCaps; PVOID pvCaps; if (NOERROR != g_pNodeController->GetUserData( pRoster->nodes[uNode].hUserData, (GUID*) &g_csguidRosterCaps, &cbCaps, &pvCaps)) { uCaps = 0; } else { ASSERT(pvCaps && (sizeof(uCaps) == cbCaps)); uCaps = *((PUINT)pvCaps); }
PGUID pguidNodeId; UINT cbNodeId; if (NOERROR != g_pNodeController->GetUserData( pRoster->nodes[uNode].hUserData, (GUID*) &g_csguidNodeIdTag, &cbNodeId, (PVOID*) &pguidNodeId)) { pguidNodeId = NULL; } else { if (sizeof(GUID) != cbNodeId) { pguidNodeId = NULL; } }
if (m_ourNodeID == pRoster->nodes[uNode].uNodeID) { fLocal = TRUE; } REFGUID rguidNodeId = pguidNodeId ? *pguidNodeId : GUID_NULL;
if (fLocal) { pMember = GetLocalMember(); } else { pMember = MatchDataToH323Member(rguidNodeId, pRoster->nodes[uNode].uNodeID, pvUserInfo); }
if(pMember) { AddDataToH323Member(pMember, pvUserInfo, cbUserInfo, uCaps, &pRoster->nodes[uNode]); #ifdef _DEBUG
nAdded++; // a data participant was effectively added
#endif // _DEBUG
} else { pMember = CreateDataMember( fLocal, rguidNodeId, pvUserInfo, cbUserInfo, uCaps, &pRoster->nodes[uNode]); #ifdef _DEBUG
if (NULL != pMember) { nAdded++; } #endif // _DEBUG
AddMember(pMember, NULL); } } } // Validate that we did the right thing:
ASSERT(nAdded == (uRosterNodes - nExistingParts)); } delete [] pMarkArray; pMarkArray = NULL; } else { ERROR_OUT(("Couldn't allocate pMarkArray - no roster diff done")); }
UINT uPrevDataMembers = m_uDataMembers; m_uDataMembers = pRoster->uNumNodes;
// Check to decide if we should auto-terminate here..
if ((1 == pRoster->uNumNodes) && (uPrevDataMembers > 1) && (1 == m_uDataMembers)) { if (!m_fServerMode) { LeaveConference(FALSE); // don't force (we could be inviting)
} } } else { WARNING_OUT(("NULL pRoster passed to CConfObject::OnRosterChanged!")); }
DebugExitBOOL(CConfObject::OnRosterChanged, bRet); return bRet; }
VOID CConfObject::AddMember(CNmMember * pMember, IH323Endpoint * pConnection) { DebugEntry(CConfObject::AddMember);
if (NULL == pMember) { ERROR_OUT(("AddMember - null member!")); return; }
NM_CONFERENCE_STATE oldNmState, newNmState; GetState(&oldNmState);
m_MemberList.AddTail(pMember); if(pConnection) { pMember->AddH323Endpoint(pConnection); ++m_uH323Endpoints;
CheckState(oldNmState); GetState(&oldNmState); } m_uMembers++;
CheckState(oldNmState);
NotifySink((INmMember *) pMember, OnNotifyMemberAdded);
DebugExitVOID(CConfObject::AddMember); }
VOID CConfObject::RemoveMember(POSITION pos) { DebugEntry(CConfObject::RemoveMember);
NM_CONFERENCE_STATE oldNmState, newNmState;
GetState(&oldNmState);
CNmMember * pMember = (CNmMember *) m_MemberList.RemoveAt(pos); --m_uMembers;
if (pMember->FLocal()) { // this is the local node:
m_pMemberLocal = NULL; }
IH323Endpoint *pConnection = pMember->GetH323Endpoint(); if(pConnection) { pMember->DeleteH323Endpoint(pConnection); --m_uH323Endpoints; }
NotifySink((INmMember *) pMember, OnNotifyMemberRemoved); pMember->Release();
CheckState(oldNmState);
DebugExitVOID(CConfObject::RemoveMember); }
BOOL CConfObject::OnConferenceEnded() { DebugEntry(CConfObject::OnConferenceEnded); BOOL bRet = TRUE;
switch (m_csState) { case CS_GOING_DOWN: { TRACE_OUT(("ConfEnded received (from CS_GOING_DOWN)")); break; }
case CS_RUNNING: { TRACE_OUT(("ConfEnded received (from CS_RUNNING)")); break; }
case CS_COMING_UP: { TRACE_OUT(("ConfEnded received (from CS_COMING_UP)")); break; }
default: { WARNING_OUT(("ConfEnded received (UNEXPECTED)")); } }
if (NULL != m_hConf) { m_hConf->ReleaseInterface(); m_hConf = NULL; } SetT120State(CS_TERMINATED);
TRACE_OUT(("OnConferenceEnded(), num participants is %d", m_uMembers));
// Empty the participant list:
NC_ROSTER FakeRoster; ClearStruct(&FakeRoster); FakeRoster.uConferenceID = m_uGCCConferenceID; OnRosterChanged(&FakeRoster);
ASSERT(0 == m_ourNodeID); ASSERT(0 == m_uDataMembers);
// Reset member variables that pertain to a conference
m_uGCCConferenceID = 0; m_fServerMode = FALSE; m_attendeePermissions = NM_PERMIT_ALL; m_maxParticipants = (UINT)-1;
SysFreeString(m_bstrConfName); m_bstrConfName = NULL; SysFreeString(m_bstrConfPassword); m_bstrConfPassword = NULL;
LeaveH323(TRUE /* fKeepAV */); DebugExitBOOL(CConfObject::OnConferenceEnded, bRet); return bRet; }
BOOL CConfObject::OnConferenceStarted(CONF_HANDLE hConf, HRESULT hResult) { DebugEntry(CConfObject::OnConferenceStarted); BOOL bRet = TRUE;
ASSERT(hConf == m_hConf);
switch (m_csState) { case CS_CREATING: case CS_COMING_UP: { switch(hResult) { case S_OK: TRACE_OUT(("ConfStarted received -> now running")); SetT120State(CS_RUNNING); break; case UI_RC_INVALID_PASSWORD: // nop, don't mess with state
// the conference is still coming up
// the incoming call handler will deal with this
break; default: SetT120State(CS_GOING_DOWN); TRACE_OUT(("ConfStarted failed")); break; } break; }
default: { WARNING_OUT(("OnConferenceStarted received (UNEXPECTED)")); break; } }
DebugExitBOOL(CConfObject::OnConferenceStarted, bRet); return bRet; }
VOID CConfObject::OnH323ChannelChange(DWORD dwFlags, BOOL fIncoming, BOOL fOpen, ICommChannel *pIChannel) { CConfObject *pco = ::GetConfObject(); IEnumNmMember *pEnumMember = NULL; ULONG cFetched; INmChannel *pINmChannel; DWORD dwMediaFlag; HRESULT hr; // find the INmChannel instance that would be associated with the
// comm channel (pIChannel).
// note the current issues with making this work for any number/type of
// channels
//
// - CConfObject has 4 hardcoded instances of send/receive audio/video
// - Those instances aren't yet associated with the ICommChannel instance
// other than by media type and direction. For receive, new instances
// could even be created dynamically as rx channel requests are
// processed. For send, need to change CNmChannelAudio
// and CNmChannelVideo to keep a reference to ICommChannel before
// the channel open attempt occurs
// - There is no base interface common to CNmChannelAudio
// and CNmChannelVideo
// - There is no internal interface on CNmMember
//
CNmMember *pMember = NULL; INmMember *pIMember = NULL;
if (PF_MEDIA_AUDIO & dwFlags) { dwMediaFlag = PF_MEDIA_AUDIO; CNmChannelAudio *pChannelAudio; if (fIncoming) { pChannelAudio = m_pChannelAudioRemote; } else { pChannelAudio = m_pChannelAudioLocal; } if (NULL != pChannelAudio) { pINmChannel = (INmChannel *) pChannelAudio; if (fOpen) { pChannelAudio->CommChannelOpened(pIChannel); } else { pChannelAudio->CommChannelClosed(); } // for every member associated with this channel, do the
// member update thing
hr = pChannelAudio->EnumMember(&pEnumMember); if(pEnumMember) { ASSERT(hr == S_OK);
while(hr == S_OK) { pIMember = NULL; hr = pEnumMember->Next(1, &pIMember, &cFetched); if(!pIMember) { break; } else { ASSERT(hr == S_OK); // this cast is ugly, but necessary because there is no
// real internal interface of CNmMember to query for.
// When in Rome........
pMember = (CNmMember *)pIMember;
if (fOpen) { pMember->AddPf(dwMediaFlag); } else { pMember->RemovePf(dwMediaFlag); } // ugly - OnMemberUpdated() should be a base interface
// method so that this code didn't have to be copied
// for the video case
pChannelAudio->OnMemberUpdated(pMember); pco->OnMemberUpdated(pMember);
if (pMember->FLocal() && (NULL != m_hConf) && (CS_RUNNING == m_csState)) { // m_hConf->UpdateUserData();
} pMember->Release(); } } pEnumMember->Release(); } NotifySink(pINmChannel, OnNotifyChannelUpdated); } } else if (PF_MEDIA_VIDEO & dwFlags) { dwMediaFlag = PF_MEDIA_VIDEO; CNmChannelVideo *pChannelVideo; if (fIncoming) { pChannelVideo = m_pChannelVideoRemote; } else { pChannelVideo = m_pChannelVideoLocal; } if (NULL != pChannelVideo) { pINmChannel = (INmChannel *) pChannelVideo; if (fOpen) { pChannelVideo->CommChannelOpened(pIChannel); } else { pChannelVideo->CommChannelClosed(); }
// for every member associated with this channel, do the
// member update thing
hr = pChannelVideo->EnumMember(&pEnumMember); if(pEnumMember) { ASSERT(hr == S_OK); while(hr == S_OK) { pIMember = NULL; hr = pEnumMember->Next(1, &pIMember, &cFetched); if(!pIMember) { break; } else { ASSERT(hr == S_OK); // this cast is ugly, but necessary because there is no
// real internal interface of CNmMember to query for.
// When in Rome........
pMember = (CNmMember *)pIMember;
if (fOpen) { pMember->AddPf(dwMediaFlag); } else { pMember->RemovePf(dwMediaFlag); } // ugly - OnMemberUpdated() should be a base interface
// method so that this code didn't have to be copied
// from the audio case
pChannelVideo->OnMemberUpdated(pMember); pco->OnMemberUpdated(pMember);
if (pMember->FLocal() && (NULL != m_hConf) && (CS_RUNNING == m_csState)) { // m_hConf->UpdateUserData();
} pMember->Release(); } } pEnumMember->Release(); } NotifySink(pINmChannel, OnNotifyChannelUpdated); } } else ASSERT(0); }
VOID CConfObject::OnAudioChannelStatus(ICommChannel *pIChannel, IH323Endpoint * lpConnection, DWORD dwStatus) { BOOL bIncoming = (pIChannel->IsSendChannel())? FALSE:TRUE; CNmChannelAudio *pChannelAudio; switch (dwStatus) { case CHANNEL_ACTIVE: if (bIncoming) { pChannelAudio = m_pChannelAudioRemote; } else { pChannelAudio = m_pChannelAudioLocal; } if (NULL != pChannelAudio) { pChannelAudio->CommChannelActive(pIChannel); } break; case CHANNEL_OPEN: OnH323ChannelChange(PF_MEDIA_AUDIO, bIncoming, TRUE, pIChannel); break; case CHANNEL_CLOSED: OnH323ChannelChange(PF_MEDIA_AUDIO, bIncoming, FALSE, pIChannel); break; default: return; } }
VOID CConfObject::OnVideoChannelStatus(ICommChannel *pIChannel, IH323Endpoint * lpConnection, DWORD dwStatus) { BOOL bIncoming = (pIChannel->IsSendChannel())? FALSE:TRUE; CNmChannelVideo *pChannelVideo; switch (dwStatus) { case CHANNEL_ACTIVE: if (bIncoming) { pChannelVideo = m_pChannelVideoRemote; } else { pChannelVideo = m_pChannelVideoLocal; } if (NULL != pChannelVideo) { pChannelVideo->CommChannelActive(pIChannel); } break;
case CHANNEL_OPEN: OnH323ChannelChange(PF_MEDIA_VIDEO, bIncoming, TRUE, pIChannel); break; case CHANNEL_CLOSED: OnH323ChannelChange(PF_MEDIA_VIDEO, bIncoming, FALSE, pIChannel); break; case CHANNEL_REJECTED: case CHANNEL_OPEN_ERROR: case CHANNEL_NO_CAPABILITY: if(bIncoming) { if (NULL != m_pChannelVideoRemote) { m_pChannelVideoRemote->CommChannelError(dwStatus); } } else { if (NULL != m_pChannelVideoLocal) { m_pChannelVideoLocal->CommChannelError(dwStatus); } } break;
case CHANNEL_REMOTE_PAUSE_ON: case CHANNEL_REMOTE_PAUSE_OFF: if(bIncoming) { if (NULL != m_pChannelVideoRemote) { BOOL fPause = CHANNEL_REMOTE_PAUSE_ON == dwStatus; m_pChannelVideoRemote->CommChannelRemotePaused(fPause); } } else { if (NULL != m_pChannelVideoLocal) { BOOL fPause = CHANNEL_REMOTE_PAUSE_ON == dwStatus; m_pChannelVideoLocal->CommChannelRemotePaused(fPause); } } break; default: break; } }
VOID CConfObject::CreateMember(IH323Endpoint * pConnection, REFGUID rguidNode, UINT uNodeID) { ASSERT(g_pH323UI); WCHAR wszRemoteName[MAX_CALLER_NAME]; if (FAILED(pConnection->GetRemoteUserName(wszRemoteName, MAX_CALLER_NAME))) { ERROR_OUT(("GetRemoteUserName() failed!")); return; } // Add the local member
CNmMember * pMemberLocal = GetLocalMember(); if (NULL != pMemberLocal) { AddH323ToDataMember(pMemberLocal, NULL); } else { // We aren't already in the list, so add ourselves here:
BSTR bstrName = NULL;
COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance(); if (NULL != pOprahNCUI) { bstrName = pOprahNCUI->GetUserName(); } pMemberLocal = new CNmMember(bstrName, H323_GCCID_LOCAL, PF_H323 | PF_LOCAL_NODE | PF_VER_CURRENT, 0, g_guidLocalNodeId, NULL, 0); if (NULL != pMemberLocal) { AddMember(pMemberLocal, NULL);
ASSERT(NULL == m_pMemberLocal); m_pMemberLocal = pMemberLocal; } }
// Add the remote member
CNmMember * pMemberRemote = MatchH323ToDataMembers(rguidNode, pConnection); if (NULL != pMemberRemote) { AddH323ToDataMember(pMemberRemote, pConnection); } else { // BUGBUG: A version number should be added here, if possible
pMemberRemote = new CNmMember( wszRemoteName, uNodeID, PF_H323, 0, rguidNode, NULL, 0); if (NULL != pMemberRemote) { AddMember(pMemberRemote, pConnection); } }
if (NULL != m_hConf && (CS_RUNNING == m_csState)) { // m_hConf->UpdateUserData();
} }
VOID CConfObject::OnH323Connected(IH323Endpoint * pConnection, DWORD dwFlags, BOOL fAddMember, REFGUID rguidNode) { HRESULT hr; UINT ui; ASSERT(NULL != pConnection); // alloc and initialize media guids.
CMediaList MediaList;
GUID MediaType; BOOL fEnableMedia;
COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance(); if (NULL != pOprahNCUI) { MediaType = MEDIA_TYPE_H323VIDEO; fEnableMedia = pOprahNCUI->IsSendVideoAllowed() && (dwFlags & CRPCF_VIDEO); MediaList.EnableMedia(&MediaType, TRUE /*send */, fEnableMedia); fEnableMedia = pOprahNCUI->IsReceiveVideoAllowed() && (dwFlags & CRPCF_VIDEO); MediaList.EnableMedia(&MediaType, FALSE /* recv, NOT send */, fEnableMedia); MediaType = MEDIA_TYPE_H323AUDIO; fEnableMedia = pOprahNCUI->IsAudioAllowed() && (dwFlags & CRPCF_AUDIO); MediaList.EnableMedia(&MediaType, TRUE /* send */, fEnableMedia); MediaList.EnableMedia(&MediaType, FALSE /* recv, NOT send */, fEnableMedia);
MediaType = MEDIA_TYPE_H323_T120; fEnableMedia = (dwFlags & CRPCF_DATA); MediaList.EnableMedia(&MediaType, TRUE /* send */, fEnableMedia); MediaList.EnableMedia(&MediaType, FALSE /* recv, NOT send */, fEnableMedia); }
hr = MediaList.ResolveSendFormats(pConnection); if(!(SUCCEEDED(hr))) { // Well, there is no way we can ever open any send channel. But It is a
// product requirement to keep the connection up just in case the other
// endpoint(s) ever wants to open a send video channel to this endpoint.
}
ICommChannel* pChannelT120 = CreateT120Channel(pConnection, &MediaList); CreateAVChannels(pConnection, &MediaList); if (pChannelT120) { OpenT120Channel(pConnection, &MediaList, pChannelT120); // no need to hold onto the T120 channel
pChannelT120->Release(); } OpenAVChannels(pConnection, &MediaList);
if (fAddMember) { CreateMember(pConnection, rguidNode, H323_GCCID_REMOTE);
if (dwFlags & (CRPCF_AUDIO | CRPCF_VIDEO)) { CNmMember* pMemberLocal = GetLocalMember(); if (pMemberLocal) { AddMemberToAVChannels(pMemberLocal); }
CNmMember* pMemberRemote = PMemberFromH323Endpoint(pConnection); if (pMemberRemote) { AddMemberToAVChannels(pMemberRemote); } }
} }
VOID CConfObject::OnH323Disconnected(IH323Endpoint * pConnection, BOOL fHasAV) { DebugEntry(CConfObject::OnH323Disconnected);
POSITION pos = m_MemberList.GetHeadPosition(); while (NULL != pos) { POSITION oldpos = pos; CNmMember * pMember = (CNmMember *) m_MemberList.GetNext(pos); ASSERT(pMember); if (pMember->GetH323Endpoint() == pConnection) { if (fHasAV) { RemoveMemberFromAVChannels(pMember); }
if (0 == (PF_T120 & pMember->GetDwFlags())) { // This is an H323 only participant, so remove now:
RemoveMember(oldpos); } else { RemoveH323FromDataMember(pMember, pConnection); } } }
CNmMember *pLocalMember = GetLocalMember(); if (pLocalMember) { if (fHasAV) { RemoveMemberFromAVChannels(pLocalMember); }
if (0 == m_uH323Endpoints) { if (0 == (PF_T120 & pLocalMember->GetDwFlags())) { // This is an H323 only participant, so remove now:
RemoveMember(pLocalMember); } else { RemoveH323FromDataMember(pLocalMember, NULL); } } }
if (fHasAV) { DestroyAVChannels(); }
#ifdef REPORT_ALL_ERRORS
DWORD dwSummary; dwSummary = pConnection->GetSummaryCode() if(CCR_REMOTE_MEDIA_ERROR == dwSummary) { ::PostConfMsgBox(IDS_REMOTE_MEDIA_ERROR); } #endif
if ((NULL != m_hConf) && (CS_RUNNING == m_csState)) { // m_hConf->UpdateUserData();
}
DebugExitVOID(CConfObject::OnH323Disconnected); }
VOID CConfObject::OnT120Connected(IH323Endpoint * pConnection, UINT uNodeID) { CNmMember *pMember = PMemberFromH323Endpoint(pConnection); if (pMember) { // save away the GCC id so that we can match this up when the member is added
pMember->SetGCCID(uNodeID); } else { CreateMember(pConnection, GUID_NULL, uNodeID); } }
// StoreAndVerifyMemberUserData
//
// Processes a member's user data and stores them for the GetUserData API call.
// If security data is among the user data, verification against the transport-level
// credentials is performed.
// Returns FALSE if security verification fails, TRUE otherwise.
BOOL StoreAndVerifyMemberUserData(CNmMember * pMember, ROSTER_DATA_HANDLE hData) { BOOL rc = TRUE; BOOL fUserDataSet;
GCCNodeRecord * pRosterEntry = (GCCNodeRecord *)hData; GCCUserData ** ppUserData = pRosterEntry->user_data_list; for (int i = 0; i < pRosterEntry->number_of_user_data_members; i++) {
fUserDataSet = FALSE;
/* Always False if ((int)ppUserData[i]->octet_string->length - sizeof(GUID) < 0)
{ WARNING_OUT(("StoreAndVerifyMemberUserData: bad user data")); rc = FALSE; break; }*/ if (!pMember->FLocal() && 0 == CompareGuid((GUID *)ppUserData[i]->octet_string->value,(GUID *)&g_csguidSecurity)) { PBYTE pb = NULL; ULONG cb = 0; if (pMember->GetSecurityData(&pb,&cb)) {
//
// Check to make sure that the current user data matches
// the transport security data.
//
if (memcmp(pb,ppUserData[i]->octet_string->value + sizeof(GUID), ppUserData[i]->octet_string->length - sizeof(GUID) - 1)) {
//
// This should NOT happen. Either there is a bug
// in the security code (credentials failed up update
// in the transport or the like), or someone is trying
// to deceive us.
ERROR_OUT(("SECURITYDATA MISMATCH")); fUserDataSet = TRUE; // so we don't do it below.
rc = FALSE; } } else { WARNING_OUT(("StoreAndVerifyMemberUserData: failed to get security data")); rc = FALSE; } CoTaskMemFree(pb); } if ( FALSE == fUserDataSet ) { pMember->SetUserData(*(GUID *)ppUserData[i]->octet_string->value, (BYTE *)ppUserData[i]->octet_string->value + sizeof(GUID), ppUserData[i]->octet_string->length - sizeof(GUID)); } } return rc; }
VOID CConfObject::ResetDataMember( CNmMember * pMember, ROSTER_DATA_HANDLE hData) { DebugEntry(CConfObject::ResetDataMember);
pMember->AddPf(PF_RESERVED); pMember->SetUserInfo(NULL, 0);
UINT cbData; PVOID pData; ASSERT(g_pNodeController); if (NOERROR == g_pNodeController->GetUserData( hData, (GUID*) &g_csguidRostInfo, &cbData, &pData)) { pMember->SetUserInfo(pData, cbData); }
UINT cbCaps; PVOID pvCaps; if (NOERROR != g_pNodeController->GetUserData( hData, (GUID*) &g_csguidRosterCaps, &cbCaps, &pvCaps)) { WARNING_OUT(("roster update is missing caps information")); } else { ASSERT(NULL != pvCaps); ASSERT(sizeof(ULONG) == cbCaps); pMember->SetCaps( *((PULONG)pvCaps) ); }
if (StoreAndVerifyMemberUserData(pMember, hData) == FALSE) { // Need to disconnect the conference in this case.
WARNING_OUT(("ResetDataMember Security Warning: Authentication data could not be verified.")); }
NotifySink((INmMember *) pMember, OnNotifyMemberUpdated);
DebugExitVOID(CConfObject::ResetDataMember); }
VOID CConfObject::RemoveOldDataMembers(int nExpected) { DebugEntry(CConfObject::RemoveOldDataMembers);
#ifdef _DEBUG
int nRemoved = 0; #endif // _DEBUG
ASSERT(nExpected >= 0);
if (nExpected > 0) { // At least one participant left:
POSITION pos = m_MemberList.GetHeadPosition(); while (NULL != pos) { POSITION oldpos = pos; CNmMember * pMember = (CNmMember *) m_MemberList.GetNext(pos); ASSERT(pMember); DWORD dwFlags = pMember->GetDwFlags(); if (!(PF_RESERVED & dwFlags)) { // This one is not in the data call:
TRACE_OUT(("CConfObject Roster: %ls (%d) has left.", pMember->GetName(), pMember->GetGCCID()));
#ifdef _DEBUG
if (dwFlags & PF_T120) { nRemoved++; } #endif // _DEBUG
if (0 == (dwFlags & PF_H323)) { // If they were data only, then remove:
RemoveMember(oldpos); } else { pMember->RemovePf(PF_DATA_ALL); pMember->SetGCCID(pMember->FLocal() ? H323_GCCID_LOCAL : H323_GCCID_REMOTE); pMember->SetGccIdParent(INVALID_GCCID); pMember->SetCaps(0); pMember->SetUserInfo(NULL, 0);
NotifySink((INmMember *) pMember, OnNotifyMemberUpdated); } } }
// Validate that we did the right thing:
ASSERT(nRemoved == nExpected); }
DebugExitVOID(CConfObject::RemoveOldDataMembers); }
CNmMember *CConfObject::MatchDataToH323Member( REFGUID rguidNode, UINT uNodeId, PVOID pvUserInfo) { DebugEntry(CConfObject::MatchDataToH323Member); CNmMember *pMemberRet = NULL; BOOL bRet = FALSE; if (GUID_NULL != rguidNode) { // try matching up guids
pMemberRet = PMemberFromNodeGuid(rguidNode); }
if (NULL == pMemberRet) { // try matching up node ids
pMemberRet = PMemberFromGCCID(uNodeId); }
if ((NULL == pMemberRet) && pvUserInfo) { // All else failed try mathcing IP addresses
CRosterInfo ri; if(SUCCEEDED(ri.Load(pvUserInfo))) { POSITION pos = m_MemberList.GetHeadPosition(); while (NULL != pos) { SOCKADDR_IN sin; CNmMember * pMember = (CNmMember *) m_MemberList.GetNext(pos); IH323Endpoint * pConnection = pMember->GetH323Endpoint(); if (pConnection && (S_OK == pConnection->GetRemoteUserAddr(&sin))) {
TCHAR szAudioIP[MAX_PATH]; TCHAR szDataIP[MAX_PATH]; HROSTINFO hRI = NULL; // BUGBUG: UNICODE issues?
lstrcpyn(szAudioIP, inet_ntoa(sin.sin_addr), CCHMAX(szAudioIP)); while (SUCCEEDED(ri.ExtractItem(&hRI, g_cwszIPTag, szDataIP, CCHMAX(szDataIP)))) { TRACE_OUT(("Comparing data IP \"%s\" with " "audio IP \"%s\"", szDataIP, szAudioIP)); if (0 == lstrcmp(szDataIP, szAudioIP)) { pMemberRet = pMember; break; // out of outer while loop
} } } } } }
DebugExitPVOID(CConfObject::MatchDataToH323Member, pMemberRet); return pMemberRet; }
VOID CConfObject::AddDataToH323Member( CNmMember * pMember, PVOID pvUserInfo, UINT cbUserInfo, UINT uCaps, NC_ROSTER_NODE_ENTRY* pRosterNode) { DebugEntry(CConfObject::AddDataToH323Member);
ASSERT(pMember); ASSERT(NULL != pRosterNode);
DWORD dwFlags = pMember->GetDwFlags(); ASSERT(0 == ((PF_MEDIA_DATA | PF_T120) & dwFlags)); dwFlags |= (PF_T120 | PF_MEDIA_DATA | PF_CA_DETACHED);
// Add version information
dwFlags = (dwFlags & ~PF_VER_MASK) | PF_VER_FromUserData(pRosterNode->hUserData);
pMember->SetDwFlags(dwFlags); pMember->SetGCCID(pRosterNode->uNodeID); pMember->SetGccIdParent(pRosterNode->uSuperiorNodeID);
ASSERT(0 == pMember->GetCaps()); pMember->SetCaps(uCaps);
pMember->SetUserInfo(pvUserInfo, cbUserInfo);
NotifySink((INmMember *) pMember, OnNotifyMemberUpdated);
ROSTER_DATA_HANDLE hData = pRosterNode->hUserData;
if (StoreAndVerifyMemberUserData(pMember, hData) == FALSE) { // Need to disconnect the conference in this case.
WARNING_OUT(("AddDataToH323Member Security Warning: Authentication data could not be verified.")); }
DebugExitVOID(CConfObject::AddDataToH323Member); }
CNmMember * CConfObject::CreateDataMember(BOOL fLocal, REFGUID rguidNode, PVOID pvUserInfo, UINT cbUserInfo, UINT uCaps, NC_ROSTER_NODE_ENTRY* pRosterNode) { DebugEntry(CConfObject::CreateDataMember);
ASSERT(NULL != pRosterNode);
DWORD dwFlags = PF_T120 | PF_MEDIA_DATA | PF_CA_DETACHED; if (fLocal) { dwFlags |= (PF_LOCAL_NODE | PF_VER_CURRENT); } if (pRosterNode->fMCU) { dwFlags |= PF_T120_MCU; }
if (0 != cbUserInfo) { dwFlags = (dwFlags & ~PF_VER_MASK) | PF_VER_FromUserData(pRosterNode->hUserData); }
CNmMember * pMember = new CNmMember(pRosterNode->pwszNodeName, pRosterNode->uNodeID, dwFlags, uCaps, rguidNode, pvUserInfo, cbUserInfo);
if (NULL != pMember) { pMember->SetGccIdParent(pRosterNode->uSuperiorNodeID); if (fLocal) { ASSERT(NULL == m_pMemberLocal); m_pMemberLocal = pMember; } }
ROSTER_DATA_HANDLE hData = pRosterNode->hUserData;
if (StoreAndVerifyMemberUserData(pMember, hData) == FALSE) { // Need to disconnect the conference in this case.
WARNING_OUT(("CreateDataMember Security Warning: Authentication data could not be verified.")); }
TRACE_OUT(("CConfObject Roster: %ls (%d) has joined.", pRosterNode->pwszNodeName, pRosterNode->uNodeID));
DebugExitPVOID(CConfObject::CreateDataMember, pMember); return pMember; }
CNmMember * CConfObject::MatchH323ToDataMembers(REFGUID rguidNodeId, IH323Endpoint * pConnection) { DebugEntry(CConfObject::MatchH323ToDataMembers); CNmMember * pMemberRet = NULL;
// This is currently called only by OnH323Connected(). Terminal label isn't assigned yet.
// so there is no need yet to INSERT SEARCH FOR MATCHING TERMINAL LABEL HERE
if (GUID_NULL != rguidNodeId) { pMemberRet = PMemberFromNodeGuid(rguidNodeId); } else { SOCKADDR_IN sin;
if (S_OK == pConnection->GetRemoteUserAddr(&sin)) { TCHAR szAudioIP[MAX_PATH]; lstrcpyn(szAudioIP, inet_ntoa(sin.sin_addr), CCHMAX(szAudioIP));
POSITION pos = m_MemberList.GetHeadPosition(); while (NULL != pos) { CNmMember * pMember = (CNmMember *) m_MemberList.GetNext(pos);
// need to try to match IP addresses
// this is how things were done in NM2.11 and earlier
TCHAR szDataIP[MAX_PATH]; HROSTINFO hRI = NULL; CRosterInfo ri; if (SUCCEEDED(ri.Load(pMember->GetUserInfo())) ) { while (SUCCEEDED(ri.ExtractItem(&hRI, g_cwszIPTag, szDataIP, CCHMAX(szDataIP)))) { TRACE_OUT(("Comparing data IP \"%s\" with " "h323 IP \"%s\"", szDataIP, szAudioIP)); if (0 == lstrcmp(szDataIP, szAudioIP)) { // close enough
return pMember; } } } } } }
DebugExitPVOID(CConfObject::MatchH323ToDataMembers, pMemberRet); return pMemberRet; }
VOID CConfObject::AddMemberToAVChannels(CNmMember *pMember) { CNmChannelAudio *pChannelAudio; CNmChannelVideo *pChannelVideo;
if (pMember->FLocal()) { pChannelAudio = m_pChannelAudioLocal;
pChannelVideo = m_pChannelVideoLocal; } else { pChannelAudio = m_pChannelAudioRemote;
pChannelVideo = m_pChannelVideoRemote; }
if (pChannelAudio) { pChannelAudio->OnMemberAdded(pMember); // set media flags if channel is open
if(S_OK == pChannelAudio->IsActive()) { pMember->AddPf(PF_MEDIA_AUDIO); pChannelAudio->OnMemberUpdated(pMember); OnMemberUpdated(pMember); } } if (pChannelVideo) { pChannelVideo->OnMemberAdded(pMember); // set media flags if channel is open
if(S_OK == pChannelVideo->IsActive()) { pMember->AddPf(PF_MEDIA_VIDEO); pChannelVideo->OnMemberUpdated(pMember); OnMemberUpdated(pMember); } }
}
VOID CConfObject::RemoveMemberFromAVChannels(CNmMember *pMember) { CNmChannelAudio *pChannelAudio; CNmChannelVideo *pChannelVideo;
if (pMember->FLocal()) { pChannelAudio = m_pChannelAudioLocal;
pChannelVideo = m_pChannelVideoLocal; } else { pChannelAudio = m_pChannelAudioRemote;
pChannelVideo = m_pChannelVideoRemote; }
if ((NULL != pChannelVideo) && (PF_MEDIA_VIDEO & pMember->GetDwFlags())) { pMember->RemovePf(PF_MEDIA_VIDEO); pChannelVideo->OnMemberRemoved(pMember); OnMemberUpdated(pMember); }
if ((NULL != pChannelAudio) && (PF_MEDIA_AUDIO & pMember->GetDwFlags())) { pMember->RemovePf(PF_MEDIA_AUDIO); pChannelAudio->OnMemberRemoved(pMember); OnMemberUpdated(pMember); } }
/* C R E A T E A V C H A N N E L S */ /*-------------------------------------------------------------------------
%%Function: CreateAVChannels Create AV channels. -------------------------------------------------------------------------*/ VOID CConfObject::CreateAVChannels(IH323Endpoint * pConnection, CMediaList* pMediaList) { HRESULT hr; GUID MediaGuid; ICommChannel *pCommChannel = NULL; MediaGuid = MEDIA_TYPE_H323AUDIO; if (pMediaList->IsInSendList(&MediaGuid)) { m_pChannelAudioLocal = new CNmChannelAudio(FALSE /* fIncoming */); if (NULL != m_pChannelAudioLocal) { hr = pConnection->CreateCommChannel(&MediaGuid, &pCommChannel, TRUE /* fSend*/); ASSERT(SUCCEEDED(hr) && (NULL != pCommChannel)); //if(SUCCEEDED(hr) && (NULL != pCommChannel))
{ NotifySink((INmChannel *) m_pChannelAudioLocal, OnNotifyChannelAdded); m_pChannelAudioLocal->OnConnected(pConnection, pCommChannel); hr = pCommChannel->EnableOpen(TRUE); ASSERT(SUCCEEDED(hr)); } pCommChannel->Release(); pCommChannel = NULL; // bug detection that can be removed later
} }
if (pMediaList->IsInRecvList(&MediaGuid)) { m_pChannelAudioRemote = new CNmChannelAudio(TRUE /* fIncoming */); if (NULL != m_pChannelAudioRemote) { hr = pConnection->CreateCommChannel(&MediaGuid, &pCommChannel, FALSE /* fSend*/); ASSERT(SUCCEEDED(hr) && (NULL != pCommChannel)); //if(SUCCEEDED(hr) && (NULL != pCommChannel))
{ NotifySink((INmChannel *) m_pChannelAudioRemote, OnNotifyChannelAdded); m_pChannelAudioRemote->OnConnected(pConnection, pCommChannel); hr = pCommChannel->EnableOpen(TRUE); ASSERT(SUCCEEDED(hr)); } pCommChannel->Release(); pCommChannel = NULL; // bug detection that can be removed later
} } MediaGuid = MEDIA_TYPE_H323VIDEO; // now doing video channels
if (pMediaList->IsInSendList(&MediaGuid)) { m_pChannelVideoLocal = CNmChannelVideo::CreateChannel(FALSE /* fIncoming */); if (NULL != m_pChannelVideoLocal) { BOOL fCreated = FALSE; // check for previous existence of preview stream/preview channel
if(NULL == (pCommChannel= m_pChannelVideoLocal->GetPreviewCommChannel())) { hr = pConnection->CreateCommChannel(&MediaGuid, &pCommChannel, TRUE /* fSend*/); ASSERT(SUCCEEDED(hr) && (NULL != pCommChannel)); fCreated = TRUE; } else { pCommChannel->SetAdviseInterface(m_pIH323ConfAdvise); }
//if(SUCCEEDED(hr) && (NULL != pCommChannel))
{ NotifySink((INmChannel *) m_pChannelVideoLocal, OnNotifyChannelAdded); m_pChannelVideoLocal->OnConnected(pConnection, pCommChannel); hr = pCommChannel->EnableOpen(TRUE); ASSERT(SUCCEEDED(hr)); } if (fCreated) pCommChannel->Release(); pCommChannel = NULL; // bug detection that can be removed later
}
}
if (pMediaList->IsInRecvList(&MediaGuid)) { m_pChannelVideoRemote = CNmChannelVideo::CreateChannel(TRUE /* fIncoming */); if (NULL != m_pChannelVideoRemote) { BOOL fCreated = FALSE; // check for previous existence of preview stream/preview channel
if(NULL == (pCommChannel= m_pChannelVideoRemote->GetCommChannel())) { hr = pConnection->CreateCommChannel(&MediaGuid, &pCommChannel, FALSE /* fSend*/); fCreated = TRUE; } else { pCommChannel->SetAdviseInterface(m_pIH323ConfAdvise); } ASSERT(SUCCEEDED(hr) && (NULL != pCommChannel)); //if(SUCCEEDED(hr) && (NULL != pCommChannel))
{ NotifySink((INmChannel *) m_pChannelVideoRemote, OnNotifyChannelAdded); m_pChannelVideoRemote->OnConnected(pConnection, pCommChannel); hr = pCommChannel->EnableOpen(TRUE); ASSERT(SUCCEEDED(hr)); } if (fCreated) pCommChannel->Release(); } } }
/* O P E N A V C H A N N E L S */ /*-------------------------------------------------------------------------
%%Function: OpenAVChannels Open AV channels. -------------------------------------------------------------------------*/ VOID CConfObject::OpenAVChannels(IH323Endpoint * pConnection, CMediaList* pMediaList) { MEDIA_FORMAT_ID idLocal;
if(m_pChannelAudioLocal) { if (pMediaList->GetSendFormatLocalID(MEDIA_TYPE_H323AUDIO, &idLocal)) { m_pChannelAudioLocal->SetFormat(idLocal); // open only if a valid negotiated format exists.
// it won't hurt to always call the Open() method, but there is
// no need to. This will and should probably change. Calling
// this with INVALID_MEDIA_FORMAT results in a call to the event
// handler for the channel, notifying the upper layer(s) that the
// channel could not be opened due to no compatible caps. User
// feedback could be much improved if it took advantage of this.
if(idLocal != INVALID_MEDIA_FORMAT) { m_pChannelAudioLocal->Open(); } } }
if(m_pChannelVideoLocal) { if (pMediaList->GetSendFormatLocalID(MEDIA_TYPE_H323VIDEO, &idLocal)) { m_pChannelVideoLocal->SetFormat(idLocal); if(m_pChannelVideoLocal->IsPreviewEnabled()) { // open only if a valid negotiated format exists. see comments
// in the MEDIA_TYPE_H323AUDIO case above
if(idLocal != INVALID_MEDIA_FORMAT) { m_pChannelVideoLocal->Open(); } } } } }
ICommChannel* CConfObject::CreateT120Channel(IH323Endpoint * pConnection, CMediaList* pMediaList) { ICommChannel *pChannelT120 = NULL; // create a T.120 channel stub
GUID MediaGuid = MEDIA_TYPE_H323_T120; if (pMediaList->IsInSendList(&MediaGuid)) { HRESULT hr = pConnection->CreateCommChannel(&MediaGuid, &pChannelT120, TRUE /* fSend*/); if(SUCCEEDED(hr)) { ASSERT(NULL != pChannelT120); hr = pChannelT120->EnableOpen(TRUE); ASSERT(SUCCEEDED(hr)); } }
return pChannelT120; }
VOID CConfObject::OpenT120Channel(IH323Endpoint * pConnection, CMediaList* pMediaList, ICommChannel* pChannelT120) { if(pChannelT120) { MEDIA_FORMAT_ID idLocal;
if (pMediaList->GetSendFormatLocalID(MEDIA_TYPE_H323_T120, &idLocal)) { // T.120 channels are different. Always call the Open() method
// If there are no common T.120 capabilities. This lets the
// channel event handler know of the absence of remote T.120
// caps.
// The T.120 call side of things is tied into the T.120 channel
// event handler.
pChannelT120->Open(idLocal, pConnection); } } }
/* D E S T R O Y A V C H A N N E L S */ /*-------------------------------------------------------------------------
%%Function: DestroyAVChannels Destroy AV channels. -------------------------------------------------------------------------*/ VOID CConfObject::DestroyAVChannels() { if (NULL != m_pChannelAudioLocal) { NotifySink((INmChannel *) m_pChannelAudioLocal, OnNotifyChannelRemoved); m_pChannelAudioLocal->Release(); m_pChannelAudioLocal = NULL; } if (NULL != m_pChannelAudioRemote) { NotifySink((INmChannel *) m_pChannelAudioRemote, OnNotifyChannelRemoved); m_pChannelAudioRemote->Release(); m_pChannelAudioRemote = NULL; } if (NULL != m_pChannelVideoLocal) { m_pChannelVideoLocal->OnDisconnected(); NotifySink((INmChannel *) m_pChannelVideoLocal, OnNotifyChannelRemoved); m_pChannelVideoLocal->Release(); m_pChannelVideoLocal = NULL; } if (NULL != m_pChannelVideoRemote) { m_pChannelVideoRemote->OnDisconnected(); NotifySink((INmChannel *) m_pChannelVideoRemote, OnNotifyChannelRemoved); m_pChannelVideoRemote->Release(); m_pChannelVideoRemote = NULL; } }
HRESULT CConfObject::GetMediaChannel (GUID *pmediaID,BOOL bSendDirection, IMediaChannel **ppI) { *ppI = NULL; if (*pmediaID == MEDIA_TYPE_H323AUDIO) { CNmChannelAudio *pAudChan = (bSendDirection ? m_pChannelAudioLocal : m_pChannelAudioRemote); *ppI = (pAudChan ? pAudChan->GetMediaChannelInterface() : NULL); } else if (*pmediaID == MEDIA_TYPE_H323VIDEO) { CNmChannelVideo *pVidChan = (bSendDirection ? m_pChannelVideoLocal : m_pChannelVideoRemote); *ppI = (pVidChan ? pVidChan->GetMediaChannelInterface() : NULL); } return (*ppI == NULL ? E_NOINTERFACE : S_OK); }
VOID CConfObject::AddH323ToDataMember(CNmMember * pMember, IH323Endpoint * pConnection) { DebugEntry(CConfObject::AddH323ToDataMember);
// Add the H323 flag bit to the member:
pMember->AddPf(PF_H323);
if (pConnection) { ASSERT(NULL == pMember->GetH323Endpoint());
pMember->AddH323Endpoint(pConnection); ++m_uH323Endpoints; }
DebugExitVOID(CConfObject::AddH323ToDataMember); }
VOID CConfObject::RemoveH323FromDataMember(CNmMember * pMember, IH323Endpoint * pConnection) { DebugEntry(CConfObject::RemoveH323FromDataMember);
// Remove the H323 flag from the member:
pMember->RemovePf(PF_H323);
if (pConnection) { pMember->DeleteH323Endpoint(pConnection); --m_uH323Endpoints; }
DebugExitVOID(CConfObject::RemoveH323FromDataMember); }
VOID CConfObject::OnMemberUpdated(INmMember *pMember) { NotifySink(pMember, OnNotifyMemberUpdated); }
VOID CConfObject::OnChannelUpdated(INmChannel *pChannel) { NotifySink(pChannel, OnNotifyChannelUpdated); }
VOID CConfObject::SetT120State(CONFSTATE state) { NM_CONFERENCE_STATE oldNmState;
GetState(&oldNmState); m_csState = state; if ( state == CS_TERMINATED ) m_fSecure = FALSE; // Reset secure flag
CheckState(oldNmState); }
VOID CConfObject::CheckState(NM_CONFERENCE_STATE oldNmState) { NM_CONFERENCE_STATE newNmState; GetState(&newNmState); if (oldNmState != newNmState) { NotifySink((PVOID) newNmState, OnNotifyStateChanged); if (NM_CONFERENCE_IDLE == newNmState) { _EraseDataChannelGUIDS(); m_fConferenceCreated = FALSE; } } }
void CConfObject::RemoveDataChannelGUID(REFGUID rguid) { POSITION pCur = m_DataChannelGUIDS.GetHeadPosition(); POSITION pNext = pCur; while(pCur) { GUID* pG = reinterpret_cast<GUID*>(m_DataChannelGUIDS.GetNext(pNext)); if(*pG == rguid) { m_DataChannelGUIDS.RemoveAt(pCur); } pCur = pNext; } }
void CConfObject::_EraseDataChannelGUIDS(void) { POSITION pCur = m_DataChannelGUIDS.GetHeadPosition(); while(pCur) { GUID* pG = reinterpret_cast<GUID*>(m_DataChannelGUIDS.GetNext(pCur)); delete pG; }
m_DataChannelGUIDS.EmptyList(); }
ULONG CConfObject::AddRef(void) { return ++m_cRef; } ULONG CConfObject::Release(void) { ASSERT(m_cRef > 0);
if (m_cRef > 0) { m_cRef--; }
ULONG cRef = m_cRef;
if (0 == cRef) { delete this; }
return cRef; }
HRESULT STDMETHODCALLTYPE CConfObject::QueryInterface(REFIID riid, PVOID *ppv) { HRESULT hr = S_OK;
if((riid == IID_INmConference2) || (riid == IID_INmConference) || (riid == IID_IUnknown)) { *ppv = (INmConference2 *)this; ApiDebugMsg(("CConfObject::QueryInterface()")); } else if (riid == IID_IConnectionPointContainer) { *ppv = (IConnectionPointContainer *) this; ApiDebugMsg(("CConfObject::QueryInterface(): Returning IConnectionPointContainer.")); } else { hr = E_NOINTERFACE; *ppv = NULL; ApiDebugMsg(("CConfObject::QueryInterface(): Called on unknown interface.")); }
if (S_OK == hr) { AddRef(); }
return hr; }
HRESULT CConfObject::GetName(BSTR *pbstrName) { HRESULT hr = E_POINTER;
if (NULL != pbstrName) { *pbstrName = SysAllocString(m_bstrConfName); hr = *pbstrName ? S_OK : E_FAIL; } return hr; }
HRESULT CConfObject::GetID(ULONG *puID) { HRESULT hr = E_POINTER;
if (NULL != puID) { *puID = m_uGCCConferenceID; hr = S_OK; } return hr; }
HRESULT CConfObject::GetState(NM_CONFERENCE_STATE *pState) { HRESULT hr = E_POINTER;
if (NULL != pState) { hr = S_OK;
switch (m_csState) { // Note: All states are valid (at least, for now)
case CS_CREATING: case CS_UNINITIALIZED: case CS_TERMINATED: if (0 == m_uH323Endpoints) { *pState = NM_CONFERENCE_IDLE; break; } //////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// else fall through !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//////////////////////////////////////////////////////////////////////////
case CS_COMING_UP: case CS_GOING_DOWN: case CS_RUNNING: if (m_uMembers < 2) { if (m_fServerMode) { *pState = NM_CONFERENCE_WAITING; } else { *pState = NM_CONFERENCE_INITIALIZING; } } else { *pState = NM_CONFERENCE_ACTIVE; } break; default: hr = E_FAIL; break; } } return hr; }
HRESULT CConfObject::GetNmchCaps(ULONG *puchCaps) { HRESULT hr = E_POINTER;
// BUGBUG: this returns secure cap only, used to be NOTIMPL
if (NULL != puchCaps) { *puchCaps = m_fSecure ? NMCH_SECURE : 0; hr = S_OK; } return hr; }
HRESULT CConfObject::GetTopProvider(INmMember **ppMember) { CNmMember *pMemberRet = NULL; HRESULT hr = E_POINTER;
if (NULL != ppMember) { POSITION pos = m_MemberList.GetHeadPosition(); while (NULL != pos) { CNmMember *pMember = (CNmMember *) m_MemberList.GetNext(pos); ASSERT(pMember);
if (pMember->FTopProvider()) { // We have found the top provider
pMemberRet = pMember; break; } }
*ppMember = pMemberRet; hr = (NULL != pMemberRet) ? S_OK : S_FALSE; } return hr; }
HRESULT CConfObject::EnumMember(IEnumNmMember **ppEnum) { HRESULT hr = E_POINTER;
if (NULL != ppEnum) { *ppEnum = new CEnumNmMember(&m_MemberList, m_uMembers); hr = (NULL != *ppEnum) ? S_OK : E_OUTOFMEMORY; } return hr; }
HRESULT CConfObject::GetMemberCount(ULONG *puCount) { HRESULT hr = E_POINTER;
if (NULL != puCount) { *puCount = m_uMembers; hr = S_OK; } return hr; }
HRESULT CConfObject::EnumChannel(IEnumNmChannel **ppEnum) { HRESULT hr = E_POINTER; if (NULL != ppEnum) { COBLIST ChannelList; ULONG cChannels = 0; if (NULL != m_pChannelAudioLocal) { ChannelList.AddTail(m_pChannelAudioLocal); ++cChannels; } if (NULL != m_pChannelAudioRemote) { ChannelList.AddTail(m_pChannelAudioRemote); ++cChannels; } if (NULL != m_pChannelVideoLocal) { ChannelList.AddTail(m_pChannelVideoLocal); ++cChannels; } if (NULL != m_pChannelVideoRemote) { ChannelList.AddTail(m_pChannelVideoRemote); ++cChannels; } *ppEnum = new CEnumNmChannel(&ChannelList, cChannels); hr = (NULL != ppEnum) ? S_OK : E_OUTOFMEMORY; ChannelList.EmptyList(); } return hr; }
HRESULT CConfObject::GetChannelCount(ULONG *puCount) { HRESULT hr = E_POINTER;
if (NULL != puCount) { ULONG cChannels = 0;
if (NULL != m_pChannelAudioLocal) { ++cChannels; } if (NULL != m_pChannelAudioRemote) { ++cChannels; } if (NULL != m_pChannelVideoLocal) { ++cChannels; } if (NULL != m_pChannelVideoRemote) { ++cChannels; }
*puCount = cChannels; hr = S_OK; } return hr; }
/* P M E M B E R L O C A L */ /*-------------------------------------------------------------------------
%%Function: PMemberLocal -------------------------------------------------------------------------*/ CNmMember * PMemberLocal(COBLIST *pList) { if (NULL != pList) { POSITION posCurr; POSITION pos = pList->GetHeadPosition(); while (NULL != pos) { posCurr = pos; CNmMember * pMember = (CNmMember *) pList->GetNext(pos); ASSERT(NULL != pMember); if (pMember->FLocal()) return pMember; } } return NULL; }
HRESULT STDMETHODCALLTYPE CConfObject::CreateDataChannelEx(INmChannelData **ppChannel, REFGUID rguid, BYTE * pER) { if (NULL != ppChannel) { if (IsBadWritePtr(ppChannel, sizeof(LPVOID))) return E_POINTER; *ppChannel = NULL; }
if (GUID_NULL == rguid) { WARNING_OUT(("CreateDataChannel: Null guid")); return E_INVALIDARG; }
{ // Make sure we're in a data conference
CNmMember * pMember = PMemberLocal(&m_MemberList); if (NULL == pMember) return E_FAIL;
// Data must be available
if (!FValidGccId(pMember->GetGCCID())) return NM_E_NO_T120_CONFERENCE; }
// Make sure the data channel has not already been created
GUID g = rguid;
POSITION pCur = m_DataChannelGUIDS.GetHeadPosition(); while(pCur) { GUID* pG = reinterpret_cast<GUID*>(m_DataChannelGUIDS.GetNext(pCur)); if(*pG == rguid) { return NM_E_CHANNEL_ALREADY_EXISTS; } }
CNmChannelData * pChannel = new CNmChannelData(this, rguid, (PGCCEnrollRequest) pER); if (NULL == pChannel) { WARNING_OUT(("CreateChannelData: Unable to create data channel")); return E_OUTOFMEMORY; }
HRESULT hr = pChannel->OpenConnection(); if (FAILED(hr)) { ERROR_OUT(("CreateDataChannel: Unable to set guid / create T.120 channels")); // Failed to create T.120 data channels
delete pChannel; *ppChannel = NULL; return hr; }
GUID* pG = new GUID; *pG = g;
m_DataChannelGUIDS.AddTail(pG);
NotifySink((INmChannel *) pChannel, OnNotifyChannelAdded); TRACE_OUT(("CreateChannelData: Created data channel %08X", pChannel));
// Now we are active
NotifySink((INmChannel*) pChannel, OnNotifyChannelUpdated);
if (NULL != ppChannel) { *ppChannel = (INmChannelData *)pChannel; // pChannel->AddRef(); // Caller needs to release the initial lock
} else { pChannel->Release(); // No one is watching this channel? - free it now
}
return S_OK; }
HRESULT STDMETHODCALLTYPE CConfObject::CreateDataChannel(INmChannelData **ppChannel, REFGUID rguid) { return CreateDataChannelEx(ppChannel, rguid, NULL); }
HRESULT CConfObject::IsHosting(void) { return m_fServerMode ? S_OK : S_FALSE; }
HRESULT CConfObject::Host(void) { HRESULT hr = E_FAIL;
if (m_fServerMode || IsConferenceActive()) { WARNING_OUT(("Conference already exists!")); // ncsRet = UI_RC_CONFERENCE_ALREADY_EXISTS;
} else { HRESULT ncsRet = CreateConference(); if (S_OK == ncsRet) { // The only success case:
TRACE_OUT(("Create local issued successfully")); m_fServerMode = TRUE; hr = S_OK; } else { // UI?
WARNING_OUT(("Create local failed!")); } } return hr; }
HRESULT CConfObject::Leave(void) { DebugEntry(CConfObject::Leave);
COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance(); if (NULL != pOprahNCUI) { pOprahNCUI->CancelCalls(); }
HRESULT hr = S_OK; switch (m_csState) { case CS_GOING_DOWN: // we are already exiting
break;
case CS_COMING_UP: case CS_RUNNING: { SetT120State(CS_GOING_DOWN); ASSERT(m_hConf); TRACE_OUT(("Calling IDataConference::Leave")); hr = m_hConf->Leave(); if (FAILED(hr)) { WARNING_OUT(("IDataConference::Leave failed")); } break; }
default: hr = E_FAIL; break; }
if(FAILED(LeaveH323(FALSE /* fKeepAV */ ))) { // overwrite return value.... I guess this error is as good as any error
hr = E_FAIL; }
DebugExitHRESULT(CConfObject::Leave, hr); return hr; }
HRESULT CConfObject::LeaveH323(BOOL fKeepAV) { HRESULT hrRet = S_OK; POSITION pos = m_MemberList.GetHeadPosition(); while (NULL != pos && !m_MemberList.IsEmpty()) { CNmMember * pMember = (CNmMember *) m_MemberList.GetNext(pos); ASSERT(pMember); HRESULT hr; DWORD dwFlags = pMember->GetDwFlags(); IH323Endpoint * pConnection = pMember->GetH323Endpoint(); if(pConnection) { if (!fKeepAV || !((PF_MEDIA_AUDIO | PF_MEDIA_VIDEO) & dwFlags)) { ConnectStateType state = CLS_Idle; hr = pConnection->GetState(&state); if (SUCCEEDED(hr)) { if(state != CLS_Idle) { ASSERT(dwFlags & PF_H323); hr = pConnection->Disconnect(); if (SUCCEEDED(hr)) { TRACE_OUT(("pConnection->Disconnect() succeeded!")); } else { hrRet = E_FAIL; WARNING_OUT(("pConnection->Disconnect() failed!")); } } } else { hrRet = E_FAIL; } } } } return hrRet; }
HRESULT CConfObject::LaunchRemote(REFGUID rguid, INmMember *pMember) { DWORD dwUserId = 0; if(m_hConf) { if (NULL != pMember) { dwUserId = ((CNmMember*)pMember)->GetGCCID(); }
ASSERT(g_pNodeController); ASSERT(m_hConf); HRESULT nsRet = m_hConf->LaunchGuid(&rguid, (PUINT) &dwUserId, (0 == dwUserId) ? 0 : 1);
return (S_OK == nsRet) ? S_OK : E_FAIL; }
return NM_E_NO_T120_CONFERENCE; }
STDMETHODIMP CConfObject::DisconnectAV(INmMember *pMember) { return E_FAIL; }
/****************************************************************************
* * CLASS: CConfObject * * FUNCTION: ConnectAV(LPCTSTR, LPCTSTR) * * PURPOSE: Switches Audio and Video to a new person (given an IP address) * ****************************************************************************/
STDMETHODIMP CConfObject::ConnectAV(INmMember *pMember) { DebugEntry(CConfRoom::SwitchAV);
HRESULT hr = E_FAIL;
DebugExitHRESULT(CConfRoom::SwitchAV, hr); return hr; }
/****************************************************************************
* * CLASS: CConfObject * * FUNCTION: GetConferenceHandle(DWORD *) * * PURPOSE: Gets the T120 conference handle * ****************************************************************************/
STDMETHODIMP CConfObject::GetConferenceHandle(DWORD_PTR *pdwHandle) { HRESULT hr = E_FAIL;
if (NULL != pdwHandle) { CONF_HANDLE hConf = GetConfHandle(); *pdwHandle = (DWORD_PTR)hConf; hr = S_OK; } return hr;
}
/* O N N O T I F Y S T A T E C H A N G E D */ /*-------------------------------------------------------------------------
%%Function: OnNotifyStateChanged -------------------------------------------------------------------------*/ HRESULT OnNotifyStateChanged(IUnknown *pConfNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pConfNotify);
((INmConferenceNotify*)pConfNotify)->StateChanged((NM_CONFERENCE_STATE)((DWORD_PTR)pv)); return S_OK; }
/* O N N O T I F Y M E M B E R A D D E D */ /*-------------------------------------------------------------------------
%%Function: OnNotifyMemberAdded -------------------------------------------------------------------------*/ HRESULT OnNotifyMemberAdded(IUnknown *pConfNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pConfNotify);
((INmConferenceNotify*)pConfNotify)->MemberChanged(NM_MEMBER_ADDED, (INmMember *) pv); return S_OK; }
/* O N N O T I F Y M E M B E R U P D A T E D */ /*-------------------------------------------------------------------------
%%Function: OnNotifyMemberUpdated -------------------------------------------------------------------------*/ HRESULT OnNotifyMemberUpdated(IUnknown *pConfNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pConfNotify);
((INmConferenceNotify*)pConfNotify)->MemberChanged(NM_MEMBER_UPDATED, (INmMember *) pv); return S_OK; }
/* O N N O T I F Y M E M B E R R E M O V E D */ /*-------------------------------------------------------------------------
%%Function: OnNotifyMemberRemoved -------------------------------------------------------------------------*/ HRESULT OnNotifyMemberRemoved(IUnknown *pConfNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pConfNotify);
((INmConferenceNotify*)pConfNotify)->MemberChanged(NM_MEMBER_REMOVED, (INmMember *) pv); return S_OK; }
/* O N N O T I F Y C H A N N E L A D D E D */ /*-------------------------------------------------------------------------
%%Function: OnNotifyChannelAdded -------------------------------------------------------------------------*/ HRESULT OnNotifyChannelAdded(IUnknown *pConfNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pConfNotify);
((INmConferenceNotify*)pConfNotify)->ChannelChanged(NM_CHANNEL_ADDED, (INmChannel *) pv); return S_OK; }
/* O N N O T I F Y C H A N N E L U P D A T E D */ /*-------------------------------------------------------------------------
%%Function: OnNotifyChannelUpdated -------------------------------------------------------------------------*/ HRESULT OnNotifyChannelUpdated(IUnknown *pConfNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pConfNotify);
((INmConferenceNotify*)pConfNotify)->ChannelChanged(NM_CHANNEL_UPDATED, (INmChannel *) pv); return S_OK; }
/* O N N O T I F Y C H A N N E L R E M O V E D */ /*-------------------------------------------------------------------------
%%Function: OnNotifyChannelRemoved -------------------------------------------------------------------------*/ HRESULT OnNotifyChannelRemoved(IUnknown *pConfNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pConfNotify);
((INmConferenceNotify*)pConfNotify)->ChannelChanged(NM_CHANNEL_REMOVED, (INmChannel *) pv); return S_OK; }
HRESULT OnNotifyStreamEvent(IUnknown *pConfNotify, PVOID pv, REFIID riid) { StreamEventInfo *pInfo = (StreamEventInfo*)pv; ASSERT(NULL != pConfNotify); HRESULT hr;
if (riid != IID_INmConferenceNotify2) return E_NOINTERFACE;
((INmConferenceNotify2*)pConfNotify)->StreamEvent(pInfo->uEventCode, pInfo->uSubCode, pInfo->pChannel); return S_OK; }
/* O N N O T I F Y N M U I */ /*-------------------------------------------------------------------------
%%Function: OnNotifyNmUI -------------------------------------------------------------------------*/ HRESULT OnNotifyNmUI(IUnknown *pConfNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pConfNotify);
((INmConferenceNotify*)pConfNotify)->NmUI((CONFN)((DWORD_PTR)pv)); return S_OK; }
/* G E T C O N F O B J E C T */ /*-------------------------------------------------------------------------
%%Function: GetConfObject
Global function to get the conference object -------------------------------------------------------------------------*/ CConfObject * GetConfObject(void) { COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance(); if (NULL != pOprahNCUI) { return pOprahNCUI->GetConfObject(); } return NULL; }
/* G E T C O N F E R E N C E */ /*-------------------------------------------------------------------------
%%Function: GetConference
Global function to get the INmConference interface to the conf object -------------------------------------------------------------------------*/ HRESULT GetConference(INmConference **ppConference) { HRESULT hr = E_POINTER; if (NULL != ppConference) { hr = E_FAIL; INmConference *pConference = GetConfObject(); if (NULL != pConference) { pConference->AddRef(); hr = S_OK; } *ppConference = pConference; } return hr; }
/* G E T M E M B E R L I S T */ /*-------------------------------------------------------------------------
%%Function: GetMemberList
Global function to get the member list -------------------------------------------------------------------------*/ COBLIST * GetMemberList(void) { CConfObject* pco = ::GetConfObject(); if (NULL == pco) return NULL; return pco->GetMemberList(); }
/* P F _ V E R _ F R O M D W */ /*-------------------------------------------------------------------------
%%Function: PF_VER_FromDw
-------------------------------------------------------------------------*/ DWORD PF_VER_FromDw(DWORD dw) { if (DWVERSION_NM_1 == dw) return PF_VER_NM_1;
if ((DWVERSION_NM_2b2 <= dw) && (DWVERSION_NM_2 >= dw)) return PF_VER_NM_2;
if ((DWVERSION_NM_3a1 <= dw) && (DWVERSION_NM_3max >= dw)) return PF_VER_NM_3;
if ((DWVERSION_NM_4a1 <= dw) && (DWVERSION_NM_CURRENT >= dw)) return PF_VER_NM_4;
if (dw > DWVERSION_NM_CURRENT) return PF_VER_FUTURE;
return PF_VER_UNKNOWN; }
/* P F _ V E R _ F R O M U S E R D A T A */ /*-------------------------------------------------------------------------
%%Function: PV_VER_FromUserData -------------------------------------------------------------------------*/ DWORD PF_VER_FromUserData(ROSTER_DATA_HANDLE hUserData) { UINT cb; PT120PRODUCTVERSION pVersion; PVOID pv;
static const GUID g_csguidVerInfo = GUID_VERSION;
ASSERT(NULL != g_pNodeController);
if (NULL == hUserData) return PF_VER_UNKNOWN; // not NetMeeting
// Try to find the T.120 Product Version guid
if ((NOERROR == g_pNodeController->GetUserData(hUserData, &g_csguidVerInfo, &cb, (PVOID *) &pVersion)) && (cb < sizeof(T120PRODUCTVERSION)) ) { return PF_VER_FromDw(pVersion->dwVersion); }
// Try to extract the build number from the hex string for VER_PRODUCTVERSION_DW
if ((NOERROR == g_pNodeController->GetUserData(hUserData, (GUID *) &g_csguidRostInfo, &cb, &pv))) { CRosterInfo ri; ri.Load(pv);
TCHAR szVersion[MAX_PATH]; if (SUCCEEDED(ri.ExtractItem(NULL, g_cwszVerTag, szVersion, CCHMAX(szVersion)))) { return PF_VER_FromDw(DwFromHex(szVersion)); } }
return PF_VER_NM_1; // Must be at least NetMeeting 1.0
}
DWORD CConfObject::GetDwUserIdLocal(void) { CNmMember * pMemberLocal = GetLocalMember();
if (NULL != pMemberLocal) { return pMemberLocal->GetGCCID(); }
return 0; }
CNmMember * CConfObject::PMemberFromGCCID(UINT uNodeID) { COBLIST* pMemberList = ::GetMemberList(); if (NULL != pMemberList) { POSITION pos = pMemberList->GetHeadPosition(); while (pos) { CNmMember * pMember = (CNmMember *) pMemberList->GetNext(pos); ASSERT(NULL != pMember); if (uNodeID == pMember->GetGCCID()) { return pMember; } } } return NULL; }
CNmMember * CConfObject::PMemberFromNodeGuid(REFGUID rguidNode) { POSITION pos = m_MemberList.GetHeadPosition(); while (NULL != pos) { CNmMember * pMember = (CNmMember *) m_MemberList.GetNext(pos);
if (pMember->GetNodeGuid() == rguidNode) { return pMember; } } return NULL; }
CNmMember * CConfObject::PMemberFromH323Endpoint(IH323Endpoint * pConnection) { COBLIST* pMemberList = ::GetMemberList(); if (NULL != pMemberList) { POSITION pos = pMemberList->GetHeadPosition(); while (pos) { CNmMember * pMember = (CNmMember *) pMemberList->GetNext(pos); ASSERT(NULL != pMember); if (pConnection == pMember->GetH323Endpoint()) { return pMember; } } } return NULL; }
CNmMember * CConfObject::PDataMemberFromName(PCWSTR pwszName) { POSITION pos = m_MemberList.GetHeadPosition(); while (NULL != pos) { CNmMember * pMember = (CNmMember *) m_MemberList.GetNext(pos);
if(pMember->FHasData()) { if (0 == UnicodeCompare(pwszName, pMember->GetName())) { return pMember; } } } return NULL; }
// IStreamEventNotify method
// get called whenever a major event on the stream occurs
HRESULT __stdcall CConfObject::EventNotification(UINT uDirection, UINT uMediaType, UINT uEventCode, UINT uSubCode) { CNmChannelAudio *pChannel = NULL; ULONG uStatus = 0; StreamEventInfo seInfo;
if (uMediaType == MCF_AUDIO) {
if (uDirection == MCF_SEND) { pChannel = m_pChannelAudioLocal; } else if (uDirection == MCF_RECV) { pChannel = m_pChannelAudioRemote; } }
if (pChannel) { // If we get a device failure notification,
// do a quick check to see if the device is indeed
// jammed. The device may have opened by the time we
// got this notification
seInfo.pChannel = pChannel; seInfo.uSubCode = uSubCode;
switch (uEventCode) { case STREAM_EVENT_DEVICE_FAILURE: { seInfo.uEventCode = (NM_STREAMEVENT)NM_STREAMEVENT_DEVICE_FAILURE; NotifySink((void*)&seInfo, OnNotifyStreamEvent); break; } case STREAM_EVENT_DEVICE_OPEN: { seInfo.uEventCode = (NM_STREAMEVENT)NM_STREAMEVENT_DEVICE_OPENED; NotifySink((void*)&seInfo, OnNotifyStreamEvent); break; } default: { break; } } }
else { return E_FAIL; }
return S_OK; }
|