在云中建立自己的私人网络电话系统

1.准备工作 && 编译

首先,需要安装一些最基本的依赖库。以Ubuntu为例:

sudo apt-get install uuid-dev libjansson-dev libxml2-dev unixodbc-dev libmyodbc

然后我们从Asterisk的官网 获取其最新的代码

wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-14-current.tar.gz

然后解压缩

tar zxvf asterisk-14-current.tar.gz

进入代码目录,进行环境配置、编译和安装

./configure --prefix=$(pwd)/../build/ --with-pjproject-bundled

make && make install && make sample

到这里Asterisk就已经安装好了,但是要经过配置才可以使用。

2.听见HelloWorld

我们在这里先配置一个最简单的测试环境,又一台手机进行拨号,系统会自动接通这一路通话,稍等5秒后播放一段HelloWorld的语言,然后自动挂断。

首先进入Asterisk安装目录下的etc子目录,修改以下文件的内容:

extensions.conf

[hello]

exten = 100,1,Answer()

same = n,Wait(5)

same = n,Playback(hello-world)

same = n,Hangup()

pjsip.conf

[transport-udp]

type=transport

protocol=udp

bind=0.0.0.0

[6001]

type=endpoint

context=hello

disallow=all

allow=ulaw

auth=6001

aors=6001

[6001]

type=auth

auth_type=userpass

password=testpwd

username=6001

[6001]

type=aor

max_contacts=1

这里简单的解释一下这两个文件的含义,extensions.conf描述了Asterisk在接到呼叫以后根据被叫号码所决定的行为,这在Asterisk中被称为Dailplan。这份Dailplan内容很简单的,只包含了一个被称为hello的Dailplan,当接到被叫号码为100的呼叫后自动接听,等待5秒,然后播放一个名叫hello-world的语言文件,然后挂断。

pjsip.conf是对应PJSIP插件的配置文件。Asterisk的插件分为很多类型,PJSIP插件属于channel类型,用来最终实现和终端的交互。PJSIP是当前Asterisk主要支持的SIP协议Channel插件。这份pjsip.conf包含了四个块。第一块,transport-udp,这一部分描述了pjsip使用udp与外部通信,并制定了监听消息的地址。后面三个块都叫做6001,分别从终端属性(Endpoint),登录信息(Auth)和授权信息(Aor)三个角度描述一个设备。Endpoint主要表述终端支持的协议,以及适用哪一个Auth和Aor信息。Auth描述了系统如何验证用户。Aor限制了用户最多可以在系统中同时登录几次。

到这里,对Asterisk就告一段落,执行下面的命令启动Asterisk

./asterisk -cvvvvv

下面我们需要对终端进行配置。

当前市面上有各种各样的SIP终端,包括各个平台上的软件和各种硬件,在这里我们建议使用Windows或者Android上的Linphone进行测试,本文中所有的配置都使用Android上的Linphone进行过测试。Linphone的官网在这里

打开Android上的Linphone,如果你是第一次打开Linphone的话,选择Use SIP Account,根据上面的配置输入用户名、密码和服务器地址,并选择Transport为UDP,如下图所示,然后点击Login。

如果看到下图一样的界面,注意界面左上角显示为绿色的已注册(Registered),就说明你已经成功的登录了Asterisk服务器,同时在服务器的命令行上也会有显示。

这时,可以尝试使用拨号盘给100打电话,看看能不能听到Hello World的声音。

一般情况下,会出现的情况是电话可以正确的接通和挂断,但是听不到声音。出现这一现象的原因是,我们的终端处于NAT内网中,而我们使用的又是UDP传输,在没有进行特殊配置的情况下,语音会被NAT所阻挡,所以会听不到声音。

NAT的组网方式多种多样,同样的配置不可能通吃所有情况,通常我们会在pjsip.conf的Endpoint块中增加如下两行,可以解决大多数由于NAT引起的语音不通。

rtp_symmetric=yes

direct_media=no

前一行强制Asterisk与终端交互时,在语音上行和下行时使用同样的UDP端口。后一行则不允许终端间以P2P的形式进行通信,强制通过Asterisk中转。由于我们的服务器通常配置在拥有公网IP的云主机上,这样的配置就可以解决大多数由于NAT引起的问题。

现在再试一试,是不是可以听到Hello World的声音了?

3.第一次接触

作为一个网络电话系统,最重要的莫过于实现两个终端间的通话,在这一部分我们就来改进我们的配置,实现这一功能。

修改pjsip.conf,增加以下内容:

[3001]

type=endpoint

rtp_symmetric=yes

context=sipcall

message_context=sipsms

disallow=all

allow=opus,h264

auth=3001

aors=3001

[3001]

type=auth

auth_type=userpass

password=pwd3001

username=3001

[3001]

type=aor

max_contacts=1

[3002]

type=endpoint

rtp_symmetric=yes

context=sipcall

message_context=sipsms

disallow=all

allow=opus,h264

auth=3002

aors=3002

[3002]

type=auth

auth_type=userpass

password=pwd3002

username=3002

[3002]

type=aor

max_contacts=1

修改extensions.conf,增加以下内容:

[sipcall]

exten = _3XXX,1,Answer()

same = n,Dial(PJSIP/${EXTEN})

same = n,Hangup()

[sipsms]

exten = _3XXX,1,NoOp(SMS receiving dialplan invoked)

same = n,NoOp(To ${MESSAGE(to)})

same = n,NoOp(From ${MESSAGE(from)})

same = n,NoOp(Body ${MESSAGE(body)})

same = n,Set(ACTUALTO=${CUT(MESSAGE(to),@,1)})

same = n,MessageSend(${ACTUALTO},${MESSAGE(from)})

same = n,NoOp(Send status is ${MESSAGE_SEND_STATUS})

same = n,Hangup()

分别解释一下新增的两部分配置文件。对pjsip.conf的修改很简单,允许两个新的终端接入,同时为其的呼叫和短信都指定了相应的Dailplan。extensions.conf中则详细的描述了sipcall和sipsms两个Dailplan。其中类似_3XXX的写法是Asterisk特有的类似于正则表达式的匹配语法,用来匹配数字号码。以$开头的则是Dailplan中的参数。Dailplan中的NoOp函数没有任何实际的作用,通常用来辅助Debug。

修改好两个配置文件之后,重新启动Asterisk,使用新的号码登录设备,就可以测试一下电话和短信功能了。


4.变得更专业

到这里,我们已经基本实现了网络电话系统最基础的功能。但是我们会发现一个问题,每当我们需要增加一个新的用户的时候,都需要修改配置文件,然后重启Asterisk。这样的操作不但流程复杂,易于出错,还使得Asterisk需要频繁重启,不能连续的提供服务。这对于一个通信系统来说可是致命的弱点。

好在,作为一个商业级的SIP服务器,Asterisk提供了Realtime功能来解决这一问题。Realtime功能可以将pjsip.conf、extensions.conf中的配置信息存入数据库,并在合适的时机从数据库中查询。使得终端的增减等简单的操作可以不需要重启Asterisk,只需要修改数据库中的数据就可以完场。下面,我们就将当前pjsip.conf中记录的终端信息迁移到数据库中。

Asterisk使用UnixODBC来实现对多种数据库的支持,在这里我们选择MySQL来存储Asterisk所需要的信息。首先我们需要配置UnixODBC。

在最开始,我们已经在系统中安装了UnixODBC和其MySQL支持。然后需要修改其配置文件。

首先是/etc/odbcinst.ini,内容如下:

[MySQL]

Description = ODBC for MySQL

Driver = /usr/lib/x86_64-linux-gnu/odbc/libmyodbc.so

Setup = /usr/lib/x86_64-linux-gnu/odbc/libodbcmyS.so

UsageCount = 2

然后是/etc/odbc.ini,内容如下:

[asterisk]

Driver = MySQL

Description = MySQL for Asterisk

Server = 【服务器地址】

Port = 【服务器端口】

Database = 【数据库名】

UserName = 【用户名】

Password = 【密码】

Socket = /var/run/mysqld/mysqld.sock

接下来是修改Asterisk的配置,首先是res_odbc.conf,增加或修改以下内容:

[asterisk]

enabled => yes

dsn => asterisk

username => 【用户名】

password => 【密码】

pre-connect => yes

然后是modules.conf,增加或修改以下内容:

preload => res_odbc.so

preload => res_config_odbc.so

接下来是extconfig.conf,增加或修改以下内容:

[settings]

ps_endpoints => odbc,asterisk

ps_auths => odbc,asterisk

ps_aors => odbc,asterisk

ps_domain_aliases => odbc,asterisk

ps_endpoint_id_ips => odbc,asterisk

ps_contacts => odbc,asterisk

紧接着是sorcery.conf,增加或修改以下内容:

[res_pjsip] ; Realtime PJSIP configuration wizard

endpoint=realtime,ps_endpoints

auth=realtime,ps_auths

aor=realtime,ps_aors

domain_alias=realtime,ps_domain_aliases

contact=realtime,ps_contacts

[res_pjsip_endpoint_identifier_ip]

identify=realtime,ps_endpoint_id_ips

最后是pjsip.conf,删除除了transport-udp块以外的其他内容。

接下来我们就需要对数据库进行配置了,Asterisk已经给我们提供了数据库中表的的结构模版,放在源代码目录下的contrib\realtime\中,根据不同的数据库类型存放在不同的文件夹中,每个文件夹中又包含了cdr、config和voicemail三个文件,在这里我们只需要导入config文件就可以。

接下来我们就可以向数据库中插入用户的数据,需要操作的有ps_aors、ps_auths、ps_endpoints,一个可以参考的操作如下面6条SQL语句表示。

insert into `ps_aors` (id,max_contacts) values ('3001','1')

insert into `ps_aors` (id,max_contacts) values ('3002','1')

insert into `ps_endpoints` (id,transport,aors,auth,context,disallow,allow,direct_media,rtp_symmetric,message_context) values ('3001', 'transport-udp', '3001', '3001', 'sip', 'all', 'opus,h264', 'no','yes')

insert into `ps_endpoints` (id,transport,aors,auth,context,disallow,allow,direct_media,rtp_symmetric,message_context) values ('3002', 'transport-udp', '3002', '3002', 'sip', 'all', 'opus,h264', 'no','yes')

insert into `ps_auths` (id,auth_type,password,username) values ('3001', 'userpass','pwd3001','3001')

insert into `ps_auths` (id,auth_type,password,username) values ('3002', 'userpass','pwd3002','3002')

完成以上所有的修改以后,我们就可以重启Asterisk。首先,查看一下数据库中的Endpoints是否已经被Asterisk所识别。在Asterisk CLI中使用下面的命令列出当前系统中的所有Endpoints。

pjsip show endpoints

通常情况下,我们应该可以看到数据库中所添加的终端,如下图所示。然后我们就可以使用终端进行登录、测试。

为了体现Realtime配置与文件配置的区别,我们在数据库中增加一个终端,在填写玩所有需要的数据后,无需Reload Asterisk,我们就可以直接使用终端登录Asterisk。

5.还可以怎么玩

以上介绍了Asterisk最基础的几个应用,Asterisk作为一个成功的商业开源通信服务器,其功能多种多样,既可以实现简单的电话软交换,也可以实现如电话会议、语言留言、呼叫中心等多种多样的商用电话功能。甚至有小规模的电信运营商将其作为交换中心的基础。因此,使用其来构建网络电话系统,是十分恰当的选择。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容