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

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 referencelrt.setInterval(50);                   // set delay interval in milisecondslrt.start();                            // start the timergetchar();                                // let it run for a while - press Enterlrt.stop();                              // stop the timergetchar();                             // wait to show it's stopped - Enterlrt.start(200);                            // start with different delaygetchar();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 10000typedef VOID (*LRTCallbackEventProc)(VOID*);class LRTimer {public:// default constructor with 1 second intervalLRTimer(DWORD dwInterval=1000);// default destructor~LRTimer();// starts timer by creating new thread. interval must be set earlierVOID start();// starts timer with given interval in milisecondsVOID start(DWORD _interval_ms);// stops the timerVOID stop();// sets time interval in milisecondsVOID setInterval(DWORD _interval_ms);// returns time interval in msDWORD getInterval();// sets function that will be called on time expirationVOID setCallbackProc( LRTCallbackEventProc pcbEventProc,  VOID* pcbParam );// returns true if LRtimer is currently runningBOOL isRunning();// It should be used if the worker class will use CRT functionsstatic HANDLE CrtCreateThread(LPSECURITY_ATTRIBUTES lpsa, DWORD dwStackSize, LPTHREAD_START_ROUTINE pfnThreadProc, void *pvParam, DWORD dwCreationFlags, DWORD *pdwThreadId) throw(){// sanity check for pdwThreadIdassert(sizeof(DWORD) == sizeof(unsigned int)); // _beginthreadex calls CreateThread which will set the last error value before it returnsreturn (HANDLE) _beginthreadex(lpsa, dwStackSize, (unsigned int (__stdcall *)(void *)) pfnThreadProc, pvParam, dwCreationFlags, (unsigned int *) pdwThreadId);}private:DWORD m_dwInterval;               // interval between alarmsLRTCallbackEventProc m_pCallback;   // pointer to user callback functionVOID              *m_pcbParam;    // pointer to user callback parameterBOOL   m_bRunning;                 // timer running stateHANDLE    m_hTimerThread;             // handle to timer threadDWORD  m_iID;                      // timer thread id - added for compatibility with Win95/98// timer clocking tread runtinevirtual DWORD WINAPI timerThread();// wrapper to thread runtine so it can be used within a classstatic  DWORD  WINAPI timerThreadAdapter(PVOID _this) {return ((LRTimer*) _this)->timerThread();}// timer callback APC procedure called when timer is signaledvirtual VOID CALLBACK TimerAPCProc(LPVOID, DWORD, DWORD);// wrapper to callback APC procedure so it can be used within a classstatic  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 0x0500LRTimer::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 functionif (NULL != m_pCallback)(*m_pCallback)(m_pcbParam);#ifdef _DEBUGelseprintf("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 timem_dwInterval,                      // Periodic timer intervalTimerAPCProcAdapter,               // Completion routinethis,                              // Argument to the completion routineFALSE );                           // Do not restore a suspended systemif ( bSuccess ) {while (m_bRunning)SleepEx(1, TRUE);  // SleepEx(0, TRUE) consumes 100% CPU usageCancelWaitableTimer(hTimer);} else {wsprintfA( szError, "SetWaitableTimer failed with Error %d.", GetLastError() );#ifdef _DEBUGMessageBoxA( NULL, szError, "Error", MB_ICONEXCLAMATION );#endifreturn 1;}CloseHandle(hTimer);return 0;}VOID LRTimer::start() {m_bRunning = TRUE;if (m_hTimerThread != 0) LPTHREAD_START_ROUTINEstop();#ifndef _INC_CRTDEFSm_hTimerThread = CreateThread(NULL, 0, timerThreadAdapter, this, 0, &m_iID);#elsem_hTimerThread = CrtCreateThread(NULL, 0, timerThreadAdapter, this, 0, &m_iID);#endifif (m_hTimerThread == NULL) {#ifdef _DEBUGprintf( "CreateThread failed (%d)/n", GetLastError() );#endifreturn;}}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;}

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

  1. Delphi之东进数字语音卡(SS1)可复用源码

    Delphi之东进数字语音卡(SS1)可复用源码 作者:成晓旭 Blog:http://blog.csdn.net/cxxsoft (声明:欢迎转载,请保证文章的完整性) 由于工作原因,本人将不在从事 ...

  2. Delphi之东进模拟语音卡(D160A)可复用源码

    Delphi之东进模拟语音卡(D160A)可复用源码 作者:成晓旭 Blog:http://blog.csdn.net/cxxsoft (声明:欢迎转载,请保证文章的完整性) 设计简介: 1.   将 ...

  3. Delphi之东进模拟语音卡(D160A)可复用源码(转)

    计 简介: 1.   将卡.通道分别单独进行设计与封装. 2.   所有的外部操作接口都封装在卡类这一类. 3.   在我的项目中,在卡类这一级还增加了适配器或者代理,分别实现了Adapter或Pro ...

  4. Delphi之东进数字语音卡(SS1)可复用源码 1

    Delphi之东进数字语音卡(SS1)

  5. C#实现IVR(基于东进的语音卡)-3

    1 using System;   2 using System.Collections.Generic;   3 using System.Text;   4 using System.Runtim ...

  6. C#实现IVR(基于东进的语音卡)-5

        /**//// <summary>     /// 语音资源操作类型     /// </summary>     public enum VoiceOperatorT ...

  7. C#实现IVR(基于东进的语音卡)-1

    上一年在公司做了一个小小的IVR项目.觉得这是一个和硬件驱动交互编程的不错例子. 共享一下.也讨论一下. 代码:(这个是调用系统驱动的DLL) using System; using System.T ...

  8. 东进语音卡 java_东进语音卡的声音文件格式

    转自东进论坛 语音卡只支持8K8bit a-law 单声道的 PCM.wave.mp3,您的立体声的mp3需要转换成单声道,8k 8bit的才能播放 问:怎么样把wav格式的文件转换成东进卡能播放的格 ...

  9. 企业级:基于语音卡呼叫中心系统 CTI语音服务器,电话排队系统,电话转接系统,电话录音系统

    <CTI通讯接口软件D081A>用  户  手  册 语音服务器软件源代码+用户手册+数据结构+开发文档 有需要的给我留言! 我的QQ  7732 4199  本系统基本上可以适用于 有语 ...

  10. 最佳实践 | 基于腾讯云MRCP-Server打造简单智能外呼系统

    一.智能外呼架构简介 智能外呼在国内已发展多年,整体的技术早已非常成熟.那么一个简单的智能外呼系统应该包含哪些东西呢? 运营商:运营商的线路资源是外呼系统的基础,国内就是移动.联通.电信,也有一些集成 ...

最新文章

  1. java 虚拟机规范_Java虚拟机规范----Java虚拟机结构
  2. input子系统分析(转)
  3. 一分钟先生之拨云见日看绩效
  4. MyBatis-09MyBatis注解方式之@Update/@Delete
  5. CNI (Container Network Interface)
  6. memcache、redis原理对比
  7. 常见排序算法(比较排序)及比较
  8. CVPR最佳作者新作!无监督学习可变形3D对象
  9. websocket java 例子_java 实现websocket的两种方式实例详解
  10. C语言线性表之循环单链表
  11. Java Queue 使用总结
  12. Gitlab管理Create Merge Request,new Merge Request创建合并请求
  13. linux android交叉编译,【转】搭建arm-linux-gcc交叉编译工具链环境(Android原生(JNI)开发环境搭建)...
  14. JAVA要不要看源码_java需要看源码吗
  15. 计算机专业的简历项目经历,计算机软件专业项目经验范文
  16. 信创办公--基于WPS的Word最佳实践系列(页眉页脚的设置)
  17. 王者荣耀战区在线查询_王者战力查询工具
  18. 【强化学习】策略梯度(Policy Gradient)
  19. XML中的standalone什么意思?
  20. mysql定时任务简单例子

热门文章

  1. Unity官网注册账号绑定手机国籍更改失败
  2. 【NLP】4 gensim word2vec库入门——官方手册embeddings和KeyedVectors
  3. 工业相机中的全局快门与卷帘快门
  4. java导出可运行文件格式,|java导出excel,excel打不开,报文件格式无效,怎么解决!...
  5. phpexcel导出excel无法打开,提示文件格式或文件名无效,文件损毁,解决办法
  6. 360极速浏览器如何设置ie8兼容模式
  7. 西南大学计算机试题答案,17秋西南大学计算机组成原理【0013】机考答案
  8. 【无标题】5 自用历程
  9. Xcode slicing 精解
  10. 使用 Tampermonkey 编写高级跨网站自动化任务脚本