1.FreeSwitch的概念
FreeSwitch是一个开源的电环交换平台,是一个跨平台的/伸缩性极好的/免费的/多协议的电话软交换平台。
1.1.FreeSwitch的特性
FreeSwitch是跨平台的。他能原生地运行于Windows、Max OS X、Linux、BSD及Solaris等诸多32/64位平台。
FreeSwitch具有很强的可伸缩性。FreeSwitch从一个简单的软电话客户端到运营商用级软交换设备几乎无所不能。
FreeSwitch是免费的。
FreeSwitch支持SIP、H323、Skype、Google Talk等多种通信协议,并能很容易的与各种开源的PBX系统通信,他也可以与商用的交换系统(如华为、中兴的交换机或思科、Avaya的交换机等)互通。
FreeSwitch可以用作一个简单的交换引擎、一个PBX、一个媒体网关或媒体支持IVR的服务器,或在运营商的IMS网络中担当CSCF或Application Server等。
FreeSwitch遵循相关RFC并支持很多高级的SIP特性,如Presence、BLF、SLA以及TCP、TLS和sRTP等,它也可以在用作一个SBC进行透明的SIP代理以支持其他媒体。
FreeSwitch支持宽带及窄带语音编码,电话会议桥接可同时支持8、12、16、24、32及48kHz的语音。
1.2.FreeSwitch的典型功能
在线计费、预付费功能。
电话路由服务器。
语音转码服务器。
支持资源优先权和QoS的服务器。
多点会议服务器。
IVR、语音通知服务器。
VoiceMail服务器。
PBX应用和软交换。
应用层网关。
防火墙/NAT穿越应用。
私有服务器。
第三方呼叫控制应用。
业务生成环境运行时引擎。
会话边界控制器。
IMS中的S-CSCF/P-CSCF/I-CSCF。
SIP网间互联网关。
SBC及安全网关。
传真服务器、T.30到T.38网关。
2.在windows上安装FreeSwitch
(1)使用安装包安装。
(2)从源代码安装。
3.连接SIP电话
FreeSwitch最典型的应用是作为一个服务器,并用电话客户端软件(一般叫软电话)连接到它。虽然FreeSwitch支持IAX、H323、Skype等众多的通信协议,但其最主要的协议还是SIP。支持SIP的软电话比较常用的有X-Lite和Zoiper。
4.FreeSwitch安装目录
FreeSwitch在windows上的默认安装位置是C:\Programming Files\FreeSwitch。
5.配置FreeSwitch
FreeSwitch配置文件默认是放在conf/下,它由一系列XML配置文件组成。最顶层的文件是FreeSwitch.xml,系统启动时它一次装入其他一些xml文件并最终组成一个大的XML文件。
基本的目录结构和主要配置文件如下:
6.FreeSwitch总体架构
总的来说,FreeSwitch由一个稳定的核心(Core)及一些外围模块组成、这些外围模块根据其功能和用途的不同又分为Endpoint、Codec、Application等不同的类别。
FreeSwitch内部使用线程模型来处理并发请求,每个连接都在单独的线程中进行处理,不同的线程间通过Mutex互斥访问共享资源,并通过消息和异步事件等方式进行通信。这种架构能处理很高的并发,并且在多核环境中运算能均匀分布到多颗CPU或单CUP的多个核心上。FreeSwitch的核心非常短小精悍,这也是其保持稳定的关键。绝大部分应用层的功能都在外围的模块中实现。外围模块是可以动态加载(以及卸载)的,在实际应用中可以自加载用到的模块。外围模块通过核心提供的Public API与核心进行通信,而核心则通过回调(或称钩子)机制执行外围模块中的代码。
FreeSwitch架构示意图:
6.1. 核心
FreeSwitch的核心是Core,它包含了关键的数据结构和复杂的代码、状态机、数据库等,这些代码只出现在核心中,并保持了最大限度的抽象和重用。外围模块只能通过核心代码提供的公共应用程序接口(Public API)调用核心的功能,因而核心运行在一个受保护的环境中。
6.2.数据库(DB)
FreeSwitch的核心除了使用内部的队列、哈希表存储数据外,也可以使用关系型数据库存储数据。FreeSwitch默认使用额数据库类型是SQLite,是一种嵌入式数据库。由于SQLite会进行读锁定,因此在使用SQLite时不建议通过外部应用直接读取核心数据库。
除SQLite外系统也支持通过使用ODBC方式连接其他数据库,路MySQL、Oracle、SqlServer(需要改动一些代码)等。
6.3.公共应用程序接口
FreeSwitch在核心层实现了一些Public API。这些Public API可以被外围的模块调用。核心的代码是任何模块都可以调用的。
6.4.接口
FreeSwitch在核心中处了实现了大量的Public API供外围模块调用外,还提供了很多抽象的接口。这些接口对同类型的逻辑或功能实体进行了抽象,但没有具体的实现。具体的实现一般由外围的模块负责,核心层通过回调(钩子)方式调用具体的实现代码或函数。
6.5.事件
除了使用Public API及接口回调方式执行内部逻辑和通信外,FreeSwitch在内部也使用消息和事件机制进行进程间和模块间通信。消息机制是完全内部的。事件机制既可以是内部使用也可以外部使用。当FreeSwitch内部状态发生变化或收到一些新的消息时,会产生一些事件。事件机制是一种“生产者—消费者”模型。事件的产生和处理是异步的,是一松耦合的关系。这些事件可以在FreeSwitch内部通过绑定一定的回调函数进行捕获,即FreeSwitch的核心事件系统会依次回调这些回调函数,完成相应的功能,另外在嵌入式脚本(如lua)中也可以订阅相关的事件并进行处理。
在FreeSwitch外部也可以通过Event Socket等接口订阅相关的事件,通过这种方式可了解FreeSwitch内部发生了什么,如当前的呼叫状态。
7.接口实现
接口都是抽象的,其中只有少量在核心中有具体实现,大部分最终由外部的模块来实现。
终点(EndPoint),Endpoint是终结FreeSwitch的地方,也就是说再往外走就超出FreeSwitch的控制了。它主要包含了不同呼叫控制协议的接口。这使得FreeSwitch可以与众多不同的电话系统进行通信。
拨号计划(Dialplan),Dialplan主要提供查找电话路由功能。系统默认的Dialplan由mod_dialplan_xml提供,它是以XML描述的。
聊天计划(Chatplan)类似于Diaplan,不同的是ChatPlan主要对文本消息进行路由,他是在mod_sms中实现的。
应用程序(Application,APP),FreeSwitch提供了许多APP使复杂的任务变得异常简单,如mod_voicemail模块可以很简单的实现语音留言,而mod_conference模块则可以高质量的实现多方会议。
命令接口(FSAPI)。FSAPI简称API,他是一种对外的命令接口,他的原理非常简单—-输入简单的字符串(以空格隔开),该字符串由模块的内部函数处理,然后得到一个输出。输出可以是一个简单的字符串、一大串文本、XML或JSON文本。通过使用FSAPI一个模块可以通过命令字符串的方式调用另一个模块提供的功能,而不用连接其他模块的函数(实际上FreeSwitch不鼓励也不支持模块间的互相连接)。系统中的大部分的API都是由mod_commands模块提供的,有的模块实现了一些与本模块相关的API。
XML接口(XML Interface)。XML接口支持多种获取XML的方式,它可以从本地的配置文件或数据库中的读取,甚至可以从一个能动态返回XML的远程HTTP服务器中读取。对XML的解析和访问时在核心中实现的,当对XML的应用和扩展都是在外部模块中完成的。
编解码器(Codec)。FreeSwitch支持最广泛的Codec,它可以同时桥接不同采样频率的电话以及电话会议等。
语音识别及语音合成(ASR/TTS)支持语音自动识别(ASR)及文本/语音转换(TTS)。可以通过本地模块实现也可以通过MRCP协议与其他语音产品对接实现。
格式、文本接口(Formate,File Interface)。支持不同格式的声音文件回访、录音、如WAV、MP3等。mod_sndfile模块通过libsndfile库提供了对大部分音频文件格式的支持。MP3格式是在mod_shout中实现的。
日志(Logger)。日志可以写到控制台、日志文件、系统日志以及远程的日志服务器。实现日志功能的模块有mod_console、mod_logfile、mod_syslog等。
定时器(Timer)。实时的语音通话需要非常准确的定时器。在FreeSwitch中可以使用软时钟或内核提供的时钟来定时。FreeSwitch最理想的工作时钟频率是1000Hz。
嵌入式语言(Embeded Language)。通过swig可支持多种嵌入式语言进而控制呼叫流程,如Lua、Perl等。
事件套接字(Event Socket)。通过Event Socket可以使用任何其他语言(只要支持socket),通过TCP Socket可控制呼叫流程、扩展FreeSwitch的功能。
8.FreeSwitch事件系统命令及使用
1)FreeSwitch添加一个用户
FreeSwitch默认设置了20个用户(1000~1019),天机用户只需要三步:
① 在con/directory/default/中添加一个用户配置文件
② 修改拨号计划(Dialplan)使其他用户可以呼叫到它。
③ 重新加载配置使其生效。
2)hupall
用于挂断呼向指定号码的通话。参数为:
clearing_type dialed_ext
举个例子来说,杀掉正处于活跃状态、目标号码是1000的通话,命令为:
fsctl hupall normal_clearing dialed_ext 1000
3)pause
可以使用参数inbound或outbound来暂停创建呼入或呼出通话,如果没有指定参数的话,则呼入呼出都暂停。resume的用法类似。
4)group_call
返回组呼bridge字符串,组呼定义请参考[[XML User Directory
Guide#Groups|call group]]。
Usage: group_call group@domain[+F][+A][+E]
+F将会以串行呼叫模式返回组成员(以“|”隔开各成员). +A将会以并行呼叫模式返回组成员(以“,”隔开各成员). +E将会议呼叫模式返回组成员(以:_:隔开各成员),关于企业呼叫请参考[[Freeswitch_IVR_Originate#Enterprise_originate|enterprise fashion]].
请注意:如果你需要设置在外呼通道上面设置用户变量,需要确保你的domain或被拨打组的变量列表里面没有设置dial-string和group-dial-string,用设置用户默认组里面的dial-string和group-dial-string来替代。这样的话,group_call将会返回user/101,user/将会设置你的外呼通道变量。
api group_call sales@192.163.20.79+E
5)in_group
判断用户是否在指定的组中。
用法: in_group <user>[@<domain>] <group_name>
6)create_uuid
创建一个新的UUID,并以字符串的形式返回。
用法: create_uuid
7)originate
发起一个新的呼叫
Usage: originate <call_url> <exten>|&<application_name>(<app_args>)
[<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>]
8)pause
停止指定通道的媒体播放
用法: pause <uuid> <on|off>
9)uuid_broadcast
在一个指定UUID的信道上执行任意一个拨号方案程序。如果指定了某录音文件名,则代表将会在该信道上播放该文件。 执行拨号方案程序的语法规则是“app::args”。
用法: uuid_broadcast <uuid> <path> [aleg|bleg|both]
在选定的腿上执行应用程序,执行完毕后挂断,并指明挂机原因。
用法: uuid_broadcast <uuid> app[![hangup_cause]]::args [aleg|bleg|both]
10)uuid_answer
应答
用法: uuid_answer <uuid>
11)uuid_audio
调整信道上面的音量,或直接通过一个媒体bug进行静音(读/写)。
用法: uuid_audio <uuid> [start [read|write] [mute|level <level>]|stop]
level的值范围从-4到4,默认值为0。
12)uuid_chat
发送聊天信息。
用法: <uuid> <text>
如果和会话(session,由uuid指定)相关的终端有一个receive_event handler,该消息会被发往终端,并以及时消息的形式显示出来。
13)uuid_exists
检查给定的uuid是否存在。
用法: uuid_exists
14)uuid_hold
保持通话。
用法:
uuid_hold <uuid> 保持通话
uuid_hold off <uuid> 结束保持,恢复正常通话
uuid_hold toggle <uuid> 在保持和取消保持间切换
15)uuid_kill
重置(杀掉)指定的信道。
用法: uuid_kill [cause]
16)api originate user/1000 &bridge(user/1003)
桥接两个用户
17)filter
指定监听的事件类型。一个套接字连接可以支持多个filters。
注意,这个命令实际上是筛选出事件,不是过滤掉这些事件。 (参考nixevent部分。)
设置多个filters可以更加精确地获得用户希望看到的事件类型。
语法: filter <EventHeader> <ValueToFilter>
18)nixevents
这个命令正好和filter相反,它禁止接收一个指定类型的事件 。
nixevents <event types | ALL | CUSTOM custom event sub-class>