最近在调研SIP代理、SIP集群和媒体集群的能力,了解到OV500这个项目,对理解Freeswitch的能力,Kamailio作为信令代理的配置等实现的学习还是很有帮助的,这个GITHUB项目地址:OV500 , 架构模型如图:
OV500环境搭建如果是有外网的情况下,还是很快的,另外借助docker的方式,可以通过起3个容器快速完成上面的架构部署;
环境部署过程中,其实容易出现的问题就是遗漏了安装过程中提到的某步或者某几步,导致出现问题,所以需要很细心的配置,另外,出现问题了也能快速定位解决,出现了几个很低级的问题:
1、nginx代理php的管理用户和文件权限问题,需要将php程序包拷贝到/var/www路径下,不能使用/home,/usr等路径;
2、iptable没关,导致网络不通;
另外,OV500提供了强大的计费管理,话单管理,对理解完整的业务链条很有帮助,建议做VOIP业务后台的同学可以细致的分析这块的完整业务;
服务部署完后,需要通过OV500的管理后台(后台管理账户可以通过查表找到,admin/123456,文档中没有说明,所以需要全面的了解,然后就不会在某块被阻塞住)添加用户,这块如果英文不好还是很难加全的,因为需要添加计费,费率,企业和企业的用户,另外,要把一些包括codec检查的开关关掉,不然呼叫可能就不通,呼叫不通这快需要看Freeswitch的日志和kamailio的日志;
单个kamailio代理多个freeswitch时,freeswitch由于收不到ACK,导致30s自动挂断问题解决,主要通过升级kamailio 到5.3.3版本解决,原来的版本号是:4.4.6,调通一对一的语音通话和会议模式通话;
多个kamailio集群时,能进行语音通话,主要在freeswitch收到sip代理转发的呼叫后,通过location定位被叫用户在sip代理的位置,进行转接呼叫,调通呼叫;
修改OV500-master/portal/api/lib/OVS.php程序:
function main($REQUEST) {
$this->Hunt_Network_Addr = $this->request['Hunt-Network-Addr'];//在这行后面,主要修改这个地址为目标sip所在的kamailio服务器ip
$this->Hunt_Network_PORT = 5063;
//update the target hunt network
$query = sprintf("select domain, contact, username, callid, socket from location where username = '%s';", $this->destination_number);
$this->writelog($query);
$this->query('KAMAILIO', $query);
$rs = $this->resultset();
if (count($rs) >= 1) {
$result = $rs[0];
$socket_target = $result['socket'];//udp:11.12.117.200:5061
//$index = strpos($socket_target, ':') ;
$arr = explode(':', $socket_target);
if (count($arr) == 3){
$this->Hunt_Network_Addr = $arr[1];//substr($socket_target, $index + 1);
$this->Hunt_Network_PORT = $arr[2];
$this->writelog("lyz get target, $this->Hunt_Network_Addr:".$this->Hunt_Network_PORT);
}
}else{
$this->writelog("lyz get target, retun null");
}
//ADD END.
}
代码中所有涉及bridge的地方进行替换修改:
$this->Gateway_XML_incoming .= "\n <action application=\"bridge\" data=\"sofia/internal/" . $this->incomingcarrierdst . "@" . $lb . ":".$this->Hunt_Network_PORT. "\"/>";
会议模式的实现,会议号统一使用conf开头的前缀,在拨号计划生成的入口处,修改拨号计划的返回即可;
关键是下面两行:
$this->Gateway_XML .= "\n<action application=\"answer\"/>";
Undefined control sequence \n
修改OV500-master/portal/api/lib/OVS.php程序:
function main($REQUEST) {
//判断是否是会议模式,如果是,则直接返回报文就可以,会议模式以conf开头
$index = strpos($this->destination_number, "conf_");
if (false !== $index){
$this->writelog("lyz add enter conference");
$this->destination_number = substr($this->destination_number, $index + 5);
$responce = $this->conferencecallxml();
return $responce;
}
//add end
}
function conferencecallxml() {
$lb = $this->request['FreeSWITCH-IPv4'];//$this->Hunt_Network_Addr;
$this->Gateway_XML .= "\n <action application=\"set\" data=\"sip_h_X-MEDIATRA=1\"/>";
$this->Gateway_XML .= "\n <action application=\"export\" data=\"sip_h_X-MEDIATRA=1\"/>";
$this->Gateway_XML .= "\n<action application=\"set\" data=\"bypass_media=false\"/>";
$this->Gateway_XML .= "\n<action application=\"set\" data=\"proxy-media=true\"/>";
$route_callid = $this->uuid;
$this->Gateway_XML .= "\n<action application=\"export\" data=\"effective_caller_id_number=" . $route_callid . "\"/>";
$this->Gateway_XML .= "\n<action application=\"export\" data=\"effective_caller_id_name=" . $route_callid . "\"/>";
$this->Gateway_XML .= "\n<action application=\"set\" data=\"effective_caller_id_number=" . $route_callid . "\"/>";
$this->Gateway_XML .= "\n<action application=\"set\" data=\"effective_caller_id_name=" . $route_callid . "\"/>";
$this->Gateway_XML .= "\n <action application=\"set\" data=\"sip_h_X-FROMURI=" . $route_callid . "\"/>";
$this->Gateway_XML .= "\n<action application=\"set\" data=\"call_timeout=30\"/>";
$this->Gateway_XML .= "\n<action application=\"set\" data=\"continue_on_fail=FALSE\"/>";
$this->Gateway_XML .= "\n<action application=\"set\" data=\"hangup_after_bridge=true\"/>";
$this->Gateway_XML .= "\n<action application=\"set\" data=\"media_mix_inbound_outbound_codecs=true\"/>";
$this->Gateway_XML .= "\n<action application=\"answer\"/>";
$this->Gateway_XML .= "\n<action application=\"conference\" data=\"".$this->destination_number."-" . $lb ."@default\"/>";
$responce .= "<?xml version = \"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>
<document type=\"OvSwitch/xml\">";
$responce .= "<section name=\"dialplan\" description=\"RE Dial Plan For OvSwitch\">";
$responce .= "\n<context name=\"default\">";
$responce .= "\n<extension name=\"outbound_international\">
<condition field=\"destination_number\" expression=\"^(.+)$\">";
$responce .= "\n<action application=\"set\" data=\"SWITCH_ISSUE=0\"/>";
$responce .= "\n<action application=\"export\" data=\"SWITCH_ISSUE=0\"/>";
$responce .= "\n<action application=\"set\" data=\"hangup_after_bridge=TRUE\"/>";
$responce .= "\n<action application=\"pre_answer\"/>";
$responce .= "\n<action application=\"set\" data=\"common_uuid=" . $this->uuid . "\"/>";
$responce .= "\n<action application=\"export\" data=\"common_uuid=" . $this->uuid . "\"/>";
$responce .= "\n<action application=\"set\" data=\"caller_callid=" . $this->caller_callid . "\"/>";
$responce .= "\n<action application=\"export\" data=\"caller_callid=" . $this->caller_callid . "\"/>";
$responce .= $this->Gateway_XML;
$responce .= "\n
</condition>
</extension>
</context>
</section>
</document>";
RETURN $responce;
}
通话建立不了可能和codec不匹配有关系,所以对freeswitch输出的日志需要有分析能力。
最后,验证一种场景,kamailio+rtpproxy, 通过rtpproxy隐藏freeswitch核心交换媒体流的ip,也就是freeswitch只在中心骨干网内部流转,验证确实是可行的,但kamailio+rtpproxy对ICE的报文修改存在问题,只支持sdp中m字段的端口修改,需要扩展对ICE地址修改的支持;这种组网情况下,kamailio在边沿节点作为SIP的接入注册和位置服务器,mysql在中心网内作为分布式数据库存在,所有kamailio的节点都指向同一个mysql的数据库,媒体代理在后端提供媒体交换的能力,示意框图如下图;
知识点:
SIP代理的作用是提供SIP信令的入口、授权、访问控制,位置存储、媒体路由和媒体的负载功能;
SIP代理的主要开源产品有:opensips、kamailio、opensers,单台sip代理服务器能注册1W的用户;
媒体服务器主要提供媒体协商、转码和RTP数据交换功能;
媒体服务器的主要开源产品有Asterisk、Freeswitch,都是擅长做媒体软交换;
Freeswitch性能测试数据,使用sipp来测试,CSDN上有篇文章值得看:Linux-sipp3.6测试Freeswitch
[root@localhost test]# sipp -sf caller_with_auth.xml 11.12.117.200:5060 -i 11.12.115.239 -p 26045 -inf data.csv -r 150 -rp 1000 -l 1000 -m 1000 -d 60000 -oocsn ooc_default -trace_err
-------------------------+---------------------------+--------------------------
Successful call | 0 | 608
Failed call | 0 | 592
-------------------------+---------------------------+--------------------------
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
19865 root 10 -10 5018876 2.6g 5264 S 387.7 33.9 53:23.79 freeswitch
[root@localhost test]# sipp -sf caller_with_auth.xml 11.12.117.200:5060 -i 11.12.115.239 -p 26045 -inf data.csv -r 150 -rp 500 -l 500 -m 500 -d 60000 -oocsn ooc_default -trace_err
-------------------------+---------------------------+--------------------------
Successful call | 0 | 234
Failed call | 0 | 266
-------------------------+---------------------------+--------------------------
[root@localhost test]# sipp -sf caller_with_auth.xml 11.12.117.200:5060 -i 11.12.115.239 -p 26045 -inf data.csv -r 100 -rp 1000 -l 300 -m 300 -d 60000 -oocsn ooc_default -trace_err
-------------------------+---------------------------+--------------------------
Successful call | 0 | 282
Failed call | 0 | 18
-------------------------+---------------------------+--------------------------
-------------------------+---------------------------+--------------------------
Successful call | 0 | 290
Failed call | 0 | 10
-------------------------+---------------------------+--------------------------
[root@localhost test]# sipp -sf caller_with_auth.xml 11.12.117.200:5060 -i 11.12.115.239 -p 26045 -inf data.csv -r 50 -rp 1000 -l 200 -m 200 -d 60000 -oocsn ooc_default -trace_err
-------------------------+---------------------------+--------------------------
Successful call | 0 | 193
Failed call | 0 | 7
-------------------------+---------------------------+--------------------------
测试呼叫,呼叫保持30s,发送30s的rtp数据,单台Freeswitch 能支持每秒100路左右通话,每分钟连接的通话数在200路,连续发送200路通话,Freeswitch的CPU到300%,但内存不高;
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有