构建VoIP Web callback系统 ---基于Web方式的phone2phone通信方式

来源:互联网 发布:宝元plc编程软件步骤 编辑:程序博客网 时间:2024/06/05 10:54
前言
  IP回拨业务,因为服务的特殊性,主叫(用户)方也是处于接听状态,只要是单向收费的手机,基本通话费就是0分。那么使用IP回拨业务来打电话,不管长途、市话,话费就非常低廉,竞争优势明显。
  系统概念
  ?         Callback原理
  callback的主要原理就是当A用户希望跟B用户通话时,他自己不需要通过手机主动拨号到B用户手机上,相反地:
  l         通过某种方式,初始化一个callback call(接下来会讨论几种激活一个callback的方式)。
  l         系统首先跟用户A建立连接,所以这时候A不是发出呼叫,而是接听这个来自系统的呼叫(在大部分的电话网络中(座机、接听免费的手机,对于这种方式的接听是0话费的))。
  l         紧接着系统建立到用户B的通话,当B接听后,系统桥接这两个calls一起,所以 A与B就能够通话了。
  ?         一个回调系统的主要组件
  上面部分是从一个终端用户的角度出发来描述callback服务。先撇开最终要探讨的web callback系统,我们看一看一个callbback系统解决方案有关的内部架构。一个callback系统主要有三个组件:
  l         Callback触发器
  l         Callback引擎
  l         认证与计费
  Callback触发器
   为什么叫触发器呢,顾名思义,所谓触发器,就是激发某种事件发生的硬件或者软件设备,在我们这里当然是指软件设备。这种触发器起到了联接用户跟 callback系统的桥梁、起到了枢纽作用——用户通过某种方式告诉系统,他想要打电话给哪个被叫,这时候系统callback触发器就能够跟终端用户 交互,基于它所收到的来自终端用户的信息,初始化callback过程。目前存在有几种类型的触发器:
  ANI(missed call) 触发(电话预约回拨)
   这应该是最古老并且是最普遍的触发器类型。原理很简单,首先话务发起方(以下称用户)拨打回拨平台接入码,平台接收到用户主叫号码后主动挂掉连接(您不 用支付该帐单,因为只响了几声,没有通)在设定时间内以运营方的身份,系统回拨到用户的话机上(实际上的第一主叫方),用户摘机后第一个通话链路建立,系 统播放提示语音,用户拨打被叫号码(真正意义的被叫),回拨平台收全被叫号后,发起第二次呼叫,同时给用户播放相应的提示音,如被叫摘机则第二条链路建立 同时回拨平台把两条链路搭通,主被叫通话建立,通话完毕,系统记录下第二条链路产生的话单并按照相应费率,在用户的账户(或卡)上扣除。
  对于这种方式,我们可以类比现在的手机200卡:
   ““手机200卡”业务平台是运营商,依托于高达40G宽带CNCnet骨干网络及数万公里CNC长途光缆,融合了互联网技术和传统电信网的新型增值业 务,只要您的手机是接全国网内免费,如(动感地带,CDMA等),就可以使用手机200卡,因为200卡的服务特殊性,使您是在接听状态下打电话,费用将 不会从移动/联通扣,直接从手机200卡里走。”
  DNIS(DID)callback
  这种方式跟上面提到的ANI(missed call) callback很接近,主要是用途在国际长途。
   您首先拨打服务提供商给您的连接号(英文叫 Access Number, 术语简称叫DID, 是10位数字的电话号码), 听到对方铃声响了后,立刻挂断。马上你的电话就响,抓起来听到拨号音和语音提示,再拨您想打的号码。比如:在美国,假设您在美国家中的号码是928- 111-2222, 您的DID是666-888-9999, 您想打的号码是中国北京父母家中86-10-5555-6666。您先拨1+6468889999, 听到铃声后立刻挂断。马上您家中928-111-2222那部电话机就响,抓起电话,听到类似这样的拨号音和提示:“请拨打您的号码……”,您就拨011 -86-10-55556666,双方就可以通话了。
  SMS callback
  SMS-callback也就是短信回拨系统,客户无需电脑,无需网络支持。仅需使用已注册手机发送指定格式的短信内容,大约5秒左右系统将自动为客户连通。 比如:
  你可以使用手机发送一条SMS消息到我们的网络来开始拨打callback电话。一般地,你所发送的SMS格式为:用户名 密码 主叫号码 被叫号码,如:
  username password 004412345678 004498765432
  Web callback
  客户通过web界面登陆,无需下载和安装任何软件。然后用正确的账号/密码登陆WEB界面,输入自己的号码以及被叫号码,系统将自动为客户接通。我们接下来将要使用开源软交换机(open-source IPBX)Asterisk实现这种功能,体验方式为:
  1. 在首页输入您的电话号码:
  2.点击“立即拨打”按钮:
  3在弹出页面输入您朋友的电话号码(固定电话加区号)
  4点击绿色“呼叫”按钮
  上面弹出来的对话框,是基本用户的体验方式考虑的,它还是一个网页,不是Skype客户端,由于这是一个免费的活动,所以没有考虑作为一个标准的基于Web的callback认证功能,所以不需要输入用户名与密码等信息。详细的说明见后面。
  Email callback
  1.最基本的通过email的形式:只带主叫号码
   发送e-mail 到call@uwtcallback.com,Email的主题为:主叫号码的后7位数,比如:如果您的DID连接号(有关DID的介绍在上面的DNIS (DID)callback里有介绍)为1 581 037 0728,那么主题将是0370728,一旦email被成功发送,系统将会回拨你的主叫,然后播放语音提示,输入被叫号码跟#键。
  2带被叫号码的形式
  在上面的基本形式中,你可以包含被叫号码:
  在主题中,输入您的DID连接号的后7位数并且紧跟着#键,然后再输入被叫号码。
  如:如果你的DID连接号为1 581 037 072,被叫号码为011-928-111-2222,主题为:0370728#0119281112222,一旦邮件发送成功,系统将会播放类似这样的语音提示:“请您稍等,系统正在为您接通电话…….”
  Callback引擎
  在VoIP网络中,其中负责建立呼叫主叫A与被叫B,并且桥接这两者的组件,称之为callback引擎(callback engine).对于callback引擎,存在有不同的实现方式,但是一般能够实现下面的功能:
  l         引擎应该含有一个接口,从callback触发器收集到的call请求信息递交到这个接口,在我们将要实现的基于Web的触发器中,这个接口就是asterisk的AMI模块;
  l         在计费过程中,应该有认证功能来确保用户是否允许拨打这个电话及是否有足够的余额来拨打(在我们目前实现的Web callback中没有这个模块)
  l         建立主叫、被叫的通话关系。
  l         当账户上的信息显示余额不足时,断开双方的通话过程,在我们的Web callback中就是当5分钟的通话时间到了,系统将断开通话过程。
  l         为了更好地计费,给用户生成通话时长和其它的相关的通话信息。(在我们目前实现的Web callback中没有这个模块)
  认证、计费
  通话认证
   在常见的VoIP系统中,这是一个很重要的模块。在计费开始之前,必须能够支持一种通话认证类型,并且对于callback服务来说,这种认证要足够详 细。对于普通的服务来说(比如说预付费方式),这种认证将像下面这样:“如果账户123的账户里有5¥的余额,他尝试呼叫861234567,这时候的问 题就是,他是否允许这次的呼叫?如果是,应该有多久的时长?”在这种情况下,计费系统将会找到拨打被叫861234567合适的费率(我们假设说 ¥0.10/min,)然后计算出允许的最大的通话时长:5/0.1=50min。
  计费
  在通话结束后,计费系统应该马上就要实施费用的计算了,并把CDR记录写进数据库中然后修改用户的账户信息等。
  接下来,以Web callback为例子,展示基于Web的callback系统。
  体验方式
  我们使用开源软交换机(open-source IPBX)Asterisk实现Web callback功能,用户体验方式为:
  1. 在首页输入您的电话号码:
  2.点击“立即拨打”按钮:
  3在弹出页面输入您朋友的电话号码(固定电话加区号)
  4点击绿色“呼叫”按钮
   上面弹出来的对话框,是基本用户的体验方式考虑的,它还是一个网页,不是Skype客户端,由于这是一个免费的活动,所以没有考虑作为一个标准的基于 Web的callback认证功能,另外,用户也不需要输入用户名与密码等信息。直接就可以在网页中输入主叫与被叫号码来体验。
  Web Callback系统设计思想
  ?         系统组件:
点击在新窗口中浏览此图片
  ?         系统网络图
点击在新窗口中浏览此图片
  ?         安装、部署思路
  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/w...
  如被叫无人接听返回的是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.co...,如果你当前使用的asterisk是.14版本而且是最新的,这时候从目录中找到最新的asterisk-addons包。
  2:从SVN库中检出
  svn checkout  http://svn.digium.com/svn/...,用这种方法要注意几点:
  http://svn.digium.com/svn/...,这个根目录下面,有
  branches/
  tags/
  team/
  trunk/
  这几个目录,如果你当前使用的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-1.4.11(对应asterisk的源代码目录)
  endif
  MODULES_DIR=$(ASTLIBDIR)/modules
  2.执行三部曲
  确定已经有了zlib-devel、mysql-devel(/usr/lib/mysql/),
  # make clean
  # make
  # make install
  三. 修改所有配置文件
  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.利用这个表,我们将决定用户的主叫号码是否可以再次参加我们的活动。