最近公司有一个项目,需要实现一套网络电话系统,主要的需求如下:支持SIP软/硬终端,支持webrtc终端,对接运营商IMS服务,媒体服务器双机负载均衡。根据多年的工作经验,很轻松的就考虑采用Opensips+Rtpengine+Freeswitch的架构来实现,其实如果项目无需支持webrtc的话,Rtpengine也是可以省去的。闲言少续,上结构图:

对于Freeswitch的配置不作为本文的重点,本文重点介绍的是Opensips+Rtpengine的相关安装和配置。为了简化部署,这次将Opensips和Rtpengine安装在同一台服务器上,操作系统为Centos7.6。

  • 源码安装配置opensips

1.从官网下载opensips,版本为2.4.11。

2.解压后执行make menuconfig(注意提前安装好mysql数据库)

在编译的过程中如果提示错误,根据错误信息去安装相应的依赖包就行。

3.配置数据库并建表

编辑 vim usr/local/etc/opensips/opensipsctlrc

执行脚本如下:

[root@os opensips]# cd /usr/local/sbin/
[root@os sbin]# ls
opensips  opensipsctl  opensipsdbctl  opensipsunix  osipsconfig  osipsconsole
[root@os sbin]#  ./opensipsdbctl  create

如果提示成功的话,安装就大功告成了!

  • 源码安装rtpengine
#!/bin/bash
# Install the packages required to compile RTP engine
set -e
yum install iptables-devel kernel-devel kernel-headers xmlrpc-c-devel
yum install "kernel-devel-uname-r == $(uname -r)"
yum install glib glib-devel gcc zlib zlib-devel openssl openssl-devel pcre pcre-devel libcurl libcurl-devel xmlrpc-c xmlrpc-c-devel
yum install libevent-devel glib2-devel json-glib-devel gperf libpcap-devel git hiredis hiredis-devel redis perl-IPC-Cmd
# MariaDB ver 10+
yum install MariaDB-devel MariaDB-client MariaDB-shared
# Spandsp
yum install spandsp-devel spandsp
# epel
yum install epel-release
# libwebsockets
yum install libwebsockets libwebsockets-devel
# ffmpeg
rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
rpm -Fvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-1.el7.nux.noarch.rpm
# check for Nux desktop repo by yum repolist
yum -y install ffmpeg ffmpeg-devel# Get The Latest Release Of RTPEngine Source From RTPEngine’s GitHub Repository
cd /usr/local/src
if [ -d rtpengine ]; thencd rtpenginemake cleangit pull
elsegit clone https://github.com/sipwise/rtpengine.git
fi# Compile and install the daemon
cd /usr/local/src/rtpengine/daemon/
make
cp rtpengine /usr/sbin/rtpengine# Compile and install iptables extension
cd /usr/local/src/rtpengine/iptables-extension
make all
cp libxt_RTPENGINE.so /usr/lib64/xtables/.# Compile and install the kernel module xt_RTPENGINE
cd /usr/local/src/rtpengine/kernel-module
make# determine kernel release
uname -a
kernel_ver=`uname -r`
cp xt_RTPENGINE.ko /lib/modules/${kernel_ver}/extra/xt_RTPENGINE.ko
depmod -a# load module at boot time
# Add the following lines to /etc/modules-load.d/rtpengine.conf (add the following lines)
CONF_FILE=/etc/modules-load.d/rtpengine.conf
echo '# load xt_RTPENGINE module' > ${CONF_FILE}
echo 'xt_RTPENGINE' >> ${CONF_FILE}# load the module and check
modprobe xt_RTPENGINE
lsmod | grep xt_RTPENGINE# check files
ls -l /proc/rtpengine/control
ls -l /proc/rtpengine/listTableID=0
# add forwarding table with an ID=$TableID. $TableID is a number between 0-63
echo 'add 0' > /proc/rtpengine/control# Adding iptables rules to forward the incoming packets to xt_RTPENGINE module
iptables -I INPUT -p udp -j RTPENGINE --id $TableID
ip6tables -I INPUT -p udp -j RTPENGINE --id $TableID

特别注意点:

系统的openssl的版本必须为1.1.1以上,否则DTLS协商会出错。

spandsp必须使用freeswitch源安装,否则编译会出错。

当以上两个软件都安装完成后,就可以通过配置opensips.cfg的脚本来实现功能了,为了避免商业纠纷,以下以简化的opensips配置来举例说明:

#
# OpenSIPS residential configuration script
#     by OpenSIPS Solutions <team@opensips-solutions.com>
#
# Please refer to the Core CookBook at:
#      http://www.opensips.org/Resources/DocsCookbooks
# for a explanation of possible statements, functions and parameters.
######## Global Parameters #########debug=3
log_stderror=no
log_facility=LOG_LOCAL0fork=yes
children=4
auto_aliases=nolisten=udp:127.0.0.0:5060 # TODO: update with your local IP and port
listen=ws:127.0.0.0:8080 # TODO: update with your local IP and port####### Modules Section ######### set module path
mpath="/usr/local/lib/opensips/modules/"#### SIGNALING module
loadmodule "signaling.so"#### StateLess module
loadmodule "sl.so"#### Transaction Module
loadmodule "tm.so"
modparam("tm", "fr_timeout", 5)
modparam("tm", "fr_inv_timeout", 30)
modparam("tm", "restart_fr_on_each_reply", 0)
modparam("tm", "onreply_avp_mode", 1)#### Record Route Module
loadmodule "rr.so"
modparam("rr", "append_fromtag", 0)#### MAX ForWarD module
loadmodule "maxfwd.so"#### SIP MSG OPerationS module
loadmodule "sipmsgops.so"#### FIFO Management Interface
loadmodule "mi_fifo.so"
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")
modparam("mi_fifo", "fifo_mode", 0666)#### URI module
loadmodule "uri.so"
modparam("uri", "use_uri_table", 0)#### USeR LOCation module
loadmodule "usrloc.so"
modparam("usrloc", "nat_bflag", "NAT")
modparam("usrloc", "db_mode",   0)#### REGISTRAR module
loadmodule "registrar.so"#### RTPengine protocol
loadmodule "rtpengine.so"
modparam("rtpengine", "rtpengine_sock", "udp:127.0.0.0:60000")#### Nathelper protocol
loadmodule "nathelper.so"
modparam("registrar|nathelper", "received_avp", "$avp(rcv)")#### UDP protocol
loadmodule "proto_udp.so"#### WebSocket protocol
loadmodule "proto_ws.so"####### Routing Logic ######### main request routing logic
route{if (!mf_process_maxfwd_header("10")) {sl_send_reply("483","Too Many Hops");exit;}if (has_totag()) {# sequential requests within a dialog should# take the path determined by record-routingif (loose_route()) {if (is_method("INVITE")) {# even if in most of the cases is useless, do RR for# re-INVITEs alos, as some buggy clients do change route set# during the dialog.record_route();}# route it out to whatever destination was set by loose_route()# in $du (destination URI).route(relay);} else {if ( is_method("ACK") ) {if ( t_check_trans() ) {# non loose-route, but stateful ACK; must be an ACK after# a 487 or e.g. 404 from upstream servert_relay();exit;} else {# ACK without matching transaction -># ignore and discardexit;}}sl_send_reply("404","Not here");}exit;}# CANCEL processingif (is_method("CANCEL")) {if (t_check_trans())t_relay();exit;}t_check_trans();if (!is_method("REGISTER")) {if (from_uri!=myself) {# if caller is not local, then called number must be localif (!uri==myself) {send_reply("403","Rely forbidden");exit;}}}# preloaded route checkingif (loose_route()) {xlog("L_ERR","Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]");if (!is_method("ACK"))sl_send_reply("403","Preload Route denied");exit;}# record routingif (!is_method("REGISTER|MESSAGE"))record_route();if (!uri==myself) {append_hf("P-hint: outbound\r\n");route(relay);}# requests for my domainif (is_method("PUBLISH|SUBSCRIBE")) {sl_send_reply("503", "Service Unavailable");exit;}# check if the clients are using WebSocketsif (proto == WS)setflag(SRC_WS);# consider the client is behind NAT - always fix the contactfix_nated_contact();if (is_method("REGISTER")) {# indicate that the client supports DTLS# so we know when he is calledif (isflagset(SRC_WS))setbflag(DST_WS);fix_nated_register();if (!save("location"))sl_reply_error();exit;}if ($rU==NULL) {# request with no Username in RURIsl_send_reply("484","Address Incomplete");exit;}# do lookup with method filteringif (!lookup("location","m")) {t_newtran();t_reply("404", "Not Found");exit;}route(relay);
}route[relay] {# for INVITEs enable some additional helper routesif (is_method("INVITE")) {t_on_branch("handle_nat");t_on_reply("handle_nat");} else if (is_method("BYE|CANCEL")) {rtpengine_delete();}if (!t_relay()) {send_reply("500","Internal Error");};exit;
}branch_route[handle_nat] {if (!is_method("INVITE") || !has_body("application/sdp"))return;if (isflagset(SRC_WS) && isbflagset(DST_WS))$var(rtpengine_flags) = "ICE=force-relay DTLS=passive";else if (isflagset(SRC_WS) && !isbflagset(DST_WS))$var(rtpengine_flags) = "RTP/AVP replace-session-connection replace-origin ICE=remove";else if (!isflagset(SRC_WS) && isbflagset(DST_WS))$var(rtpengine_flags) = "UDP/TLS/RTP/SAVPF ICE=force";else if (!isflagset(SRC_WS) && !isbflagset(DST_WS))$var(rtpengine_flags) = "RTP/AVP replace-session-connection replace-origin ICE=remove";rtpengine_offer("$var(rtpengine_flags)");
}onreply_route[handle_nat] {fix_nated_contact();if (!has_body("application/sdp"))return;if (isflagset(SRC_WS) && isbflagset(DST_WS))$var(rtpengine_flags) = "ICE=force-relay DTLS=passive";else if (isflagset(SRC_WS) && !isbflagset(DST_WS))$var(rtpengine_flags) = "UDP/TLS/RTP/SAVPF ICE=force";else if (!isflagset(SRC_WS) && isbflagset(DST_WS))$var(rtpengine_flags) = "RTP/AVP replace-session-connection replace-origin ICE=remove";else if (!isflagset(SRC_WS) && !isbflagset(DST_WS))$var(rtpengine_flags) = "RTP/AVP replace-session-connection replace-origin ICE=remove";rtpengine_answer("$var(rtpengine_flags)");
}

大家在测试的过程中一定要通过抓包和查看日志来分析判断问题,并且建议一定要对SIP协议(以RFC3261为主)有比较好的理解。最后,大家如有什么问题和建议,也可以给我留言沟通。

基于Opensips+Rtpengine+Freeswitch实现的网络电话系统相关推荐

  1. 从0到1打造自己的VOIP网络电话系统(基于FreePBX)

    从0到1打造自己的网络电话系统 最近流量卡越来越便宜了,看看自己手里的"坑不死老用户"的联通卡,顿时感觉到深深的恶意,但是iPhone没有双卡功能,所以只好自己动手打造一个网络电话 ...

  2. php如何开发网络电话,利用开源软件30分钟搭建自己的voip网络电话系统V1.1

    Author:高进波 Time:2010-05-08 利用开源软件30分钟搭建自己的voip网络电话系统V1.1 大家可以根据以下文档在30分钟内就能搭建一个功能强大的voip网络电话系统,在此基础上 ...

  3. 利用开源软件30分钟搭建自己的voip网络电话系统V1.1

    利用开源软件30分钟搭建自己的voip网络电话系统V1.1 Posted on 2010 年 5 月 8 日by 高进波 Author:高进波   Time:2010-05-08     利用开源软件 ...

  4. 使用Opensips和FreeSwitch搭建万级别的高可用软交换架构

    最近因为项目的原因,需要提供一个支持万级别以上,支持多应用的软交换服务端架构,对以前的架构做了一个调整,写一篇文章总结下. 新的架构主要解决了一下几个问题: 单套要支持1w左右并发的呼叫 完全的高可用 ...

  5. CVPR2020:基于层次折叠的跳跃式注意网络点云完成

    CVPR2020:基于层次折叠的跳跃式注意网络点云完成 Point Cloud Completion by Skip-Attention Network With Hierarchical Foldi ...

  6. PluckerNet:一种基于3D线匹配的配准网络(CVPR2021)

    标题:PluckerNet: Learn to Register 3D Line Reconstructions 作者:Liu Liu, Hongdong Li , Haodong Yao and R ...

  7. 基于注意力机制的图卷积网络预测药物-疾病关联

    BIB | 基于注意力机制的图卷积网络预测药物-疾病关联 智能生信 人工智能×生物医药 ​关注 科学求真 赢 10 万奖金 · 院士面对面 9 人赞同了该文章 今天给大家介绍华中农业大学章文教授团队在 ...

  8. CVPR 2022 | GeoTransformer:基于Transformer的点云配准网络

    ©作者 | 秦政 单位 | 国防科技大学 研究方向 | 三维视觉 本文提出了一种基于 Transformer 的点云配准网络.通过引入点云中的全局结构信息,GeoTransformer 能够显著提高 ...

  9. 行政编码json_基于FME国内县级及以上网络公开行政区划边界的获取

    基于FME国内县级及以上网络公开行政区划边界的获取 在上一篇记录<基于FME零编码获取新冠病毒(COVID-2019)患者曾逗留小区(场所)数据及可视化>中,给自己挖了个坑,这篇记录就是为 ...

最新文章

  1. 功能受限_比亚迪秦80变速器功能受限故障检修
  2. 实现一个不能被继承的类
  3. 何洁音乐会今晚开唱 大手笔打造pure show
  4. 定义咯一个枚举变量枚举变量怎么打印出来 linux c,以C语言的字符串形式输出枚举变量...
  5. mysql qps如何查看_一款查看mysql QPS的脚本
  6. 编程体系结构(06):Java面向对象
  7. 生产者消费者模型 java
  8. java代码颜色_JAVA颜色代码
  9. 查看抽取解压缩和修改war包
  10. 使用电脑小技巧70个
  11. 图灵专访:郭霖的成长之路
  12. 愿所有我和码农们 printf(“前程似锦”)
  13. 2020-02-23
  14. 台式计算机没有声音怎么办,台式电脑没有声音了怎么恢复(在家用这两个方法轻松解决)...
  15. 抖音seo源码二次开发,短视频seo源码二次开发
  16. 实战篇ConstraintLayout的崛起之路
  17. 期货贴水如何交割(期货交割升贴水)
  18. 虹软Linux离线激活,虹软linux错误
  19. 如何恢复微信删除的聊天记录
  20. android 更改字体_如何在Android中更改字体

热门文章

  1. WMS系统(一)成品入库需求分析
  2. 不想重置路由器,如何由已连接设备快速获取wifi密码?
  3. Android判断当前系统时间是否在指定时间的范围内(免消息打扰)
  4. 计算机无法连接蓝牙键盘,蓝牙鼠标连接不上电脑怎么办?
  5. 内网渗透笔记——三层发现and四层发现
  6. 美股分时交易数据 API 接口
  7. IT行业最全的服务器硬件基础知识大全,值得收藏!
  8. 华为机试题python版节选(基础编程题)
  9. 项目管理之团队与团队精神
  10. python爬虫企业工商信息_Python 爬虫进阶必备 | 企业信用公示系统公告加密解析...