我们使用开源软交换机(open-source IPBX)Asterisk实现Web callback功能,用户体验方式为:
1. 在首页输入您的电话号码:
<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1027" style="WIDTH: 306.75pt; HEIGHT: 67.5pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:%5CDOCUME~1%5CGAOLIN~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C09%5Cclip_image001.png"></imagedata></shape>
2.点击“立即拨打”按钮:
<shape id="_x0000_i1028" style="WIDTH: 307.5pt; HEIGHT: 67.5pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:%5CDOCUME~1%5CGAOLIN~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C09%5Cclip_image003.png"></imagedata></shape>
3在弹出页面输入您朋友的电话号码(固定电话加区号)
<shape id="_x0000_i1029" style="WIDTH: 242.25pt; HEIGHT: 315pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:%5CDOCUME~1%5CGAOLIN~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C09%5Cclip_image005.png"></imagedata></shape>
4点击绿色“呼叫”按钮
上面弹出来的对话框,是基本用户的体验方式考虑的,它还是一个网页,不是Skype客户端,由于这是一个免费的活动,所以没有考虑作为一个标准的基于Web的callback认证功能,另外,用户也不需要输入用户名与密码等信息。直接就可以在网页中输入主叫与被叫号码来体验。
Ø 系统组件:
<shape id="_x0000_i1025" style="WIDTH: 353.25pt; HEIGHT: 373.5pt" filled="t" type="#_x0000_t75" o:ole=""><font size="3"><fill opacity="0" color2="black"></fill><imagedata o:title="" src="file:///C:%5CDOCUME~1%5CGAOLIN~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C09%5Cclip_image007.emz"></imagedata></font></shape>
Ø 系统网络图
<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 414.75pt; HEIGHT: 375pt" type="#_x0000_t75"><imagedata o:title="未命名10" src="file:///C:%5CDOCUME~1%5CGAOLIN~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C17%5Cclip_image001.png"></imagedata></shape>
<shape id="_x0000_i1026" style="WIDTH: 7in; HEIGHT: 455.25pt" filled="t" type="#_x0000_t75" o:ole=""><font size="3"><fill opacity="0" color2="black"></fill><imagedata o:title="" src="file:///C:%5CDOCUME~1%5CGAOLIN~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C09%5Cclip_image009.emz"></imagedata></font></shape>
Ø 安装、部署思路
l Web trigger层
1. 配置文件config.php,在这个文件里说明了callback.php中将要通过AMI连接Asterisk的连接端口(5038),用户名、密码等(这个在Callback engine层的manager.conf配置文件中说明)。
2. 服务器处理文件callback.php,在这个外部文件中执行对应主叫与被叫的拨号方案,先后拨通主叫与被叫。
l Callback engine层
AMI层的配置(为了在外部程序中执行Asterisk,需要赋予权限,就在manager.conf中设置)
在manager.conf中添加结点
;用户名
[admin]
;密码
secret = 123456
;不同级别的认证信息
read = system,call,log,verbose,command,agent,user
write = system,call,log,verbose,command,agent,user
拨号方案的配置
/etc/asterisk/目录上新建了一个专用于这个项目的IVR配置文件web_callback.conf:
;对应主叫方的拨号方案
[skype-web-callback-dial]
;在主叫方的手机上来电显示被叫的手机号
exten => s,1,Set(CALLERID(all)=${CALLED})
;先拨通主叫,如果主叫没通,被叫的输出通道(不存在被叫Sip通道),即被叫的拨号方
;案(a.b.c.d为落地网关的IP地址)
exten => s,2,Dial(SIP/${CALLING}@a.b.c.d||gjA(Welcome))
;如果主叫接听了,记录下主叫是在响铃后主动挂断
exten => s,3,Set(CDR(userfield)=Hangupcause:${HANGUPCAUSE})
exten => s,4,Hangup()
;如果是主叫在响铃一段时间后又不响了,记录下是否由于发生了500的服务器错误。
exten => h,1,Set(CDR(userfield)=Hangupcause:${HANGUPCAUSE})
;对应被叫的拨号方案
[skype-web-callback-answer]
;在被叫方的手机上来电显示主叫的手机号
exten => s,1,Set(CALLERID(all)=${CALLING})
;对于被叫来说需要满足以下需求:
;1.与主叫的通话时间保持5分钟,所以L()这个Dial应用的option选项恰能满足,其中L()第一个参数300000(ms)是总的通话时间,5分钟,第二个参数20000表示还剩下20秒时主叫方将听到timeleft系统提示音(由三个语音文件组成: vm-youhave.gsm
[你还有],20.gsm [20],queue-seconds.gsm[秒通话时间])
有关L()几个参数的说明:
'L(x[:y][:z])' -- Limit the call to 'x' ms warning when 'y' ms are left (repeated every 'z'ms)
--Only 'x' is required, 'y' and 'z' are optional.
--The following special variables are optional:
**LIMIT_PLAYAUDIO_CALLER (default yes) Play sounds to the caller.
**LIMIT_PLAYAUDIO_CALLEE Play sounds to the callee.
**LIMIT_TIMEOUT_FILE File to play when time is up.
**LIMIT_CONNECT_FILE File to play when call begins.
**LIMIT_WARNING_FILE File to play as warning if 'y' is defined.
--'timeleft' is a special sound macro to auto-say the time left and is the default.
;2.${ANSWEREDTIME} 为通道变量,利用被叫方的这个通道变量,可以获取到被叫总的通话时间,根据${ANSWEREDTIME}的值是否等于5分钟,如果通话时间还未到时,被叫方挂断电话,此时转到执行exten => s,7,Playback(PartnerHangup)主叫听到 PartnerHangup[对方已挂机...],如果通话时间已到,转到执行exten=> s,5,Playback(TimeoutHangup)[通话时间到...]
;3.利用另外一个通道变量${HANGUPCAUSE},它将记载从落地网关返回的与PSTN级错误有关的信息,查找 Asterisk wiki上的Recommended SIP <-> ISDN Cause codes部分:
http://www.voip-info.org/wiki/index.php?page=Asterisk+variable+hangupcause
如被叫无人接听返回的是18或19:no answer from the user,转换成Sip返回码为:
480 Temporarily unavailable,如果Dial未成功(被叫响铃一会就断了,或者根本没响铃等异常情况),此时记载下错误码,然后转到相应的执行方案,如无人接听[s-19]。
exten =>s,2,
Dial(SIP/${CALLED}@ a.b.c.d ||gjL(300000:20000:20000:0:1:timeleft::timeleft))
exten => s,3,Set(CDR(userfield)=Hangupcause:${HANGUPCAUSE})
exten => s,4,GotoIf($[${ANSWEREDTIME} = 300]]?5:7)
exten => s,5,Playback(TimeoutHangup)
exten => s,6,Hangup()
exten => s,7,Playback(PartnerHangup)
exten => s,8,Hangup()
exten => s,103,Goto(s-${HANGUPCAUSE},s,1)
exten => h,1,Goto(s-${HANGUPCAUSE},s,1)
;系统忙
;503 Service unavailable
[s-38]
exten => s,1,Playback(SystemBusy)
exten => s,2,Hangup()
;用户忙,拒绝接听此次来电
;call rejected
;403 Forbidden
[s-21]
exten => s,1,Playback(PartnerBusy)
exten => s,2,Hangup()
;电话无人接听
;no user responding
[s-18]
exten => s,1,Playback(PartnerAway)
exten => s,2,Hangup()
;电话无人接听
;no answer from the user
;480 Temporarily unavailable
[s-19]
exten => s,1,Playback(PartnerAway)
exten => s,2,Hangup()
l 系统日志层
CDR记录的保存
Asterisk可以存储CDR记录到一个MYSQL数据库中,也可以选择以CSV文本文件的形式保存起来,在Tom-Skype callback系统中,我们选择了保存到MYSQL数据库。由于Mysql客户端开发库的版权问题,Mysql billing应用程序不再作为Asterisk标准发布版本中的其中一部分来发布,而是以附加内容的形式存在:asterisk-addons,为了让Asterisk支持把CDR日志保存到mysql数据库中,必须下载asterisk-addons包,然后编译与mysql有关的几个模块,并且装载到Asterisk服务器中。
一.下载asterisk-addons包。
有两种方式:
1:官方网站上发布的:
http://downloads.digium.com/pub/asterisk/,如果你当前使用的asterisk是.14版本而且是最新的,这时候从目录中找到最新的asterisk-addons包。
2:从SVN库中检出
svncheckout http://svn.digium.com/svn/asterisk-addons/branches/1.4/,用这种方法要注意几点:
http://svn.digium.com/svn/asterisk-addons/,这个根目录下面,有
这几个目录,如果你当前使用的asterisk是.14版本而且是最新的,这时候应该要从branches分支目录中找到最新的版本下载,注意:不要直接check out trunk/目录。
二. 编译安装asterisk addons
1. 修改Makefile文件
在编译asterisk addons之前,必须修改asterisk addons源文件下的Makefile文
件:
CFLAGS+=-fPIC
ifeq ($(OSARCH),SunOS)
ASTETCDIR=/var/etc/asterisk
ASTLIBDIR=/opt/asterisk/lib
else
ASTLIBDIR=/usr/lib/asterisks (对应asterisk安装后的模块目录上一级目录)
ASTETCDIR=/home/asterisk-<chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False">1.4.11</chsdate>(对应asterisk的源代码目录)
endif
MODULES_DIR=$(ASTLIBDIR)/modules
2.执行三部曲
确定已经有了zlib-devel、mysql-devel(/usr/lib/mysql/),
#makeclean
#make
#makeinstall
三. 修改所有配置文件
1:编辑cdr_manager.conf:enabled = yes
2:编辑modules.conf,在[modules],
增加:load => cdr_addon_mysql.so
3:编辑cdr_mysql.conf,如果目前还没有这个文件,新创建一个
[global]
hostname=localhost (Mysql数据库服务器)
dbname=skypecallback (数据库名)
user=root
password=123456
port=3306
sock = /var/run/mysqld/mysqld.sock
userfield=1
四.在Mysql数据库中新建数据数据库、表
CREATE DATABASE skypecallback;
CREATE TABLE `cdr` (
`calldate` datetime NOT NULL default '0000-00-00 00:00:00',
`clid` varchar(80) NOT NULL default '',
`src` varchar(80) NOT NULL default '',
`dst` varchar(80) NOT NULL default '',
`dcontext` varchar(80) NOT NULL default '',
`channel` varchar(80) NOT NULL default '',
`dstchannel` varchar(80) NOT NULL default '',
`lastapp` varchar(80) NOT NULL default '',
`lastdata` varchar(80) NOT NULL default '',
`duration` int(11) NOT NULL default '0',
`billsec` int(11) NOT NULL default '0',
`disposition` varchar(45) NOT NULL default '',
`amaflags` int(11) NOT NULL default '0',
`accountcode` varchar(20) NOT NULL default '',
`uniqueid` varchar(32) NOT NULL default '',
`userfield` varchar(255) NOT NULL default ''
);
ALTER TABLE `cdr` ADD INDEX ( `calldate` );
ALTER TABLE `cdr` ADD INDEX ( `dst` );
ALTER TABLE `cdr` ADD INDEX ( `accountcode` );
系统运行的即时监控
C++后台即时监控程序,根据CDR信息,它对数据库中的CDR记录表进行了二次统计,抽取出了有用信息,存到了另外一个表skypecallback.利用这个表,我们将决定用户的主叫号码是否可以再次参加我们的活动。