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

 

InBound模式:FS作爲服務端,監聽所配置的端口,FS啓動時自動加載,當外部客戶端程序主動向FS發起socket連接來實現通信。

該模式由於是可以主動連接並可長期穩定保持,且此通道有且只有一個,心跳、外呼和註冊等動作必須通過此種連接完成。

2、外連模式OutBound

 

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

 

c.編輯event_socket配置文件:vim ./conf/autoload_configs/event_socket.conf.xml

 

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
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章