引言
mod_callcenter呼叫中心队列模块,能够提供丰富的坐席管理和呼叫功能。以上功能都可以通过配置callcenter.conf.xml来完成,我们可以选择静态配置也可以通过mod_xml_curl模块动态加载callcenter.conf.xml来实现,本章讲解动态加载配置文件
本人已经使用freeswitch开发出整体的核心产品,提供功能接口,通过接口即可实现呼叫中心业务功能,无需关心freeswitch开发。功能包括IVR动态导航、坐席动态添加、动态拨号计划、坐席登入、登出、置忙、空闲、通话、呼叫转移、呼叫保持、墙插、强拆、通话记录上传、弹屏上传等功能,只需要调用http接口即可实现呼叫中心业务,有意合作可邮箱联系mokeily99@126.com
原理
通过mod_xml_curl模块配置远端服务地址,远端服务返回对应的callcenter.conf.xml文件内容
步骤
1、开启mod_callcenter功能
1.1加载mod_callcenter模块
mod_callcenter模块并不是默认编译安装的,需要将modules.xml中的mod_callcenter选项打开
然后源码目录执行
make mod_callcenter-install
在autoload_configs/modules.conf.xml中去掉<load module="mod_callcenter"/>的注释,重启freeswitch(或者load mod_callcenter)
1.2呼叫中心队列文件callcenter.conf.xml
autoload_configs/callcenter.conf.xml即为队列文件,如下:
<configuration name="callcenter.conf" description="CallCenter">
<settings>
<param name="odbc-dsn" value="MYSQLTP:root:xxxxxx"/>
<!--<param name="dbname" value="/dev/shm/callcenter.db"/>-->
</settings>
<queues>
<queue name="support@default">
<param name="strategy" value="random"/>
<param name="moh-sound" value="/usr/local/freeswitch/scripts/sound/waiting.wav"/>
<param name="record-template" value="/root/web-app/record/apache-tomcat-8.5.76/webapps/record/${strftime(%Y-%m-%d-%H-%M-%S)}_${caller_id_number}_${destination_number}.wav"/>
<param name="time-base-score" value="system"/>
<param name="max-wait-time" value="40"/><!--最大等待时间(超过时间未被接通将退出callcenter)0为禁用-->
<param name="max-wait-time-with-no-agent" value="2"/><!--无成员(没有成员的状态是available)等待超时时间: 超出时间电话会退出callcenter 0为禁用-->
<param name="max-wait-time-with-no-agent-time-reached" value="1"/><!--如果有电话有因为(max-wait-time-with-no-agent)的原因退出队列, 队列将在延迟一定时间不允许新的电话呼入到队列-->
<param name="tier-rules-apply" value="false"/>
<param name="tier-rule-wait-second" value="300"/>
<param name="tier-rule-wait-multiply-level" value="true"/>
<param name="tier-rule-no-agent-no-wait" value="true"/>
<!--<param name="discard-abandoned-after" value="10"/>-->
<!--<param name="abandoned-resume-allowed" value="true"/>-->
</queue>
</queues>
<!-- WARNING: Configuration of XML Agents will be updated into the DB upon restart. -->
<!-- WARNING: Configuration of XML Tiers will reset the level and position if those were supplied. -->
<!-- WARNING: Agents and Tiers XML config shouldn't be used in a multi FS shared DB setup (Not currently supported anyway) -->
<agents>
<!--<agent name="1000@default" type="callback" contact="[call_timeout=10]user/1000@default" status="Available" max-no-answer="3" wrap-up-time="10" reject-delay-time="10" busy-delay-time="60" />-->
<agent name="1001@default" type="callback" contact="[call_timeout=10]user/1001" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="5" busy-delay-time="2" />
<agent name="1002@default" type="callback" contact="[call_timeout=10]user/1002" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="5" busy-delay-time="2" />
<agent name="1004@default" type="callback" contact="[call_timeout=10]user/1004" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="5" busy-delay-time="2" />
</agents>
<tiers>
<!-- If no level or position is provided, they will default to 1. You should do this to keep db value on restart. -->
<!-- <tier agent="1000@default" queue="support@default" level="1" position="1"/> -->
<tier agent="1001@default" queue="support@default" state="Ready" level="1" position="1"/>
<tier agent="1002@default" queue="support@default" state="Ready" level="1" position="1"/>
<!--<tier agent="1004@default" queue="support@default" state="Ready" level="1" position="1"/>-->
</tiers>
</configuration>
注:文件中采用了数据入库操作<param name="odbc-dsn" value="MYSQLTP:root:xxxxxx"/>参照Freeswitch替换sqlLit改为mysql,同时记录通话话单_freeswitch mysql_十年一梦惊觉醒的博客-CSDN博客中2:配置mysql的DSN。目标数据库需要创建坐席表,以及包含坐席号和密码字段。
1.3动态加载callcenter.conf.xml
静态的队列文件局限性较大,每次增加队列都需要手动修改xml。动态加载通过mod_xml_curl模块加载xml文件即可实现callcenter.conf.xml的动态加载,原理就是mod_xml_curl模块会通过xml_curl.conf.xml文件中配置的远程服务,加载相应的xml配置文件内容,远程服务只需要动态拼装所需的xml内容即可
1.3.1加载mod_xml_curl模块
已加载该模块的无需操作该步骤。
进入项目源码编辑文件modules.conf
,取消掉xml_int/mod_xml_curl
的注释
make mod_xml_curl-install
修改autoload_configs/modules.conf.xml文件,去掉<load module="mod_xml_curl"/>的注释,重启freeswitch(或者load mod_xml_curl)。
1.3.2编辑xml_curl.conf.xml文件
xml_curl.conf.xml是动态加载xml配置文件,理论上他能加载freeswitch的所有xml文件。标红处为修改内容,通过configuration方式加载callcenter.conf.xml文件,注:configuration理论上可以加载所有xml配置文件,web接口处可以打印下入参,根据不同请求返回不同xml配置文件内容。
<configuration name="xml_curl.conf" description="cURL XML Gateway">
<bindings>
<binding name="example">
<!-- Allow to bind on a particular IP for requests sent -->
<!--<param name="bind-local" value="$${local_ip_v4}" />-->
<!-- The url to a gateway cgi that can generate xml similar to
what's in this file only on-the-fly (leave it commented if you dont
need it) -->
<!-- one or more |-delim of configuration|directory|dialplan -->
<!-- <param name="gateway-url" value="http://www.freeswitch.org/gateway.xml" bindings="dialplan"/> -->
<!-- set this to provide authentication credentials to the server -->
<!--<param name="gateway-credentials" value="muser:mypass"/>-->
<!--<param name="auth-scheme" value="basic"/>-->
<!-- optional: this will enable the CA root certificate check by libcurl to
verify that the certificate was issued by a major Certificate Authority.
note: default value is disabled. only enable if you want this! -->
<!--<param name="enable-cacert-check" value="true"/>-->
<!-- optional: verify that the server is actually the one listed in the cert -->
<!-- <param name="enable-ssl-verifyhost" value="true"/> -->
<!-- optional: these options can be used to specify custom SSL certificates
to use for HTTPS communications. Either use both options or neither.
Specify your public key with 'ssl-cert-path' and the private key with
'ssl-key-path'. If your private key has a password, specify it with
'ssl-key-password'. -->
<!-- <param name="ssl-cert-path" value="$${certs_dir}/public_key.pem"/> -->
<!-- <param name="ssl-key-path" value="$${certs_dir}/private_key.pem"/> -->
<!-- <param name="ssl-key-password" value="MyPrivateKeyPassword"/> -->
<!-- optional timeout -->
<!-- <param name="timeout" value="10"/> -->
<!-- optional: use a custom CA certificate in PEM format to verify the peer
with. This is useful if you are acting as your own certificate authority.
note: only makes sense if used in combination with "enable-cacert-check." -->
<!-- <param name="ssl-cacert-file" value="$${certs_dir}/cacert.pem"/> -->
<!-- optional: specify the SSL version to force HTTPS to use. Valid options are
"SSLv3" and "TLSv1". Otherwise libcurl will auto-negotiate the version. -->
<!-- <param name="ssl-version" value="TLSv1"/> -->
<!-- optional: enables cookies and stores them in the specified file. -->
<!-- <param name="cookie-file" value="$${temp_dir}/cookie-mod_xml_curl.txt"/> -->
<!-- one or more of these imply you want to pick the exact variables that are transmitted -->
<!--<param name="enable-post-var" value="Unique-ID"/>-->
</binding>
<binding name="configuration">
<param name="gateway-url" value="http://127.0.0.1:18892/fs-core/pbxInter/initCallcenterInfo" bindings="configuration"/>
</binding>
</bindings>
</configuration>
<binding name="configuration">
<param name="gateway-url" value="http://127.0.0.1:18892/fs-core/pbxInter/initCallcenterInfo" bindings="configuration"/>
</binding>
为修改内容
1.3.2创建远程服务
以上配置中http://127.0.0.1:18892/fs-core/pbxInter/initCallcenterInfo即为需要创建的服务地址。服务代码参照:
@RequestMapping(value = "/initCallcenterInfo")
@ResponseBody
public String initCallcenterInfo(HttpServletRequest req, HttpServletResponse res) {
String keyValue = req.getParameter("key_value");
String profile = req.getParameter("profile");
String code = req.getParameter("code");
logger.info("获取callcenter xml-请求参数:code=" + code + ",keyValue=" + keyValue + ",profile=" + profile);
StringBuffer sb = new StringBuffer();
try {
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
sb.append(" <document type=\"freeswitch/xml\">\n");
sb.append(" <section name=\"configuration\">\n");
sb.append(" <configuration name=\"callcenter.conf\" description=\"CallCenter\">\n");
sb.append(" <settings>\n");
sb.append(" <param name=\"odbc-dsn\" value=\"MYSQLTP:root:AA39noway\"/>\n");
sb.append(" </settings>\n");
sb.append(" <queues>\n");
List<Map<String, Object>> queueList = queueService.getQueueList(null);
for (Map<String, Object> queue : queueList) {
sb.append(" <queue name=\"" + queue.get("queue_acc") + "@default\">\n");
sb.append(" <param name=\"strategy\" value=\"" + queue.get("queue_strategy") + "\"/>\n");
sb.append(
" <param name=\"moh-sound\" value=\"/usr/local/freeswitch/scripts/sound/waiting.wav\"/>\n");
sb.append(
" <param name=\"record-template\" value=\"/root/web-app/record/apache-tomcat-8.5.76/webapps/record/${uuid}.wav\"/>\n");
sb.append(" <param name=\"time-base-score\" value=\"system\"/>\n");
sb.append(" <param name=\"max-wait-time\" value=\"20\"/>\n");
sb.append(" <param name=\"max-wait-time-with-no-agent\" value=\"2\"/>\n");
sb.append(" <param name=\"max-wait-time-with-no-agent-time-reached\" value=\"1\"/>\n");
sb.append(" <param name=\"tier-rules-apply\" value=\"false\"/>\n");
sb.append(" <param name=\"tier-rule-wait-second\" value=\"300\"/>\n");
sb.append(" <param name=\"tier-rule-wait-multiply-level\" value=\"true\"/>\n");
sb.append(" <param name=\"tier-rule-no-agent-no-wait\" value=\"true\"/>\n");
sb.append(" </queue>\n");
}
sb.append(" </queues>\n");
sb.append(" <agents>\n");
List<Map<String, Object>> seatList = seatService.getSeatList(null);
for (Map<String, Object> seat : seatList) {
sb.append(" <agent name=\"" + seat.get("seat_no")
+ "@default\" type=\"callback\" contact=\"[call_timeout=10]user/" + seat.get("seat_no")
+ "\" status=\"Available\" max-no-answer=\"100\" wrap-up-time=\"2\" reject-delay-time=\"20\" busy-delay-time=\"10\" no-answer-delay-time=\"10\" />\n");
}
sb.append(" </agents>\n");
sb.append(" <tiers>\n");
List<Map<String, Object>> tierList = seatService.getTierList(null);
for (Map<String, Object> tier : tierList) {
sb.append(" <tier agent=\"" + tier.get("seat_no") + "@default\" queue=\""
+ tier.get("queue_acc") + "@default\" state=\"Ready\" level=\"1\" position=\"1\"/>\n");
}
sb.append(" </tiers>\n");
sb.append(" </configuration>\n");
sb.append(" </section>\n");
sb.append(" </document>\n");
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
logger.info("获取callcenter xml-返回参数:" + JSONObject.fromObject(result).toString());
return sb.toString();
}
服务返回xml参照以下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="freeswitch/xml">
<section name="configuration">
<configuration name="callcenter.conf" description="CallCenter">
<settings>
<param name="odbc-dsn" value="MYSQLTP:root:AA39noway"/>
</settings>
<queues>
<queue name="support@default">
<param name="strategy" value="random"/>
<param name="moh-sound" value="/usr/local/freeswitch/scripts/sound/waiting.wav"/>
<param name="record-template" value="/root/web-app/record/apache-tomcat-8.5.76/webapps/record/${uuid}.wav"/>
<param name="time-base-score" value="system"/>
<param name="max-wait-time" value="20"/>
<param name="max-wait-time-with-no-agent" value="2"/>
<param name="max-wait-time-with-no-agent-time-reached" value="1"/>
<param name="tier-rules-apply" value="false"/>
<param name="tier-rule-wait-second" value="300"/>
<param name="tier-rule-wait-multiply-level" value="true"/>
<param name="tier-rule-no-agent-no-wait" value="true"/>
</queue>
</queues>
<agents>
<agent name="1006@default" type="callback" contact="[call_timeout=10]user/1006" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="20" busy-delay-time="10" no-answer-delay-time="10" />
<agent name="1003@default" type="callback" contact="[call_timeout=10]user/1003" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="20" busy-delay-time="10" no-answer-delay-time="10" />
<agent name="2007@default" type="callback" contact="[call_timeout=10]user/2007" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="20" busy-delay-time="10" no-answer-delay-time="10" />
<agent name="2008@default" type="callback" contact="[call_timeout=10]user/2008" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="20" busy-delay-time="10" no-answer-delay-time="10" />
<agent name="6666@default" type="callback" contact="[call_timeout=10]user/6666" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="20" busy-delay-time="10" no-answer-delay-time="10" />
<agent name="1001@default" type="callback" contact="[call_timeout=10]user/1001" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="20" busy-delay-time="10" no-answer-delay-time="10" />
<agent name="8888@default" type="callback" contact="[call_timeout=10]user/8888" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="20" busy-delay-time="10" no-answer-delay-time="10" />
<agent name="1004@default" type="callback" contact="[call_timeout=10]user/1004" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="20" busy-delay-time="10" no-answer-delay-time="10" />
<agent name="2009@default" type="callback" contact="[call_timeout=10]user/2009" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="20" busy-delay-time="10" no-answer-delay-time="10" />
<agent name="2001@default" type="callback" contact="[call_timeout=10]user/2001" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="20" busy-delay-time="10" no-answer-delay-time="10" />
<agent name="2005@default" type="callback" contact="[call_timeout=10]user/2005" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="20" busy-delay-time="10" no-answer-delay-time="10" />
<agent name="2010@default" type="callback" contact="[call_timeout=10]user/2010" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="20" busy-delay-time="10" no-answer-delay-time="10" />
<agent name="2006@default" type="callback" contact="[call_timeout=10]user/2006" status="Available" max-no-answer="100" wrap-up-time="2" reject-delay-time="20" busy-delay-time="10" no-answer-delay-time="10" />
</agents>
<tiers>
<tier agent="2006@default" queue="support@default" state="Ready" level="1" position="1"/>
<tier agent="1001@default" queue="support@default" state="Ready" level="1" position="1"/>
<tier agent="8888@default" queue="support@default" state="Ready" level="1" position="1"/>
<tier agent="2007@default" queue="support@default" state="Ready" level="1" position="1"/>
<tier agent="2010@default" queue="support@default" state="Ready" level="1" position="1"/>
<tier agent="1003@default" queue="support@default" state="Ready" level="1" position="1"/>
<tier agent="6666@default" queue="support@default" state="Ready" level="1" position="1"/>
<tier agent="2005@default" queue="support@default" state="Ready" level="1" position="1"/>
<tier agent="1006@default" queue="support@default" state="Ready" level="1" position="1"/>
<tier agent="2009@default" queue="support@default" state="Ready" level="1" position="1"/>
<tier agent="1004@default" queue="support@default" state="Ready" level="1" position="1"/>
<tier agent="2008@default" queue="support@default" state="Ready" level="1" position="1"/>
</tiers>
</configuration>
</section>
</document>
启动远端服务,重启freeswitch即可动态加载callcenter。如有问题可咨询mokeily99@126.com