freeswitch模块之event_socket
這是我之前整理的關(guān)于freeswitch mod_event_socket的相關(guān)內(nèi)容,這里記錄下,也方便我以后查閱。
mod_event_socket以socket的形式,對(duì)外提供控制FS一種途徑, 缺省的IP是127.0.0.1,TCP端口是8021,可以在外部通過(guò)sokcet執(zhí)行API/APP命令。
連接模式
連接分兩種模式: inbound/outbound
mod_event_socket 的默認(rèn)加載模式是inbound,outbound模式需要在dialplan的配置文件中設(shè)置。
InBound模式由于是可以主動(dòng)連接并可長(zhǎng)期穩(wěn)定保持,且此通道有且只有一個(gè),心跳、外呼和注冊(cè)等動(dòng)作必須通過(guò)此種連接完成;
OutBound模式由于是在外線呼入和內(nèi)線呼出的時(shí)候才會(huì)觸發(fā)socket連接事件,所以是不穩(wěn)定的,且由于同一時(shí)間呼入數(shù)量不唯一,所以此連接的數(shù)目也是動(dòng)態(tài)變化的,但是由于其每個(gè)來(lái)電建立一個(gè)socket連接,所以在大負(fù)荷情況下不會(huì)造成命令和事件的堵塞。
使用inbound模式
1、修改acl配置:
配置autoload_configs/acl.conf.xml文件:
<list name="domains" default="deny"><!-- domain= is special it scans the domain from the directory to build the ACL --><node type="allow" domain="$${domain}"/><!-- use cidr= if you wish to allow ip ranges to this domains acl. --><!-- <node type="allow" cidr="192.168.0.0/24"/> --><node type="allow" cidr="192.168.168.0/24"/><node type="allow" cidr="127.0.0.0/24"/> </list>2、修改esl配置:
配置autoload_configs/event_socket.conf.xml文件:
<configuration name="event_socket.conf" description="Socket Client"><settings><param name="nat-map" value="false"/><param name="listen-ip" value="0.0.0.0"/><param name="listen-port" value="8021"/><param name="password" value="ClueCon"/><param name="apply-inbound-acl" value="domains"/><!--<param name="apply-inbound-acl" value="loopback.auto"/>--><!--<param name="stop-on-bind-error" value="true"/>--></settings> </configuration>3、重啟freeswitch
4、通過(guò)inbound方式使用freeswitch python示例代碼如下:
import socket import json sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('127.0.0.1', 8021)) # send auth sock.send('auth ClueCon\r\n\r\n') # send command sock.send('event json ALL\r\n\r\n') #sock.send('event plain ALL\r\n\r\n') while True:print sock.recv(10240)使用outbound模式
1、編輯conf/dialplan/default.xml,增加如下內(nèi)容:
<extension name="123456789 Entrance"><condition field="destination_number" expression="^123456789$"> <action application="socket" data="127.0.0.1:9000 async full" /> <action application="playback" data="$${hold_music}"/><action application="hangup" data="" /> </condition> </extension>2、啟動(dòng)監(jiān)聽(tīng)服務(wù)器 監(jiān)聽(tīng)listen-ip:listen-port(如在Linux下可以通過(guò) nc -v -l 9000),
然后撥打配置的電話號(hào)碼(本例中為123456789) 即可收到Connection from 127.0.0.1 port 9000 [tcp/*] accepted 的消息, 鍵入connect\n\n即可進(jìn)入OutBound模式
?
通過(guò)socket控制freeswitch
?
可以通過(guò)任何支持socket的語(yǔ)言控制freeswitch,這里以python為例子描述怎么通過(guò)socket控制freeswitch。
?
-
auth
auth <password>
語(yǔ)法:當(dāng)用戶第一次通過(guò)mod_event_socket連接到freeswitch時(shí),必須進(jìn)行認(rèn)證,認(rèn)證示例:
sock.send(“auth ClueCon\r\n\r\n”) -
api
sock.send('api originate user/1000 &echo\r\n\r\n') sock.send('api originate user/1001 &echo\r\n\r\n')
執(zhí)行freeswitch的API命令,阻塞執(zhí)行。
語(yǔ)法:
api?
示例:socket會(huì)將上述兩條指令同時(shí)發(fā)送給freeswitch,但freeswitch按順序阻塞執(zhí)行。
-
bgapi
sock.send('bgapi originate user/1000 &echo\r\n\r\n') sock.send('bgapi originate user/1001 &echo\r\n\r\n')
功能和api相同,非阻塞執(zhí)行。
語(yǔ)法:
bgapi?
示例:socket會(huì)將上述兩條指令同時(shí)發(fā)送給freeswitch,同時(shí)執(zhí)行。
-
event
啟動(dòng)或停止事件流。
語(yǔ)法:
eventformat : plain、json、xml
sock.send('event json ALL\r\n\r\n')
Event types : 參考freeswitch事件類型
示例:接收f(shuō)reeswitch所有事件,并以json格式返回。
-
noevents
關(guān)閉上一個(gè)event開(kāi)啟的事件
語(yǔ)法 :
noevents示例:
sock.send('noevents\r\n\r\n') -
divert_events
腳本注冊(cè)接收事件的函數(shù)分轉(zhuǎn)到event socket上。
語(yǔ)法:
divert_events -
filter
設(shè)置event socket接收事件的類型。
語(yǔ)法:
filter示例:
sock.send('filter Event-Name CHANNEL_EXECUTE\r\n\r\n')
只訂閱CHANNEL_EXECUTE事件只訂閱uuid為34602e08-557a-494a-af47-99e9d55e26ed的事件
sock.send('filter Unique-ID 34602e08-557a-494a-af47-99e9d55e26ed\r\n\r\n') -
filter delete
取消訂閱的事件。
語(yǔ)法:
filter delete示例:
sock.send('filter delete Event-Name CHANNEL_EXECUTE\r\n\r\n') sock.send('filter delete Unique-ID 34602e08-557a-494a-af47-99e9d55e26ed\r\n\r\n') -
nixevents
nixevents <event types | ALL| CUSTOM custom event sub-class>
設(shè)置event socket禁止接收的事件類型。
語(yǔ)法:示例:
sock.send('nixevent HEARTBEAT\r\n\r\n')
不訂閱HEARTBEAT事件 -
sendevent
sendevent <event-name>
發(fā)送一個(gè)事件到系統(tǒng)隊(duì)列中。
語(yǔ)法:示例(消息內(nèi)容):
sendevent SOME_NAME Event-Name: CUSTOM Event-Subclass: albs::Section-Alarm Section: 33 Alarm-Type: PIR State: ACTIVE -
sendmsg
給一個(gè)uuid發(fā)送一個(gè)消息,可以執(zhí)行其他模塊的應(yīng)用接口,也可以掛斷電話等。
sendmsg <uuid>
語(yǔ)法:示例(消息內(nèi)容):
sendmsg <uuid> call-command: execute execute-app-name: playback execute-app-arg: /tmp/test.wav -
execute
sendmsg <uuid> call-command: execute execute-app-name: <one of the applications> execute-app-arg: <application data> loops: <number of times to invoke the command, default: 1>
執(zhí)行一個(gè)撥號(hào)規(guī)則的應(yīng)用。
語(yǔ)法: -
hangup 對(duì)活動(dòng)的呼叫掛機(jī)。
sendmsg <uuid> call-command: hangup hangup-cause: <one of the causes listed below>
語(yǔ)法: -
nomedia
控制freeswitch是否處于實(shí)時(shí)的媒體路徑,這個(gè)命令支持用戶對(duì)指定的通道啟用或關(guān)閉媒體處理。
語(yǔ)法:
sendmsg <uuid> call-command: nomedia nomedia-uuid: <noinfo> -
log 語(yǔ)法:
log <level>設(shè)置日志級(jí)別。
-
nolog
禁止日志。
-
linger
告訴freeswitch當(dāng)一個(gè)通道掛機(jī)時(shí)不要關(guān)閉socket連接,直到收取相關(guān)通道的最后一個(gè)事件。
-
nolinger
關(guān)閉上次開(kāi)啟的linger命令。
?
通過(guò)freeswitch提供的ESL庫(kù)進(jìn)行控制?
這里以python為例描述下ESL庫(kù)的基本使用及api接口。
安裝ESL
以python為例進(jìn)行安裝:
cd libs/esl/ make pymod make pymod-installESL示例
-
InBound模式
Python示例代碼:
import ESL import timehostIp,port,user = "127.0.0.1","8021","ClueCon"con = ESL.ESLconnection(hostIp,port,user) con.events("json","all") for i in range(100):eventData = con.recvEvent()print eventData.getHeader("Event-Name") con.disconnect() -
OutBound模式
配置dialplan:
<action application="socket" data="127.0.0.1:9000 async full"/>Python示例代碼:
import SocketServer import ESLclass ESLRequestHandler(SocketServer.BaseRequestHandler ):def setup(self):print self.client_address, 'connected!'fd = self.request.fileno()con = ESL.ESLconnection(fd)if con.connected():info = con.getInfo()uuid = info.getHeader("unique-id")print uuidcon.execute("answer","", uuid)con.execute("playback","/tmp/sample.wav", uuid)server = SocketServer.ThreadingTCPServer(('', 9000), ESLRequestHandler) server.serve_forever()
ESL接口介紹
eslSetLogLevel函數(shù)
該函數(shù)用于設(shè)置服務(wù)器的日志級(jí)別,使用方式如下:
eslSetLogLevel(loglevel)其中l(wèi)oglevel是一個(gè)整數(shù)變量,從0到7,含義如下:
0 是 EMERG
1 是 ALERT
2 是 CRIT
3 是 ERROR
4 是 WARNING
5 是 NOTICE
6 是 INFO
7 是 DEBUG
ESLconnection對(duì)象
ESLconnection對(duì)象維護(hù)與freeswitch之間的連接,以發(fā)送命令并進(jìn)行事件處理。 成員函數(shù)列表如下:
-
socketDescriptor()
該函數(shù)返回連接的UNIX文件句柄 -
connected()
判斷是否已連接,連接返回1,否則返回0 -
getInfo()
當(dāng)freeswitch使用outbound模式連接時(shí),它將首先發(fā)一個(gè)CHANNEL_DATA事件,getInfo會(huì)返回該事件;
在inbound模式中返回None -
send(command)
向freeswitch發(fā)送一個(gè)command,但不會(huì)等待返回結(jié)果,需要顯式調(diào)用recvEvent或recvEventTimed以接收返回的事件。 -
sendRecv(command)
向freeswitch發(fā)送一個(gè)command,并等待返回結(jié)果(一個(gè)ESLevent對(duì)象)。 -
api(command[,arguments])
向freeswitch發(fā)送api命令,阻塞執(zhí)行 -
bgapi(command[, arguments][,custom_job_uuid])
向freeswitch發(fā)送bgapi命令,后臺(tái)執(zhí)行,非阻塞執(zhí)行 -
sendEvent(event)
向freeswitch發(fā)送一個(gè)事件 -
sendMSG(event,uuid)
參考sendmsg命令 -
recvEvent()
從freeswitch接收事件,阻塞模式 -
recvEventTimed(milliseconds)
與recvEvent類似,但不會(huì)無(wú)限等待,而是在參數(shù)指定的毫秒數(shù)會(huì)返回。
recvEventTimed(0)會(huì)立即返回。 -
filter (header,value)
事件過(guò)濾,類似filter命令。 -
events (event_type,value)
事件訂閱,類似event命令。 -
execute (app[,arg][,uuid])
執(zhí)行dialplan的app,并阻塞等待返回. 返回結(jié)果為一個(gè)ESLevent對(duì)象,通過(guò)getHeader(“Reply-Text”)可以獲取返回值,”+OK”表示成功,”-ERR”表示失敗。 -
executeAsync (app[,arg][,uuid])
與execute()相同,但非阻塞執(zhí)行。 -
setAsyncExecute(value)
強(qiáng)制將socket設(shè)置為異步模式,value為1是異步,0是同步。 -
setEventLock(value)
使用該選項(xiàng)后,后續(xù)所有的execute()調(diào)用都將帶有”event-lock:true”頭域。 -
disconnect()
主動(dòng)中斷與freeswitch的連接。
ESLevent對(duì)象
當(dāng)接收一個(gè)事件時(shí),用戶將獲得一個(gè)ESLevent對(duì)象,這個(gè)對(duì)象包含各種幫助函數(shù)變量 來(lái)幫助解析和處理收到的事件。
con = ESL.ESLconnection("127.0.0.1", "8021", "ClueCon") con.events("json", "all"); eventData = con.recvEvent()eventData即為ESLevent對(duì)象
ESLevent對(duì)象成員函數(shù)列表如下:
- serialize([format])?
將event數(shù)據(jù)轉(zhuǎn)換成”name:value”型數(shù)據(jù),format參數(shù)可以為:
"xml"
"json"
"plain" (default)示例如下:
eventData.serialize('json') 獲取json格式數(shù)據(jù) - setPriority([number])
設(shè)置事件的級(jí)別 -
getHeader(headerName)
獲取header對(duì)應(yīng)的value,示例如下:eventData .getHeader('Event-Name') #獲取事件名稱
- getBody()
獲取事件的正文 - getType()
獲取event object的事件類型 - addBody(value)
向事件中加入正文,可以調(diào)用多次 - addHeader(key,value)
向事件中加入一個(gè)頭域(ESL_STACK_BOTTOM) - pushHeader(key,value)
向事件中加入一個(gè)頭域(ESL_STACK_PUSH) - unshiftHeader(key,value)
向事件中加入一個(gè)頭域(ESL_STACK_UNSHIFT) - delHeader(key)
從Event中刪除頭域 - firstHeader()
將指針指向Event的第一個(gè)頭域,并返回它的key值。它必須在nextHeader之前調(diào)用 - nextHeader()
移動(dòng)指針指向下一個(gè)header,在函數(shù)調(diào)用前必須先調(diào)用firstHeader()
本文github地址:
https://github.com/mike-zhang/mikeBlogEssays/blob/master/2016/20160926_freeswitch模塊之event_socket.md
歡迎補(bǔ)充??
轉(zhuǎn)載于:https://www.cnblogs.com/MikeZhang/p/freeswitch_mod_vent_socket_20160926.html
總結(jié)
以上是生活随笔為你收集整理的freeswitch模块之event_socket的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 深度好文
- 下一篇: “全能”选手—Django 1.10文档