1. 基本配置
opensipsctl fifo which opensipsctl fifo lb_list # 查看负载均衡的配置是否生效
Wireshark软件的Telephony菜单里有一个VoIP Call菜单项,可以自动发现sip呼叫,可以整理出呼叫过程中,所有消息的流程图。分析流程图可以找到问题所在,然后去搜索解决方案,就比较容易了。
FreeSwitch的三种媒体处理方式:参考
录音这个顺序很重要,不能把顺序和bridge的弄反了,否则会录音不成功:
vim /usr/local/freeswitch/conf/dialplan/public.xml
<extension name="fs2os"> <condition field="destination_number" expression="^(2(.*))$"> <!--action application="bridge" data="sofia/external/2001@192.168.2.160;fs_path=sip:192.168.2.160:5060"/--> <action application="set" data="RECORD_STEREO=true"/> <action application="record_session" data="/tmp/record.wav"/> <action application="bridge" data="sofia/external/$1@192.168.2.160"/> </condition> </extension>
acl配置,注意是cidr而不是domain:
vim /usr/local/freeswitch/conf/autoload_configs/acl.conf.xml
脚本主要修改的地方:
# 注销掉location的查找,就可以不验证,直接打电话了。查找location会改变du、ru变量。 route[relay] { # for INVITEs enable some additional helper routes if (is_method("INVITE")) {
# 如果 INVITE 是从 FS 传回来的,则将找到的分级 relay if($si=~"192.168.2.57") { xlog("xxxxxxxxxxxxxxxxx [$ru] [$du]\n"); if (lookup("location","m")) { xlog("yyyyyyyyyyyyyyyy [$ru] [$du]\n"); #$ru="sip:2001@192.168.2.160:5060"; } } else {
# 第一次收到的 INVITE 要转给 FS t_on_branch("per_branch_ops"); t_on_reply("handle_reply"); t_on_failure("missed_call"); # relay to FS xlog("Alex6 ...... [$ru] [$si]\n"); rewritehostport("192.168.2.57:5080"); } } if (! t_relay()) { send_reply("500","Internal Error"); } exit; }
虽然依赖DAILOG模块,但是并没有太多的函数调用,只加了validate the sequential request against dialog 这个判断,应该也可以去掉,然后就是直接调用 if (! load_balance("1", "pstn")) 了,在数据库 load_balancer里面有配置。

# # OpenSIPS residential configuration script # by OpenSIPS Solutions <team@opensips-solutions.com> # # This script was generated via "make menuconfig", from # the "Residential" scenario. # You can enable / disable more features / functionalities by # re-generating the scenario with different options.# # # Please refer to the Core CookBook at: # https://opensips.org/Resources/DocsCookbooks # for a explanation of possible statements, functions and parameters. # ####### Global Parameters ######### log_level=3 log_stderror=no log_facility=LOG_LOCAL0 children=4 /* uncomment the following lines to enable debugging */ #debug_mode=yes /* uncomment the next line to enable the auto temporary blacklisting of not available destinations (default disabled) */ #disable_dns_blacklist=no /* uncomment the next line to enable IPv6 lookup after IPv4 dns lookup failures (default disabled) */ #dns_try_ipv6=yes /* comment the next line to enable the auto discovery of local aliases based on reverse DNS on IPs */ auto_aliases=no listen=udp:192.168.2.160:5060 # CUSTOMIZE ME ####### Modules Section ######## #set module path mpath="/usr/local//lib64/opensips/modules/" db_default_url="mysql://opensips:opensipsrw@192.168.2.160:3306/opensips" #loadmodule "proto_udp.so" loadmodule "db_mysql.so" loadmodule "auth.so" loadmodule "auth_db.so" modparam("auth_db", "calculate_ha1", 1) modparam("auth_db", "use_domain", 1) modparam("auth_db", "password_column", "password") #### 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" /* do not append from tag to the RR (no need for this script) */ 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", "db_mode", 1) modparam("usrloc", "nat_bflag", "NAT_BFLAG") modparam("usrloc", "use_domain", 1) modparam("usrloc", "hash_size", 16) #modparam("usrloc", "nat_bflag", "NAT") #modparam("usrloc", "working_mode_preset", "single-instance-no-db") #### REGISTRAR module loadmodule "registrar.so" modparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT") modparam("registrar", "max_contacts", 1) modparam("registrar", "min_expires", 30) modparam("registrar", "max_expires", 300) modparam("registrar", "default_expires", 120) /* uncomment the next line not to allow more than 10 contacts per AOR */ #modparam("registrar", "max_contacts", 10) #### ACCounting module loadmodule "acc.so" /* what special events should be accounted ? */ modparam("acc", "early_media", 0) modparam("acc", "report_cancels", 0) /* by default we do not adjust the direct of the sequential requests. if you enable this parameter, be sure to enable "append_fromtag" in "rr" module */ modparam("acc", "detect_direction", 0) #### DIALOG module loadmodule "dialog.so" modparam("dialog", "dlg_match_mode", 1) modparam("dialog", "default_timeout", 21600) # 6 hours timeout modparam("dialog", "db_mode", 2) modparam("dialog", "db_url", "mysql://opensips:opensipsrw@localhost/opensips") # CUSTOMIZE ME loadmodule "proto_udp.so" ### load balance loadmodule "load_balancer.so" modparam("load_balancer", "db_url", "mysql://opensips:opensipsrw@192.168.2.160:3306/opensips") modparam("load_balancer", "probing_method", "OPTIONS") modparam("load_balancer", "probing_interval", 30) ####### Routing Logic ######## # main request routing logic route { if (! mf_process_maxfwd_header("10")) { send_reply("483","Too Many Hops"); exit; } if (is_method("OPTIONS")) { t_reply("200", "OK"); exit; } $var(pTg) = has_totag(); xlog("method[$rm] has_totag = $var(pTg)"); if ($var(pTg) > 0) { if (loose_route()) { xlog("loose_route ---> as receive message method[$rm]"); # 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 server xlog("receive message method[$rm] from [$ru] then do t_relay"); t_relay(); exit; } else { xlog("receive message method[$rm] no transaction , then exit"); exit; } } sl_send_reply("404","Not here"); } # validate the sequential request against dialog if ( $DLG_status!=NULL && !validate_dialog() ) { xlog("In-Dialog $rm from $si (callid=$ci) is not valid according to dialog\n"); ## exit; } exit; } # CANCEL processing if (is_method("CANCEL")) { if (t_check_trans()) t_relay(); exit; } # absorb retransmissions, but do not create transaction t_check_trans(); if (!is_method("REGISTER|MESSAGE")) { record_route(); } if (is_method("PUBLISH|SUBSCRIBE")) { t_reply("405", "Method Not Allowed "); exit; } if (is_method("REGISTER")) { xlog("Alex1--Do REGISTER AUTH : [$rm] ci[$ci] si[$si] sp[$sp] rd[$rd] rU[$rU] fU[$fU]");` route(AUTH); } if ($rU==NULL) { # request with no Username in RURI send_reply("484","Address Incomplete"); exit; } route(relay); } branch_route[per_branch_ops] { xlog("new branch at Alex2 $ru $rU\n"); } onreply_route[handle_reply] { xlog("incoming reply [$ci] [$si:$sp] [$rs]\n"); } failure_route[missed_call] { if (t_was_cancelled()) { exit; } } route[relay] { # for INVITEs enable some additional helper routes if (is_method("INVITE")) { if ($si=~"192.168.2.57") { xlog("Alex111 [$ru] [$du]\n"); if (lookup("location","m")) { xlog("yyyyyyyyyyyyyyyy [$ru] [$du]\n"); #$ru="sip:2001@192.168.2.160:5060"; } } else if($si=~"192.168.2.176") { xlog("Alex222 [$ru] [$du]\n"); if (lookup("location","m")) { xlog("yyyyyyyyyyyyyyyy [$ru] [$du]\n"); #$ru="sip:2001@192.168.2.160:5060"; } } else { t_on_branch("per_branch_ops"); t_on_reply("handle_reply"); t_on_failure("missed_call"); # relay to FS # rewritehostport("192.168.2.57:5080"); if (! load_balance("1", "pstn")) { xlog("Alex333 [$ru] [$si]\n"); sl_send_reply("500", "Service full."); exit; } } } if (! t_relay()) { send_reply("500","Internal Error"); } exit; } route[AUTH] { # the same as --> www_authorize("", "subscriber"); $var(authRslt) = www_authorize("$td", "subscriber"); xlog("register auth result [$var(authRslt)] rd [$rd] user[$fU] source ip[$si] Alex1: $rp"); switch ($var(authRslt)) { case -1: send_reply("404", "Not Found"); exit; case -2: case -5: send_reply("403", "Forbidden"); exit; case -3: case -4: ###www_challenge("$td","1"); www_challenge("$td","0"); exit; } $var(pA) = is_ip_registered("location", "$tu", "$si"); if ($var(pA) < 0) { xlog("====SIP contact ct:[$ct] [$fu] ci:[$ci] did not registe on, then check registe status for fU:[$fU]."); if (is_registered("location")) { xlog("L_WARN", "====Forbid $ct to registe on, cuase by : exist another $fU has registed"); send_reply("403", "Occupied"); exit; } } if (! save("location", "f")) { sl_reply_error(); } $var(expire) = "0"; if ($hdrcnt(Expires) == 0) { $var(expire) = $ct.fields(expires); xlog("no expire header ,contact expire is [$var(expire)]"); } else { $var(expire) = $hdr(Expires); xlog("expires header , expire [$var(expire)]"); } exit; }
数据库的配置:
mysql> select * from load_balancer; +----+----------+------------------------+-----------+------------+-------------+ | id | group_id | dst_uri | resources | probe_mode | description | +----+----------+------------------------+-----------+------------+-------------+ | 1 | 1 | sip:192.168.2.57:5060 | pstn=500 | 1 | FS1 | | 2 | 1 | sip:192.168.2.176:5060 | pstn=500 | 1 | FS2 | +----+----------+------------------------+-----------+------------+-------------+
配置命令:
INSERT INTO `opensips`.`load_balancer` (`id`, `group_id`, `dst_uri`, `resources`, `probe_mode`, `description`) VALUES ('1', '1', 'sip:192.168.2.57:5060', 'pstn=500', '1', 'FS1'); INSERT INTO `opensips`.`load_balancer` (`id`, `group_id`, `dst_uri`, `resources`, `probe_mode`, `description`) VALUES ('2', '1', 'sip:192.168.2.176:5060', 'pstn=500', '1', 'FS2'); UPDATE `load_balancer` SET description='FS2' WHERE id=2; opensipsctl dispatcher addgw 1 sip:192.168.2.57 5060 0 50 'FS1' '节点1' opensipsctl dispatcher addgw 1 sip:192.168.2.176 5060 0 50 'FS2' '节点2' opensipsctl dispatcher show # 查看负载均衡配置
opensipsctl fifo lb_status 2 1 # 将目的地2配置为可用的状态
sofia profile internal siptrace on # 在fs中执行,查看信令流 注意是 insert into 不是 info
2. 语音流和信令
补充小任务:配置FS,使其支持无限回放,即一条腿的情况。