现在的位置: 首页 > 综合 > 正文

东进的语音卡编程:最简单的电话外呼程序

2013年10月14日 ⁄ 综合 ⁄ 共 13071字 ⁄ 字号 评论关闭

东进的语音卡编程:最简单的电话外呼程序

cheungmine

2008-6-23

    整个工程是Console程序,它对D081A进行编程,实现一个最简单的电话外呼程序:CallTest.exe。工程包含3个文件:

    CallTest.cpp和LRTimer.h、LRTimer.cpp。

    后2个文件是一个C++的定时器类。这里没有使用Windows自带的定时器。CallTest.cpp是一个根据东进的例子程序Dial改编的,但是我去掉了Windows窗口部分,下面我把全部文件贴出来,通过这个最简单的程序,算是对东进语音卡状态机编程的入门吧:

///////////////////////////////////////////////////////////////////////////////

// CallTest.cpp

//  

// 说明:使用东进的D081A语音卡的一个自动呼叫电话的例子。

//       完成打一个电话的整个动作。

//

//

//

// 2008-6-23 创建

//

///////////////////////////////////////////////////////////////////////////////

#include <stdio.h>

#include <stdlib.h>

#include <assert.h>



#include "LRTimer.h"



#include "C:/DJDBDK/Inc/tc08a32.h"

#include "C:/DJDBDK/Inc/newsig.h"



#pragma comment(lib, "C:/DJDBDK/Lib/Tc08a32.lib")

#pragma comment(lib, "C:/DJDBDK/Lib/NewSig.lib")



#define ACD_SUCCESS 0

#define ACD_ERROR   1



#define ACD_NUMLEN  32



static char VoicePath[]="C:/DJDBDK/Voc/";



typedef enum

{

	CH_FREE = 0,

	CH_DIAL,

	CH_CHECKSIG,

	CH_PLAY,

	CH_ONHOOK,

	CH_CONNECT,

	CH_OFFHOOK,

	CH_BUSY,

	CH_NOBODY,

	CH_NOSIGNAL,

	CH_NODIALTONE,

	CH_NORESULT

}ACD_CHANNEL_STATE;



typedef struct

{

	int		nType;

	int		State;

	char	TelNum[ACD_NUMLEN];

}ACD_LINESTRUCT;



// 重置通道

void acdResetChannel(ACD_LINESTRUCT* pChannels, int iChNo)

{

	if(pChannels[iChNo].nType == CHTYPE_TRUNK)

	{

		HangUp(iChNo);

		Sig_ResetCheck(iChNo);

		StartSigCheck(iChNo);

	}

	pChannels[iChNo].TelNum[0]=0;

	pChannels[iChNo].State = CH_FREE;

}



// 外线呼出

typedef struct

{

	ACD_LINESTRUCT* pChannels;

	int				iChNo;

}ACD_DIALOUT;



// 实现呼叫工作, 这个是最主要的回调函数, 在定时事件中回调

//

static void acdCallJob(void* pJobParam)

{

	ACD_LINESTRUCT* pChannels = ((ACD_DIALOUT*)pJobParam)->pChannels;

	int iChNo = ((ACD_DIALOUT*)pJobParam)->iChNo;

	

	// 维持放音操作

	PUSH_PLAY();



	// 维持断续振铃及信号音的函数

	FeedSigFunc();

	

	switch(pChannels[iChNo].State)

	{

	case CH_FREE:

		break;



	case CH_DIAL:

		if(CheckSendEnd(iChNo) == 1)

		{

			StartSigCheck(iChNo);

			pChannels[iChNo].State = CH_CHECKSIG;

		}

		break;



	case CH_CHECKSIG:

		{

			int res = Sig_CheckDial(iChNo);



			switch(res)

			{

			case S_BUSY:

				pChannels[iChNo].State = CH_BUSY;

				break;

			

			case S_CONNECT:

				pChannels[iChNo].State = CH_CONNECT;

				break;

			

			case S_NOSIGNAL:

				pChannels[iChNo].State= CH_NOSIGNAL;

				break;

			

			case S_NOBODY:

				pChannels[iChNo].State= CH_NOBODY;

				break;

			

			case S_NODIALTONE:

				pChannels[iChNo].State= CH_NODIALTONE;

				break;

			}

		}

		break;



	case CH_BUSY:

	case CH_NOSIGNAL:

	case CH_NOBODY:

	case CH_NODIALTONE:

		acdResetChannel(pChannels, iChNo);

		break;



	case CH_CONNECT:

		char FileName[MAX_PATH];



		RsetIndexPlayFile(iChNo);

		strcpy_s(FileName, MAX_PATH, VoicePath);

		strcat_s(FileName, MAX_PATH, "dial.001");

		AddIndexPlayFile(iChNo, FileName);



		strcpy_s(FileName, MAX_PATH,VoicePath);

		strcat_s(FileName, MAX_PATH,"dial.002");

		AddIndexPlayFile(iChNo, FileName);



		strcpy_s(FileName, MAX_PATH,VoicePath);

		strcat_s(FileName, MAX_PATH,"d1");

		AddIndexPlayFile(iChNo, FileName);



		strcpy_s(FileName, MAX_PATH,VoicePath);

		strcat_s(FileName, MAX_PATH,"d2");

		AddIndexPlayFile(iChNo, FileName);



		strcpy_s(FileName, MAX_PATH,VoicePath);

		strcat_s(FileName, MAX_PATH,"d8");

		AddIndexPlayFile(iChNo, FileName);



		strcpy_s(FileName, MAX_PATH,VoicePath);

		strcat_s(FileName, MAX_PATH,"d15");

		AddIndexPlayFile(iChNo, FileName);



		strcpy_s(FileName, MAX_PATH,VoicePath);

		strcat_s(FileName, MAX_PATH,"d9");

		AddIndexPlayFile(iChNo,FileName);



		strcpy_s(FileName, MAX_PATH,VoicePath);

		strcat_s(FileName, MAX_PATH,"d7");

		AddIndexPlayFile(iChNo, FileName);



		strcpy_s(FileName, MAX_PATH,VoicePath);

		strcat_s(FileName, MAX_PATH,"dial.003");

		AddIndexPlayFile(iChNo, FileName);



		strcpy_s(FileName, MAX_PATH,VoicePath);

		strcat_s(FileName, MAX_PATH,"dial.004");

		AddIndexPlayFile(iChNo, FileName);

		pChannels[iChNo].State = CH_OFFHOOK;

		break;



	case CH_OFFHOOK:

		StartIndexPlayFile(iChNo);

		pChannels[iChNo].State=CH_PLAY;

		break;



	case CH_PLAY:

		if(CheckIndexPlayFile(iChNo) == 1)

		{

			StopIndexPlayFile(iChNo);

			pChannels[iChNo].State = CH_ONHOOK;

		}

		break;



	case CH_ONHOOK:

		acdResetChannel(pChannels, iChNo);

		break;

	}	//end switch



	// 处理异常

	if(pChannels[iChNo].nType==CHTYPE_TRUNK && pChannels[iChNo].State != CH_FREE)

	{

		if (Sig_CheckBusy(iChNo))

		{

			if(CH_PLAY == pChannels[iChNo].State)

			{

				StopIndexPlayFile(iChNo);

			}



			acdResetChannel(pChannels, iChNo);

		}

	}

}



// 外线呼出

void acdDialOut(ACD_LINESTRUCT* pChannels, int iChNo, const char* TelNum)

{

	if( CHTYPE_TRUNK != pChannels[iChNo].nType )

	{

		MessageBox(0, "请选择一个外线呼出!", "系统提示", MB_OK);

		return;

	}



	OffHook(iChNo);

	

	char  tel[ACD_NUMLEN];

	strcpy_s(tel, ACD_NUMLEN, TelNum);

	Sig_StartDial(iChNo, tel, "", 0);

	

	strcpy_s(pChannels[iChNo].TelNum, ACD_NUMLEN, tel);

	pChannels[iChNo].State = CH_DIAL;



	// 启动定时器

	//

	ACD_DIALOUT  dialOut;

	dialOut.pChannels = pChannels;

	dialOut.iChNo = iChNo;

		

	LRTimer  timer(100);

	timer.setCallbackProc(acdCallJob, (void*)&dialOut);

	timer.start();

	getchar();

	timer.stop();	

}



///////////////////////////////////////////////////////////////////////////////

// 

// calltest 主程序

//

///////////////////////////////////////////////////////////////////////////////

#define USES_LINENO  1

#define USES_TELNUM  "8566"



int main(int argc, char** argv)

{

	printf("CallTest 东进语音卡 D081A 测试程序 1.0/n");





	// 加载语音卡驱动

	//

	long result = LoadDRV();

	if ( result != ACD_SUCCESS ) 

	{

		MessageBox( 0, "LoadDRV 失败", "系统提示", MB_OK );

		return ACD_ERROR;

	}



	// 检查通道, 并给每个通道分配缓冲区

	//

	WORD wUsedCh = CheckValidCh();

	printf("总线路: %d/n/n", wUsedCh);



	result = EnableCard(wUsedCh, 8196);

	if ( result != ACD_SUCCESS ) 

	{

		FreeDRV();

		MessageBox( 0, "EnableCard 失败", "系统提示", MB_OK );

		return ACD_ERROR;

	}



	// 分配通道并设置每通道状态

	//

	ACD_LINESTRUCT * pLines = (ACD_LINESTRUCT*) calloc(wUsedCh, sizeof(ACD_LINESTRUCT));

	assert(pLines);



	// 设置拨号参数

	SetDialPara(1000, 4000, 350, 7);



	for (int i=0; i<wUsedCh; i++)

	{

        pLines[i].nType = CheckChTypeNew(i);

		pLines[i].State = CH_FREE;

	}



	// 在初始化D161A 卡之后调用信号音检测初始化函数Sig_Init

	Sig_Init(0);



	// 检查每通道状态

	//

	printf(" 线号    状态  /n-------------------/n");

	for(int i=0; i<wUsedCh; i++)

	{

		pLines[i].TelNum[0] = 0;



		switch (pLines[i].nType)

		{

		case CHTYPE_TRUNK:

			printf(" %d/t内线/n", i);

			break;

		case CHTYPE_USER:

			printf(" %d/t外线/n", i);

			break;

		case CHTYPE_RECORD:

			printf(" %d/t录音/n", i);

			break;

		case CHTYPE_EMPTY:

			printf(" %d/t悬空/n", i);

			break;

		}		

	}



	// 拨号: USES_TELNUM 是要拨的号码, 使用外线 USES_LINENO

	//

	printf("/n#%d 线路正在呼出: %s ...... (按Enter键退出)/n", USES_LINENO, USES_TELNUM);

	acdDialOut(pLines, USES_LINENO, USES_TELNUM);



	

	// 释放每个通道

	//

	for(int i=0; i<wUsedCh; i++)

	{

		if(pLines[i].nType == CHTYPE_TRUNK)

		{

			// 如果是内线则挂掉此线路

			HangUp(i);

			Sig_ResetCheck(i);

		}

	}



	DisableCard();

	

	// 释放驱动

	FreeDRV();

	

	free(pLines);



	return 0;

}

附加的类LRTimer:

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

* LRTimer.h                                                                    *

*                                                                              *

* Written by Max Gurdziel 2005 under GNU General Public License                *

* contact me: max[at]remoteSOS[dot]com                                         *

*                                                                              *

* LRTimer is a low resolution timer class with own timing thread. It allows    *

*  an external callback function to be supplied that will be called in         *

*  pre-defined time intervals.                                                 *

*  The smallest timer interval you can use is 1ms.                             *

*                                                                              *

* Tested with gcc mingw & Visual C++ 6.0 under WindowsXP Home and Pro          *

*                                                                              *

*                                                                              *

*     LRTimer timer;                                  // define LRTimer object *

*     timer.setInterval(100);                         // set interval of 100ms *

*     timer.setCallbackProc(&myCallbackFunction, 0);  // set callback function *

*                                                     // it's prototype is:    *

*                               //     void myCallbackFunction(void* pParam);  *

*                                                                              *

*     timer.start();            // start the timer                             *

*     ....                                                                     *

*     timer.stop();             // stops the timer                             *

*     ....                                                                     *

*     timer.start(200);         // starts timer with new interval              *

*                                                                              *

*                                                                              *

*   Example code:                                                              *

*   Copy and paste below sample code to test LRTimer                           *

*                                                                              *

________________________________________________________________________________



#include <stdlib.h>

#include "LRTimer.h"





// define callback function

//

static void myCallback(void* data) 

{

	static DWORD cnt = 0;

	char c;

	cnt++;

	switch (cnt % 4) 

	{

	case 0: c = '|'; break;

	case 1: c = '/'; break;

	case 2: c = '-'; break;

	case 3: c = '//';

	}

	printf("/b%c",c);

}





int main(int argc, char *argv[]) 

{

	LRTimer lrt;

	lrt.setCallbackProc(&myCallback, NULL);	// set the callback function by reference

	lrt.setInterval(50);					// set delay interval in miliseconds

	lrt.start();							// start the timer

	getchar();								// let it run for a while - press Enter

	lrt.stop();								// stop the timer

	getchar();								// wait to show it's stopped - Enter

	lrt.start(200);							// start with different delay

	getchar();

	lrt.stop();

	system("PAUSE");

	return 0;

}



________________________________________________________________________________

*                                                                              *

* Permission to use, copy, modify, and distribute this software and its        *

* documentation under the terms of the GNU General Public License is hereby    *

* granted. No representations are made about the suitability of this software  *

* for any purpose. It is provided "as is" without express or implied warranty. *

* See http://www.gnu.org/copyleft/gpl.html for more details.                   *

*                                                                              *

* All I ask is that if you use LRTimer in your project retain the              *

* copyright notice. If you have any comments and suggestions please email me   *

* max[at]remoteSOS[dot]com                                                     *

*                                                                              *

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



#ifndef LRTIMER_H__

#define LRTIMER_H__





#define _WIN32_WINNT 0x0500



// compile with: /MT /D "_X86_" /c

// processor: x86



#include <windows.h>

#include <process.h>    /* _beginthread, _endthread */

#include <stdio.h>

#include <assert.h>



// define a second in terms of 100ns - used with waitable timer API

#define _SECOND 10000



typedef VOID (*LRTCallbackEventProc)(VOID*);



class LRTimer 

{

public:

	// default constructor with 1 second interval

	LRTimer(DWORD dwInterval=1000);



	// default destructor

	~LRTimer();

	

	// starts timer by creating new thread. interval must be set earlier

	VOID start();

	

	// starts timer with given interval in miliseconds

	VOID start(DWORD _interval_ms);

	

	// stops the timer

	VOID stop();

	

	// sets time interval in miliseconds

	VOID setInterval(DWORD _interval_ms);

	

	// returns time interval in ms

	DWORD getInterval();

	

	// sets function that will be called on time expiration

	VOID setCallbackProc( LRTCallbackEventProc pcbEventProc,  VOID* pcbParam );



	// returns true if LRtimer is currently running

	BOOL isRunning();



	// It should be used if the worker class will use CRT functions

	static HANDLE CrtCreateThread(LPSECURITY_ATTRIBUTES lpsa, DWORD dwStackSize, LPTHREAD_START_ROUTINE pfnThreadProc, void *pvParam, DWORD dwCreationFlags, DWORD *pdwThreadId) throw()

	{

		// sanity check for pdwThreadId

		assert(sizeof(DWORD) == sizeof(unsigned int)); 



		// _beginthreadex calls CreateThread which will set the last error value before it returns

		return (HANDLE) _beginthreadex(lpsa, dwStackSize, (unsigned int (__stdcall *)(void *)) pfnThreadProc, pvParam, dwCreationFlags, (unsigned int *) pdwThreadId);

	}



private:

	DWORD	m_dwInterval;				// interval between alarms



	LRTCallbackEventProc m_pCallback;   // pointer to user callback function

	VOID				*m_pcbParam;	// pointer to user callback parameter



	BOOL	m_bRunning;					// timer running state

	HANDLE	m_hTimerThread;				// handle to timer thread

	DWORD	m_iID;						// timer thread id - added for compatibility with Win95/98



	// timer clocking tread runtine

	virtual DWORD WINAPI timerThread();



	// wrapper to thread runtine so it can be used within a class

	static  DWORD  WINAPI timerThreadAdapter(PVOID _this) 

	{

		return ((LRTimer*) _this)->timerThread();

	}



	// timer callback APC procedure called when timer is signaled

	virtual VOID CALLBACK TimerAPCProc(LPVOID, DWORD, DWORD);



	// wrapper to callback APC procedure so it can be used within a class

	static  VOID CALLBACK TimerAPCProcAdapter(PVOID _this, DWORD a1=0, DWORD a2=0) 

	{

		((LRTimer*) _this)->TimerAPCProc( NULL, a1, a2 );

	}

};



#endif
 
实现文件:
/*******************************************************************************

* LRTimer.cpp                                                                  *

*                                                                              *

* Written by Max Gurdziel 2005 under GNU General Public License                *

* contact me: max[at]remoteSOS[dot]com                                         *

*                                                                              *

* LRTimer is a low resolution timer class with own timing thread. It allows    *

*  an external callback function to be supplied that will be called in         *

*  pre-defined time intervals. The smallest timer interval you can use is 1ms. *

*                                                                              *

*  See header file for more info, usage information and example                *

*                                                                              *

*                                                                              *

*                                                                              *

* Permission to use, copy, modify, and distribute this software and its        *

* documentation under the terms of the GNU General Public License is hereby    *

* granted. No representations are made about the suitability of this software  *

* for any purpose. It is provided "as is" without express or implied warranty. *

* See http://www.gnu.org/copyleft/gpl.html for more details.                   *

*                                                                              *

* All I ask is that if you use LRTimer in your project you retain the          *

* copyright notice. If you have any comments and suggestions please email me   *

* max[at]remoteSOS[dot]com                                                     *

*                                                                              *

* 2008-6-23 Modified by ZhangLiang                                             *

*                                                                              *

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



#include "LRTimer.h"



#define _WIN32_WINNT 0x0500



LRTimer::LRTimer(DWORD dwInterval):

	m_dwInterval(dwInterval),

	m_bRunning(FALSE),

  	m_pCallback(NULL),

	m_pcbParam(NULL),

    m_hTimerThread(0)

{}



LRTimer::~LRTimer()

{}



VOID CALLBACK LRTimer::TimerAPCProc(LPVOID, DWORD, DWORD) 

{

	// call custom callback function

	if (NULL != m_pCallback)

		(*m_pCallback)(m_pcbParam);



#ifdef _DEBUG

	else

		printf("No callback function set/n");

#endif

}



DWORD WINAPI LRTimer::timerThread() 

{

	HANDLE          hTimer;

	BOOL            bSuccess;

	LARGE_INTEGER   liDueTime;

	CHAR            szError[255];





	if ( hTimer = CreateWaitableTimerA( NULL, FALSE, "LRTimer" ) )

		liDueTime.QuadPart=-(LONGLONG)m_dwInterval * _SECOND;



	bSuccess = SetWaitableTimer(

				  hTimer,                            // Handle to the timer object

				  &liDueTime, 						 // When timer will become signaled first time

				  m_dwInterval,                      // Periodic timer interval

				  TimerAPCProcAdapter,               // Completion routine

				  this,                              // Argument to the completion routine

				  FALSE );                           // Do not restore a suspended system

	

	if ( bSuccess ) {

		while (m_bRunning)

			SleepEx(1, TRUE);	// SleepEx(0, TRUE) consumes 100% CPU usage

		CancelWaitableTimer(hTimer);

	} else {

		wsprintfA( szError, "SetWaitableTimer failed with Error %d.", GetLastError() );

#ifdef _DEBUG

		MessageBoxA( NULL, szError, "Error", MB_ICONEXCLAMATION );

#endif

		return 1;

	}

	CloseHandle(hTimer);

	return 0;

}





VOID LRTimer::start() 

{

	m_bRunning = TRUE;



	if (m_hTimerThread != 0) LPTHREAD_START_ROUTINE

		stop();



#ifndef _INC_CRTDEFS

	m_hTimerThread = CreateThread(NULL, 0, timerThreadAdapter, this, 0, &m_iID);

#else

	m_hTimerThread = CrtCreateThread(NULL, 0, timerThreadAdapter, this, 0, &m_iID);

#endif



	if (m_hTimerThread == NULL) 

	{

#ifdef _DEBUG

		printf( "CreateThread failed (%d)/n", GetLastError() );

#endif

		return;

	}

}



VOID LRTimer::start(DWORD _interval_ms) 

{

	setInterval(_interval_ms);

	start();

}



VOID LRTimer::stop()

{

	m_bRunning = FALSE;

	CloseHandle(m_hTimerThread);

	m_hTimerThread = 0;

}



VOID LRTimer::setInterval(DWORD _interval_ms)

{

	m_dwInterval = _interval_ms;

}



DWORD LRTimer::getInterval()

{

	return m_dwInterval;

}



VOID LRTimer::setCallbackProc( LRTCallbackEventProc pcbEventProc, VOID* pcbParam) 

{

	m_pCallback = pcbEventProc;

	m_pcbParam = pcbParam;

}



BOOL LRTimer::isRunning() 

{

	return m_bRunning;

}

抱歉!评论已关闭.