网络通信 频道

语音卡应用编程实例(1)


目前电话语音产品已在各方面得到广泛应用,常用的语音卡具有4线或8线通道,可以同时处理4线或8线电话的请求。以下介绍利用语音卡实现计算机自动应答的医疗及养老帐户金语音查询系统。


系统功能


当外线电话打入时,计算机自动检测到振铃信号,并开始播放提示音,同时开始接收用户的电话按键信息。用户通过电话按键选择查询类别、输入身份证号码、查询年度,计算机根据接收的信息从后台ORACLE数据库中取得查询结果数据,并将相应帐户金额数据进行语音合成,再通过语音卡的相应外线电话通道播放查询结果,例如:"姓名张三 年度1999您的医疗帐户金余额是一千二百三十四元五角六分 上年利息一百二十三元 统筹金划入二十三元四角 个人缴纳二十八元五角 帐户内报销八百零八元八角八分"。用户端电话接听所查帐户数据的语音信号。


编程思路


系统应划分为6个运行阶段:


1、 初始化语音卡、连接数据库,等待外线电话打入。检测到振铃后进入下一阶段。
2、 接收用户选择的查询类别。
播放提示音:"欢迎使用,查询医疗帐户请拨1,查询养老帐户请拨2,查询离退休金请拨3"。用户选择1-3后进入下一阶段。默认选择为1。
3、 接收用户输入的身份证号码。
播放提示音:"请您输入身份证号码"。用户输入后,系统判断数据库中是否存在此身份证号码,如果存在,则进入下一阶段。否则提示重新输入。
4、 接收用户输入查询年度。
播放提示音:"请您输入查询年度"。用户输入后,生成查询条件,取得查询数据。进入下一阶段。
5、 合成及播放姓名语音。
6、 帐户金数额语音合成及播放。


具体实现


由于电话语音卡的编程接口以windows动态链接库(TW8VID32.DLL)方式提供,可以使用目前常用的可视化开发工具,如:delphi ,vb, pb, visual c++等。下面以PB环境举例说明。


首先建立一个新的application ,一个新的窗口yyk,在application的open事件中,连接后台ORACLE数据库,并对语音卡进行初始化。设置窗口的定时器。也可以在窗口yyk中设置一些代表各个通道当前状态的提示文本,在系统响应用户按键时可以随时更新提示文本,以反映各通道的工作状态。

函数声明Global external functions ,以及常量定义
FUNCTION int TV_Installed() library "tw8vid32.dll"
SUBROUTINE TV_Initialize() library "tw8vid32.dll"
SUBROUTINE TV_Disable() library"tw8vid32.dll"
FUNCTION int TV_ChannelType(int chno) library"tw8vid32.dll"
FUNCTION int TV_OffHookDetect(int chno) library"tw8vid32.dll"
FUNCTION int TV_RingDetect(int chno) library"tw8vid32.dll"
......................略
详细的函数声明附录在最后。

定义结构ch_stru
{ string Fname //通道放音文件名
int wstate //通道状态
int jieduan //运行阶段
int cx_select //查询类型
string sfzhm //身份证号码
string nd //查询年度
string xingmin //姓名
string sentence //通道放音字符 }

定义全局变量ch_stru channel[8]
int chnum
定义application的open事件
integer i
string ls_startupfile
l_startupfile = "yyk.ini"
//设置数据库事务对象参数
sqlca.DBMS = ProfileString (l_startupfile, "database", "dbms", "")
sqlca.database = ProfileString (l_startupfile, "database", "database", "")
sqlca.userid = ProfileString (l_startupfile, "database", "userid", "")
sqlca.dbpass = ProfileString (l_startupfile, "database", "dbpass", "")
sqlca.logid = ProfileString (l_startupfile, "database", "logid", "")
sqlca.logpass = ProfileString (l_startupfile, "database", "LogPassWord", "")
sqlca.servername = ProfileString (l_startupfile, "database", "servername", "")
sqlca.dbparm = ProfileString (l_startupfile, "database", "dbparm", "")
connect; //连接数据库
if sqlca.sqlcode <> 0 then
MessageBox ("不能连通数据库", sqlca.sqlerrtext)
return
end if
open(yyk)
if timer(0.06,yyk)=-1 then
MessageBox ("错误提示","设置定时器失败, 程序不能执行!")
return
end if
chnum=tv_installed()
if chnum<=0 then
MessageBox ("错误提示","未安装语音卡!")
else
tv_initialize() //初始化语音卡
if chnum>8 then
chnum=8
end if
initchannel () //初始化各通道
end if
//application的open事件定义结束

定义函数initchannel (),初始化各通道结构channel[i]
for i=1 to 8
channel[i].FName="welcome.tw"
channel[i].wstate=WS_FREE
channel[i].jieduan=1
channel[i].cx_select=1
channel[i].sfzhm=’’
channel[i].nd=’’
channel[i].xingmin=’’
channel[i].sentence=" "
if i>chnum then
channel[i].chtype = CT_EMPTY
else
channel[i].chtype=tv_channelType(i -1) //判断通道类型,外线或内线或空
end if
next
//退出应用时,使语音卡无效。
if chnum>0 then
tv_disable()
end if
disconnect using sqlca ; //取消连接数据库

//在窗口yyk的timer事件中处理各通道的请求
int i
for i=1 to chnum
if channel[i].chtype=1 then
//如果是外线通道,处理请求
externalyyk (i) //自定义函数
end if
next

自定义函数externalyyk (int chno)定义如下:
// 函数externalyyk ()开始
long retval
integer DtmfVal,temp
unsignedinteger sigtype
double num
string strRet, password,yyk_path,xm_temp
CHOOSE CASE channel[chno].jieduan
case 1 //选择查询类别

CHOOSE CASE channel[chno].wstate
CASE WS_FREE
if tv_ringdetect(chno -1) > 1 then //检测到振铃
channel[chno].wstate=WS_STARTFILE
tv_offhookctrl(chno -1) //控制摘机
tv_flushdtmf(chno -1) //清空某通道的双音多频码(dtmf)
end if
case WS_STARTFILE
//开始播放提示音,"欢迎使用,查询医疗帐户请拨1,查询养老帐户......"
f_start_file(chno,WS_ONFILE)
//自定义函数f_start_file(int chno ,int next_state) 定义如下:
// long retval
//启动某通道文件放音
// retval=tv_startplayfile(ch_no -1,channel[ch_no].FName,0,300000)
// if retval<=0 then
// tv_hangupctrl(ch_no -1) //如果启动放音失败则挂断
// channel[ch_no].wstate=WS_FREE
// channel[ch_no].jieduan=1
// 设置提示音文件
// channel[ch_no].FName="welcome.tw"
// else
// 否则改变通道状态标志
// channel[ch_no].wstate=next_state
// end if
//
// return 1
case WS_ONFILE
//如果检测到忙音,则停止放提示音,并控制挂断。
if tv_monitorbusy(chno -1,SIG_BUSY1,5)<>0 or tv_monitorbusy(chno -1,SIG_BUSY2,5)<>0 then
tv_stopplayfile(chno -1)
channel[chno].wstate=WS_FREE
tv_hangupctrl(chno -1)
channel[chno].jieduan=1
else
//否则继续播放剩余提示音
retval=tv_playfilerest(chno -1)
if retval<=0 then //如果提示音播放完毕
//设置等待接收双音多频码DTMF的时间为35秒
tv_starttimer(chno -1,35)
//准备转到接收双音多频码DTMF
channel[chno].wstate=WS_WAITDTMF
else
DtmfVal=tv_getdtmfchar(chno -1) //检测用户按键信息
if DtmfVal<>-1 then
tv_stopplayfile(chno -1) //检测到按键,停止播放提示音
channel[chno].wstate=WS_WAITDTMF
if char(DtmfVal)<>’*’ and char(DtmfVal)<>’#’ then
channel[chno].DtmfStr=""
channel[chno].DtmfStr=channel[chno].dtmfstr+char(dtmfval)
if len(channel[chno].dtmfstr)>=1 then
channel[chno].wstate=WS_STARTFILE
channel[chno].jieduan=2 //准备转到身份证输入部分
channel[chno].FName="srsfzhm.tw" //设置提示音文件,提示输入身份证
if integer(left(channel[chno].dtmfstr,1)) > 3 or integer(left(channel[chno].dtmfstr,1)) < 1 then
channel[chno].cx_select=1 //默认选择为1
else
channel[chno].cx_select=integer(left(channel[chno].dtmfstr,1))
end if
end if
end if
end if
end if
end if
case WS_WAITDTMF
DtmfVal=tv_getdtmfchar(chno -1) //检测用户按键信息
if DtmfVal<>-1 then //检测到按键
channel[chno].wstate=WS_WAITDTMF
if char(DtmfVal)<>’*’ and char(DtmfVal)<>’#’ then
channel[chno].DtmfStr=""
channel[chno].DtmfStr=channel[chno].dtmfstr+char(dtmfval)
if len(channel[chno].dtmfstr)>=1 then
channel[chno].wstate=WS_STARTFILE
channel[chno].jieduan=2 //准备转到接收身份证号部分
channel[chno].FName="srsfzhm.tw" //设置放音文件名,提示输入身份证号码
if integer(left(channel[chno].dtmfstr,1)) > 3 or integer(left(channel[chno].dtmfstr,1)) < 1 then
channel[chno].cx_select=1 //默认选择为1(查询医疗帐户)
else
channel[chno].cx_select=integer(left(channel[chno].dtmfstr,1))
end if
end if
end if

else //未检测到用户按键信息
if tv_monitorbusy(chno -1,SIG_BUSY1,5)<>0 or tv_monitorbusy(chno -1,SIG_BUSY2,5)<>0 then
channel[chno].wstate=WS_FREE //检测到忙音,挂机,改变通道状态为空闲
tv_hangupctrl(chno -1)
else
if tv_timerelapsed(chno -1)<0 then
channel[chno].wstate=WS_FREE //等待接收Dtmf数据码超时,挂机
tv_hangupctrl(chno -1)
end if
end if
end if
end choose
case 2 //获取身份证号部分

CHOOSE CASE channel[chno].wstate
case WS_STARTFILE
f_start_file(chno,WS_ONFILE)
case WS_ONFILE
//........省略,与前面类似
case WS_WAITDTMF
//........省略,与前面类似
case WS_GETDTMF
//..............省略
if len(channel[chno].dtmfstr)=15 then
channel[chno].sfzhm=channel[chno].dtmfstr //得到身份证号码(15位)
//准备转到查询数据库中是否存在此身份证号部分
channel[chno].wstate=WS_looksfzhmfromdb
end if
case WS_looksfzhmfromdb
channel[chno].a1=0
//判断数据库中是否存在所输的身份证号码
choose case channel[chno].cx_select
case 1 //从数据库中医疗帐户表中查找
//a1>=1表示数据库中存在所输的身份证号码
channel[chno].a1=f_count_yiliao(channel[chno].sfzhm)
case 2 //从数据库中养老帐户表中查找
channel[chno].a1=f_count_yanglao(channel[chno].sfzhm)
case 3 //从数据库中离退休表中查找
channel[chno].a1=f_count_lituixiu(channel[chno].sfzhm)
end choose
//如果数据库中存在所输的身份证号码
if channel[chno].a1 >= 1 then
//从数据库中获取姓名
choose case channel[chno].cx_select
case 3
channel[chno].xingmin=f_getxingmin_lituixiu(chno)
case 2
channel[chno].xingmin=f_getxingmin_yanglao(chno)
case 1
channel[chno].xingmin=f_getxingmin_yiliao(chno)
end choose
channel[chno].wstate=WS_STARTFILE
channel[chno].jieduan=4 //准备转到接收查询年度部分
channel[chno].FName="srnd.tw" //设置放音文件名,提示输入查询年度
else
//数据库中不存在所输的身份证号码
channel[chno].wstate=WS_STARTFILE
channel[chno].jieduan=2 //准备转到接收身份证号码部分
//设置放音文件名,身份证号码有误或为找到,请重输
channel[chno].FName="nosfzhm.tw"
end if
end choose

 

转载地址:http://www.voipchina.cn/technology/2004-03-24/36869.shtml

0
相关文章