⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtcevent.cpp

📁 Windows CE .Net 下面 VOIP编程的经典实例。对于初学Windows 平台下VOIP编程技术的程序员颇具借鉴意义!
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//
// 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:

    RTCEvent.cpp

Abstract:

    RTC event handler.

Notes:

******************************************************************************/

#include <windows.h>
#include <rtccore.h>
#include "rtcInternal.h"
#include <winsock.h>
	
/************************************************************************************************
 
   Globals
 
 ************************************************************************************************/
DWORD g_dwEventHandle;  // handle for notifying RTC of Event processor
extern DWORD g_dwMainThreadID; // tell the main window proc we've received the shutdown message
extern HANDLE g_hShutdownEventComplete;

/************************************************************************************************
 * The following string tables are used to simplify debug messages
 *************************************************************************************************/

STRING_TBL EventTbl[] = {
    RTCE_CLIENT,						L"RTCE_CLIENT",
    RTCE_REGISTRATION_STATE_CHANGE,		L"RTCE_REGISTRATION_STATE_CHANGE",
    RTCE_SESSION_STATE_CHANGE,			L"RTCE_SESSION_STATE_CHANGE",
    RTCE_SESSION_OPERATION_COMPLETE,	L"RTCE_SESSION_OPERATION_COMPLETE",
    RTCE_PARTICIPANT_STATE_CHANGE,		L"RTCE_PARTICIPANT_STATE_CHANGE",
    RTCE_MEDIA,		L"RTCE_MEDIA",
    RTCE_INTENSITY,	L"RTCE_INTENSITY",
    RTCE_MESSAGING,	L"RTCE_MESSAGING",
    RTCE_BUDDY,		L"RTCE_BUDDY",			
	RTCE_WATCHER,	L"RTCE_WATCHER",		
	RTCE_PROFILE,	L"RTCE_PROFILE",
	END_VAL, L"Unknown event type"
}; // used by Event()


STRING_TBL SessionStateTbl[] = {
    RTCSS_IDLE,         L"RTCSS_IDLE",
    RTCSS_INCOMING,     L"RTCSS_INCOMING",
    RTCSS_ANSWERING,    L"RTCSS_ANSWERING",
    RTCSS_INPROGRESS,   L"RTCSS_INPROGRESS",
    RTCSS_CONNECTED,    L"RTCSS_CONNECTED",
    RTCSS_DISCONNECTED, L"RTCSS_DISCONNECTED",
    END_VAL, L"Unknown session state"
}; // used by HandleSessionStateChangeEvent()


STRING_TBL SessionTypeTbl[] = {
	RTCST_IM,				L"RTCST_IM",
	RTCST_PC_TO_PC,			L"RTCST_PC_TO_PC",
	RTCST_PHONE_TO_PHONE,	L"RTCST_PHONE_TO_PHONE",
	RTCST_PC_TO_PHONE,		L"RTCST_PC_TO_PHONE",
	END_VAL, L"Unknown session type"
};

STRING_TBL ParticipantStateTbl[] = {
	RTCPS_IDLE,			L"RTCPS_IDLE",
	RTCPS_PENDING,		L"RTCPS_PENDING",
	RTCPS_INCOMING,		L"RTCPS_INCOMING",
	RTCPS_ANSWERING,	L"RTCPS_ANSWERING",
	RTCPS_INPROGRESS,	L"RTCPS_INPROGRESS",
	RTCPS_ALERTING,		L"RTCPS_ALERTING",
	RTCPS_CONNECTED,	L"RTCPS_CONNECTED",
	RTCPS_DISCONNECTING, L"RTCPS_DISCONNECTING",
	RTCPS_DISCONNECTED, L"RTCPS_DISCONNECTED",
	END_VAL, L"Unknown participant state"
}; // used by HandleParticipantStateChangeEvent()

STRING_TBL MediaEventTbl[] = {
	RTCMET_STOPPED,		L"RTCMET_STOPPED",
	RTCMET_STARTED,		L"RTCMET_STARTED",
	RTCMET_FAILED,		L"RTCMET_FAILED",
	END_VAL, L"Unknown media event"
}; // used by HandleMediaEvent()

STRING_TBL MediaReasonTbl[] = {
    RTCMER_NORMAL,		L"RTCMER_NORMAL",
    RTCMER_HOLD,		L"RTCMER_HOLD",
	RTCMER_TIMEOUT,		L"RTCMER_TIMEOUT",
	RTCMER_BAD_DEVICE,	L"RTCMER_BAD_DEVICE",
	END_VAL, L"Unknown media reason"
}; // used by HandleMediaEvent()

STRING_TBL ClientEventTbl[] = {
	RTCCET_VOLUME_CHANGE,			L"RTCCET_VOLUME_CHANGE",
    RTCCET_DEVICE_CHANGE,			L"RTCCET_DEVICE_CHANGE",
    RTCCET_NETWORK_QUALITY_CHANGE,	L"RTCCET_NETWORK_QUALITY_CHANGE",
	RTCCET_ASYNC_CLEANUP_DONE,		L"RTCCET_ASYNC_CLEANUP_DONE",
	END_VAL, L"Unknown client event"
}; // used by HandleClientEvent()

STRING_TBL RegistrationStateTbl[] = {
	RTCRS_NOT_REGISTERED,	L"RTCRS_NOT_REGISTERED",
	RTCRS_REGISTERING,		L"RTCRS_REGISTERING",
	RTCRS_REGISTERED,		L"RTCRS_REGISTERED",
	RTCRS_REJECTED,			L"RTCRS_REJECTED",
	RTCRS_UNREGISTERING,	L"RTCRS_UNREGISTERING",
	RTCRS_ERROR,			L"RTCRS_ERROR",
	END_VAL, L"Unknown registration event"
}; // used by HandleRegistrationStateChangeEvent() 

extern STRING_TBL BuddyStatusTbl[];
// used by HandleBuddyEvent(), and SetMyStatus() in rtcs.cpp 


/************************************************************************************************

 Function prototypes internal to this file

 ************************************************************************************************/

// Event handlers
HRESULT HandleMessagingEvent( IDispatch* pEvent );
HRESULT HandleClientEvent( IDispatch* pEvent );
HRESULT HandleParticipantStateChangeEvent( IDispatch* pEvent );
HRESULT HandleSessionStateChangeEvent( IDispatch* pEvent );
HRESULT HandleBuddyEvent( IDispatch* pEvent );
HRESULT HandleWatcherEvent( IDispatch* pEvent );
HRESULT HandleRegistrationStateChangeEvent( IDispatch* pEvent );	
HRESULT HandleMediaEvent( IDispatch* pEvent );

// Helper functions
DWORD GetValFromString( LPWSTR pstr, STRING_TBL pst );
LPWSTR GetStringFromVal( DWORD dwVal, STRING_TBL pst );
BOOL SipURIsResolve(BSTR bstrLocalURI, BSTR bstrIncomingURI);
HRESULT ResolveHostName( IN PSTR HostName, OUT ULONG *pIPAddr );
HRESULT ResolveHost( IN PSTR szHost,OUT ULONG *pIpAddr );



/************************************************************************************************
 
   VOID RegisterEventInterface ( VOID )
 
 	Registers the event notification COM object with the RTC API.
 
	This step must be taken before any RTC events are communicated from the API
 	thus it should be called in the initialization phase.
 
 ************************************************************************************************/

VOID RegisterEventInterface()
{
    IRTCEventNotification         * pNotif;
    
    IConnectionPointContainer * pCPC;
    IConnectionPoint * pCP;
    
    HRESULT hr = g_pRTCClient->QueryInterface(IID_IConnectionPointContainer, (VOID**)&pCPC);
    
    if (SUCCEEDED(hr))
    {
        hr = pCPC->FindConnectionPoint(IID_IRTCEventNotification, &pCP);
    
        pCPC->Release();
    
        g_pRTCEvents->QueryInterface(
			                         IID_IRTCEventNotification,
									 (VOID **)&pNotif
									 );
        if (SUCCEEDED(hr))
        {
            hr = pCP->Advise(pNotif, &g_dwEventHandle);
    
            pCP->Release();
        }

        pNotif->Release();
    }
} // end RegisterEventInterface()

/************************************************************************************************

  VOID UnregisterEventInterface ( VOID )
 
 	Removes the registration of the event interface with the RTC API.
 
 	This function is necessary for proper shutdown and release of all RTC API references.
 	Call this function AFTER all expected RTC messages are seen, otherwise they will be lost
 	especially important for async shutdown.
 
 ************************************************************************************************/

VOID UnregisterEventInterface()
{
    IConnectionPointContainer * pCPC;
    IConnectionPoint * pCP;

    HRESULT hr = g_pRTCClient->QueryInterface(IID_IConnectionPointContainer, (VOID**)&pCPC);

    if (SUCCEEDED(hr))
    {
        hr = pCPC->FindConnectionPoint(IID_IRTCEventNotification, &pCP);

        pCPC->Release();

        if (SUCCEEDED(hr))
        {
            hr = pCP->Unadvise(g_dwEventHandle);

            pCP->Release();
        }
    }
} // end UnregisterEventInterface()

/************************************************************************************************

  VOID EventNotification ( VOID )
 
 	Main event handler for RTC API events. Passes IDispatch to the appropriate handler.
 
 ************************************************************************************************/

HRESULT
EventSink(
		  IN RTC_EVENT enEvent,
		  IN IDispatch * pEvent
		  )
{
	DEBUGMSG( ZONE_STATUS, ( L"VoipDemo:Event %s\r\n", GetStringFromVal( enEvent, EventTbl) ) );

    HRESULT hr = S_OK;	

    switch (enEvent)
    {
    case RTCE_SESSION_STATE_CHANGE:
        {
			hr = HandleSessionStateChangeEvent(pEvent);
			break;
        } // end RTCE_SESSION_STATE_CHANGE       

    case RTCE_PARTICIPANT_STATE_CHANGE:
        {
			hr = HandleParticipantStateChangeEvent(pEvent);
			break;
        } // end RTCE_PARTICIPANT_STATE_CHANGE        

	case RTCE_CLIENT:
		{
			hr = HandleClientEvent(pEvent);			
			break;				
		} // end RTCE_CLIENT
				
	case RTCE_MESSAGING:
		{
			hr = HandleMessagingEvent(pEvent);
			break;
		} // end RTCE_MESSAGING
		
	case RTCE_BUDDY:
		{
			hr = HandleBuddyEvent(pEvent);
			break;
		}

	case RTCE_WATCHER:
		{
 			hr = HandleWatcherEvent(pEvent);
			break;
		}

	case RTCE_REGISTRATION_STATE_CHANGE:
		{
			hr = HandleRegistrationStateChangeEvent(pEvent);
			break;
		}
	default:
		break;
	}
		
	return hr;
} // end EventNotification()

/************************************************************************************************

  HRESULT HandleSessionStateChangeEvent ( IN IDispatch * pEvent )
 
 	Event handler for session state change events.
 
 	Relevant Events:
 		INCOMING	-	set g_IncomingSession, notify user through playring.  Can't notify
 						user through GUI yet, we can't get the participant data to see if the
 						the user would like to accept.
 		CONNECTED	-	move local session data from incoming to appropriate container
 		DISCONNECTED-	cleanup, notify user
 ************************************************************************************************/		

HRESULT
HandleSessionStateChangeEvent(
						IN IDispatch * pEvent
						)
{
	HRESULT hr = S_OK;
	
	IRTCSessionStateChangeEvent * pSSC;           
	IRTCSession * pSess;
	RTC_SESSION_STATE enRSS;
	RTC_SESSION_TYPE enRST;
	
	hr = pEvent->QueryInterface(
		IID_IRTCSessionStateChangeEvent,
		(VOID **)&pSSC
		);
	
	hr = pSSC->get_State(&enRSS);
	
	if (FAILED(hr)) {	
		DEBUGMSG( ZONE_ERROR, ( L"VoipDemo:Event SessionState get_State failed! 0x%lx\r\n", hr ) );
		goto Cleanup;
	}	

	DEBUGMSG( ZONE_ERROR | ZONE_CALL, ( L"VoipDemo:Event RTCE_SESSION_STATE_CHANGE - %s\r\n", GetStringFromVal(enRSS, SessionStateTbl) ) );

	hr = pSSC->get_Session(&pSess); // does AddRef(pSess)
	
	if(FAILED(hr) || pSess == NULL) {
		DEBUGMSG( ZONE_ERROR, ( L"VoipDemo:Event SessionState get_Session failed! 0x%lx\r\n", hr  ) );
		goto Cleanup;
	}
	
	hr = pSess->get_Type( &enRST );
	
	if (FAILED(hr)) {						
		DEBUGMSG( ZONE_ERROR, ( L"VoipDemo:Event SessionState get_SessionType failed! 0x%lx\r\n", hr ) );
		goto Cleanup;
	}
	
	switch(enRSS) {
	case RTCSS_INCOMING:
		{					
			// Incoming session, notify UI to display, play phone noise
			// determine what type of session it is, IM, phone, etc.
			DEBUGMSG( ZONE_STATUS|ZONE_CALL, ( L"VoipDemo:Event incoming %s session\r\n", GetStringFromVal(enRST, SessionTypeTbl )) );

			// create a new CSession object to store the session
			CSession* pSessionObj = new CSession( pSess, enRST, enRSS, g_fnSWCB );

			// add another reference to pSess on Incoming???

			switch (enRST) {
			case RTCST_PC_TO_PC:
			
				EnterCriticalSection( g_pcsSessionDataLock );
				
				// ensure only one phone call at a time !
				if ( g_bVoiceSessionOpen == TRUE) {		
					
					LeaveCriticalSection( g_pcsSessionDataLock );
					
					// later allow for multiple sessions
					DEBUGMSG( ZONE_ERROR|ZONE_STATUS|ZONE_CALL, ( L"VoipDemo:Event Rejecting incoming voice session.\r\n" ) );
					DEBUGMSG( ZONE_ERROR|ZONE_STATUS|ZONE_CALL , ( L"\t\t Reason: previous voice session in progress.\r\n" ) );
					pSessionObj->Hangup( RTCTR_BUSY );
					delete pSessionObj;
					goto Cleanup;
				} else {				
					g_bVoiceSessionOpen = TRUE;

					LeaveCriticalSection( g_pcsSessionDataLock );
				}
				break;
			case RTCST_IM:

				EnterCriticalSection( g_pcsSessionDataLock );
				
				// ensure only one IM session at a time !
				if (g_bIMSessionOpen == TRUE) {
				
					LeaveCriticalSection( g_pcsSessionDataLock );
					
					DEBUGMSG( ZONE_ERROR|ZONE_STATUS|ZONE_CALL, ( L"VoipDemo:Event Rejecting incoming IM session.\r\n" ) );
					DEBUGMSG( ZONE_ERROR|ZONE_STATUS|ZONE_CALL, ( L"\t\t Reason: previous IM session in progress.\r\n" ) );
					pSessionObj->Hangup( RTCTR_BUSY );
					delete pSessionObj;
					goto Cleanup;
				} else {					
					g_bIMSessionOpen = TRUE;
					
					LeaveCriticalSection( g_pcsSessionDataLock );
				}
				break;
			} // end switch (session type)
			
			// store session object in session container.
			HANDLE hSess = NULL;

			hSess = g_pSessionContainer->Add( pSess, pSessionObj );

			if (hSess == NULL) {
				DEBUGMSG( ZONE_ERROR, ( L"VoipDemo:Event error adding incoming session to the container.\r\n" ) );
		
				EnterCriticalSection( g_pcsSessionDataLock );
				
				if ( enRST = RTCST_IM ) 
					g_bVoiceSessionOpen = FALSE;
				else
					g_bIMSessionOpen = FALSE;
			
				LeaveCriticalSection( g_pcsSessionDataLock );

				pSessionObj->Hangup();
				delete pSessionObj;
				goto Cleanup;
			}

			// store session state locally
			(*g_pSessionContainer)[pSess]->put_SessionState( enRSS );

			// set the connected URI

			switch(enRST) {
			case RTCST_PC_TO_PC:
				// ring for incoming session
				hr = g_pRTCClient->PlayRing( RTCRT_PHONE, VARIANT_TRUE );

				if (FAILED(hr)) {
					DEBUGMSG( ZONE_ERROR, (  L"VoipDemo: Event PlayRing failed! 0x%lx\r\n", hr ) );
				}
				break;				
				
			case RTCST_IM:						
				// ring for incoming session
				hr = g_pRTCClient->PlayRing( RTCRT_MESSAGE, VARIANT_TRUE);

				if (FAILED(hr)) {
					DEBUGMSG( ZONE_ERROR, (  L"VoipDemo: Event PlayRing failed! 0x%lx\r\n", hr ) );
				}
				break;

			case RTCST_PHONE_TO_PHONE:
			case RTCST_PC_TO_PHONE: // shouldn't happen but leave in just in case									
			default:
				// PHONE_TO_PHONE will ring the actual phone, no need to ring here
				break;
			} // end switch Session Type
			
			break;
		} // end RTCSS_INCOMING
		
	case RTCSS_ANSWERING:
		{
			// store session state locally
			(*g_pSessionContainer)[pSess]->put_SessionState( enRSS );

			if (enRST == RTCST_PC_TO_PC) {
				// case RTCST_PHONE_TO_PHONE:
				// case RTCST_PC_TO_PHONE:
				
				// turn off incoming voice session ring
				hr = g_pRTCClient->PlayRing( RTCRT_PHONE, VARIANT_FALSE );

				if (FAILED(hr)) {
					DEBUGMSG( ZONE_ERROR, (  L"VoipDemo: Event PlayRing failed! 0x%lx\r\n", hr ) );
				}
			}
								
			break;				
		}
							
	case RTCSS_CONNECTED:
		{
			// Try to figure out what's going on when incoming events are disconnected
			// on accepted incoming voice sessions
			if ((*g_pSessionContainer)[pSess]->get_SessionState() == RTCSS_ANSWERING) {
				pSess->AddRef();
			}

			// store session state locally
			(*g_pSessionContainer)[pSess]->put_SessionState( enRSS );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -