FreeSWITCH 是一个可扩展的开源跨平台的电话平台,支持音频、视频、文本或任何其他形式的媒体使用的协议的路由与交互。它于2006年成立。FreeSWITCH也提供一个稳定的技术平台,可供许多电话应用开发利用的免费工具。
FreeSWITCH 最初由Anthony Minessale在Brian West和Michael Jerris的协助下设计和开发。这三人原先都是asterisk的开发者。这个项目的设计目标包括模块化、跨平台的支持,可扩展性和稳定性。今天,许多更多的开发者和使用者都为FreeSWITCH在贡献力量。
FreeSWITCH支持各种通信技术,如Skype,SIP、H.323、GoogleTalk,因此它容易与其他的开源PBX进行对接,如:sipXecs、Call Weaver、Bayonne、YATE 和Asterisk。
FreeSWITCH支持许多高级的SIP特性,如presence、BLF、SLA以及TCP TLS和 sRTP。它也可以作为一个透明代理(有媒体或无媒体),扮演SBC和T.38代理的角色。
FreeSWITCH既支持宽带、窄带编码。Voice channel和conference bridge模块可以支持8k、16k、24k、32k和48k不同的码率,而且这些不同码率的通道可以进行bridge。如果G.729编解码经过授权,FreeSWITCH也是支持的。
FreeSWITCH支持Windows,Mac OS X ,Linux,BSD和Solaris的32与64位平台。
FreeSWITCH支持传真,无论是音频,还是T.38,而且可以微微音频和T.38的网关。
FreeSWITCH的很多开发者,都是非常有经验的开发人员。他们同时也参与其他开源软交换产品的开发,如:openSER, sipXecs, Asterisk和Call Weaver.
目录结构
├── configure
├── configure.in
├── Makefile.am
├── Makefile.in
├── modules.conf :需要编译的module列表
├── patches/ :补丁包
│ ├── MODAPP-293.diff
│ ├── mod_portaudio_snow_leopard.diff
│ ├── sofia.diff
│ └── zrtp_bnlib_pic.diff
├── src/
│ ├── CMakeLists.txt
│ ├── g711.c
│ ├── include/
│ ├── inet_pton.c
│ ├── Makefile.am
│ ├── Makefile.in
│ ├── mod/
│ ├── switch_apr.c
│ ├── switch_buffer.c
│ ├── switch.c :main入口
│ ├── switch_caller.c
│ ├── switch_channel.c
│ ├── switch_config.c
│ ├── switch_console.c
│ ├── switch_core_asr.c
│ ├── switch_core.c
│ ├── switch_core_codec.c
│ ├── switch_core_db.c
│ ├── switch_core_directory.c
│ ├── switch_core_event_hook.c
│ ├── switch_core_file.c
│ ├── switch_core_hash.c
│ ├── switch_core_io.c
│ ├── switch_core_media_bug.c
│ ├── switch_core_memory.c
│ ├── switch_core_port_allocator.c
│ ├── switch_core_rwlock.c
│ ├── switch_core_session.c
│ ├── switch_core_speech.c
│ ├── switch_core_sqldb.c
│ ├── switch_core_state_machine.c
│ ├── switch_core_timer.c
│ ├── switch_cpp.cpp
│ ├── switch_dso.c
│ ├── switch_event.c
│ ├── switch_ivr_async.c
│ ├── switch_ivr_bridge.c
│ ├── switch_ivr.c
│ ├── switch_ivr_menu.c
│ ├── switch_ivr_originate.c
│ ├── switch_ivr_play_say.c
│ ├── switch_ivr_say.c
│ ├── switch_loadable_module.c
│ ├── switch_log.c
│ ├── switch_mprintf.c
│ ├── switch_nat.c
│ ├── switch_odbc.c
│ ├── switch_pcm.c
│ ├── switch_profile.c
│ ├── switch_regex.c
│ ├── switch_resample.c
│ ├── switch_rtp.c
│ ├── switch_scheduler.c
│ ├── switch_stun.c
│ ├── switch_swig.c
│ ├── switch_swig.i
│ ├── switch_time.c
│ ├── switch_utils.c
│ ├── switch_xml.c
│ └── switch_xml_config.c
├── libs/
启动逻辑
FreeSwitch主程序的入库函数在src/switch.c文件中。Main函数启动:
1. 分析启动参数;
2. 为全局变量SWITCH_GLOBAL_dirs分配内存和赋值;
3. 创建pid文件;
4. 调用switch_core.c中的switch_core_init_and_modload()函数,初始化并加载所有的module,内部实现逻辑如下:
a) switch_core_init_and_modload
i. 首先调用switch_core_init
1. 初始化全局变量runtime的相关参数;
2. 对SWITCH_GLOBAL_dirs指定的目录进行创建;
3. load_mime_types加载conf/mime.types加载所有的mime类型;
4. 设置运行参数的默认值(注意:switch_find_local_ip获取本地IP的时候会访问外网);
5. 依次调用:switch_core_session_init、switch_console_init、switch_event_init、switch_xml_init、switch_log_init进行相关的初始化,初始化的内容主要:hash、mutex。
6. 加载"switch.conf"配置文件;
7. switch_core_state_machine_init对state_machine进行初始化;
8. switch_core_sqldb_start,启动数据库相关线程;
9. switch_scheduler_task_thread_start,启动任务调度模块
10. switch_rtp_init:初始化rtp/zrtp相关的
11. switch_scheduler_add_task( heartbeat_callback),将心跳任务加入任务调度模块;
ii. switch_loadable_module_init()[switch_loadable_module.c]加载各module,freeswitch为了后续高效的运行module中的各种接口,将所有的接口都存放到了hash表中,每种接口建立了一个hash桶:
1. 初始化全局变量:loadable_modules的各类hash。
2. 加载集成module:CORE_SOFTTIMER_MODULE、CORE_PCM_MODULE;
a) switch_loadable_module_load_file进行module加载
i. 找到name##_module_interface的全局变量进行加载(module中宏SWITCH_MODULE_DEFINITION定义的);
ii. 执行module->load(会初始化参数module_interface,是SWITCH_MODULE_LOAD_FUNCTION定义的函数的一个参数),load中会增加各类接口:API、CHAT、APP、DIALPLAN、CODEC
b) switch_loadable_module_process
i. 遍历每个节点的endpoint_interface、codec_interface、dialplan_interface、timer_interface、application_interface、api_interface、file_interface、speech_interface、asr_interface、directory_interface、chat_interface、say_interface、management_interface,加载并存储到hash。
c) 创建线程,执行module->runtime()
3. 遍历conf/modules.conf加载所有配置的module;
4. 遍历conf/post_load_modules.conf加载所有配置的module;
5. 如果除集成module之外配置的模块为0,则从SWITCH_GLOBAL_dirs.mod_dir加载所有的mod;
6. switch_loadable_module_runtime,为每个module的runtime入口创建一个线程并运行runtime;
事件处理模型
FreeSWITCH内部处理事件的基本数据结构和逻辑如下图:
1. freeSWITCH启动的时候,会创建3个EVENT_QUEUE,用来保存相关api、dialplan或呼叫触发的事件,队列长度为100000,每个队列的优先级不一样,平台根据事件的优先级将事件入队。注意:如果符合优先级要求的队列已经满了或其他原因造成入队失败,可能将事件放入到低优先级的队列[c1] ;
2. 每个EVENT_QUEUE会伴随一个event_thread线程,该线程的作用就是将EVENT_QUEUE的事件转移到EVENT_DISPATCH_QUEUE,队列长度为5000。FreeSWITCH启动的时候会创建1个EVENT_DISPATCH_QUEUE队列,正常情况下,event_thread会将事件放入到EVENT_DISPATCH_QUEUE[0],如果该队列已满或其他原因造成入队失败,再系统会动态创建EVENT_DISPATCH_QUEUE[1],[c2] 将事件放入该队列,依次类推;
3. 每个EVENT_DISPATCH_QUEUE队列伴随一个event_dispatch_thread,该线程的作用就是将EVENT_DISPATCH_QUEUE的事件转移到对应的事件订约方队列NODE_EVENT_QUEUE,每个订阅会自带一个NODE_EVENT_QUEUE,长度为100000.。
媒体处理方式FreeSWITCH有三种媒体处理方式,分别是:default、proxy、bypass,具体的应用和对比参考下表:
Default | Proxy (proxy_media=true) | Bypass (bypass_media=true) | |
FreeSWITCH是否有媒体经过 | Y | Y | N |
是否可以对媒体流进行编解码 | Y | N | N |
是否需要终端语音编解码协商一致 | N | Y | Y |
支持录音、DTMF解析、会议、编解码转换 | Y | N | N |
[c1]带来了可能的事件时序错误的问题
[c2]带来了可能的事件时序错误的问题