PS:才对asterisk感兴趣,freeswich的声音又多起来了……
转自http://www.dujinfang.com/past/2010/1/22/freeswitch-yu-asteriskyi/
Anthony Minssale/文 Seven/译
VoIP通信,与传统的电话技术相比,不仅仅在于绝对的资费优势,更重要的是很容易地通过开发相应的软件,使其与企业的业务逻辑紧密集成。Asterisk作为开源VoIP软件的代表,以其强大的功能及相对低廉的建设成本,受到了全世界开发者的青睐。而FreeSWITCH作为VoIP领域的新秀,在性能、稳定性及可伸缩性等方面则更胜一筹。本文原文在http://www.freeswitch.org/node/117, 发表于2008年4月,相对日新月异的技术来讲,似乎有点过时。但本文作为FreeSWITCH背后的故事,仍很有翻译的必要。因此,本人不揣鄙陋,希望与大家共读此文,请不吝批评指正。 –译者注
FreeSWITCH 与 Asterisk 两者有何不同?为什么又重新开发一个新的应用程序呢?最近,我听到很多这样的疑问。 为此,我想对所有在该问题上有疑问的电话专家和爱好者们解释一下。我曾有大约三年的时间用在开发 Asterisk 上,并最终成为了 FreeSWITCH 的作者。因此,我对两者都有相当丰富的经验。首先,我想先讲一点历史以及我在 Asterisk 上的经验;然后,再来解释我开发FreeSWITCH的动机以及我是如何以另一种方式实现的。
我从2003年开始接触 Asterisk,当时它还不到1.0版。那时对我来讲,VoIP还是很新的东西。我下载并安装了它,几分钟后,从插在我电脑后面的电话机里传出了电话拨号音,这令我非常兴奋。接下来,我花了几天的时间研究拨号计划,绞尽脑汁的想能否能在连接到我的Linux PC上的电话上实现一些好玩的东西。由于做过许多Web开发,因此我积累了好多新鲜的点子,比如说根据来电显示号码与客户电话号码的对应关系来猜想他们为什么事情打电话等。我也想根据模式匹配来做我的拨号计划,并着手编写我的第一个模块。最初,我做的第一个模块是app_perl,现在叫做res_perl,当时曾用它在Asterisk中嵌入了一个Perl5的解释器。现在我已经把它从我的系统中去掉了。
后来我开始开发一个Asterisk驱动的系统架构,用于管理我们的呼入电话队列。我用app_queue和现在叫做AMI(大写字母总是看起来比较酷)的管理接口开发了一个原型。它确实非常强大。你可以从一个T1线路的PSTN号码呼入,并进入一个呼叫队列,坐席代表也呼入该队列,从而可以对客户进行服务。非常酷!我一边想一边看着我的可爱的Web页显示着所有的队列以及他们的登录情况。并且它还能周期性的自动刷新。令人奇怪的是,有一次我浏览器一角上的小图标在过了好长时间后仍在旋转。那是我第一次听说一个词,一个令我永远无法忘记的词 — 死锁。
那是第一次,但决不是最后一次。那一天,我几乎学到了所有关于GNU调试器的东西,而那只是许多问题的开始。队列程序的死锁,管理器的死锁。控制台的死锁开始还比较少,后来却成了一个永无休止的过程。现在,我非常熟悉“段错误(Segmentation Fault)”这个词,它真是一个计算机开发者的玩笑。经过一年的辛勤排错,我发现我已出乎意料的非常精通C语言并且有绝地战士般的调试技巧。我有了一个分布于七台服务器、运行于DS3 TDM信道的服务平台。与此同时,我也为这一项目贡献了大量的代码,其中有好多是我具有明确版权的完整文件(http://www.cluecon.com/anthm.html)。
到了2005年,我已经俨然成了非常有名的Asterisk开发者。他们甚至在CREDITS文件以及《Asterisk,电话未来之路》这本书中感谢我。在Asterisk代码树中我不仅有大量的程序,而且还有一些他们不需要或者不想要的代码,我把它们收集到了我的网站上。(至今仍在 http://www.freeswitch.org/node/50)
Asterisk 使用模块化的设计方式。一个中央核心调入称为模块的共享目标文件以扩展功能。模块用于实现特定的协议(如SIP)、程序(如个性化的IVR)和其它外部接口(如管理接口)等。 Asterisk的核心是多线程的,但它非常保守。仅仅用于初始化的信道以及执行一个程序的信道才有线程。任何呼叫的B端都与A端都处于同一线程。当某些事件发生时(如一次转移呼叫必须首先转移到一个称作伪信道的线程模式),该操作把一个信道所有内部数据从一个动态内存对象中分离出来,放入另一个信道中。它的实现在代码注释中被注明是“肮脏的”[1]。反向操作也是如此,当销毁一个信道时,需要先克隆一个新信道,才能挂断原信道。同时也需要修改CDR的结构以避免将它视为一个新的呼叫。因此,对于一个呼叫,在呼叫转移时经常会看到3或4个信道同时存在。
这种操作成了从另一个线程中取出一个信道事实上的方法,同时它也正是开发者许许多多头痛的源头。这种不确定的线程模式是我决定着手重写这一应用程序的原因之一。
Asterisk使用线性链表管理活动的信道。链表通过一种结构体将一系列动态内存串在一起,这种结构体本身就是链表中的一个成员,并有一个指针指向它自己,以使它能链接无限的对象并能随时访问它们。这确实是一项非常有用的编程技术,但是,在多线程应用中它非常难于管理。在线程中必须使用一个信号量(互斥体,一种类似交通灯的东西)来确保在同一时刻只有一个线程可以对链表进行写操作,否则当一个线程遍历链表时,另一个线程可能会将元素移出。甚至还有比这更严重的问题 ─ 当一个线程正在销毁或监听一个信道的同时,若有另外一个线程访问该链表时,会出现“段错误”。“段错误”在程序里是一种非常严重的错误,它会造成进程立即终止,这就意味着在绝大多数情况下会中断所有通话。我们所有人都看到过“防止初始死锁”[2]这样一个不太为人所知的信息,它试图锁定一个信道,在10次不成功之后,就会继续往下执行。
管理接口(或AMI)有一个概念,它将用于连接客户端的套接字(socket)传给程序,从而使你的模块可以直接访问它。或者说,更重要的是你可以写入任何你想写入的东西,只要你所写入的东西符合Manager Events所规定的格式(协议)。但遗憾的是,这种格式没有很好的结构,因而很难解析。
Asterisk的核心与某些模块有密切的联系。由于核心使用了一些模块中的二进制代码,当它所依赖的某个模块出现问题,Asterisk就根本无法启动。如果你想打一个电话,至少在 Asterisk 1.2中,除使用app_dial和res_features外你别无选择,这是因为建立一个呼叫的代码和逻辑实际上是在app_dial中,而不是在核心里。同时,桥接语音的顶层函数实际上包含在res_features中。
Asterisk的API没有保护,大多数的函数和数据结构都是公有的,极易导致误用或被绕过。其核心非常混乱,它假设每个信道都必须有一个文件描述符,尽管实际上某些情况下并不需要。许多看起来是一模一样的操作,却使用不同的算法和杰然不同的方式来实现,这种重复在代码中随处可见。
这仅仅是我在Asterisk中遇到的最多的问题一个简要的概括。作为一个程序员,我贡献了大量的时间,并贡献了我的服务器来作为CVS代码仓库和Bug跟踪管理服务器。我曾负责组织每周电话会议来计划下一步的发展,并试图解决我在上面提到过的问题。问题是,当你对着长长的问题列表,思考着需要花多少时间和精力来删除或重写多少代码时,解决这些问题的动力就渐渐的没有了。值得一提的是,没有几个人同意我的提议并愿意同我一道做一个2.0的分支来重写这些代码。所以在2005年夏天我决定自己来。
在开始写FreeSWITCH时,我主要专注于一个核心系统,它包含所有的通用函数,即受到保护又能提供给高层的应用。像Asterisk一样,我从Apache Web服务器上得到很多启发,并选择了一种模块化的设计。第一天,我做的最基本的工作就是让每一个信道有自己的线程,而不管它要做什么。该线程会通过一个状态机与核心交互。这种设计能保证每一个信道都有同样的、可预测的路径和状态钩子,同时可以通过覆盖向系统增加重要的功能。这一点也类似其它面向对象的语言中的类继承。
做到这点其实不容易,容我慢慢讲。在开发FreeSWITCH的过程中我也遇到了段错误和死锁(在前面遇到的多,后来就少了)。但是,我从核心开始做起,并从中走了出来。由于所有信道都有它们自己的线程,有时候你需要与它们进行交互。我通过使用一个读、写锁,使得可以从一个散列表(哈希)中查找信道而不必遍历一个线性链表,并且能绝对保证当一个外部线程引用到它时,一个信道无法被访问也不能消失。这就保证了它的稳定,也不需要像Asterisk中“Channel Masquerades”之类的东西了。
FreeSWITCH核心提供的的大多数函数和对象都是有保护的,这通过强制它们按照设计的方式运行来实现。任何可扩展的或者由一个模块来提供方法或函数都有一个特定的接口,从而避免了核心对模块的依赖性。
整个系统采用清晰分层的结构,最核心的函数在最底层,其它函数分布在各层并随着层数和功能的增加而逐渐减少。
例如,我们可以写一个大的函数,打开一个任意格式的声音文件向一个信道中播放声音。而其上层的API只需用一个简单的函数向一个信道中播放文件,这样就可以将其作为一个精减的应用接口函数扩展到拨号计划模块。因此,你可以从你的拨号计划中,也可以在你个性化的C程序中执行同样的playback函数,甚至你也可以自己写一个模块,手工打开文件,并使用模块的文件格式类服务而无需关注它的代码。
FreeSWITCH由几个模块接口组成,列表如下:
拨号计划(Dialplan): 实现呼叫状态,获取呼叫数据并进行路由。
终点(Endpoint): 为不同协议实现的接口,如SIP,TDM等。
自动语音识别/文本语音转换(ASR/TTS): 语音识别及合成。
目录服务(Directory): LDAP类型的数据库查询。
事件(Events): 模块可以触发核心事件,也可以注册自己的个性事件。这些事件可以在以后由事件消费者解析。
事件句柄(Event handlers): 远程访问事件和CDR。
格式(Formats): 文件模式如wav。
日志(Loggers): 控制台或文件日志。
语言(Languages): 嵌入式语言,如Python和JavaScript。
语音(Say): 从声音文件中组织话语的特定的语言模块。
计时器(Timers): 可靠的计时器,用于间隔计时。
应用(Applications): 可以在一次呼叫中执行的程序,如语音信箱(Voicemail)。
FSAPI(FreeSWITCH 应用程序接口) 命令行程序,XML RPC函数,CGI类型的函数,带输入输出原型的拨号计划函数变量。
XML 到核心XML的钩子可用于实时地查询和创建基于XML的CDR。
所有的FreeSWITCH模块都协同工作并仅仅通过核心API或内部事件相互通信。我们非常小心地实现它以保证它能正常工作,并避免其它外部模块引起不期望的问题。
FreeSWITCH的事件系统用于记录尽可能多的信息。在设计时,我假设大多数的用户会通过一个个性化的模块远程接入FreeSWITCH来收集数据。所以,在FreeSWITCH中发生的每一个重要事情都会触发一个事件。事件的格式非常类似于一个电子邮件,它具有一个事件头和一个事件主体。事件可被序列化为一个标准的Text格式或XML格式。任何数量的模块均可以连接到事件系统上接收在线状态,呼叫状态及失败等事件。事件树内部的mod_event_socket可提供一个TCP连接,事件可以通过它被消费或记入日志。另外,还可以通过此接口发送呼叫控制命令及双向的音频流。该套接字可以通过一个正在进行的呼叫进行向外连接(Outbound)或从一个远程机器进行向内(Inbound)连接。
FreeSWITCH中另一个重要的概念是中心化的XML注册表。当FreeSWITCH装载时,它打开一个最高层的XML文件,并将其送入一个预处理器。预处理器可以解析特殊的指令来包含其它小的XML文件以及设置全局变量等。在此处设置的全局变量可以在后续的配置文件中引用。
如,你可以这样用预处理指令设置全局变量:
<X-PRE-PROCESS cmd="set" data="moh_uri=local_stream://moh"/>
现在,在文件中的下一行开始你就可以使用 $$(moh_uri},它将在后续的输出中被替换为 local_stream://moh。处理完成后XML注册表将装入内存,以供其它模块及核心访问。它有以下几个重要部分:
配置文件: 配置数据用于控制程序的行为。
拨号计划: 一个拨号计划的XML表示可以用于 mod_dialplan_xml,用以路由呼叫和执行程序。
分词: 可标记的IVR分词是一些可以“说”多种语言的宏。
目录: 域及用户的集合,用于注册及账户管理。
通过使用XML钩子模块,你可以绑定你的模块来实时地查询XML注册表,收集必要的信息,以及返回到呼叫者的静态文件中。这样你可以像一个WEB浏览器和一个CGI程序一样,通过同一个模型来控制动态的SIP注册,动态语音邮件及动态配置集群。
通过使用嵌入式语言,如Javascript, Java, Python和Perl等,可以使用一个简单的高级接口来控制底层的应用。
FreeSWITCH工程的第一步是建立一个稳定的核心,在其上可以建立可扩展性的应用。我很高兴的告诉大家在2008年5月26日将完成FreeSWITCH 1.0 PHOENIX版。有两位敢吃螃蟹的人已经把还没到1.0版的FreeSWITCH 用于他们的生产系统。根据他们的使用情况来看,我们在同样的配置下能提供Asterisk 10倍的性能。
我希望这些解释能足够概括FreeSWICH和Asterisk的不同之处以及我为何决定开始FreeSWITCH项目。我将永远是一个Asterisk开发者,因为我已深深的投入进去。并且,我也希望他们在以后的Asterisk开发方面有新的突破。我甚至还收集了很多过去曾经以为已经丢失的代码,放到我个人的网站上供大家使用, 也算是作为我对引导我进入电话领域的这一工程的感激和美好祝愿吧。
Asterisk是一个开源的PBX,而FreeSWITCH则是一个开源的软交换机。与其它伟大的软件如 Call Weaver、Bayonne、sipX、OpenSER以及更多其它开源电话程序相比,两者还有很大发展空间。我每年都期望能参加在芝加哥召开的 ClueCon大会,并向其它开发者展示和交流这些项目(http://www.cluecon.com)。
我们所有人都可以相互激发和鼓励以推进电话系统的发展。你可以问的最重要的问题是:“它是完成该功能的最合适的工具吗?”
[1] / XXX This is a seriously wacked out operation. We’re essentially putting the guts of the clone channel into the original channel. Start by killing off the original channel’s backend. I’m not sure we’re going to keep this function, because while the features are nice, the cost is very high in terms of pure nastiness. XXX/
[2] Avoiding initial deadlock
PS:摘抄网上的:
1:Asterisk是针对百人左右的小型系统,相同的硬件配置下单系统并发也就几百路(不同版本性能有一定差异,大概在 200-400之间),而根据国外爱好者测试freeswitch 可达到2000-3000路sip通道(媒体流并发),
2:Asterisk用动态链表来管理每个打开的通道,这样在多线程中非常难于管理(需要频繁的锁定和解锁)。而freeswitch每个呼叫通道都会用一个线程来管理呼叫状态,大大减少了死锁发生的几率,freeswitch核心代码高度抽象,尽量将复杂代码集中化。
3:Asterisk用DUNDi协议设计分布式系统,Fs使用外部数据库实现分布系统,做得更好,甚至可以一台服务器通过数据库注册到另一台服务器上。
4:freeswitch 支持夸平台,linux, unix, windows 等,asterisk基本只支持 linux, bsd系列。
5. freeswitch配置采用xml,asterisk采用linux下面通用配置文件格式语法,而 采用xml格式配置文件是freeswich使用者抱怨最多的部分,对于不懂xml格式的开发者在刚开始使用时是个折磨。
原文
How does FreeSWITCH compare to Asterisk? Why did you start over with a new application? These are questions I’ve been hearing a lot lately so I decided to explain it for all of the telephony professionals and enthusiasts alike who are interested to know how the two applications compare and contrast to each other. I have a vast amount of experience with both applications with about 3 years of doing asterisk development under my belt and well, being the author of FreeSWITCH. First I will provide a little history and my experience with Asterisk, then I will try to explain the motivations and the different approach I took with FreeSWITCH.
I first tried Asterisk in 2003. It was still pre 1.0 and VoIP was still very new to me. I downloaded and installed it and in a few minutes I was tickled pink over the dial tone emitting from my phone plugged into the back of my computer. I spent the next few days playing with my dial plan and racking my brain to think of cool stuff I could do with a phone that was hooked up to a Linux PC. Since I had done an extensive amount of web development in my past life I had all sorts of nifty ideas like matching the caller id to the customer’s account number and trying to guess why they were calling etc. I also wanted to move on in my dial plan based on pattern matching and started hacking my first module. Before I knew it I had made the first cut of app_perl, now res_perl where I had embedded a Perl5 interpreter in Asterisk.
Now that I had that out of my system, I started developing an Asterisk-driven infrastructure to use for our inbound call Queues. I prototyped it using app_queue and the Manager Interface now proudly dubbed “AMI” (initials always make things sound cooler). It was indeed magnificent! You could call in from a PSTN number over a T1 and join a call queue where our agents who also called in could service the calls. “This rocks!” I thought to myself as I watched from my fancy web page showing all the queues and who was logged in. It even refreshed periodically by itself which was why I was surprised when the little icon in the corner of my browser was still spinning for quite some time. That’s when I first heard it. That word. The one I can never forget, deadlock.
That was the first time, but it wasn’t the last. I learned all about the GNU debugger that day and it was just the first of many incidents. Deadlock in the queue app. Deadlock in the manager, Avoiding Deadlock on my console. It was starting to get to me a little but I kept going. By this time I was also quite familiar with the term Segmentation Fault another foe to the computer developer. After about a year’s time wrestling with bugs I found myself a lot more well-versed in the C programming language than I even imagined and near Jedi caliber debugging skills. I had a working platform running several services on a DS3 worth of TDM channels spread over 7 asterisk boxes and I had given tons of code to the project including some entire files on which I hold the copyright. http://www.cluecon.com/anthm.html
By 2005, I had quite a reputation as an asterisk developer. They even thanked me in both the CREDITS file and in the book, Asterisk, The Future of Telephony. I not only had tons of applications for asterisk in tree, I had my own collection of code they did not need or want on my own site. (Still available today at http://www.freeswitch.org/node/50)
Despite all of this I could not completely escape the deadlocks and crashes. I hid the problem well with restart scripts and 7 machine clusters but I could not see a way to scale my platform much more. I had to abandon some features because they just would not work right based on the way Asterisk was designed.Asterisk uses a modular design where a central core loads shared objects to extend the functionality with bits of code known as “modules”. Modules are used to implement specific protocols such as SIP, add applications such as custom IVRs and tie in other external interfaces such as the Manager Interface. The core of Asterisk is a threading model but a very conservative one. Only origination channels and channels executing an application have threads. The B leg of any call operate only within the same thread as the A leg and when something happens like a call transfer the channel must first be transferred to a threaded mode which often times includes a practice called channel masquerade, a process where all the internals of a channel are torn from one dynamic memory object and placed into another. A practice that was once described in the code comments as being “nasty”. The same went for the opposite operation the thread was discarded by cloning the channel and letting the original hang-up which also required hacking the cdr structure to avoid seeing it as a new call. One will often see 3 or 4 channels up for a single call during a call transfer because of this.
/* XXX This is a seriously wacked out operation. We're essentially putting the guts of
the clone channel into the original channel. Start by killing off the original
channel's backend. I'm not sure we're going to keep this function, because
while the features are nice, the cost is very high in terms of pure nastiness. XXX */This became the de facto way to pull a channel out of the grips of another thread and the source of many headaches for application developers. This uncertain threading scheme was one of the motivating factors for a rewrite.
Asterisk uses linked-lists to manage its open channels. A linked-list is a series of dynamic memory chained together by using a structure that has a pointer to its own type as one of the members allowing you to endlessly chain objects and keep track of them.
They are indeed a useful programming practice but when used in a threaded application become very difficult to manage. One must use mutexes, a kind of traffic light for threads to make sure only 1 thread ever has write access to the list or you risk one thread tearing a link out of a list while another is traversing it. This also leads to horrible situations where one thread may be destroying or masquerading a channel while another is accessing it which will result in a Segmentation Fault which is a fatal error in the program and causes it to instantly halt which, of course means in most cases all your calls will be lost. We’ve all seen the infamous “Avoiding initial deadlock” message which essentially is an attempt to lock a channel 10 times and if still won’t lock, just go ahead and forget about the lock.The manager interface or AMI has a concept where the socket used to connect the client is passed down into the applications letting your module have direct access to it and essentially write any data you want to that socket in the form of Manager Events which are not very structured and thus the protocol is very difficult to parse.
Asterisk’s core has linking dependencies on some of it’s modules which means that the application will not start if a certain module is not present because the core is actually using some of the binary code from the module shared object directly. To make a call in asterisk in at least version 1.2 you have no choice but to use app_dial and res_features because the code actually lives in those modules. The logic to establish a call and to do things like a forked dial actually reside in app_dial not the core, and res_features actually contains the top level function that bridges the audio.
Asterisk has no protection of its API. The majority of the functions and data structures are public and can easily be misused or bypassed. The core is anarchy with assumptions about channels having a file descriptor, which is not always necessary in reality but is mandatory for any asterisk channel. Many algorithms are repeated throughout the code in completely different ways with every application doing something different on seemingly identical operations.
This is only a brief summary of the leading issues I had with Asterisk. I donated my time as a coder, my servers to host the CVS repository and served as a bug marshal and maintainer. I organized a weekly conference call to plan for the future and address some of the issues I have described above. The problem was, when one looks at this long list of fundamental changes then thinks about how much work it would take and how much code may have to be erased or rewritten, the motivation to address the issues begins to fade. I could tell not many people would be on board with my proposal to start a 2.0 branch and rewrite the code. That is why in the summer of 2005 I decided I would do it myself.
My primary focus on FreeSWITCH was to start from the core and trap all the common functionality under the hood and expose it in a pyramid to the higher levels of the application. Like Asterisk, the Apache Web Server heavily inspired me and I chose to use a modular design. From the first day the basic fundamentals I chose to adhere to were that every channel has it’s own thread no matter what it was doing and that thread would use a state machine function to navigate its way through the core. This would ensure that every channel would follow the same predictable path and state hooks and overrides could be placed into the machine to add important functionality very similar to how methods and class inheritance works in an object oriented programming language.
It hasn’t been easy. Let me tell you. I’ve had my fair share of Segmentation Faults and Deadlocks while coding FreeSWITCH , (a lot more of the former than the latter I must say). But I built the code from the core and went from there. Since all of the channels operate in their own thread and there are occasions where you need to interact with them, I use read/write locking so the channels can be located from a hashing algorithm rather than a linked list and there is an absolute guarantee that the channel cannot be accessed or go away while an outside thread has reference to it. This alone makes it much easier to sleep at night and obsoletes the need for “Channel Masquerades” and other such voodoo.
The majority of functions and objects supplied by the FreeSWITCH core are protected from the caller by forcing them to be used the way they were designed. Any concept that is extensible or provided by a module has a specific interface which is used to front end that functionality therefore the core has no linking dependency on any of its modules.
There is a clear cut layered API with the core functions being on the bottom and the amount of functions on each subsequent layer decreasing as the functionality increases.
For instance it’s possible to write a large function that uses an arbitrary file format module to open and play audio to a channel. But in the next layer of API there is simply a single function that will play a file to a channel that is then extended to the dial plan tools module as a tiny application interface function. So you can execute the playback from your dial plan, from your custom C application using the same function or you can write your own module that manually opens the file and plays it all using the services of the file format class of modules without ever divulging it’s code.FreeSWITCH is broken into several module interfaces. Here is a list of them:
Dialplan:
Implement the ring state of a call, take the call data and make a routing decision.Endpoint:
Protocol specific interface SIP, TDM etc.ASR/TTS:
Speech recognition and synthesis.Directory:
LDAP type database lookups.Events:
Modules can fire existing core events as well as register their own custom events
Which can be parsed from an event consumer at a later time.Event Handlers:
Remote access to events and CDR.Formats:
File formats such as wav.Loggers:
Console or file logging.Languages:
Embedded languages such as Python and JavaScript.Say:
Language specific modules to construct utterances from sound files.Timers:
Reliable timers for packet interval timing.Applications:
Applications you can execute on the call such as Voicemail.FSAPI (FreeSWITCH API interface [see I use initials too!] )
Command line functions, XMLRPC functions, CGI type functions, Dialplan function variables exposed with a string in, string out prototype.XML
There are hooks to the core XML registry that make it possible to do realtime
lookups and create XML based CDRsAll of the FreeSWITCH modules work together and communicate with each other only via the core API and the internal event system. Great care was taken to ensure this and avoid any unwanted behavior from outside modules.
The event system in FreeSWITCH was designed to keep track of as much as possible. I designed it under the assumption that most users of the software would be connecting to FreeSWITCH remotely or using a custom module to gather call data. Thus, every important thing that happens in FreeSWITCH results in an event firing. The events are very similar to an email format having headers and a body. Events can be serialized into either a standard text format or an XML representation. Any number of modules may be written to connect to the event subsystem and receive events about presence, call state and failures. The in-tree mod_event_socket provides a TCP connection on which events can be consumed as well as log data. In addition call control commands may be sent over this interface as well as bi-directional audio flow. The socket can be established by either an in-progress call as an outbound connection or from a remote machine as an inbound connection.
Another important concept in FreeSWITCH is the centralized XML registry. When FreeSWITCH loads it opens a top-level XML file which is fed into a pre-processor that parses special directives to include other smaller xml files and to set global variables which can be referenced from that point forward to template the configuration.
For instance you can set the preprocessor directive to set a global variable like this:<X-PRE-PROCESS cmd="set" data="moh_uri=local_stream://moh"/>
now even on the next line in the file you can use $${moh_uri} and it will be replaced by local_stream://moh in the post processed output. The final post processed registry is loaded into memory and accessed by the modules and the core to provide several vital sections to the application:
Configuration
Configuration data to control the behaviour of the application.Dialplan
An XML representation of a dialplan that can be used by mod_dialplan_xml to
route calls and execute applications.Phrases
A markup of IVR phrase macros to use from IVRs and to speak multiple languages.Directory
A collection of domains and users for registration and account management.Using XML hook modules, you can bind your module to lookups in the XML registry and, in real time, gather the required information and return it to the caller in place of the static data in the file. This makes it possible to do purely dynamic SIP registrations and dynamic voice mailboxes and dynamic configuration of a cluster using the same model as a web browser and a CGI application.
With embedded languages such as JavaScript, Java, Python and Perl, it’s possible to write scripted application that can control the underlying power with a simple high-level interface.
The first phase of the FreeSWITCH project was to create a stable core on which to build scalable applications. I am happy to report that it will be completed on May 26th 2008 with the release of FreeSWITCH 1.0 “phoenix”. We have been able to out perform Asterisk by a factor of 10 in similar situations according to the accounts of two separate early adopters brave enough to go into production pre-1.0.
I hope this explanation is sufficient to outline the difference between FreeSWITCH and Asterisk and will shed some light on my decision to start the FreeSWITCH project. I will forever remain an Asterisk developer due to my vast involvement in the project and I wish them all the luck in the world with the future design of the application. I may even dig up some more of my long lost Asterisk code in my personal archives and release it to the public as a gesture of good will towards the project that gave me my start in telephony.
Asterisk is an open source PBX and FreeSWITCH is an open source soft switch. There is plenty of room for both applications among the other great open source Telephony applications such as Call Weaver, Bayonne, sipX, OpenSER and many many more. I look forward every year to presenting with and talking to all the developers of these projects at ClueCon in Chicago this summer.http://www.cluecon.com
We can all inspire each other to push the envelope on Telephony even farther. The most important question you can ask is. “Is it the right tool for the job?”