www.pudn.com > CP_IVR.zip > HCentralManager.cpp


 /***************************************************************** 
 * HCentralManager.cpp: implementation of the CHCentralManager 
 * class. 
 * 
 * Auther: Hamed.M. 
 * eMail : HamedMosavi @ hotmail.com 
 *		   HamedMosavi @ gmail.com 
 *****************************************************************/ 
 
#include "stdafx.h" 
#include "HCentralManager.h" 
#include "HSettings.h" 
#include "HDevices.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
/********************************************************************* 
 * Globals & Statics 
 ********************************************************************/ 
						   /* A handle to main communication thread */ 
extern unsigned long	g_lMngrThread; 
										/* Saves programme settings */ 
extern CHSettings		g_settings; 
										   /* Device list inventory */ 
extern CHDevices		g_devices; 
					   /* Will keep the phone#, if got successfully */ 
extern CString			g_phoneNumber; 
							   /* Program executable folder address */ 
extern CString			g_path; 
 
BOOL CHCentralManager::s_threadTerminate = FALSE; 
 
/********************************************************************* 
 * Construction: CHCentralManager class 
 ********************************************************************/ 
CHCentralManager::CHCentralManager() 
{ 
	g_lMngrThread = 0; 
	m_pThread = NULL; 
	s_threadTerminate = FALSE; 
} 
 
/********************************************************************* 
 * Destruction: CHCentralManager class 
 ********************************************************************/ 
CHCentralManager::~CHCentralManager() 
{ 
									  /* Terminating Message Thread */ 
	s_threadTerminate = TRUE; 
	Sleep(200);						 /* Give time to thread to exit */ 
} 
 
/********************************************************************* 
 * Will get all messages and process them. 
 ********************************************************************/ 
void CHCentralManager::ProcessMessage(MSG msg) 
{ 
	switch (msg.message) { 
 
	case WM_DTMF:				   /* New DTMF code pressed by user */ 
		if (m_pWParent) 
			m_pWParent->PostMessage( 
				WM_STATUS_CHNGD,msg.lParam,ST_DTMF); 
										 /* Play him/her a response */ 
		OnProcessDtmf(msg.lParam); 
		break; 
									   /* Playlist playback is done  
						(& we already asked the sound to inform us)*/ 
	case WM_SOUND_DONE: 
		// UNDONE : Restart the line, perhaps. 
		break; 
 
						/* Line status changed, do appropriate job. */ 
	case WM_STATUS_CHNGD: 
							    /* If TAPI Failed, cleanup and exit */ 
		if (msg.lParam==ST_FAILED) { 
			OnFailed(); 
			break; 
		} else if (msg.wParam == ST_PICKED_UP &&  
				   msg.lParam == ST_BUSY) { 
			OnAnswerTheCall(); 
			break; 
		} 
							  /* Update UI (Inform the UI manager!) */ 
//		ASSERT(m_pWParent); 
		if (m_pWParent) 
			m_pWParent->PostMessage( 
				WM_STATUS_CHNGD,msg.wParam,msg.lParam); 
		else { 
						 /* If this class has not any parent window */ 
		// UNDONE : Inform developer. 
		} 
		break; 
 
									  /* If users callerId received */ 
	case WM_CALLERID: 
		g_phoneNumber = m_line.GetCallerID(); 
												   /* Inform parent */ 
		m_pWParent->PostMessage(WM_STATUS_CHNGD,0,ST_CALLER_ID); 
		break; 
 
	default : break; 
	} 
} 
 
/********************************************************************* 
 * Wakes up all managers! 
 ********************************************************************/ 
BOOL CHCentralManager::WakeUp() 
{ 
	try { 
 
		/* Begin a message thread so that others can communicate us */ 
		m_pThread = AfxBeginThread( 
			MessageThread, 
			(LPVOID)this, 
			THREAD_PRIORITY_BELOW_NORMAL, 
			0, 
			NULL, 
			0); 
										 /* If we can't run manager */ 
		if (!m_pThread) return FALSE; 
											 /* Set global variable */ 
		g_lMngrThread = m_pThread->m_nThreadID; 
 
				/* Run a message thread to get sound class messages */ 
		m_pSoundThread = AfxBeginThread( 
			SoundThread, 
			(LPVOID)this, 
			THREAD_PRIORITY_BELOW_NORMAL, 
			0, 
			NULL, 
			0); 
										 /* If we can't run manager */ 
		if (!m_pSoundThread) return FALSE; 
											 /* Set global variable */ 
					   /* Run a message thread to get DTMF Messages */ 
		m_pDTMFThread = AfxBeginThread( 
			DTMFThread, 
			(LPVOID)this, 
			THREAD_PRIORITY_NORMAL, 
			0, 
			NULL, 
			0); 
										 /* If we can't run manager */ 
		if (!m_pDTMFThread) return FALSE; 
												/* Set sound's boss */ 
		m_soundManager.SetManager(m_pSoundThread->m_nThreadID); 
		m_soundManager.Reset(); 
 
								/* Set athread to get DTMF messages */ 
		m_line.SetBossMessenger(m_pDTMFThread->m_nThreadID); 
 
					 /* Check to conform with user defined settings */ 
		if (g_settings.m_ringCount!=0) { 
			m_line.SetRingCount(g_settings.m_ringCount); 
		} else { 
			g_settings.m_ringCount = 2; 
			m_line.SetRingCount(2); 
		} 
									   /* Statr the line operations */ 
		m_line.Start(); 
										  /* Statr the phone device */ 
		m_phone.Start(); 
 
								  /* Handle line & phone exceptions */ 
	} catch (CTapiObj::TEx e) { 
 
		CHErrLogger::LogError(e); 
		if (g_lMngrThread) 
			PostThreadMessage( 
			g_lMngrThread,WM_STATUS_CHNGD,0,ST_FAILED); 
		return FALSE; 
										 /* Handle other exceptions */ 
	} catch ( ... ) { 
		CHErrLogger::LogError(_T("Unknown error in waking up") 
			_T("line manager. source: Central Manager")); 
							   /* There was an error, inform parent */ 
		if (g_lMngrThread) 
			PostThreadMessage( 
			g_lMngrThread,WM_STATUS_CHNGD,0,ST_FAILED); 
 
		return FALSE; 
	} 
 
	return TRUE; 
} 
 
/********************************************************************* 
 * Update parent pointer 
 ********************************************************************/ 
void CHCentralManager::SetParent(CWnd *pWParent) 
{ 
	m_pWParent = pWParent; 
} 
 
/********************************************************************* 
 * A thread to receive message from other managers 
 ********************************************************************* 
 * A pointer to this thread will be available globaly, so that others 
 * can access central manager. 
 * TAPI classes (line & phone) will send their message to this thread 
 * either. 
 ********************************************************************/ 
UINT CHCentralManager::MessageThread (LPVOID pParam) 
{ 
	CHCentralManager* pCM = (CHCentralManager*) pParam; 
	MSG msg; 
 
	while (1) { 
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { 
					  /* New Message arrived -> process it please!! */ 
			pCM->ProcessMessage(msg); 
		} else { 
						 /* Chaeck message queue every 10 M.Seconds */ 
			Sleep(10); 
 
								   /* Are we permitted to continue? */ 
			if (s_threadTerminate) { 
				break; 
			} 
		}; 
	} 
												  /* We are exiting */ 
	s_threadTerminate = FALSE; 
	return 0; 
} 
 
/********************************************************************* 
 * Reset sound playback 
 ********************************************************************/ 
void CHCentralManager::ResetSound() 
{ 
	// Don't blame me with a function calling 1 other function! 
	// In my app. it had more duties!!! 
	// This is just some pieces of it. 
	m_soundManager.Close(); 
} 
 
/********************************************************************* 
 * Restart everythings 
 ********************************************************************/ 
void CHCentralManager::Restart() 
{ 
											   /* Shutdown the line */ 
	m_line.ShutDown(); 
											  /* Shutdown the phone */ 
	m_phone.ShutDown(); 
											   /* Empty device list */ 
	g_devices.Restart(); 
 
	try { 
												  /* Start the line */ 
		m_line.Start(); 
												 /* Start the Phone */ 
		m_phone.Start(); 
												    /* Catch errors */ 
	} catch ( ... ) { 
		CHErrLogger::LogError(_T("Unknown error in waking up") 
			_T("line manager. source: Central Manager")); 
								 
										/* We failed, inform parent */ 
		PostThreadMessage(g_lMngrThread,WM_STATUS_CHNGD,0,ST_FAILED); 
 
		return; 
	} 
} 
 
/********************************************************************* 
 * Does reverse of wakeup! Freezes everythings 
 ********************************************************************/ 
void CHCentralManager::SleepAll() 
{ 
											   /* Shutdown the line */ 
	m_line.ShutDown(); 
											  /* Shutdown the phone */ 
	m_phone.ShutDown(); 
											   /* Empty device list */ 
	g_devices.Restart(); 
 
	if (m_pThread) {				   /* If thread already started */ 
										/* Terminate Message Thread */ 
		s_threadTerminate = TRUE; 
										/* Sleep while thread exits */ 
		if ( WaitForSingleObject(m_pThread->m_hThread,300) ==  
			WAIT_TIMEOUT) { 
 
			TerminateThread(m_pThread->m_hThread, 0); 
		} 
										/* Sleep while thread exits */ 
		if ( WaitForSingleObject(m_pSoundThread->m_hThread,300) ==  
			WAIT_TIMEOUT) { 
 
			TerminateThread(m_pSoundThread->m_hThread, 0); 
		} 
										/* Sleep while thread exits */ 
		if ( WaitForSingleObject(m_pDTMFThread->m_hThread,300) ==  
			WAIT_TIMEOUT) { 
 
			TerminateThread(m_pDTMFThread->m_hThread, 0); 
		} 
	} 
} 
 
/********************************************************************* 
 * A function added in a very very time, to transfer line to phone 
 * so that you can speak in your microphone and here in your headphone 
 * If your modem supports this. 
 ********************************************************************/ 
long CHCentralManager::EnableSpeakerHook() 
{ 
	long lResult; 
 
	if (lResult = m_phone.SwichToMicSpk()){ 
		 
		TRACE(_T("\n\n\n  %x"),lResult); 
	}; 
	return 0; 
} 
 
/********************************************************************* 
 * Will be called uppon a failier 
 ********************************************************************/ 
void CHCentralManager::OnFailed() 
{ 
	g_settings.m_deviceId = -1; 
	g_settings.m_ringCount = 2; 
	 
	m_line.ShutDown(); 
	m_phone.ShutDown(); 
	g_devices.Restart(); 
	AfxMessageBox(_T("Can't open device, device is") 
		_T("not ready for voice or ...")); 
} 
 
/********************************************************************* 
 * Start playing first sentences(welcome message) 
 ********************************************************************/ 
void CHCentralManager::OnAnswerTheCall() 
{ 
										  /* Add a file to playlist */ 
	m_soundManager.AddToPlayList(g_path +  
		_T("Voices\\CP_IVR_WELCOME.wav")); 
												  /* Start playback */ 
	m_soundManager.PlayList(m_line.GetDevWavID(),FALSE,TRUE); 
} 
 
/********************************************************************* 
 * On each DTMF arrival 
 ********************************************************************/ 
void CHCentralManager::OnProcessDtmf(UINT dtmfCode) 
{ 
	CString str = _T(""); 
									 /* Make sure nothing's playing */ 
	m_soundManager.Reset(); 
										  /* Add a file to playlist */ 
	str.Format(g_path + _T("Voices\\%d.wav"),dtmfCode); 
	m_soundManager.AddToPlayList(str); 
												  /* Start playback */ 
	m_soundManager.PlayList(m_line.GetDevWavID()); 
} 
 
/********************************************************************* 
 * A thread to receive message from DTMF manager 
 ********************************************************************* 
 * A thread to receive DTMF messages. Don't try to mix this message 
 * thread with MessageThread. The reason I separated these two is 
 * to be able to detect and respond to line messages more quickly and 
 * independent to current status of the other thread. Think about a  
 * chicky user who pressed 100 digits one after the other and then  
 * disconnected, calling parent's ProcessMessage() function directly,  
 * make us busy the line untill all button process completed and then 
 * process disconnect message.(It's a queue). But separating these 2 
 * ensures that line messages will be processed as soon as comming. 
 ********************************************************************/ 
UINT CHCentralManager::DTMFThread (LPVOID pParam) 
{ 
	CHCentralManager* pCM = (CHCentralManager*) pParam; 
	MSG msg; 
 
	while (1) { 
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { 
					  /* New Message arrived -> process it please!! */ 
			pCM->ProcessMessage(msg); 
		} else { 
						 /* Chaeck message queue every 10 M.Seconds */ 
			Sleep(5); 
 
								   /* Are we permitted to continue? */ 
			if (s_threadTerminate) { 
				break; 
			} 
		}; 
	} 
												  /* We are exiting */ 
	s_threadTerminate = FALSE; 
	return 0; 
} 
 
/********************************************************************* 
 * A thread to receive message from Sound manager 
 ********************************************************************* 
 * Will receive messages regurding to sound class 
 * In this sample app just 1 message!! It had more duties in my own 
 * The message here says that a playlist playback is done, and you 
 * asked in your PlayList() call that I inform you! perhaps you want 
 * to terminate the session now?! 
 ********************************************************************/ 
UINT CHCentralManager::SoundThread (LPVOID pParam) 
{ 
	CHCentralManager* pCM = (CHCentralManager*) pParam; 
	MSG msg; 
 
	while (1) { 
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { 
					  /* New Message arrived -> process it please!! */ 
			pCM->ProcessMessage(msg); 
		} else { 
						 /* Chaeck message queue every 10 M.Seconds */ 
			Sleep(10); 
 
								   /* Are we permitted to continue? */ 
			if (s_threadTerminate) { 
				break; 
			} 
		}; 
	} 
												  /* We are exiting */ 
	s_threadTerminate = FALSE; 
	return 0; 
} 
 
/********************************************************************* 
 * End of Central manager :) 
 ********************************************************************/