FreeSWITCH的设计目标是提供一个围绕在switching核心的模块化,可扩展,并且为开发人员提供用来添加和控制系统的健全接口的通讯系统。FreeSWITCH中的每一个分子都是彼此独立,同时不需要了解其他部分是如何工作,此外,每个分子所提供的我们叫作“裸露功能”。
FreeSWITCH的功能同样可以使用加载模块进行扩展,一种可以绑定外部功能到核心的特殊技术。
FreeSWITCH 拥有很多不同的模块类型围绕在中央核心。列表如下:
通过各个模块接口的功能相结合,FreeSWITCH可以配置连接IP电话,POSTS lines和基于IP的电话服务。它也可以转换音频格式和你可以自己创建带自定义菜单系统的接口。你甚至可以从其他的机器上来控制一台正在运行中的Freeswitch 服务器。让我们从一个使用很广泛的模块终端模块来开始更进一步的观察。
终端模块是极为重要的,添加了一些使FreeSWITCH变成现在强大平台的关键性的功能。
终端模块扮演的主要角色是添加通用的通信技术,然后将他们初始化成一个 我们叫做session的抽象实体。一个Session代表一个FreeSWITCH的和特定的协议之间的连接。目前FreeSWITCH拥有好些个终端模块,已经实现了像SIP,H323,GTALK以及其他的通信协议。我们将会花一些时间去了解freeswitch中一个比较常用叫mod_sofia的模块。Sofia-SIP(http://sofia-sip.sourceforge.net)是一个由诺基亚(NOKIA)赞助的开源项目。这个项目的设计之初是为会话发始协议也叫SIP做一个程序接口。我们在FreeSWITCH中的mod_sofia模块中使用了这个库。mod_sofia模块注册了所有在FreeSWITCH中创建模块的必要 Hook. 同时互相转换FreeSWITCH结构和SIP结构。模块的配置信息取自FreeSWITCH的中心配置文件,允许mod_sofia加载用户定义的参数和详细连接信息。这样FreeSWITCH 就可以接受SIP电话设备的注册,注册到其他的SIP服务,发送通知,以及提供像语言留言这样的服务。当一个SIP呼叫已经建立在FreeSWITCH与另一个SIP设备之间,它会在FreeSWITCH中显示为一个活动中的会话。如果有电话打进来,可以将呼叫转移或格拉到IVR菜单,保持音乐,一个或多个分机,有许多其它的选择可用。让我们来看一个典型的场景,当一个已经注册的SIP电话分机2000呼叫分机2001,希望建立一个呼叫。首先,SIP电话通过网络发送一个呼叫建立消息(INVITE)到mod_sofia(mod_sofia 正在侦听等待这类的消息).收到消息后,mod_sofia 模块分析有关细节,同时将呼叫转入到FreeSWITCH的核心状态机。下一步是寻找拨号方案模块,依据配置内容进行呼叫终端。默认及最常用的拨号文案模块是XML 拨号方案模块。XML拨号方案模块设计用来从freeswitch的中央XML注册表中读取指令列表。XML拨号方案模块使用 正则表达式 匹配来 解析一系列的XML扩展对象。
当我们呼叫2001时,我们希望找到一个XML extension 测试其destination_number字段是否匹配“2001”,然后再使用相应的规则进行路由(route);拨号方案并不是限制仅匹配一个extension.
其实,在第五章,理解XML拨号方案,你将会得到extension的更详细的定义。XML拨号方案为每一个通话创建了一种“task list”, 每一个可以匹配的extension中的action都将会添加到通话的“task list”。假设FreeSWITCH至少找到一个extension符合通话,XML Diaplan 将会插入一些尝试把通话连接到2001的一些说明到会话对象。一旦这些instructions被插入到会话中,通话的状态由ROUTING转到EXECUTE状态,EXECUTE从列表中找下一个handler drill同时执行由ROUTING状态获得的instructions。This is where the application interface comes into the picture.每一个添加到session的instruction都使用包含 应用名称和一个将要传到应用的数据参数.
在例子中我们要用的应用是bridge.这个应用的目的是创建一个session和另一个出站连接(outbound connection), 然后连接这两个session,开启语音交流。
我们提供给bridge的参数是user/2001, 一个很简单的方式生成一个呼叫分机2001的通话。
一个2001拨号规则的条目可以看起来像这样:
<extension name="example">
<condition field="destination_number" expression="^2001$">
<action application="bridge" data="user/2001"/>
</condition>
</extension>
Extension的名字是”example”,它只有一个条件可以匹配。
如果条件被匹配,它只有一个应用去执行。
用白话来说,刚才提到的extension,可以这样表达:如果 主叫 拨打了2001,然后在主叫和对端(一个电话)2001确立一个连接。思考一下这是怎样发生的。
一旦我们插入instructions到一个session, 它的状态就会从切换到EXECUTE, FreeSWITCH的核心将会使用收集到的数据执行想要的行为.首先, 默认执行的将会是解析命令以便于执行bridge 到 user/2001, 然后它会寻找bridge应用, 然后传送参数 user/2001 到bridge 应用中.FreeSWTICH的核心将会建立一个所需类型的outbound session.用户2001也是一个SIP电话, 所以user/2001将会解析到一个SIP的拨号字符串, 它将用来传送到mod_sofia 去请求mod_sofia去创建一个新的outbound session.
如果新的session建立成功, 现在FreeSWTICH核心中会有两个session.
Bridge应用将会取得新的session和原来的session(主叫的电话), 然后在它们之间执行bridge function.
这样只要分机2001的人实际上接听了电话, 双向的语音流就可以传输了.
如果用户无法接听或繁忙, 一个超时(这表示一个失败)将会产生,同时发送对应的MESSAGE到主叫的电话.
如果电话未接通或分机繁忙, 很多的 routing 选项是可选择的, 像呼叫转移或语音邮箱.
所有的一切都由一个简单的动作产生—拿起电话听筒然后拨打2001.
FreeSWTICH拥有复杂的SIP协议的全部, 同时把它的复杂性减少到了一个common denominator.
From there, 它通过允许我们来配置一个简单的指令到拨号规则实现连接电话2000到电话2001来进一步降低复杂度.
如果我们想让2001电话能拨打电话2000, 我们可以添加另一个相反的条目到拨号方案.
<extension name="example 2">
<condition field="destination_number" expression="^2000$">
<action application="bridge" data="user/2000/">
</condition>
</extension>
在这个情景中, 终端模块把SIP转换为FreeSWTICH的session, 拨号方案模块转换XML为extension.
Bridge应用把创建一个outbound call 和连接音频的复杂代码转换为一个简单的 应用/参数 对。
无论是拨号方案模块和应用模块接口的设计都是围绕在通用的FreeSWITCH sessions.
因此, 抽象不仅仅使用户级别更加简单,同时它也简化了应用和拨号方案的设计,因为they can be made agnostic of the actual endpoint technology involved in the call.
就是因为这种抽象, 当我们明天添加一个新的模块为一些其它协议像Skype(顺便说一下,也确实有一个这样的存在),我们可以再使用相同的应用和拨号方案模块。相同的理论适用与Say, ASR, TTS等其他模块。
如果你想让一些由终端的原生协议提供的一些特有的数据变的可用,这也是可能的。
举个例子,在SIP中有几个特有的协议头以及SIP包中一些有趣数据。
我们通过向channel中添加变量去解决这个问题。使用channel变量,mod_sofia可以设置它独有的值,,在你的拨号方案和应用中你可以通过名字从channel重新取得这些值。这样, 我们分享我们对于这些特殊变量的理解通过SIP终端。然而, FreeSWITCH的核心仅仅把它们当作是专用的channel变量,这些核心并不关心。也有一些保留的channel变量,它们可以影响FreeSWITCH的行为通过很多有的趣的方式。如果你使用过一种脚本语言,或使用变量的配置文件引擎, 那么有助于你的理解,因为channel变量和它们的概念非常的相似。一个简单的变量名和一个值传到了channel中,数值就被设定了。甚至有一个应用接口专门为此: SET应用允许你通过diaplan来设置你自己的变量。
<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的变量。这个变量将会自始至终存在于这个通话中,在通话结束时的详细记录中也会被提及。
我们把事情分的越细,越多的相同的底层资源就可以被复用, 使系统可以简单地使用。
例如, 编码接口除了关心它的编码解码世界,对核心一无无知。一旦一个可用的编码模块已经被写成, 它就可以被任何终端使用,在它的音频流中使用这个编码。这表明如果我们把一个 文字-到-语音 模块工作正常,我们可以生成合成的语音在任何,所有FreeSWITCH支持的模块。 这不需要关心哪一个模块先被添加,互相也不需要更改些什么。TTS模块因它可以使用更多的编码更变得更有用;编码变得更有用,因为我们利用它们添加了一个新的功能。同样的想法用于用 应用模块。如果我们写了一个新的应用模块,已经存在终端可以立即执行和使用那个应用。
FreeSWITCH降低了许多高级应用的复杂性。让我们来看一下更复杂的应用中的两个示例。
-3.1.Voicemail语音邮件
第一个我们要讨论的模块就是语音邮件应用。这个模块的作用是很容易猜到。它提供语音留言服务。在通话不能正常接通的情况下,这个应用作为第二个选择是很有用的。我们可以使用一个精心的组合去实现这个应用选择,这两个中的某一个新奇的变量,我们已经了解过了。
让我们来看一下最后的一个extension. 它允许我们留下一个口讯。
<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>
这里我们看到了channel 变量的两种用法。首先,我们设置hangup_after_bridge=true 告诉系统,一旦我们至少成功bridge一个通话到另一个电话则挂断,忽视其余的指令。
你已经看到了,我们也通过以美元符号做前缀括号使用了domain变量,${domain}. 这个特殊的变量默认是所有的电话配置文件中的自动配置的域名。在例子中,我们检查如果有人正在拨打2000,我们尝试去bridge注册在分机2000的电话。如果呼叫失败或对方正忙,我们会执行下一个指令,也就是进入语言留言应用。我们提供了一些应用需要的一些信息,哪一个分机要进入语音邮件,所以语音邮件应用知道在这种情形下怎么去处理。下一步, 语音邮件应用播放预先录制的问候语或使用我们刚才简短的讨论过的SAY模块接口去生成一个问候语。SAY模块串连一些语音文件去生成一个语音说:“分机2000的人现在没空,请留下您的口信”。然后,mod_voicemail 提醒你去录下你的留言,现在是你的选择是否通过留下一个口信来留下你的标记在那个人的收件箱里。还有一个附加的功能,如果你对你的录音不太满意,你可以重复录音多次,直到你满意。一旦你最终提交了口信,一个FreeSWITCH的 MESSAGE_WAITING 事件被触发到核心的事件系统,它被mod_sofia作为一个实现事件接收器的方式,就是把事件信息转换为SIP。如果一切都能如计划一样进行,注册在分机2000的电话将会点亮它的消息提醒灯。
再回到这个例子中来,除了表面我们能看到的怎么去播放一个问候语,录下一条留言,然后发送它到用户那里,我们也揭开了另一个没有被歌颂的英雄--事件系统。
FreeSWITCH的事件系统不是一个像其它例子中那样的模块化接口,它是一个核心引擎,你可以用它来侦听特定命令的消息,然后当事件被收到时根据你的需要来进行响应。换句话说,整个FreeSWITCH的核心,都是事件的发来和接收。
模块可以侦听很多消息,当然也可以”fire”消息到 core engine(事件引擎)中,其它的模块可以侦听这些消息。如我们讨论的那样,sofia SIP模块侦听和订阅 指定的事件 为获取MESSAGE_WAITING 信息。这样就允许我们的mod_voicemail 模块和mod_sofia模块进行交互,互相不需要拥有任何了解关于对方的存在。事件由mod_voicemail触发,由mod_sofia接收然后转换事件到合适的SIP消息—一切看起来是神奇的,人性化的事件系统。当考虑到所有的需要被支持的语言以及如何自动化的播放文件和把它们串连起来,还有好几个难点在这样一个复杂的交互式的系统中。Say模块提供了一个很好的方式能把语音文件串连起来,但在有些情况,如说一个单词,计算或说一个特定的日期,它就显得不足了。我们克服这个困难通过在Say模块的上层定义了一个更复杂的层—宏片(Phrase Macros).宏片是一个XML语法的集合,它通过正则表达式匹配来组建一个参数列表和执行一串命令。这和XML 的diaplan工作原理非常相似,只有量身定制的交互式语音应答方案系统(IVR)。例如,当mod_voicemail请求你录下留言, 不是编码文件的字符串去例say去说的,而是仅仅调用 宏片(Phrase Macro) voicemail_record_message.这个特定的字符串在mod_voicemail和 宏片 间共享,允许我们和用户去编辑文件而不用任何奇特的编程。
<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的时候,它首先对pattern进行匹配,在这个例子中是匹配所有,因为这个特别的宏没有输入。
如果宏有输入的话,pattern匹配根据不同的输入可以用来执行不行的动作。 一旦寻找到一个匹配,被匹配的参数就被解析成XML标签就像我们的dialplan例子。
这个宏仅仅是播放文件vm_record_message.wav, 但是更复杂的宏,像那个验证你的录音或告诉你的语音收件箱里有几封语音留言的宏,他们可能需要使用许多次say模块和播放声音文件。宏短语会详细的讨论在第6章-使用内置的XML IVR引擎,然后更广范的使用在第7章节-使用LUA建立IVR应用。
再说一次,我们让phrase系统,声音文件和SAY模块,由系统加载在一起使他们协作可以提供强大的功能。Say模块是专门为一种特定语言或某中语言的声音所开发的。我们可以通过编程来请求说一个特定的时间和根据输入的变量来翻译这个时间到合适的say模块。Phrase Macro 系统是一个很伟大的方式去在你的代码中加入更大的变量概念,这样可以让普通用户非常容易的调整.
例如,如果我们想要建立一个轻量级的IVR,请求用户输入一个4位的号码然后把它读出来后挂断通话,我们可以建立一个宏叫“myapp_ask_for_digits”和另一个宏叫“myapp_read_digits”。
在我们的代码中,我们可以用过名字来执行这些宏--当是时候请求数字的时候执行第一个,另一个去读回我们输入后传入的数字。一旦这些就位,一个无经验的个人就有能力实现通过XML文件去播放适当的声音。他/她可以使用say模块去读出输入的数字,并且支持多种语言而不需要再进行编码。Voicemail仅仅是FreeSWITCH作为一个应用服务器使用的例子。当我们使用FreeSWITCH连接电话和电脑时,一切皆有可能!
3.2.多方会议
FreeSWITCH的另一个非常受欢迎的功能是由mod_conference模块提供的会议功能。mod_conderence模块提供动态的会议室,会议室可以将好几个不同的语音通道桥接在一起。
这样可以用来支持会议,当有好几个呼叫者想互相沟通在同一个通话中。每一个新的session连接到相同的会议室时将会互相连接,并且可以立即在相同的时间向与会的所有成员聊天。通用一个Diaplan的示例,和brigde到其他的电话一样,我们可以使一个分机加入一个会议室:
<extension name=”example 4”>
<condition field=”destination_number” expression=”^3000$”>
<action application="conference" data="3000@default"/>
</condition>
</extension>
这和连接一通电话很像,但是在这个extension中特别地是很多的主叫者都可以呼叫3000去加入相同的会议室。如果三个人加入了这个会议,其中的一个决定离开,其它的两个人依然可以继续他们的会议。这个会议模块还有一个特别的功能,像可以播放声音文件或TTS,甚至只是一个单个成员会议。
你可能已经猜到了,我们可以通过TTS和声音文件接口他们各自的模块去提供这些功能。再说一遍,
the smaller pieces组合在一起可以不需要清楚的了解系统中其它组件去扩展功能。
会议模块通过一个叫做自定义事件(custom events)的方式去使用事件系统。像mod_conference这样的模块在它被加载的时候可以保留一个特殊的事件命名空间的子集。当我们关心的事件发生,像一个成员加入或离开了会议,它触发这类CUSTOM的事件到核心中。当我们对接收这类的事件很感兴趣时,所有我们需要做的是仅仅是订阅这个CUSTOM事件,提供一个额外的子集字符标识,这个标识用来指定哪一种CUSTOM的事件我们希望接收。在这个例子中,这是conference::maintenance.这样就使获取到重要的事件,像有人加入或离开会议,开始和结束讲话,变成了可能。会议将会在在第10章,高级应用和加深阅读,进行详细的讨论。
FreeSWITCH中另一个非常强大的模块接口是FSAPI模块。
这一类的的接口的设计原则很简单—它接收一个字符串作为参数,可能也可能不被解析,主要由下面的代码决定。返回的值也是一个字符串,任意大小,从一个字符大小到几页纸,这由被调用的函数决定。
FSAPI的功能的主要好处就是一个模块可以使用它调用其它的模块,而不需要直接连接实际的代码。
FreeSWITCH的命令行接口或CLI 使用FSAPI函数根据你的输入传入命令。这里是一个小的示例关于如何从FreeSWITCH的CLI中执行status 这个FSAPI命令。
freeswitch> status
API CALL [status()] output:
UP 0 years, 3 days, 23 hours, 31 minutes, 31 seconds, 524 milliseconds,
576 microseconds
438 session(s) since startup
6 session(s) 0/30
1000 session(s) max
当我们敲下status然后按下回车键的时候真实发生了什么呢, 关键字’status’被用来寻找status FSAPI函数从它被实现的模块中.
下面的函数然后被调用,core 正在查询它的状态信息。一旦状态数据被获取,输出会通过流传送回来同时作为命令行的结果显示出来。
我们已经知道一个模块可以创建和导出FSAPI函数,这些可以从任何地方调用像CLI中。但是不止如此,还有更多!模块也可以向FSAPI的接口执行命令然后通过一个特定的协议返回结果。在FreeSWITCH中有两个模块就是有这个功能的—mod_event_socket 和 mod_xml_rpc(mod_event_socket 将会详细的讨论在第9章节,从外部控制FreeSWITCH)。
来一看mod_xml_rpc的例子。这个模块把标准的XML-RPC协议实现作为一个FreeSWITCH的模块。
客户端可以使用XML-RPC接口连接到FreeSWITCH和执行任何FSAPI命令。所以一个远端的客户端可以执行一个RPC 调用到 status,也可以得到一个就像我们在前一个例子中看到的相同的状态信息。
这个模块也将FreeSWITCH作为一个通用的WEB服务器,这样就可以允许用过直接的URL访问来执行FSAPI命令。例子,某要可以在浏览器中输入http://example.freeswitch.box:8080/api/status通过万维网来使用命令status.通过这种技术,创建一个工作像CGI那样,提供一个可以直接接入到FreeSWITCH内部的动态的WEB应用是可行的。
如我们所看到的那样,FSAPI接口几乎是万能的。现在我们知道它可以用来提供一个命令行接口,一个可以让模块互相调用的方式和导出WWW或XML-RPC函数。还有一个FSAPI的功能我们还没有讲到。我们在之前已经轻微的接触过channel 变量的概念,仅仅是使用表达式${myvariable}
去获得一个指定变量的值。FSAPI函数也可通过${myfunction()}
这样的格式去调用。
这个标记表示名叫”myfuntion”的FSAPI的命令会被调用,并且这个表达式会被它调用的函数的输出替换。
因此,我们可以在任何地方使用${status()},变量被展开去获取status命令,例如:
<action application=”set” data=”my_status=${status}”/>
My_status变量中的值是status命令行的输出。
单一模块提供多种功能的弊端是,为了达成这样的目的,我们不得不让函数变得弱类型(”loosely type”)。这表示有好几种情况,一个FSAPI会被很容易的调用,使用我们已经讨论过的方式。另外,也有一个特殊的函数被设计成使用一个特殊的方式调用。例如,如果我们我们开发一个FSAPI的命令,提供输出HTML则有意使用一个浏览器来调用,我们不想使用命令行调用或作为一个变量来引用它。
同样地,如果我们写了一个FSAPI函数用来计算通话中的某些值,它的设计就是从diaplan中调用,如果从命令行或WEB来调用的话就显得没有多大的意义了。所以,拥有非凡的能力也就意味着要承担重大的责任,我们需要使用通常的理解去决定何时在哪里使用合适的FSAPI函数来对它们最大的利用。
我们已经讨论了FreeSWITCH核心中大部分重要的组件和他们是如何互相作用的。我们已经了解event system 如何携带信息穿过核心,XML Dialplan如何从XML 的注册表中的查询数据。现在是个好的时间去解释XML注册表更多一些了。XML注册表是一个主要的管理XML文档,它拥有所有的可以保证FreeSWITCH运行正常地重要的数据。初始的文档是由你的硬盘中被加载,然后传入到一个特定的预处理器。这个预处理器可以包含其它的XML文档和其它特殊的操作,如设置全局变量,这些操作会被预处理器解析然后另入到文档中。
一旦整个文件和所有它包含的都会解析,替换和生成为一个静态的XML文档,这个文件就会被加载到内存中。XML的注册表被分成了好几个部分—配置,拨号方案,目录和片(宏)。核心和模块从configuration部分中来获取他们的配置文件。XML diaplan 模块从diaplan部分中来获取它的拨号方案数据。SIP的验证,用户查询,以及voicemail模块读取他们的账户信息从directory 部分。Phrase Macros获取它的配置信息从phrases 部分。如果我们把在硬盘上的文档修改了,我们可以通过重新加载更新到内部中通过从CLI中执行命令reloadxml.(CLI是一个使用FSAPI接口与freeSWITCH核心进行通信的示例)。
一种独特的模块类型,它们没有像文件模块和终端模块那样有直接的接口到FreeSWITCH,但是依然提供一个极大的丰富的连接到已经存在的技术,它们就是语言模块(language module).语言模块呢嵌入一个编程语言像Lua,javascript或perl到FreeSWITCH中,同时在核心和语言运行环境中间来转换功能。这可以允许IVR 应用使用嵌入式应用来编写,可以简化很多使用。Language模块通常以应用接口的方式注册到核心中,FSAPI接口是通过Diaplan来调用地。Language 模块提供很多的可能性和非常的强大。通过language模块,你可以使用标准的编程语言来编写一个强大的语音应用。在某些方面,你可以通过一种编程语言来真实的控制一个电话。
理解所有的这些概念远非易事,同时作为一个软件的维护者,我们不希望大部分的人做的只是”点击”。
这就是为什么,我们在核心中设置了这么多的层,把事情变得简单化和易学。默认的配置文件就是 新手和令人疯狂的,复杂的,有时候彻头彻尾邪恶的被称为电话的东西之间的最后的防线。 我们非常的努力去拯救用户从这些令人抓狂的东西里。
默认配置文件的主要目的是列出你在使用中会遇到的数百个参数.我们提供一个可用的配置文件,在你冒险进入未知的电话世界和动手修改一些选项前,事实上不需要更改就可以使用一些功能。把FreeSWITCH想作是一个乐高积木(lego set)。FreeSWITCH和所有的组件就像一个品牌积木一样,使用这些部分去创建我们想像的任何东西。默认的配置呢就像你在积木介绍册子里看到的示例飞船一样。它包含准确的,手把手的配置介绍教你怎么去配置一个可工作的环境。当你学到了一些经验,你可能就想去修改你的乐高飞船添加一些额外的功能,或者可能重建他们为一个汽车或者其它新的创造。对于FreeSWITCH来说的好消息是它已经被组装好了。因此,不像一桶乐高积木那样,如果你把它弄碎了或你对你的配置文件灰心了,你可以重新安装默认的配置文件而你不需要从头开始重建。默认的配置文件会在第三章进行讨论-尝试驾驭默认的配置。
一旦FreeSWITCH已经在你的系统上编译成功,你只需要执行程序,不需要更改配置文件。你可以注册一个SIP电话或软件SIP电话到你电脑的IP地址上和打一通测试电话。如果你有勇气和希望连接到传统的电话,你需要对SIP相关的知识牢牢的掌握。这是因为这需要一些工作(包括为你的电脑购买一个硬件板卡或一个神奇的设备叫ATA-模拟电话适配器)。
如果你不止有一部电话,你可以把它们配置的拥有一个独立的分机号在1000—1019之间,这是在默认的配置文件中已经定义好的。一旦你有两个电话注册成功,你可以使用它们去互相通话或让他们去参加在号码3000-3399之间的会议室。如果你呼叫了一个没有注册的电话或一个电话长时间没有接听,语音邮件应用将会使用phrase系统去提示你所呼叫的用户暂时无法接通,以及让你留一下一个留言。如果你拨打5000,你可以听到一个默认的IVR菜单,提供一些菜单中的选择示例,展示在条条框框之外其他各种巧妙的事情。有很多小的变化,可以向默认的配置,同时仍保持它的完整补充。
例如,使用我们之前看过的预处理器,默认的配置文件加载从某些地方的文件到XML注册表,意味着在特殊文件夹的文件将会组合到最终的XML配置文档中。
最重要的两点是,在哪里保存用户账号和拨号方案中的extension。那默认预先配置20个分机都保存在它们个自的文件中。我们可以很容易的添加带有独立账号定义的新文件,把它放置到directory目录去添加另一个账号,然后从FreeSWITCH的CLI中执行命令 reloadxml。
同样的方法也适用于示例拨号方案,我们可以添加到单个的extension到单独的文件,然后把它放置到我们想放置的地方。
FreeSWITCH是由可拆解的组件组成的复杂的系统,这样耦合在一起是为了提供一个,可靠的,稳定的核心,灵活,易扩展和附加组件。核心扩展它的接口到模块。这些模块进一步的简化应用,然后提供这些功能给用户。模块也可以通过转换不同的协议到一个通用的,众所周知的模式把外部的功能加入到FreeSWITCH. 我们已经看了很多种模块类型,以及它们如何围绕在核心周围如何互相作用实现转换简单抽象的概念到高层次的功能。我们接触了一些在FreeSWITCH中比较受欢迎的应用-会议和语音邮件模块,以及它们如何使用系统中的模块,甚至它们都不知道对方。这种不可认知是由事件系统实现的。我们也了解了默认配置文件是如何提供一些可用的示例的,去帮助实现一个全功能的软件交换系统来取代另一种商业的系统。