第一章 FreeSWITCH 的架构

FreeSWITCH 的架构

        欢迎来到FreeSWITCH的世界!如果您正在阅读本书,那么您可能对这些事务感兴趣:实时通信、WebRTC、电信、VoIP。Freeswitch是一个完整的应用服务器和一个灵活的工具集,在全球范围内用于构建先进的和未来可靠的通信应用程序。在研究这个功能强大的软件的架构之前,让我们先回顾一下电信的世界。这将有助于您把FreeSWITCH纳入视野。

    在这一章里,我们将涉及以下内容:

  1. 通信的双重革命
  2. FreeSWITCH的优势
  3. 终端(Endpoint)和拨号方案(Dialplan)模块
  4. FreeSWITCH是如何简化诸如voicemail和视频会议这样的复杂应用的。

 

没什么神秘的实时通信

        实时通信(Real-time communication (RTC))始于19世纪下半页电话的发明,几乎立刻演变成一个由大公司和基础设施组成的 全球互联网络。

        直到几年前,电话还是一座由大公司严格把守的带围墙的堡垒,几乎没有人能完全理解它是如何运作的。通过参加内部技术研讨会和内部学校,你有机会获得这些深奥的知识,甚至这些知识也仅限于你要工作的系统部分(中央办公室、最后一英里、PBX等)。承载和路由呼叫的基础设施以及应答和管理呼叫的应用程序都是临时的、僵化的、彼此不兼容的,并且需要大量的投资。

        两次革命彻底摧毁了旧世界。第一次是VoIP电话革命,它带来了一个开放协议(SIP),首先革新的是应用程序/PBX领域,然后是基础设施领域。原有体系中,有一个专用的PBX,它只能通过更换同一家公司生产的内部硬件卡来扩展,只提供自己的类型和型号的硬件电话。变革后,它被标准PC架构的标准服务器取代,使用现成的扩展卡,能够支持任何类型的标准兼容电话。紧接着,SIP从下到上爬到了大型电信基础设施的核心。今天,包括大型电信公司和运营商在内的所有电信基础设施都在运行SIP协议的某些版本。

        第二次革命,现在正在进行,还需要几年才能完成并取得成果,它就是WebRTC。这是一个误导性很强的名字,WebRTC根本不需要web页面和浏览器。WebRTC是一系列用于通信终端间加密互联的标准。只不过这些WebRTC标准正好首先在浏览器中实现而已。与此同时,它已成为物联网的主流通信方式,从智能手机应用到汽车、电梯、商店出纳和销售点。

        如今,我们有可能建立一个比传统的语音、视频和会议服务更好的通信系统,并以相对低廉的成本提供现高级的功能。Freeswitch的设计就是为了让所有这些变得更简单,我们将仔细研究它的架构,以便更好地理解它是如何工作的。

        如果你不能一下子掌握所有内容,不必担心。学习需要时间,尤其是RTC和VoIP。事实上,我们建议您反复阅读这一章的内容。第一次通读时尽可能多地吸收,然后在读完第6章XML拨号方案后再回头。你会惊讶于你对FreeSWITCH的理解有多大的提升。然后,在读过第10章(拨号方案、目录、通过XML_CURL和脚本实现一切)之后,回来第三次浏览它,您将牢固掌握FreeSWITCH的概念。给自己一些时间去消化这些概念,您将成为熟练的FreeSWITCH管理员。

        今天,我们生活在多种实时通信技术的生态系统中,它们同时共存:电话系统(如电话交换机和PBX)、传统的模拟电话(POTS线路或普通的老式电话服务)、运营商运营的传统电话网(PSTN或公共交换电话网)、移动电话(CDMA、GSM、LTE等)、传真、WebRTC、智能手机应用程序、VoIP电话和企业系统。

        FreeSWITCH就位于这些生态系统的中心:它连接并接受来自所有这些技术的连接,将它们桥接并混合在一起,它为用户提供交互应用和服务,无论他们的终端是什么类型的。FreeSwitch能够连接到外部数据服务、遗留的内部系统、计算机程序和业务程序等等。FreeSWITCH是跨平台的,可以运行在Linux、Windows、Mac OS X、BSD和Solaris上。我们有很多硬件可以选择,从大型服务器到Raspberry Pi都支持。因此,您可以在您的笔记本上开发,然后把它部署到数据中心或嵌入式设备上。第2章详细描述了FreeSWITCH的安装部署过程。

 

FreeSWITCH设计-模块化、可扩展和稳定性

 

        FreeSWITCH的设计目标是提供一个模块化的可扩展的系统,围绕一个稳定的交换内核,为开发人员添加和控制系统提供一个强大的接口。Freeswitch中的各种元素彼此独立,除了“Freeswitch API”中提供的内容外,对其他模块的工作方式没有太多的了解。Freeswitch的功能可以通过可加载模块进行扩展,这些模块将特定功能或外部技术绑定到核心中。

        在FreeSWITCH中,有许多不同类型的模块围绕着内核,就像一个机器人的大脑连接着许多传感器和接口一样。这些模块的类型列表如下:

 

模块类型

用途

Endpoint终端

电话协议,比如SIP,PSTN。

Application应用

执行某种任务,比如播放音频,发送数据。

Automated Speech Recognition ( ASR ) 自动语音识别

语音识别系统的处理接口

Chat聊天

桥接交换各种聊天协议。

Codec编解码

在音频编码格式间相互转换。

Dialplan拨号方案

解析话务详情,并决定话务路由。

Directory目录

连接内核查询与目录信息服务(比如LDAP)的API

Event handlers事件处理

允许外部程序控制FreeSWITCH。

File文件

提供一个用于提取和播放各种格式音频文件的接口。

Formats格式

播放各种格式的音频文件

Languages语言

用于控制话务的编程语言接口。

Loggers

日志控制接口,输出到控制台、系统日志或日志文件。

Say

将各种语言的音频文件串在一起,以提供反馈,以便说出电话号码、一天中的时间、单词拼写等内容。

Text-To-Speech (TTS)

TTS引擎的接口。

Timers

应用程序中的POSIX或Linux内核时钟。

XML Interfaces

XML接口,用于CDR、CURL、LDAP、RPC等。

 

 

        下图体现了FreeSWITCH的架构和FreeSWITCH的内核与外围模块的关系:


        通过组合各种功能模块,可以把FreeSwitch配置为IP电话、POTS线路、WebRTC和基于IP的电话服务。它还可以转换音频格式,自定义交互式语音菜单(IVR)系统。还可以从另一台计算机控制FreeSwitch服务器。接下来,我们介绍两个重要的模块。

 

重要模块—终端和拨号方案

        终端模块是非常重要 ,正因为它实现了一些关键功能,才使FreeSWITCH成为强大的平台。终端模块的主要功能是采用某些公共的通信技术,并将它们规范化为一个公共抽象实体,我们称之为会话(session)。一个会话描述了FreeSWITCH和一种特定协议间的连接。FreeSWITCH附带了几个终端模块,它们实现了几种不同的协议,如SIP、H.323、Jingle、Verto、WebRTC和其他一些协议。我们将花点时间来解释其中一个最为流行的模块,它的名字叫mod_sofia。

        Sofia-SIP (http://sofia-sip.sourceforge.net)是一个开源项目,最早由诺基亚开发,它提供会议初始化协议(SIP)的接口实现。Freeswitch开发人员对它进行了大量的开发和修复,进一步增强了其健壮性和特性。在FreeSWITCH中我们使用自己的定制版本库(/usr/src/freeswitch/libs/sofia-sip),这是通过一个名为mod_sofia的模块实现的。这个模块注册FreeSwitch所需的所有必要钩子,以生成终端模块,它将FreeSwitch的原生结构转换为Sofia SIP结构,反之亦然。配置信息取自freeswitch配置文件,这使mod_sofia可以加载用户定义的首选项和连接详细信息。它允许FreeSwitch接受来自SIP电话和设备的注册,可以向其他SIP服务器(如服务提供商)注册,发送通知,并为话机设备提供服务(如亮灯和语音邮件服务)。

当FreeSWITCH与其它SIP设备建立一个SIP音/视频通话时,这个通话在FreeSWITCH里表现为一个活跃的会话。如果通话是呼入的,它可以被转移或桥接到IVR菜单、保持音乐(音频或视频的),或其它分机。或者,它可以被桥接到一个新的外呼话务,连接PSTN线,或WebRTC浏览器。让我们研究一个典型的场景,一个内部注册的分机2000,拨打2001分机,希望建立通话。

        首先,SIP话机通过网络向FreeSWITCH发送一条建立通话的消息(mod_sofia时刻监听这类消息)。收到消息后,mod_sofia反向解析相关细节,建立一个内核能够理解的抽象呼叫会话数据结构实例,并将它传递给FreeSWITCH的内核状态机。然后状态机迁移到ROUTING状态(意味着正在寻找目的地)。

        内核的下一步是根据呼叫终端的配置数据确定拨号方案模块。XML拨号方案模块是缺省的和使用最广泛的模块。这个模块的设计逻辑是从FreeSWITCH内存中的XML树查找一系列指令集。XML拨号方案模块会用正则表达式匹配来解析一系列的XML对象。

        当我们正尝试呼叫2001时,会在XML节点中寻找一个destination_number字段与2001相匹配的分机。此外,我们要记住拨号方案并没有限定只能匹配一个分机。一个呼叫在拨号方案中允许有多个匹配,在第6章,XML 拨号方案主题里,您将会得到分机这个术语的扩展定义。XML拨号方案模块会为呼叫建立一个TODO列表。每个匹配的分机将它的操作要求添加到呼叫的TODO列表中。

        假设FreeSWITCH至少找到一个条件匹配的分机,XML拨号方案模块将会向会话对象中插入指令,其中包含尝试呼叫2001所需要的信息(建立这个呼叫的TODO列表)。一旦指令就绪,呼叫会议的状态会从ROUTING迁移到EXECUTE,内核将钻取列表,并逐个执行ROUTING状态下所堆积的指令。这就是API发挥作用的地方。

        每条指令都以一个命名application形式添加到会话中,可以向application传递一个data参数数据。在本例中,我们将会用到bridge app。这个app的作用是创建一个新的会话,建立外呼连接,然后把两个会话连接在一起进行音频数据交换。我们将给bridge提供一个参数:user/2001,这是生成内部注册分机呼叫电话对象的最简单方式。针对2001的拨号方案条目,看起来是这样的:

<extension name="example">

<condition field="destination_number"

expression="^2001$">

<action application="bridge" data="user/2001"/>

</condition>

</extension>

 

        这个分机被命名为example,它有一个单一的匹配条件。如果条件匹配成功,它需要执行一条单一的app。可以理解为:如果主叫方拨打2001,那么将在主叫方与终端间建立一条连接

        一旦指令在会话的TODO列表中插入完毕,会话的状态立刻迁移到EXECUTE,FreeSWITCH内核将开始使用所搜集到的数据执行所需的操作。它首先解析列表,发现它必须对user/2001执行bridge;接下来,查找bridge app,并将参数user/2001传递给它。这将导致FreeSWITCH内核按所需类型创建一个新的外呼会话(也就是一路呼叫)。我们假定2001分机的用户用一个SIP电话注册到FreeSWITCH ,那么user/2001将被解析为一个SIP拨号串,这个拨号串将被传递给mod_sofia,请求建立一个外呼会话(指向2001的SIP话机)。

        如果新的会话建立成功,那么FreeSWITCH内核中将会存在两个会话:新建会话和原始会话(主叫侧建立的会话)。Bridge app将会接管这两个会话,将对它们调用bridge函数。在被叫接听后,bridge调用将使音频和/或视频流在双向间流动。如果用户不能应答或正忙,会触发超时(也就是呼叫失败),那么会给主叫话机回传一条失败消息。如果一个电话无人应答或分机占线,拨号方案中可以有许多种不同的响应,其中包括呼叫转接或语音信箱。

        FreeSWITCH继承了SIP的所有复杂性,并将其简化为一个公共的(内部的)接口。然后通过允许我们使用拨号方案中的一条指令将2000分机的电话连接到2001分机的电话,进一步降低了复杂性。如果我们还想让2001分机能够呼叫2000分机,我们可以在拨号方案中添加另一个条目:

<extension name="example 2">

<condition field="destination_number" expression="^2000$">

<action application="bridge" data="user/2000"/>

</condition>

</extension>

        在这个场景中,终端模块(mod_sofia)把呼入的SIP呼叫转换为FreeSWITCH会话,而拨号方案模块(mod_dialplan_xml)把XML转换为分机。然后,bridge app(由mod_dptools模块提供)把复杂的外呼和连接媒体流的过程,变成了一个简单的应用/数据对。拨号方案模块和app模块接口都是围绕FreeSWITCH会话设计的。抽象不仅让用户层的工作变得更容易,而且还简化了app和拨号方案的设计,因为它可以使呼叫过程中涉及的终端技术细节透明化。正是由于这种抽象技术,当明天我们为三维全息通信网络编写一个新的终端模块时,我们将能够重用所有的app模块和拨号方案模块。对于FreeSWITCH内核和其它所有FreeSWITCH模块来说,仅是多了一种全息三维呼叫方式,它也仅仅是一个标准的会话抽象而已。您可能希望使用终端的协议提供的一些特定数据。比如说在SIP协议中,包含了几个特定的头域或其它一些有趣的数据,您可能希望获取这些特别的信息。我们通过向通道(channel,会话结构中与终端交互的部分)添加变量来解决这个问题。使用通道变量,mod_sofia可以创建在SIP数据中遇到的任意值,您可以在拨号方案或app中通过变量名检索这些值。这些最初是底层SIP消息的特定(任意)部分,然而,FreeSWITCH内核只是将它们视为内核可以忽略的普通通道变量。此外,还有一些特殊的保留通道变量,它们可以以许多有用的方式影响FreeSWITCH的行为。如果您曾经使用过某种脚本语言或配置引擎,而且它们有变量的概念(有时叫属性值AVP),那么通道变量的概念和它们几乎是一样的。它们仅是一个简单的名字与值的配对,可以传递给通道,可以设置数据值。有一个用于设置通道变量的app叫set,在拨号方案中,我们可以用它设置自己的通道变量:

<extension name="example 3">

<condition field="destination_number" expression="^2000$">

<action application="set" data="foo=bar"/>

<action application="bridge" data="user/2000"/>

</condition>

</extension>

 

        这个例子与之前的几乎相同,只是在外呼之前,我们将通道变量foo的值设置为bar。这个变量会一直保留到呼叫结束,甚至可以在呼叫结束后的CDR中引用它。

        用小块构建的东西越多,可以重用的相同底层资源就越多,从而使整个系统的使用变得更简单。例如:codec接口,除了它自己世界中的音视频包编解码之外,对内核的其它内容一无所知。一旦写了某个特定的codec模块,任何可以携带相应媒体流的终端接口都可以直接使用它。这意味着,如果我们有一个文语转换(TTS模块可以工作,那么我们就可以在所有的FreeSWITCH支持的终端上生成合成的语音。如果系统支持更多的codec,TTS也会变得更有用;反过来,如果我们添加一可以使用某个codec的功能,也会使对应的codec模块变得更有价值。如果我们写了一个新的app模块,现有的终端立刻就能运行和使用这个app。

 

复杂应用的简单化

FreeSWITCH从高级应用程序中消除了很多复杂性。让我们看两个更复杂applications示例

 

Voicemail

        我们首先讨论的是voicemail应用。这个应用可以添加在bridge后,在呼叫未能完成时完成,以提供一种有用的话务处理选择。我们可以通过一个特定变量来实现这个功能。让我们看一下最新的分机处理版本,它允许我们进行语音留言:

<extension name="example 4">

<condition field="destination_number" expression="^2000$">

<action application="set"

data="hangup_after_bridge=true"/>

<action application="bridge" data="user/2000"/>

<action application="voicemail"

data="default ${domain} 2000"/>

</condition>

</extension>

 

        在这里,我们用到了两个通道变量。第一个是hangup_after_bridge=true,它告诉系统,如果我们成功桥接呼叫,那么通话结束后就直接挂机,忽略掉其余的指令。我们还引用了domain变量,其语法是以一个$符引导的一对花括符:${domain}。这是一个特殊的变量,默认为自动配置的域名,它来自XML配置。

        在这个实例中,我们首先检查被叫号码2000。如果有人拨打2000,那么尝试桥接注册2000分机的的终端。如果呼叫失败,或者没应答(比如说,bridge尝试失败了,我们不要在bridge后直接调用hangup),我们将继续执行下一条指令,在这里就是voicemail app。我们提供app需要了解的信息(例如,语音邮件属于哪个域)和语音邮件所属的分机号,以便app知道如何处理。接下下,voicemail app播放预先录制好的欢迎辞,或者通过我们之前简单讨论过的Say模块的接口生成一个欢迎辞。然后,它将一串播一些组合的简短语音文件来做一些提示,听起来像这样:拨的分机2000暂时不可达,请留言。接下来,mod_voicemail提示您录制一条消息。作为一个附加功能,如果您对自己的录音不太自信,您可以先试听,不满意的话重新录制,次数不限。一旦您最终提交信息,会触发一个FreeSWITCH MESSAGE_WAITING事件,事件将在内核事件队列中排队,mod_sofia作为事件消费者,将拾回这个事件,转换为SIP格式(SIP NOTIFY)的消息发送给SIP电话,通知终端有新的语音邮件生成。接收终端上会有一个亮灯(MWI)事件以提醒用户。

        在这个实例中,我们不仅看到了系统是怎样播放欢迎辞、录制消息并为用户转换为语音邮件的,还接触到了FreeSWITCH内核的一个重要组成部分—事件系统。和之前的模块接口不同,FreeSWITCH事件系统不是额外接口,它是一个核心引擎特性,您可以使用它绑定自己的命名事件,并在接收到事件时做出相应的反应。模块可以绑定到(即侦听)各种事件。它们还可以将事件触发到事件引擎中;其他模块可以监听这些事件。您可以将其视为类似于其他排队系统,如RabbitMQ(实际上,有一个模块将FreeSwitch的内部事件系统与RabbitMQ对接,因此您可以将其集成到企业排队系统中,或让多个FreeSwitch服务器成为同一个大型分布式队列的一部分)。正如我们所讨论的,Sofia SIP模块绑定(订阅)MESSAGE_WAITING消息所指定的事件。这允许mod_voicemail模块与mod_sofia交互,而不需要任何一个系统了解另一个系统的存在。该事件是由mod_voicemail触发(fire和forget,军事术语),由mod_sofia拦截,并翻译成适当的SIP消息。

        考虑到所有可能需要支持的语言,以及自动消息播放什么文件,如何将它们串在一起时,这样一个复杂的声音串接系统存在几个挑战。Say模块提供了一种将文件串在一起的好方法,但它仅限于某些特定的内容,例如拼写单词、计数,或说出某个日期。我们克服这一点的方法是在Say模块上定义一个更复杂的层,称为短语宏。短语宏是XML表达式的集合,通过匹配正则表达式并执行一系列命令来拉出参数列表。这与XML拨号计划的工作方式非常相似,只是为IVR场景定制的。例如,当mod_voicemail要求您录制消息时,不需要在文件的字符串中编码,使其说出您所需要的内容,而只需要在代码中调用一个名为voicemail_record_message的短语宏。在XML配置的短语宏部分中定义了一系列的声音片段,允许我们(管理员)在不修改语音邮件IVR程序的情况下编辑短语:

<macro name="voicemail_record_message">

<input pattern="^(.*)$">

<match>

<action function= "play-file"

data="voicemail/vm-record_message.wav"/>

</match>

</input>

</macro>

 

        当mod_voicemail调用voicemail_record_message宏时,它首先匹配模式,在本例中,模式将匹配所有内容,因为输入内容对这个特定的宏没有用处(即,无论您给它什么输入,都不使用)。如果宏确实使用了输入,则模式匹配可用于根据不同的输入播放不同的声音片段。一旦找到匹配项,XML的匹配标记就会被解析为动作标记,就像我们拨号方案示例中那样。这个宏仅执行一个动作:播放vm-record_message.wav文件,但是更复杂的宏,例如用于验证录制或告诉您收件箱中有多少条消息的宏,可能会使用各种Say操作的组合并播放许多不同的音频文件。在第6章,XML拨号方案和第8章,Lua FreeSWITCH脚本中将继续讨论短语宏的细节。

 

        在这里,我们也可以看到freeswitch架构的各个部件之间的协作:短语系统、音频文件和内核加载的Say模块一起使用,以实现强大的功能。Say模块专门为语言中的特定语言或语音编写。我们可以通过编程请求说出当前时间,并根据输入变量通过特定的Say模块将其翻译成西班牙语或俄语声音。短语宏系统是将一个抽象层放入代码中的一种很好的方法,系统管理员可以轻松地对其进行调整。例如,如果我们想做一个小的IVR,要求我们拨一个四位数的号码,然后把它读回来,最后挂断,我们可以定义一个名为myapp_ask_for_digits的宏,再定义一个名为myapp_read_digits的宏。在我们的代码中,将按名字执行这些宏—前者在要求输入时调用,后者在读取并回传输入信息时调用。一旦一切就绪,经验不足的个人(例如,本地管理员)就可以通过编辑XML文件来播放正确的声音。她可以使用Say模块读回数字,不需要进一步编码,就能适应多种语言。Voicemail只是使用FreeSwitch作为应用服务器的一个例子。当我们使用freeswitch连接实时通信的计算机时,有无限的可能性。

 

多方音/视频会议

        FreeSWITCH的另一个重要特性是由mod_conference会议模块提供的。mod_conference提供动态的会议室,可以把几个音视频用户桥接到一块。它可以将视频流混合在一起,对它们应用GC(计算机图表学)转换。例如将不同的与会者实时地组合在一起,而不是将带有名称和角色的标题强加给每个用户的视频流;共享每个与会者的屏幕(比如PowerPoint演示文稿),等等。此外,可以在会议中添加实时聊天,这样与会者可以在主音频/视频的带外交换文本信息。显然,这个模块也可以用于普通的音频电话会议。

        每个连接到同一会议室的新会话都会彼此联合,并马上能够彼此交谈和看到其他所有与会者(根据会议管理员的心血来潮,可以选择谁可以显示,谁可以发言,等等)。用一个和电话桥接类似的实例来说明一下,我们可以通过一个分机来加入一个会议室:

<extension name="example 4">

<condition field="destination_number"       expression="^3000$">

<action application="conference" data="3000@default"/>

</condition>

</extension>

 

        这个例子和普通呼叫格拉一样简单,除了调用的app变成conference之外,似乎没什么不同,conference app允许许多人同时呼叫某个分机(本例中的3000),并把所有通道桥接到同一个会议室。如果三个人加入这个会议后,其中的某个人决定离开,另外的两个人可以继续他们的交谈。

        会议模块还具有其他特殊的功能,例如向与会的全体人员播放声音或视频文件,发送TTS消息,甚至可以向特定成员定向发送。正如您可能已经猜到的,我们可能通过TTS和它们各自模块提供的视频/音频文件接口来实现这个功能。小块功能集成在一起扩展功能,不需要彼此了解对方的实现。

        会议模块还以另一种方式使用事件系统,即所谓的自定义事件。当它第一次加载时,模拟可以保留一个称为subclass的特殊事件名字空间。当一些有趣的事情发生时,比如一个用户加入或离开会议时,它在内核队列的CUSTOM事件通道上触发这些事件。如果我们对这类事件感兴趣,我们所需要做的的只是通过一个额外的subclass串订阅CUSTOM事件,这个串指定了我们所感兴趣的CUSTOM事件。在这个例子中,它是conference::maintenance。

          这使得人们可以注意一些重要的事情,例如某人加入或离开会议,他们开始和停止交谈,他们显示在视频上,或者当前正在使用什么视频布局(屏幕配置)。会议将在第13章会议和WebRTC视频会议中详细讨论。

FreeSWITCH API 命令 (FSAPI)

        FreeSWITCH的另一个强大的概念是FSAPI。大部分API命令由mod_commands模块实现,几乎所有其它模块都会添加一些可以通过FSAPI执行的命令。FSAPI的机制非常简单,它以一个字符串作为输入,可以解析,也可以不解析,并执行一个特定的操作。返回值也是个字符串,它可以是任意长度的字符串,从单个字符到几页的文本都可以,这取决于API调用输入所指定的功能。FSAPI的一个最大的是一个模块可以使用API调用另一个模块中的程序,而不需要直接链接实际编译的代码(从而避免突然的不兼容性和崩溃)。最令人惊叹的例子是FreeSWITCH的CLI命令行接口工具,它使用FSAPI功能传递FreeSWITCH API命令。

这里我们看一个简单的小例子:怎么在FreeSWITCH CLI 上执行FSAPI命令status,


        当我们输入status并按下回车键时,发生了些什么事情呢?关键字status用于从实现模块中检索status  FSAPI函数,然后调用基础函数(如果有参数则同时传递,本例中不带参数),接下来,内核查询状态消息。一旦获取到状态数据,马上写入到一个输出字符串流中。

        我们已经了解到一个模块可以创建和导出FSAPI函数,这些API可以在任何地方被调用执行,比如CLI。但其实还有更多的内容。模块可以通过FSAPI接口执行命令,然后通过某种特定协议发送执行结果。FreeSWITCH中有两个模块实现了这样的功能,它们是mod_xml_rpc和mod_event_socket(在第10章和第11章中将分别讨论这两个模块)。考虑mod_xml_rpc的例子,它作为FreeSWITCH的一个模块,实现标准的XML-RPC协议(通过XML进行远程过程调用)。任何使用XML-RPC标准接口的客户端,都可以连接到FreeSWITCH并执行FSAPI命令。因此,一个远程客户端可以通过RPC调用来执行status命令,并获取一个类似我们前面例子所示的状态消息。这个模块还为FreeSWITCH提供了一个WEB服务,允许直接通过URL链接访问并执行FSAPI命令。比如说,我们可以打开浏览器,通过http://example.freeswitch.box:8080/api/status直接执行status命令。通过这项技术,可以创建与CGI类似的FSAPI命令,为动态WEB应用提供访问FreeSWITCH内部的接口(关于HTTP集成的更多高级内容,请参考第12章中HTTTPAPI的描述)。

        如我们所示,FSAPI接口是多功能的。现在,我们知道它可以用于提供CLI接口;可以提供模块间互相调用函数的方式;提供了导出HTTP或XML-RPC功能的方式。但还有一种FSAPI功能我们没提及。之前我们简要介绍过通道变量的概念,注意到我们可以通过表达式${myvariable}来获取通道变量的值。FSAPI函数也可以通过这样的格式调用:${myfunction()}。这个符号表示调用FSAPI命令myfunction,并且获取该函数调用的输出。因此,我们可以在任何地方使用${status()}来获取状态信息,并将其赋值给某个变量。例如:

<action application="set" data="my_status=${status()}"/>

变量my_status的值将变成status命令的输出内容。

        大部分FSAPI命令可以使用刚才讨论的方式轻松访问。但是有些命令只有在通过特定方法访问时才有意义。例如,如果我们生成了一个FSAPI命令,该命令生成了一个要通过Web浏览器访问的HTML,那么我们可能不希望通过CLI或变量引的方式访问它。但是,千万不要说“不”,在某些情况下,它是有用的,您可以灵活地执行它。

XML登记表

        我们讨论了许多FreeSWITCH内核的基本基本组件,并描述了它们间是如何相互作用的。我们已经见识到事件系统是如何跨越内核将信息携带给模块的;也了解了XML拨号方案是如何查询XML登记表中的数据的。现在,是进一步了解XML登记表的一个良好契机。XML登记表是一棵XML树文档,它保存了FreeSWITCH正常运行所需要的所有关键数据。FreeSWITCH从硬盘加载文件,并将它传递给它自己的预处理器,从而构建这个文档。这个预处理器能够包含其它XML文档,并执行一些其它特殊操作,比如设置全局变量。当文档树的其它内容引用到全局变量时,将由FreeSWITCH解析。当整个文档所有包含文件解析替换完毕后,最终生成一个静态的XML文档,这个最终的静态文档(替换了所有的全局变量)将被加载到内存中。XML登记表(树)被分成几个部分:配置、拨号方案、目录、聊天计划、语言、短语等等。内核和模块从配置部分提取它们的配置信息。XML拨号方案模块从拨号方案部分提取数据信息。SIP和Verto的身份鉴权信息、用户查找和语音邮件的帐号信息,这些都取自目录(directory)部分。短语宏从短语部分提取它们的配置信息。如果我们改变了磁盘中XML文件的任何内容,我们可以从CLI执行reloadxml命令修改内容加载到内存中。如果我们修改了某个全局变量的值,那么仅执行reloadxml是不够的,这时需要重启FreeSWITCH才能生效。

 

脚本语言模块

        脚本语言模块将某种编程语言嵌入到FreeSWITCH中,脚本运行时与FreeSWITCH内核直接传递信息,支持的语言有Lua、JavaScript、Perl、C#等等。这允许用脚本语言编写IVR这样的应用,然后回到FreeSWITCH,通过一个简单的接口完成所有繁重的工作。通常情况下,语言模块通过应用接口和FSAPI接口注册到内核,然后由拨号方案执行。语言模块提供了很多机会,而且非常强大。使用语言模块,您可以用您熟悉的标准编程语言构建强大的实时通信应用程序,使用语言的库的固有接口进行数据操作。

 

演示配置

        立刻理解所有这些概念并不容易,作为软件的维护人员,我们并不希望大多数人仅是点点鼠标就能完成所有工作。这就是在内核之上每放置一个新层都使事情变得简单易学的主要原因。FreeSWITCH的demo配置文件是软件新用户和所有疯狂、复杂、有时甚至是彻底邪恶的东西(通常称为实时通信)之间的最后一道防线。我们非常努力地从这些事情中拯救用户。

        FreeSWITCH提供Demo配置文件的主要目的是展示数百个参数的协调工作。将它们以一种工作配置的方式呈现在您的眼前,您可以在尝试改变一些选项之前,先保持原样试试水。把FreeSWITCH想象成乐高玩具一样。Freeswitch和它所有的小部件就像一桶全新的乐高积木,有很多部件可以用来建造我们能想象的任何东西。Demo配置文件就像您在乐高说明书里找到的宇宙飞船。它包含了逐步的指令说明,具体教您如何构建您想要的东西。积累一定经验后,您可以开始修改您的乐高船以获得一些扩展功能,或者干脆重新组装组件,打造一辆轿车还是其它物品。显然,您可以不使用该配置中内置的大多数功能,而只使用在特定部署中有用的功能。关于FreeSWITCH的好消息是它不是盒装的商品,因此,和乐高积木桶不同的是,如果您感到沮丧并将它砸得粉碎,也不需要重头构建它,只需要重装缺省的配置文件就行。我们将在第3章详细讨论demo配置文件。

         只要安装了FreeSWITCH,您不需要修改任何配置就能直接开始运行它。您可以立即将一个SIP电话或基于软件的SIP软电话指向服务器的地址(无论是您的笔记本电脑、虚拟机、48核服务器、Raspberry PI或Amazon实例),进行测试呼叫,并访问FreeSWITCH的所有功能。与其它协议的对接将需要一些额外的配置(比如WebRTC需要安装SSL证书),但最终的结果将完全相同。如果您有多部话机,使用缺省配置文件,您可以为每部话机分配一个分机号,在Demo配置中预定义的分机范围是1000—1019。话机注册之后,您可以在它们之间相互呼叫,或者,拨打3000—3399间的同一个号码,召集一个电话会议。如果您拨打一个没有注册的分机,或者让被叫话机振铃超时,那么短语系统将会处理语音留言,提示您对方不可达,并请您留下留言信息。如果您拨打5000,您会被接入到一个IVR系统实例,展示几个菜单选项,演示FreeSWITCH可以做的一些简洁的事情。在保持演示配置完整的同时,可以对其进行许多小的变更和扩充。

        例如:使用之前讨论的预处理器,演示配置从特定位置加载了一序列文件到XML登记表中,这意味着特定文件夹中的每个文件都将被组合到最终的XML文档中。其中最重要的两个点是存储用户账号和拨号方案分机的地方。缺省情况下,预配置的20个分机,每个都有其对应的独立文件。我们可以轻松地创建一个新的文件,并将其放到适当的位置以添加一个新的用户,最后在FreeSWITCH CLI 上发送reloadxml命令加载。这个思想同样适用于拨号方案示例。我们可以把每个分机的方案独立文件存储,并在您需要时把它放到适当的位置下。

 

总结

        FreeSWITCH一个复杂的系统,它由许多部件组成,这些部件集成在一起生成一个坚固、稳定的内核,还有一些灵活且易于扩展的组件。内核通过接口扩展模块。模块也可以把各种通信协议转换为一种通用的、抽象的内部格式,将一些外部功能集成进FreeSWITCH。我们研究了各种模块类型,并演示了它们如何围绕内核旋转,如何相互作用,将简单的抽象概念转化为更高层次的功能。我们描述了一些FreeSWITCH最为通用的app:会议和语音信箱模块,以及它们是如何在不了解其它模块细节的情况下使用其它模块的。这种不可知论是通过事件系统实现的。我们还介绍了演示配置文件提供的几个工作实例,帮助您从一个功能齐全的软交换业务端看问题,从纷繁复杂的事务中解脱出来。

        在下一章中,我们将迈开第一步,朝着启动和运行FreeSWITCH的目标前进。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值