1. 方案设计
FreeSWITCH 通过 unimrcp 模块来对接 MRCP 服务器,该模块在启动时会根据 mrcp profile 配置文件创建 MRCP 客户端。在使用 MRCP 功能时,FreeSWITCH 通过 mrcp profile 的名称来指定要使用的 MRCP 客户端,进而决定要连接的 MRCP 服务器。在 MRCPv2 服务器的负载分发方案分析 中笔者分析到只要做好 SIP 信令的负载均衡就可以实现 MRCP 的负载均衡,基于此,一个可行的方案如下:
- FreeSWITCH 配置 mrcp 的 profile 指向 OpenSIPS 服务器,profile 中配置 ua 名称,作为 mrcp 请求的识别标志
- OpenSIPS 的脚本中判断 INVITE 请求中的 ua 名称,如果是 mrcp 请求,则做对应处理
- 在 OpenSIPS 数据库中插入对应的 mrcp 服务器地址记录,处理时调用 dispatcher 模块的 ds_select_dst 函数选中 mrcp 服务器,该函数会填充 $du 后将请求转发到 $du 指向的地址
2. 实现方式
2.1 FreeSWITCH 的配置
在 FreeSWITCH 的 conf/mrcp_profiles 目录 下新增一个配置文件,将其指向 OpenSIPS 服务器并指定 UA 名称,然后重启 FreeSWITCH
<include>
<!-- UniMRCP Server MRCPv2 -->
<profile name="opensips-tts-mrcp2" version="2">
<!-- OpenSIPS 服务器地址 端口号-->
<param name="server-ip" value="127.0.0.1"/>
<param name="server-port" value="8060"/>
<!-- FreeSWITCH IP、端口以及 SIP 传输方式 -->
<param name="client-ip" value="$${local_ip_v4}" />
<param name="client-port" value="5072"/>
<param name="sip-transport" value="udp"/>
<param name="speechsynth" value="speechsynthesizer"/>
<param name="speechrecog" value="speechrecognizer"/>
<!-- SIP 请求携带的 ua 名称 -->
<param name="ua-name" value="OPENSIPS_TTS_MRCP_CLIENT"/>
<!-- Add any default MRCP params for SPEAK requests here -->
<synthparams>
</synthparams>
<!-- Add any default MRCP params for RECOGNIZE requests here -->
<recogparams>
<!--param name="start-input-timers" value="false"/-->
</recogparams>
</profile>
</include>
2.2 OpenSIPS 3.1 的配置
- 注意,笔者在此强调了 OpenSIPS 版本为 3.1,这是因为 OpenSIPS 不同版本 api 有变化,如果版本不匹配本文中给出的脚本代码很可能发生异常
- 实践前读者必须保证 OpenSIPS 已经编译加载了 dispatcher 模块。如果 OpenSIPS 启动过程中报出模块找不到的异常,可以自行编译源码模块,然后将源码根目录下
modules目录
中对应模块目录下的 so 动态库复制到异常提示的目录中即可
2.2.1 OpenSIPS 保存 MRCP 服务器地址
执行以下 SQL 语句,往 OpenSIPS 数据库的 dispatcher 表中插入目标 MRCP 服务器地址记录。这个表中 setid
是组概念的标识,脚本中调用 ds_select_dst 函数时需要指定该参数。如果在脚本中配置了 dispatcher 模块的数据库地址,则 OpenSIPS 启动时会从数据库中查询数据加载到内存,读者如有兴趣可参考 dispatcher 官方文档
dispatcher 表可以用 opensips-cli 工具 创建,由于权限问题无法创建时也可以在 OpenSIPS 源码根目录下的
scripts目录
中选择对应的数据库类型目录,查找该目录下相应的表创建文件,例如 scripts/mysql/dispatcher-create.sql,复制其内容到数据库中执行即可
INSERT INTO `dispatcher` (`setid`, `destination`, `state`, `weight`, `priority`, `attrs`, `description`) VALUES
(19, 'sip:10.129.39.88:7010', 0, 1, 100, 'pstn=100', 'TTS_MRCP_CLIENT_FS_7010'),
(19, 'sip:10.129.39.88:7011', 0, 1, 100, 'pstn=100', 'TTS_MRCP_CLIENT_FS_7011');
2.2.2 OpenSIPS 脚本开发
脚本最主要的分发代码如下,上文已经提到了具体处理,此处不再赘述,但仍然需要注意以下几点:文章来源:https://www.toymoban.com/news/detail-455309.html
- 对于 FreeSWITCH 发起的 MRCP INVITE 请求,$rU 肯定为 null,如果脚本中有对这个变量的空判断,需要做相应规避。如读者对 OpenSIPS 的各个核心变量不了解,可前往 官方传送门
- OpenSIPS 启动时会对脚本进行语法检查,读者可以先用前台模式启动 OpenSIPS 然后观察启动日志,如有报错信息一一解决即可
route {
# 省略无关代码 ...
if (is_method("INVITE")) {
xlog("ua = $ua , callid = $ci, fu = $fu , tu = $tu , ru = $ru , du =$du src:$si, $(rb{sdp.line,m})");
$var(dlgPingTag) = "Pp";
if ( $ua == "OPENSIPS_TTS_MRCP_CLIENT" ) {
$var(dlgPingTag) = ""; # TTS 的SIP通道不能做 OPTION 探测
}
if ( !create_dialog("$var(dlgPingTag)")) {
send_reply(500,"Internal Server Error");
exit;
}
if ( $ua == "OPENSIPS_TTS_MRCP_CLIENT" ) {
# 指定 setid 为 19,与插入 dispatcher 表的数据相匹配,选择可用的节点
$var(lbRst) = ds_select_dst(19, 4);
if($var(lbRst) == -1) {
xlog("Failed by dispatcher group_id: 19");
t_reply(480, "MRCP server Unavailable");
exit();
}
if ( $var(lbRst) > 0) {
$ru = "sip:" + $(du{uri.host}) + ":" + $dp;
xlog("[$fU->$rU] Route to $ru");
} else {
xlog("[$fU->$rU] No available server now");
t_reply(480, "$var(node_type) Unavailable");
exit();
}
} else {
# 其他类型 INVITE 处理 .....
}
}
route(relay);
}
route[relay] {
# for INVITEs enable some additional helper routes
if (isflagset("NAT")) {
add_rr_param(";nat=yes");
}
if (!t_relay()) {
send_reply(500,"Internal Error");
}
exit;
}
2.3 实现效果
文章来源地址https://www.toymoban.com/news/detail-455309.html
到了这里,关于OpenSIPS 3.1 负载均衡 MRCP 服务器的实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!