贝高林的Blog

IMS——更软的软交换,固移融合——IMS解决方案

用户操作
[留言]  [发消息]  [加为好友] 
订阅我的博客
XML聚合    FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
lin_bei的公告
<EMBED src="http://www.aswis.net/100000/clock/clock6.swf" type="application/x-shockwave-flash" width="180" height="180"></EMBED> <body style="CURSOR:url(http://img.xiaonei.com/photos/81/941/orig15467.ani)"></body> <!-- 中国农历开始 --> <SCRIPT language=JavaScript><!-- var lunarInfo=new Array( 0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2, 0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977, 0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970, 0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950, 0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557, 0x06ca0,0x0b550,0x15355,0x04da0,0x0a5d0,0x14573,0x052d0,0x0a9a8,0x0e950,0x06aa0, 0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0, 0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b5a0,0x195a6, 0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570, 0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0, 0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5, 0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930, 0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530, 0x05aa0,0x076a3,0x096d0,0x04bd7,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45, 0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0) var Animals=new Array("鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"); var Gan=new Array("甲","乙","丙","丁","戊","己","庚","辛","壬","癸"); var Zhi=new Array("子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"); var now = new Date(); var SY = now.getYear(); var SM = now.getMonth(); var SD = now.getDate(); //==== 传入 offset 传回干支, 0=甲子 function cyclical(num) { return(Gan[num%10]+Zhi[num%12])} //==== 传回农历 y年的总天数 function lYearDays(y) { var i, sum = 348 for(i=0x8000; i>0x8; i>>=1) sum += (lunarInfo[y-1900] & i)? 1: 0 return(sum+leapDays(y)) } //==== 传回农历 y年闰月的天数 function leapDays(y) { if(leapMonth(y)) return((lunarInfo[y-1900] & 0x10000)? 30: 29) else return(0) } //==== 传回农历 y年闰哪个月 1-12 , 没闰传回 0 function leapMonth(y) { return(lunarInfo[y-1900] & 0xf)} //====================================== 传回农历 y年m月的总天数 function monthDays(y,m) { return( (lunarInfo[y-1900] & (0x10000>>m))? 30: 29 )} //==== 算出农历, 传入日期物件, 传回农历日期物件 // 该物件属性有 .year .month .day .isLeap .yearCyl .dayCyl .monCyl function Lunar(objDate) { var i, leap=0, temp=0 var baseDate = new Date(1900,0,31) var offset = (objDate - baseDate)/86400000 this.dayCyl = offset + 40 this.monCyl = 14 for(i=1900; i<2050 && offset>0; i++) { temp = lYearDays(i) offset -= temp this.monCyl += 12 } if(offset<0) { offset += temp; i--; this.monCyl -= 12 } this.year = i this.yearCyl = i-1864 leap = leapMonth(i) //闰哪个月 this.isLeap = false for(i=1; i<13 && offset>0; i++) { //闰月 if(leap>0 && i==(leap+1) && this.isLeap==false) { --i; this.isLeap = true; temp = leapDays(this.year); } else { temp = monthDays(this.year, i); } //解除闰月 if(this.isLeap==true && i==(leap+1)) this.isLeap = false offset -= temp if(this.isLeap == false) this.monCyl ++ } if(offset==0 && leap>0 && i==leap+1) if(this.isLeap) { this.isLeap = false; } else { this.isLeap = true; --i; --this.monCyl;} if(offset<0){ offset += temp; --i; --this.monCyl; } this.month = i this.day = offset + 1 } function YYMMDD(){ var cl = '<font color="#0000df" STYLE="font-size:9pt;">'; if (now.getDay() == 0) cl = '<font color="#c00000" STYLE="font-size:9pt;">'; if (now.getDay() == 6) cl = '<font color="#00c000" STYLE="font-size:9pt;">'; return(cl+SY+'年'+(SM+1)+'月'+SD+'日</font>'); } function weekday(){ var day = new Array("星期日","星期一","星期二","星期三","星期四","星期五","星期六"); var cl = '<font color="#ff0000" STYLE="font-size:9pt;">'; if (now.getDay() == 0) cl = '<font color="#c00000" STYLE="font-size:9pt;">'; if (now.getDay() == 6) cl = '<font color="#00c000" STYLE="font-size:9pt;">'; return(cl+ day[now.getDay()]+ '</font>'); } //==== 中文日期 function cDay(m,d){ var nStr1 = new Array('日','一','二','三','四','五','六','七','八','九','十'); var nStr2 = new Array('初','十','廿','卅',' '); var s; if (m>10){s = '十'+nStr1[m-10]} else {s = nStr1[m]} s += '月' switch (d) { case 10:s += '初十'; break; case 20:s += '二十'; break; case 30:s += '三十'; break; default:s += nStr2[Math.floor(d/10)]; s += nStr1[d%10]; } return(s); } function solarDay1(){ var sDObj = new Date(SY,SM,SD); var lDObj = new Lunar(sDObj); var cl = '<font color="violet" STYLE="font-size:9pt;">'; var tt = '【'+Animals[(SY-4)%12]+'】'+cyclical(lDObj.monCyl)+'月 '+cyclical(lDObj.dayCyl++)+'日' ; return(cl+tt+'</font>'); } function solarDay2(){ var sDObj = new Date(SY,SM,SD); var lDObj = new Lunar(sDObj); var cl = '<font color="#000066" STYLE="font-size:9pt;">'; //农历BB'+(cld[d].isLeap?'闰 ':' ')+cld[d].lMonth+' 月 '+cld[d].lDay+' 日 var tt = cyclical(SY-1900+36)+'年 '+cDay(lDObj.month,lDObj.day); return(cl+tt+'</font>'); } function solarDay3(){ var sTermInfo = new Array(0,21208,42467,63836,85337,107014,128867,150921,173149,195551,218072,240693,263343,285989,308563,331033,353350,375494,397447,419210,440795,462224,483532,504758) var solarTerm = new Array("小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至") var lFtv = new Array("0101*春节","0109 老婆生日","0115 元宵节","0505 端午节","0707 七夕情人节","0715 中元节","0815 中秋节","0909 重阳节","1208 腊八节","1224 小年","0100*除夕") var sFtv = new Array("0101*元旦","0214 情人节","0308 妇女节","0312 植树节","0315 消费者权益日","0401 愚人节","0501 劳动节","0504 青年节","0512 护士节","0601 儿童节","0701 建党节 香港回归纪念", "0801 建军节","0808 父亲节","0909 毛泽东逝世纪念","0910 教师节","0928 孔子诞辰","1001*国庆节", "1006 老人节","1024 联合国日","1112 孙中山诞辰","1220 澳门回归纪念","1225 圣诞节","1226 毛泽东诞辰") var sDObj = new Date(SY,SM,SD); var lDObj = new Lunar(sDObj); var lDPOS = new Array(3) var festival='',solarTerms='',solarFestival='',lunarFestival='',tmp1,tmp2; //农历节日 for(var i = 0 ; i < lFtv.length ; i ++) if(lFtv[i].match(/^(\d{2})(.{2})([\s\*])(.+)$/)) { tmp1=Number(RegExp.$1)-lDObj.month tmp2=Number(RegExp.$2)-lDObj.day if(tmp1==0 && tmp2==0) lunarFestival=RegExp.$4 } //国历节日 for(var i = 0 ; i < sFtv.length ; i ++) if(sFtv[i].match(/^(\d{2})(\d{2})([\s\*])(.+)$/)){ tmp1=Number(RegExp.$1)-(SM+1) tmp2=Number(RegExp.$2)-SD if(tmp1==0 && tmp2==0) solarFestival = RegExp.$4 } //节气 tmp1 = new Date((31556925974.7*(SY-1900)+sTermInfo[SM*2+1]*60000)+Date.UTC(1900,0,6,2,5)) tmp2 = tmp1.getUTCDate() if (tmp2==SD) solarTerms = solarTerm[SM*2+1] tmp1 = new Date((31556925974.7*(SY-1900)+sTermInfo[SM*2]*60000)+Date.UTC(1900,0,6,2,5)) tmp2= tmp1.getUTCDate() if (tmp2==SD) solarTerms = solarTerm[SM*2] if(solarTerms == '' && solarFestival == '' && lunarFestival == '') festival = ''; else festival = '<TABLE WIDTH=100% BORDER=0 CELLPADDING=2 CELLSPACING=0 BGCOLOR="#CCFFCC"><TR><TD>'+ '<FONT COLOR="#000000" STYLE="font-size:9pt;">'+solarTerms + ' ' + solarFestival + ' ' + lunarFestival+'</FONT></TD>'+ '</TR></TABLE>'; var cl = '<font color="#000066" STYLE="font-size:9pt;">'; return(cl+festival+'</font>'); } function setCalendar(){ document.write('<table align=center CELLPADDING=2 CELLSPACING=0 border=1><tr><td bgcolor=#FEFEEF><table border=0 CELLPADDING=0 CELLSPACING=0><tr><td align=center>'); document.write(YYMMDD()+'&nbsp;&nbsp;'+weekday()); document.write('</td></tr>'); document.write('<tr><td align=center>'); document.write(solarDay1()); document.write('</td></tr><tr><td align=center>'); document.write(solarDay2()); document.write('</td></tr><tr><td>'); document.write(solarDay3()); document.write('</td></tr></table></td></tr></table>'); } setCalendar(); //--></SCRIPT> <!-- 中国农历结束 --> <!-- 新闻滚动 --> <iframe name=sina_roll src=http://news.sina.com.cn/o/allnews/input/index.html height=14 width=175 Frameborder=No Border=0 Marginwidth=0 Marginheight=0 Scrolling=No></iframe> <!-- 新闻滚动结束--> <br> <a href=http://blog.csdn.net/lin_bei title="点击此处进入首页">首页</a> <!-- QQ在线状态显示 --> <a href="http://wpa.qq.com/msgrd?V=1&Uin=94799058"><img border=0 src="http://wpa.qq.com/pa?p=1:94799058:7" alt="点击这里给我发消息"></a><!-- Begin Online Status Indicator code --><!-- End Online Status Indicator code --> <script language="JavaScript" type="text/javascript" charset="gb2312" src=" http://c6.50bang.com/click.js?user_id=403116"></script> <br> <embed src="http://www.yyzjzx.net/jswy/mhf/cailiao/endless%20love.mp3" width="170" height="25" type="audio/mpeg" autostart="true" loop="infinite"></embed> <img src=http://nmc2.jy.js.cn/cgi-bin/counter.pl?id=csdn_blog_lin&md=a4&ln=6&from=0&bd=$0;$0;$255> <!-- Google--> <script>var s="http://www.google.com/search?hl=zh-CN&lr=lang_zh-CN&q=";</script> <a href="http://www.google.com"><img border="0" src="http://www.google.com/logos/Logo_25wht.gif"></a><input name="q" type="text" value="" style="font-size:9pt"> <input name="btnG" type="button" value="google搜索" onclick="window.open(s+document.all.q.value)"> <IFRAME border=0 name=play marginWidth=0 marginHeight=0 src=http://www1.xise.cn/baidu/140_80.htm frameBorder=0 width=140 scrolling=no height=80></IFRAME> <iframe scrolling="no" frameborder="0" width="150" height="25" src="http://www.xise.cn/qita/ip3.htm" allowtransparency="true"></iframe> <IFRAME border=0 name=play marginWidth=0 marginHeight=0 src=http://www1.xise.cn/tian.htm frameBorder=0 width=168 scrolling=no height=52></IFRAME> <br> <a href=' http://www.blogdove.com/' target='_blank'> 博鸽-最好用的好友博客阅读器<br><img src=' http://www.blogdove.com/images/logo.gif' /></a>
文章分类
IT专家
Bob大叔
Eric Newcomer
Martin Fowler's Bliki
夏昕的专栏
孟岩
林信良的专栏
良葛格学习笔记
Open-Source SOA Resource
bloger's SOA resource
open-source ESB petals
open-source esb ServiceMix
Service Oriented Business Integration
开源社区与论坛
Csdn社区
IBM Java开发者社区
ITPUB论坛
JavaEye
JavaResearchOrg
Java开源大全(全)
martinfowler大师的主页
Matrix与Java共舞
中国Eclipse社区
最重要的J2EE门户
面向Java/J2EE的软件站点
同事blog链接
TOM-Skype掌门人(RSS)
同学blog链接
xiaofeng同学
微笑的百合
文生
团队blog
bettyna
Cactus团队blog
李彦超
赵宁
存档

原创  构建VoIP Web callback系统 ---基于Web方式的phone2phone通信方式(1) 收藏

 

前言

IP回拨业务,因为服务的特殊性,主叫(用户)方也是处于接听状态,只要是单向收费的手机,基本通话费就是0分。那么使用IP回拨业务来打电话,不管长途、市话,话费就非常低廉,竞争优势明显。

系统概念                        

Ø         Callback原理

callback的主要原理就是当A用户希望跟B用户通话时,他自己不需要通过手机主动拨号到B用户手机上,相反地:

l         通过某种方式,初始化一个callback call(接下来会讨论几种激活一个callback的方式)。

l         系统首先跟用户A建立连接,所以这时候A不是发出呼叫,而是接听这个来自系统的呼叫(在大部分的电话网络中(座机、接听免费的手机,对于这种方式的接听是0话费的))。

l         紧接着系统建立到用户B的通话,当B接听后,系统桥接这两个calls一起,所以 AB就能够通话了。

 

Ø         一个回调系统的主要组件

上面部分是从一个终端用户的角度出发来描述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, 您的DID666-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客户端,由于这是一个免费的活动,所以没有考虑作为一个标准的基于Webcallback认证功能,所以不需要输入用户名与密码等信息。详细的说明见后面。

Email callback

1.最基本的通过email的形式:只带主叫号码

发送e-mail call@uwtcallback.comEmail的主题为:主叫号码的后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的触发器中,这个接口就是asteriskAMI模块;

l         在计费过程中,应该有认证功能来确保用户是否允许拨打这个电话及是否有足够的余额来拨打(在我们目前实现的Web callback中没有这个模块)

l         建立主叫、被叫的通话关系。

l         当账户上的信息显示余额不足时,断开双方的通话过程,在我们的Web callback中就是当5分钟的通话时间到了,系统将断开通话过程。

l         为了更好地计费,给用户生成通话时长和其它的相关的通话信息。(在我们目前实现的Web callback中没有这个模块)

认证、计费

通话认证

在常见的VoIP系统中,这是一个很重要的模块。在计费开始之前,必须能够支持一种通话认证类型,并且对于callback服务来说,这种认证要足够详细。对于普通的服务来说(比如说预付费方式),这种认证将像下面这样:“如果账户123的账户里有5¥的余额,他尝试呼叫861234567,这时候的问题就是,他是否允许这次的呼叫?如果是,应该有多久的时长?”在这种情况下,计费系统将会找到拨打被叫861234567合适的费率(我们假设说¥0.10/min,)然后计算出允许的最大的通话时长:5/0.150min

计费

在通话结束后,计费系统应该马上就要实施费用的计算了,并把CDR记录写进数据库中然后修改用户的账户信息等。

接下来,以Web callback为例子,展示基于Webcallback系统。

   

发表于 @ 2007年10月14日 16:58:00 | 评论( loading... ) | 编辑| 举报| 收藏

旧一篇:l转:博鸽常见下载网址收录  | 新一篇:构建VoIP Web callback系统 ---基于Web方式的phone2phone通信方式(2)

  • 发表评论
  • 评论内容:
  •  
Copyright © lin_bei
Powered by CSDN Blog