Freeswitch Event Socket IVR外呼方案

 

一、项目应用解决方案

1、内呼方案流程:

客户拨号 <——> 运营商/网关 <——> FreeSWITCH(MRCP +ASR/TTS/NLP) <——>Lua(嵌入FS)

Ps: 根据特定号码,FS路由配置好的拨号计划(dialplan),进而调用lua APP,Lua脚本的运行,实现业务逻辑控制,每一通电话都可以调用该lua脚本;

2、外呼方案流程:

Web(http) <——> Python(ESL) <——> FreeSWITCH(MRCP +ASR/TTS/NLP) <——> 运营商/网关 <——> 目标客户

Ps: Python脚本通过http协议对接Web,实现批量的自动拨号与电话通道的管理与控制;当客户接通电话后,调用Lua脚本实现外呼的业务逻辑;

二、Event Socket

与Lua嵌入式脚本不同,通过Event Socket方式,可以在远程机器的外部独立程序控制FreeSWITCH。大多数语言都支持Socket,所以几乎可以和任何语言开发的程序通信,便于跟任何系统进行集成。

Event Socket的连接分两种模式: InBound/OutBound

1、内连模式InBound

Freeswitch Event Socket IVR外呼方案_第1张图片

 

InBound模式:FS作为服务端,监听所配置的端口,FS启动时自动加载,当外部客户端程序主动向FS发起socket连接来实现通信。

该模式由于是可以主动连接并可长期稳定保持,且此通道有且只有一个,心跳、外呼和注册等动作必须通过此种连接完成。

2、外连模式OutBound

Freeswitch Event Socket IVR外呼方案_第2张图片

 

OutBound模式:FS作为客户端,需要在dialplan的配置文件中设置,当有电话进来时,FS路由dialplan, 触发一个app(socket)动作,向外部服务端程序建立一个socket连接来实现通信。

该模式一般用于外线电话呼入的时候会触发socket连接事件,支持同一时间呼入数量不唯一,每个来电建立一个socket连接,所以此连接的数目也是动态变化的。

3、FS mod_event_socket模块配置

a.进入安装FS的根目录:

cd /usr/local/freeswitch(默认)

b.编辑FS模块加载配置文件:vim ./conf/autoload_configs/modules.conf.xml

Freeswitch Event Socket IVR外呼方案_第3张图片

 

c.编辑event_socket配置文件:vim ./conf/autoload_configs/event_socket.conf.xml

Freeswitch Event Socket IVR外呼方案_第4张图片

 

d. 重启freeswitch,使相应配置生效。

 

三、Event Socket Library

FreeSWITCH用C语言将Event Socket协议写了一些库函数,并用SWIG封装成各种高级语言的接口,目前支持的语言有Perl、PHP、Python、Ruby、Java、C#等,这些高级语言的库函数开发接口即为ESL(Event Socket Library),通过这些开发接口来使用FS内部提供的APP和API,可以很方便地与FreeSWITCH交互,进而控制FS的所有通道和各种媒体功能。

本文介绍Python 利用 Event Socket Library 与FreeSWITCH通信,并控制其进行相应操作;

1、Python ESL的两种安装方式

a.FS源码的Pymod编译、安装:

cd /usr/src/freeswitch/libs/esl

make pymod 

make pymod-install

(默认安装路径:/usr/lib/pythonX.X/site-packages/)

 

b.在线pip安装:pip install python-ESL

(默认安装路径:/usr/lib64/pythonX.X/site-packages/)

 

2、Python ESL使用

ESLconnection对象

ESLconnection对象维护与freeswitch之间的连接,以发送命令并进行事件处理。 成员函数列表如下:

  • socketDescriptor()
    该函数返回连接的UNIX文件句柄
  • connected()
    判断是否已连接,连接返回1,否则返回0
  • getInfo()
  • 当freeswitch使用outbound模式连接时,它将首先发一个CHANNEL_DATA事件,getInfo会返回该事件;
    在inbound模式中返回None
  • send(command)
    向freeswitch发送一个command,但不会等待返回结果,需要显式调用recvEvent或recvEventTimed以接收返回的事件。
  • sendRecv(command)
    向freeswitch发送一个command,并等待返回结果(一个ESLevent对象)。
  • api(command[,arguments])
    向freeswitch发送api命令,阻塞执行
  • bgapi(command[, arguments][,custom_job_uuid])
    向freeswitch发送bgapi命令,后台执行,非阻塞执行
  • sendEvent(event)
    向freeswitch发送一个事件
  • sendMSG(event,uuid)
    参考sendmsg命令
  • recvEvent()
    从freeswitch接收事件,阻塞模式
  • recvEventTimed(milliseconds)
    与recvEvent类似,但不会无限等待,而是在参数指定的毫秒数会返回。
    recvEventTimed(0)会立即返回。
  • filter (header,value)
    事件过滤,类似filter命令。
  • events (event_type,value)
    事件订阅,类似event命令。
  • execute (app[,arg][,uuid])
    执行dialplan的app,并阻塞等待返回. 返回结果为一个ESLevent对象,通过getHeader(“Reply-Text”)可以获取返回值,”+OK”表示成功,”-ERR”表示失败。
  • executeAsync (app[,arg][,uuid])
    与execute()相同,但非阻塞执行。
  • setAsyncExecute(value)
    强制将socket设置为异步模式,value为1是异步,0是同步。
  • setEventLock(value)
    使用该选项后,后续所有的execute()调用都将带有”event-lock:true”头域。
  • disconnect()
    主动中断与freeswitch的连接。

ESLevent对象

当接收一个事件时,用户将获得一个ESLevent对象,这个对象包含各种帮助函数变量 来帮助解析和处理收到的事件。

  • ESLevent对象成员函数列表如下:
  • serialize([format])
  • 将event数据转换成”name:value”型数据,format参数可以为:
  • "xml"
    "json"
    "plain" (default)
  • 示例如下:
  •   eventData.serialize('json') 获取json格式数据
  • setPriority([number])
    设置事件的级别
  • getHeader(headerName)
    获取header对应的value,示例如下:
  • eventData .getHeader('Event-Name') #获取事件名称
  • getBody()
    获取事件的正文
  • getType()
    获取event object的事件类型
  • addBody(value)
    向事件中加入正文,可以调用多次
  • addHeader(key,value)
    向事件中加入一个头域(ESL_STACK_BOTTOM)
  • pushHeader(key,value)
    向事件中加入一个头域(ESL_STACK_PUSH)
  • unshiftHeader(key,value)
    向事件中加入一个头域(ESL_STACK_UNSHIFT)
  • delHeader(key)
    从Event中删除头域
  • firstHeader()
    将指针指向Event的第一个头域,并返回它的key值。它必须在nextHeader之前调用
  • nextHeader()
    移动指针指向下一个header,在函数调用前必须先调用firstHeader()

 

应用示例:

Python InBound模式示例代码:


import ESL
import time

hostIp,port,user = "127.0.0.1","8021","ClueCon"

con = ESL.ESLconnection(hostIp,port,user)

con.events("CHANNEL_CREATE")

eventData = con.api("originate {ignore_early_media=true}user/1005 &park")
print eventData.getHeader("Job-UUID")

while True:
	eventData = con.recvEvent()
	print eventData.getHeader("Event-Name")

con.disconnect()


originate返回的事件信息:

//tcp header
Content-Length: 625
Content-Type: text/event-plain

//event header
Job-UUID: 7f4db78a-17d7-11dd-b7a0-db4edd065621
Job-Command: originate
Job-Command-Arg: sofia/default/1005%20'%26park'
Event-Name: BACKGROUND_JOB
Core-UUID: 42bdf272-16e6-11dd-b7a0-db4edd065621
FreeSWITCH-Hostname: ser
FreeSWITCH-IPv4: 192.168.1.104
FreeSWITCH-IPv6: 127.0.0.1
Event-Date-Local: 2008-05-02%2007%3A37%3A03
Event-Date-GMT: Thu,%2020%20Jun%202008%2023%3A37%3A03%20GMT
Event-Date-timestamp: 1209685023894968
Event-Calling-File: mod_event_socket.c
Event-Calling-Function: api_exec
Event-Calling-Line-Number: 609
Content-Length: 41

//event body
+OK 7f4de4bc-17d7-11dd-b7a0-db4edd065621
 

 

Freeswitch Event Socket IVR外呼方案_第5张图片

你可能感兴趣的:(Freeswitch)