📄 rtcs.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*************************************************************************
Disclaimer:
This code and information is provided "as is" without warranty of
any kind, either expressed or implied, including but not limited to
the implied warranties of merchantability and/or fitness for a
particular purpose.
Module Name:
rtcs.cpp
Abstract:
Provides functions for UI to interface with the rest of the app.
Notes:
This helps to keep the UI and RTC as separate as possible.
**************************************************************************/
// instantiate global variables
#define _Instantiate_Globals_ 1
#include <windows.h>
#include "rtcs.h"
#include "rtcInternal.h"
#include <iptypes.h>
#include <iphlpapi.h>
int g_iAlloc = 0;
int g_iFree = 0;
HANDLE g_hShutdownEventComplete = NULL;
extern DWORD g_dwMainThreadID;
BSTR ReadProfileFromFile(void);
/***********************************************************************************************
Global variables
************************************************************************************************/
extern LOCAL_USER_INFO* g_pLocalUserInfo; // local user information
extern HINSTANCE m_hInstance; // main program instance (for resources, etc.)
STRING_TBL BuddyStatusTbl[] = {
RTCXS_PRESENCE_OFFLINE, L"RTCXS_PRESENCE_OFFLINE",
RTCXS_PRESENCE_ONLINE, L"RTCXS_PRESENCE_ONLINE",
RTCXS_PRESENCE_AWAY, L"RTCXS_PRESENCE_AWAY",
RTCXS_PRESENCE_IDLE, L"RTCXS_PRESENCE_IDLE",
RTCXS_PRESENCE_BUSY, L"RTCXS_PRESENCE_BUSY",
RTCXS_PRESENCE_BE_RIGHT_BACK, L"RTCXS_PRESENCE_BE_RIGHT_BACK",
RTCXS_PRESENCE_ON_THE_PHONE, L"RTCXS_PRESENCE_ON_THE_PHONE",
RTCXS_PRESENCE_OUT_TO_LUNCH, L"RTCXS_PRESENCE_OUT_TO_LUNCH",
END_VAL, L"Unknown Buddy Status"
}; // used by HandleBuddyEvent(), and SetMyStatus() in rtcs.cpp
IRES_TBL EstatRTCTbl[] = {
ES_ONLINE, RTCXS_PRESENCE_ONLINE,
ES_OFFLINE, RTCXS_PRESENCE_OFFLINE,
ES_AWAY, RTCXS_PRESENCE_AWAY,
ES_PHONE, RTCXS_PRESENCE_ON_THE_PHONE,
ES_LUNCH, RTCXS_PRESENCE_OUT_TO_LUNCH,
ES_BUSY, RTCXS_PRESENCE_BUSY,
ES_BEBACK, RTCXS_PRESENCE_BE_RIGHT_BACK,
END_VAL, -1
}; // used to match internal presence status with RTC presence status codes
/************************************************************************************************
Internal function prototypes
************************************************************************************************/
BOOL InitializePresence(BSTR bstrName);
BOOL OpenRegKey( LPWSTR szRegKey, HKEY* hKey );
/************************************************************************************************
InitializeRTC
Performs all steps necessary to initialize the RTC side of the app.
- Creates & initializes the COM objects
registers the event handler with RTC & starts to listen for incoming connections
- Calls InitializePresence
- sets the local URI and name for outgoing SIP headers
************************************************************************************************/
BOOL
InitializeRTC(
FARPROC fnSWCB,
HINSTANCE hInst
)
{
HRESULT hr = S_OK;
BOOL bRV = TRUE;
HANDLE hDB = NULL;
CEOID oid = 0;
BOOL bDone = FALSE;
// Connect to the RTC stuff
DEBUGMSG( ZONE_STATUS|ZONE_INIT|ZONE_WARN, (L"Voipdemo: Beginning Initialization of RTC.\r\n") );
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr)) {
DEBUGMSG( ZONE_ERROR, (L"VoipDemo: CoInitializeEx Failed 0x%X\r\n", hr) );
return FALSE;
}
hr = CoCreateInstance(
CLSID_RTCClient,
NULL,
CLSCTX_INPROC_SERVER,
IID_IRTCClient,
(LPVOID *)&g_pRTCClient
);
if (FAILED(hr)) {
DEBUGMSG( ZONE_ERROR, (L"VoipDemo: CoCreateInstance(RTCClient) Failed 0x%X\r\n", hr) );
return FALSE;
}
hr = g_pRTCClient->Initialize();
if (FAILED(hr)) {
DEBUGMSG( ZONE_ERROR, (L"VoipDemo: Failed to initialize RTCClient 0x%lx\r\n",hr) );
bRV = FALSE;
goto Cleanup;
}
g_pcsSessionDataLock = new CRITICAL_SECTION;
InitializeCriticalSection( g_pcsSessionDataLock );
g_pRTCEvents = new CRTCEvents;
if (g_pRTCEvents == NULL) {
DEBUGMSG( ZONE_ERROR, (L"VoipDemo: Unable to allocate memory for event interface.") );
bRV = FALSE;
goto Cleanup;
}
// Register the event handler with the RTC Client
RegisterEventInterface();
// Get notifications for desired events only
// Media and Intensity events are not necessary
g_pRTCClient->put_EventFilter(
RTCEF_CLIENT |
RTCEF_REGISTRATION_STATE_CHANGE |
RTCEF_SESSION_STATE_CHANGE |
RTCEF_PARTICIPANT_STATE_CHANGE |
RTCEF_MESSAGING |
RTCEF_BUDDY |
RTCEF_WATCHER
);
// To store the email address of the person, we need to use profiles, or message headers on the IM messages...
if (!InitializePresence( g_pLocalUserInfo->get_Name() )) {
bRV = FALSE;
goto Cleanup;
}
// store name and URI for other clients to pull from the session connections
g_pRTCClient->put_LocalUserURI( g_pLocalUserInfo->get_Addr() );
g_pRTCClient->put_LocalUserName( g_pLocalUserInfo->get_Name() );
#ifdef RTC_PERSISTENT_STORAGE_UNIMPLEMENTED
// import the buddies/watchers list from the CE DB
hDB = MyAddrDB_Init( hInst );
do {
CEPROPVAL* pPropVal = NULL;
oid = MyAddrDB_Read( hDB, 0, &pPropVal);
if ( oid == -1 || oid == 0 || !pPropVal ) {
bDone = TRUE;
} else {
switch ((BUDDYTYPE) pPropVal[DBF_TYPE].val.lVal)
{
case BT_WATCHER:
// note, we use EMAIL as a way of holding the watcher's state (allowed or blocked)
AddWatcherRTC(pPropVal[DBF_ADDR].val.lpwstr, pPropVal[DBF_NAME].val.lpwstr, pPropVal[DBF_BLOB].val.lpwstr, FALSE );
break;
case BT_MYSELF:
// change my info (use email to store phone number, if exist
// SetMyInfo(pPropVal[DBF_ADDR].val.lpwstr, pPropVal[DBF_NAME.val.lpwstr], pPropVal[DBF_BLOB].val.lpwstr);
break;
case BT_PHONE:
// note DBF_BLOB is actually the phone number
AddBuddyRTC(pPropVal[DBF_BLOB].val.lpwstr, pPropVal[DBF_NAME].val.lpwstr, (BUDDYTYPE) pPropVal[DBF_TYPE].val.lVal, VARIANT_TRUE, NULL);
break;
case BT_COMPUTER:
AddBuddyRTC(pPropVal[DBF_ADDR].val.lpwstr, pPropVal[DBF_NAME].val.lpwstr, (BUDDYTYPE) pPropVal[DBF_TYPE].val.lVal, VARIANT_TRUE, NULL);
break;
default:
break;
} // end switch(buddytype)
} // end if valid buddy
}while (!bDone);
MyAddrDB_Close(hDB);
// notify re-added watchers of my status, change so RTC is certain to send out the notification
SetMyStatusRTC(ES_OFFLINE);
SetMyStatusRTC(ES_ONLINE);
#endif // RTC_PERSISTENT_STORAGE_UNIMPLEMENTED
// instantiate session container
g_pSessionContainer = new CSessionContainer;
if (g_pSessionContainer == NULL) {
DEBUGMSG( ZONE_ERROR, (L"VoipDemo: Unable to allocate memory for CSessionContainer.") );
bRV = FALSE;
goto Cleanup;
}
// store SWCB function pointer
ASSERT(fnSWCB != NULL);
g_fnSWCB = (SWCB_FN_PTR) fnSWCB;
DEBUGMSG( ZONE_STATUS|ZONE_CALL, (L"VoipDemo: Setting RTC to listen for new calls\r\n") );
hr = g_pRTCClient->put_ListenForIncomingSessions( RTCLM_BOTH );
if (FAILED(hr)) {
DEBUGMSG( ZONE_ERROR, (L"VoipDemo: put_ListenForIncomingSessions failed 0x%lx\r\n", hr) );
bRV = FALSE;
goto Cleanup;
}
Cleanup:
if (bRV == FALSE) {
ForceShutdownRTC();
}
DEBUGMSG( ZONE_STATUS|ZONE_INIT|ZONE_WARN, (L"Voipdemo: Initialization of RTC Successful.\r\n") );
return bRV;
} // end InitializeRTC( )
/************************************************************************************************
************************************************************************************************/
BOOL
InitializePresence(BSTR bstrName)
{
HRESULT hr = S_OK;
#ifdef USE_AMUNSERVER
IRTCClientProvisioning* pProvisioning;
hr = g_pRTCClient->QueryInterface(IID_IRTCClientProvisioning, (LPVOID *)&pProvisioning);
if (FAILED(hr)) {
DEBUGMSG( ZONE_ERROR|ZONE_PROVISION, (L"Voipdemo: Error querying client interface for provisioning interface.\r\n") );
ASSERT(FALSE);
}
// Load the default XML profile
BSTR bstrProfile = NULL;
// Read the profile from file "profile.xml"
bstrProfile = ReadProfileFromFile();
// If "profile.xml" is not found on disk use the default profile
if (!bstrProfile)
{
DEBUGMSG( ZONE_ERROR|ZONE_PRESENCE|ZONE_PROVISION, (L"Voipdemo: \"profile.xml\" not found, using default profile\r\n") );
bstrProfile = SysAllocString( DEFAULT_XML_PROFILE );
}
if (!bstrProfile) {
DEBUGMSG( ZONE_ERROR|ZONE_PRESENCE|ZONE_PROVISION, (L"Voipdemo: Error parsing XML profile, non-existent\r\n") );
ASSERT(FALSE);
return FALSE;
}
DEBUGMSG( ZONE_STATUS|ZONE_PRESENCE|ZONE_PROVISION, (L"VoipDemo: Creating default XML profile for registration\r\n") );
hr = pProvisioning->CreateProfile(bstrProfile,&g_pRTCProfile);
SysFreeString(bstrProfile);
if (FAILED(hr)) {
DEBUGMSG( ZONE_ERROR|ZONE_PRESENCE|ZONE_PROVISION, (L"VoipDemo: InitializePresence() CreateProfile Failed! 0x%lx\r\n") );
pProvisioning->Release();
return FALSE;
}
// update credentials
hr = g_pRTCProfile->SetCredentials(g_pLocalUserInfo->get_Addr(), g_pLocalUserInfo->get_Name(), NULL);
DEBUGMSG( ZONE_STATUS|ZONE_PRESENCE|ZONE_PROVISION, (L"VoipDemo: Enabling profile\r\n") );
//register
hr = pProvisioning->EnableProfile( g_pRTCProfile, RTCRF_REGISTER_ALL );
#ifndef NO_PHONE_TO_PHONE
// Load the phone to phone XML profile
bstrProfile = SysAllocString( PHONE_TO_PHONE_XML_PROFILE );
if (!bstrProfile) {
DEBUGMSG( ZONE_ERROR|ZONE_PRESENCE|ZONE_PROVISION, (L"Voipdemo: Error parsing phone to phone XML profile, non-existent\r\n") );
ASSERT(FALSE);
return FALSE;
}
IRTCProfile* pP2PProfile = NULL
DEBUGMSG( ZONE_STATUS|ZONE_PRESENCE|ZONE_PROVISION, (L"VoipDemo: Creating phone to phone XML profile for registration\r\n") );
hr = pProvisioning->CreateProfile(bstrProfile,&pP2PProfile);
SysFreeString(bstrProfile);
if (FAILED(hr)) {
DEBUGMSG( ZONE_ERROR|ZONE_PRESENCE|ZONE_PROVISION, (L"VoipDemo: InitializePresence() CreateProfile Failed on phone to phone profile! 0x%lx\r\n") );
pProvisioning->Release();
return FALSE;
}
// update credentials
hr = pP2PProfile->SetCredentials(g_pLocalUserInfo->get_Addr(), g_pLocalUserInfo->get_Name(), NULL);
DEBUGMSG( ZONE_STATUS|ZONE_PRESENCE|ZONE_PROVISION, (L"VoipDemo: Enabling phone to phone profile\r\n") );
//register
hr = pProvisioning->EnableProfile( pP2PProfile, RTCRF_REGISTER_ALL );
// release our reference to phone to phone profile (the rtc core will take care of it now)
pP2PProfile->Release();
#endif
pProvisioning->Release();
if (FAILED(hr)) {
DEBUGMSG( ZONE_ERROR, (L"VoipDemo: InitializePresence() EnableProfile Failed! 0x%lx\r\n") );
return FALSE;
}
#endif // USE_AMUNSERVER
hr = g_pRTCClient->QueryInterface( IID_IRTCClientPresence, (LPVOID *)&g_pRTCPresence );
if (FAILED(hr)) {
DEBUGMSG( ZONE_ERROR|ZONE_PRESENCE, (L"VoipDemo: Unable to QueryInterface IRTCClientPresence interface from the RTC Client 0x%lx",hr) );
return FALSE;
}
VARIANT v;
::VariantInit(&v);
// Enable presence & store it to/read it from a file
#ifdef RTC_PERSISTENT_STORAGE_UNIMPLEMENTED
hr = g_pRTCPresence->EnablePresence(VARIANT_FALSE, v);
#else
v.bstrVal = SysAllocString(DEFAULT_PRESENCE_STORAGE);
v.vt = VT_BSTR;
hr = g_pRTCPresence->EnablePresence(VARIANT_TRUE, v);
if (SUCCEEDED(hr)) {
DEBUGMSG( ZONE_STATUS|ZONE_PRESENCE, (L"VoipDemo: Enabled Presence, using %s as persistent store\r\n", v.bstrVal) );
SysFreeString(v.bstrVal);
}
#endif // RTC_PERSISTENT_STORAGE_UNIMPLEMENTED
if (FAILED(hr)) {
DEBUGMSG( ZONE_ERROR|ZONE_PRESENCE, (L"Voipdemo: EnablePresence failed! 0x%lx\r\n", hr) );
g_pRTCPresence->Release();
return FALSE;
}
#ifdef RTC_PERSISTENT_STORAGE_UNIMPLEMENTED
hr = g_pRTCPresence->put_OfferWatcherMode(RTCOWM_OFFER_WATCHER_EVENT);
DEBUGMSG( ZONE_STATUS|ZONE_PRESENCE, (L"VoipDemo: Incoming watchers will trigger a watcer event so that they may be stored outside of RTC\r\n") );
#else
hr = g_pRTCPresence->put_OfferWatcherMode(RTCOWM_AUTOMATICALLY_ADD_WATCHER);
DEBUGMSG( ZONE_STATUS|ZONE_PRESENCE, (L"VoipDemo: Auto-add watchers set to true\r\n") );
#endif //RTC_PERSISTENT_STORAGE_UNIMPLEMENTED
hr = g_pRTCPresence->SetLocalPresenceInfo(RTCXS_PRESENCE_ONLINE, NULL);
DEBUGMSG( ZONE_STATUS|ZONE_PRESENCE, (L"VoipDemo: Set Presence Online\r\n") );
return TRUE;
}
/************************************************************************************************
ForceShutdownRTC
Force a hard shutdown. This will be called during errors before the main thread msg loop.
If the function is called in the main loop, any attempts to read from the RTC interface
pointers will fail.
************************************************************************************************/
VOID
ForceShutdownRTC()
{
HRESULT hr = S_OK;
DEBUGMSG( ZONE_STATUS|ZONE_INIT, ( L"VoipDemo: Forcing hard shutdown of RTC.\r\n" ) );
if (g_pSessionContainer)
delete g_pSessionContainer;
if (g_pRTCPresence) {
// tell my buddies I'm leaving
SetMyStatusRTC(ES_OFFLINE);
g_pRTCPresence->Release();
g_pRTCPresence = NULL;
}
#ifdef USE_AMUNSERVER
if (g_pRTCProvision) {
g_pRTCProvision->DisableProfile(g_pRTCProfile);
if (g_pRTCProfile) {
g_pRTCProfile->Release();
g_pRTCPresence = NULL;
}
}
#endif
if (g_pRTCClient) {
hr = g_pRTCClient->Shutdown();
}
if (FAILED(hr)) {
DEBUGMSG( ZONE_ERROR, ( L"VoipDemo: Shutdown call on RTCClient object failed 0x%lx!\r\n", hr ) );
// make sure we know that this happened
ASSERT(FALSE);
}
// final app cleanup
DEBUGMSG( ZONE_STATUS, (L"VoipDemo: Unregistering event notification interface.\r\n") );
UnregisterEventInterface();
if (g_pcsSessionDataLock) {
EnterCriticalSection( g_pcsSessionDataLock );
LeaveCriticalSection( g_pcsSessionDataLock );
DeleteCriticalSection( g_pcsSessionDataLock );
delete g_pcsSessionDataLock;
g_pcsSessionDataLock = NULL;
}
if (g_pRTCEvents) {
delete g_pRTCEvents;
g_pRTCEvents = NULL;
}
g_pRTCClient->Release();
g_pRTCClient = NULL;
CoUninitialize();
DEBUGMSG( 1, ( L"VoipDemo: Successful termination of RTCClient\r\n" ) );
NKDbgPrintfW( L"VoipDemo: Exiting\r\n" );
}
/*-----------------------------------------------------------------------------
Function: ShutdownRTC( void )
Parameters:
Return value: 0
Abstract: Attempt a graceful shutdown
Notes: None
-------------------------------------------------------------------------------*/
DWORD WINAPI ShutdownRTC( LPVOID option )
{
// Stop listening for incoming sessions
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -