这是我之前整理的关于freeswitch mod_event_socket的相关内容,这里记录下,也方便我以后查阅。

mod_event_socket以socket的形式,对外提供控制FS一种途径, 缺省的IP是127.0.0.1,TCP端口是8021,可以在外部通过sokcet执行API/APP命令。

连接模式

连接分两种模式: inbound/outbound
mod_event_socket 的默认加载模式是inbound,outbound模式需要在dialplan的配置文件中设置。

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

OutBound模式由于是在外线呼入和内线呼出的时候才会触发socket连接事件,所以是不稳定的,且由于同一时间呼入数量不唯一,所以此连接的数目也是动态变化的,但是由于其每个来电建立一个socket连接,所以在大负荷情况下不会造成命令和事件的堵塞。

使用inbound模式

1、修改acl配置:

配置autoload_configs/acl.conf.xml文件:

  1. <list name="domains" default="deny">
  2. <!-- domain= is special it scans the domain from the directory to build the ACL -->
  3. <node type="allow" domain="$${domain}"/>
  4. <!-- use cidr= if you wish to allow ip ranges to this domains acl. -->
  5. <!-- <node type="allow" cidr="192.168.0.0/24"/> -->
  6. <node type="allow" cidr="192.168.168.0/24"/>
  7. <node type="allow" cidr="127.0.0.0/24"/>
  8. </list>

2、修改esl配置:

配置autoload_configs/event_socket.conf.xml文件:

  1. <configuration name="event_socket.conf" description="Socket Client">
  2. <settings>
  3. <param name="nat-map" value="false"/>
  4. <param name="listen-ip" value="0.0.0.0"/>
  5. <param name="listen-port" value="8021"/>
  6. <param name="password" value="ClueCon"/>
  7. <param name="apply-inbound-acl" value="domains"/>
  8. <!--<param name="apply-inbound-acl" value="loopback.auto"/>-->
  9. <!--<param name="stop-on-bind-error" value="true"/>-->
  10. </settings>
  11. </configuration>

3、重启freeswitch

4、通过inbound方式使用freeswitch python示例代码如下:

  1. import socket
  2. import json
  3. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  4. sock.connect(('127.0.0.1', 8021))
  5. # send auth
  6. sock.send('auth ClueCon\r\n\r\n')
  7. # send command
  8. sock.send('event json ALL\r\n\r\n')
  9. #sock.send('event plain ALL\r\n\r\n')
  10. while True:
  11. print sock.recv(10240)

使用outbound模式

1、编辑conf/dialplan/default.xml,增加如下内容:

  1. <extension name="123456789 Entrance">
  2. <condition field="destination_number" expression="^123456789$">
  3. <action application="socket" data="127.0.0.1:9000 async full" />
  4. <action application="playback" data="$${hold_music}"/>
  5. <action application="hangup" data="" />
  6. </condition>
  7. </extension>

2、启动监听服务器 监听listen-ip:listen-port(如在Linux下可以通过 nc -v -l 9000),

然后拨打配置的电话号码(本例中为123456789) 即可收到Connection from 127.0.0.1 port 9000 [tcp/*] accepted 的消息, 键入connect\n\n即可进入OutBound模式

通过socket控制freeswitch

可以通过任何支持socket的语言控制freeswitch,这里以python为例子描述怎么通过socket控制freeswitch。

  • auth
    语法:

    1. auth <password>

    当用户第一次通过mod_event_socket连接到freeswitch时,必须进行认证,认证示例:

    1. sock.send(“auth ClueCon\r\n\r\n”)
  • api
    执行freeswitch的API命令,阻塞执行。
    语法:
    api 
    示例:

    1. sock.send('api originate user/1000 &echo\r\n\r\n')
    2. sock.send('api originate user/1001 &echo\r\n\r\n')

    socket会将上述两条指令同时发送给freeswitch,但freeswitch按顺序阻塞执行。

  • bgapi
    功能和api相同,非阻塞执行。
    语法:
    bgapi 
    示例:

    1. sock.send('bgapi originate user/1000 &echo\r\n\r\n')
    2. sock.send('bgapi originate user/1001 &echo\r\n\r\n')

    socket会将上述两条指令同时发送给freeswitch,同时执行。

  • event
    启动或停止事件流。
    语法:
    event

    format : plain、json、xml
    Event types : 参考freeswitch事件类型
    示例:

    1. sock.send('event json ALL\r\n\r\n')

    接收freeswitch所有事件,并以json格式返回。

  • noevents
    关闭上一个event开启的事件
    语法 :
    noevents

    示例:

    1. sock.send('noevents\r\n\r\n')
  • divert_events
    脚本注册接收事件的函数分转到event socket上。
    语法:
    divert_events

  • filter
    设置event socket接收事件的类型。
    语法:
    filter

    示例:
    只订阅CHANNEL_EXECUTE事件

    1. sock.send('filter Event-Name CHANNEL_EXECUTE\r\n\r\n')

    只订阅uuid为34602e08-557a-494a-af47-99e9d55e26ed的事件

    1. sock.send('filter Unique-ID 34602e08-557a-494a-af47-99e9d55e26ed\r\n\r\n')
  • filter delete
    取消订阅的事件。
    语法:
    filter delete

    示例:

    1. sock.send('filter delete Event-Name CHANNEL_EXECUTE\r\n\r\n')
    2. sock.send('filter delete Unique-ID 34602e08-557a-494a-af47-99e9d55e26ed\r\n\r\n')
  • nixevents
    设置event socket禁止接收的事件类型。
    语法:

    1. nixevents <event types | ALL| CUSTOM custom event sub-class>

    示例:
    不订阅HEARTBEAT事件

    1. sock.send('nixevent HEARTBEAT\r\n\r\n')
  • sendevent
    发送一个事件到系统队列中。
    语法:

    1. sendevent <event-name>

    示例(消息内容):

    1. sendevent SOME_NAME
    2. Event-Name: CUSTOM
    3. Event-Subclass: albs::Section-Alarm
    4. Section: 33
    5. Alarm-Type: PIR
    6. State: ACTIVE
  • sendmsg

    给一个uuid发送一个消息,可以执行其他模块的应用接口,也可以挂断电话等。
    语法:

    1. sendmsg <uuid>

    示例(消息内容):

    1. sendmsg <uuid>
    2. call-command: execute
    3. execute-app-name: playback
    4. execute-app-arg: /tmp/test.wav
  • execute
    执行一个拨号规则的应用。
    语法:

    1. sendmsg <uuid>
    2. call-command: execute
    3. execute-app-name: <one of the applications>
    4. execute-app-arg: <application data>
    5. loops: <number of times to invoke the command, default: 1>
  • hangup 对活动的呼叫挂机。
    语法:

    1. sendmsg <uuid>
    2. call-command: hangup
    3. hangup-cause: <one of the causes listed below>
  • nomedia

    控制freeswitch是否处于实时的媒体路径,这个命令支持用户对指定的通道启用或关闭媒体处理。

    语法:

    1. sendmsg <uuid>
    2. call-command: nomedia
    3. nomedia-uuid: <noinfo>
  • log 语法:

    1. log <level>

    设置日志级别。

  • nolog

    禁止日志。

  • linger

    告诉freeswitch当一个通道挂机时不要关闭socket连接,直到收取相关通道的最后一个事件。

  • nolinger

    关闭上次开启的linger命令。

通过freeswitch提供的ESL库进行控制

这里以python为例描述下ESL库的基本使用及api接口。

安装ESL

以python为例进行安装:

  1. cd libs/esl/
  2. make pymod
  3. make pymod-install

ESL示例

  • InBound模式

    Python示例代码:

    1. import ESL
    2. import time
    3.  
    4. hostIp,port,user = "127.0.0.1","","ClueCon"
    5.  
    6. con = ESL.ESLconnection(hostIp,port,user)
    7. con.events("json","all")
    8. for i in range(100):
    9. eventData = con.recvEvent()
    10. print eventData.getHeader("Event-Name")
    11. con.disconnect()
  • OutBound模式

    配置dialplan:

    1. <action application="socket" data="127.0.0.1:9000 async full"/>

    Python示例代码:

    1. import SocketServer
    2. import ESL
    3.  
    4. class ESLRequestHandler(SocketServer.BaseRequestHandler ):
    5. def setup(self):
    6. print self.client_address, 'connected!'
    7. fd = self.request.fileno()
    8. con = ESL.ESLconnection(fd)
    9. if con.connected():
    10. info = con.getInfo()
    11. uuid = info.getHeader("unique-id")
    12. print uuid
    13. con.execute("answer","", uuid)
    14. con.execute("playback","/tmp/sample.wav", uuid)
    15.  
    16. server = SocketServer.ThreadingTCPServer(('', 9000), ESLRequestHandler)
    17. server.serve_forever()

ESL接口介绍

eslSetLogLevel函数

该函数用于设置服务器的日志级别,使用方式如下:

  1. eslSetLogLevel(loglevel)

其中loglevel是一个整数变量,从0到7,含义如下:

0 是 EMERG
1 是 ALERT
2 是 CRIT
3 是 ERROR
4 是 WARNING
5 是 NOTICE
6 是 INFO
7 是 DEBUG

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对象,这个对象包含各种帮助函数变量 来帮助解析和处理收到的事件。

  1. con = ESL.ESLconnection("127.0.0.1", "", "ClueCon")
  2. con.events("json", "all");
  3. eventData = con.recvEvent()

eventData即为ESLevent对象

ESLevent对象成员函数列表如下:

  • serialize([format])

    将event数据转换成”name:value”型数据,format参数可以为:

    "xml"
    "json"
    "plain" (default)

    示例如下:

    1. 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()

本文github地址:

https://github.com/mike-zhang/mikeBlogEssays/blob/master/2016/20160926_freeswitch模块之event_socket.md

欢迎补充

freeswitch模块之event_socket的更多相关文章

  1. freeswitch python模块

    概述 freeswitch支持多种语言的业务开发,包括C/C++,java,python,js,lua,Golang等等.freeswitch在使用python做业务开发时,有俩种接入方式,一种是ES ...

  2. FreeSWITCH命令大全

    FreeSWITCH启动.查看.及关闭 FreeSWITCH一般安装在路径 /usr/local/freeswitch ,可执行程序位于/usr/local/freeswitch/bin 下,配置文件 ...

  3. Freeswitch Tutorial

    I. Install Freeswitch 1) FreeSWITCH Explained https://freeswitch.org/confluence/ https://freeswitch. ...

  4. FreeSWITCH的安装与使用

    FreeSWITCH

  5. fs event_socket

    mod_event_socket     Skip to end of metadata   Created by John Boteler, last modified by Niek Vlesse ...

  6. freeswitch 一些坑

    1.You must install libopus-dev to build mod_opus. Stop. 确实已经安装libopus-dev后 将文件 usr/local/src/mod/cod ...

  7. 《FreeSWITCH: VoIP实战》:SIP 模块 - mod_sofia

    SIP 模块是 FreeSWITCH 的主要模块,所以,值得拿出专门一章来讲解. 在前几章时里,你肯定见过几次 sofia 这个词,只是或许还不知道是什么意思.是这样的,Sofia-SIP 是由诺基亚 ...

  8. FreeSWITCH 加载模块过程解读

    今天来学习FreeSWITCH 加载模块过程. 哪些模块需要编译,是由源码下的 modules.conf 文件决定的. 哪些模块在程序启动时自动加载,是由 freeswitch/conf/autolo ...

  9. freeswitch新增模块API

    概述 上一章我们讲解了freeswitch的源码基本结构,以及如何新增一个插件式模块. freeswitch的架构非常适合这种业务开发模式,即以freeswitch的基本功能为开发平台,新增插件式模块 ...

随机推荐

  1. 使用T4模板生成不同部署环境下的配置文件

    在开发企业级应用的时候,通常会有不同的开发环境,比如有开发环境,测试环境,正式环境,生产环境等.在一份代码部署到不同环境的时候,不同环境的配置文件可能需要根据目标环境不同而不同.比如在开发环境中,数据 ...

  2. ABP架构设计交流群-上海线下交流会的内容分享(有高清录像视频的链接)

    点这里进入ABP系列文章总目录 ABP架构设计交流群-7月18日上海线下交流会内容分享 因为最近工作特别忙,很久没有更新博客了,真对不起关注我博客和ABP系列文章的朋友! 原计划在7月11日举行的AB ...

  3. TODO:MongoDB的查询更新删除总结

    TODO:MongoDB的查询更新删除总结 常用查询,条件操作符查询,< .<=.>.>=.!= 对应 MongoDB的查询操作符是$lt.$lte.$gt.$gte.$ne ...

  4. React Native 环境搭建

    1,安装 HomeBrew /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install ...

  5. C/S架构和B/S架构的概念和区别

    C/S 架构 C/S 架构是一种典型的两层架构,其全程是Client/Server,即客户端服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据库服务器端,客户端 ...

  6. WPF自定义RoutedEvent事件代码段

    今天在写东西的时候,发现常用的代码段里没有RoutedEvent的,因此,写了一个代码段,方便以后使用,顺便记录一下,如何做代码段. 1.在项目中新建一个XML文件,将扩展名修改为snippet. 2 ...

  7. .NET Core下的日志(3):如何将日志消息输出到控制台上

    当我们利用LoggerFactory创建一个Logger对象并利用它来实现日志记录,这个过程会产生一个日志消息,日志消息的流向取决于注册到LoggerFactory之上的LoggerProvider. ...

  8. Javascript之自定义事件

    Javascript自定义事件,其本质就是观察者模式(又称订阅/发布模式),它的好处就是将绑定事件和触发事件相互隔离开,并且可以动态的添加.删除事件. 下面通过实例,一步一步构建一个具体的Javasc ...

  9. URI编码解码和base64

    概述 对于uri的编解码,在js中有3对函数,分别是escape/unescape,encodeURI/decodeURI,encodeURIComponent/decodeURIComponent. ...

  10. MVC 传值

    1.ViewBag    Controller:ViewBag.Message = "Hello, Word";    View:@ViewBag.Message   注:View ...