1、核心头文件
freeswitch是服务端程序,它的入口main函数在src/switch.c实现,相关的头文件还有switch.h、private/switch_core_pvt.h。先看下switch.h内容。
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <assert.h>
#include <setjmp.h>
...
#include "switch_platform.h"
#include "switch_types.h"
#include "switch_apr.h"
#include "switch_mprintf.h"
#include "switch_core_db.h"
#include "switch_dso.h"
#include "switch_regex.h"
#include "switch_core.h"
#include "switch_loadable_module.h"
#include "switch_console.h"
#include "switch_utils.h"
#include "switch_caller.h"
#include "switch_frame.h"
#include "switch_rtcp_frame.h"
#include "switch_module_interfaces.h"
#include "switch_channel.h"
#include "switch_buffer.h"
#include "switch_event.h"
#include "switch_resample.h"
#include "switch_ivr.h"
#include "switch_rtp.h"
#include "switch_log.h"
#include "switch_xml.h"
可以看到,switch.h可以说是freeswitch的总include,包含了系统和核心等所有对外头文件。所有模块,都通过include “switch.h”来包含核心。
2、main
#include <switch.h>
#include "private/switch_core_pvt.h" //核心内部定义
int main(int argc, char *argv[])//switch.c
{
//命令行参数解析
SWITCH_GLOBAL_dirs.xx_dir =
//初始化和加载模块
switch_core_init_and_modload();//switch_core.c
{
switch_core_init();
switch_loadable_module_init();//switch_loadable_module.c
switch_load_core_config("post_load_switch.conf");
}
switch_core_runtime_loop();
}
main函数可以简化为以上流程,首先是对命令行参数进行解析,并且存储到一些全局变量,然后调用switch_core_init_and_modload,顾名思义,就是初始化核心和加载模块,最后调用switch_core_runtime_loop循环等待用户输入,然后执行响应的命令。
2.1 命令行参数
命令行参数可以看switch.c的usage数组,这里只介绍几个常用的。
-nc:
“\t-nc – do not output to a console and background\n”
加上这个参数,就不会在前台运行,下面看对此参数的操作,使用nc,则调用daemonize函数,该函数会使用后台运行,该函数不再展开。
1.if (nc) {
2.ifdef WIN32
3. FreeConsole();
4.else
5. if (!nf) {
6. daemonize(do_wait ? fds : NULL);
7. }
8.endif
9.}
“\t-nonat – disable auto nat detection\n”
Freeswitch默认会尝试在路由器上“打洞”,影响使用速度,使用nonat可以在内网测试时,加速启动。
3、核心初始化
上面提到,main函数会调用switch_core_init_and_modload进行核心初始化和加载模块,现在先来看核心初始化switch_core_init。
1.switch_core_init();
2.{
3. runtime.xxx
4. sqlite3_initialize();
5. apr_initialize();
6. //初始化session_manager
7. switch_core_session_init();
8. switch_curl_init();
9. switch_console_init();
10. switch_event_init();
11. //初始化channel的globals
12. switch_channel_global_init();
13. switch_xml_init();
14. switch_nat_init();
15. switch_log_init();
16. //解析全局参数,比如core-db-dsn保存到runtime.odbc_dsn
17. switch_load_core_config("switch.conf");
18. switch_core_state_machine_init();
19. switch_core_sqldb_start();
20. switch_core_media_init();
21. switch_scheduler_task_thread_start();
22. switch_nat_late_init();
23. switch_rtp_init(runtime.memory_pool);
24.}
3.1、全局结构体runtime
1.struct switch_runtime {
2. switch_memory_pool_t *memory_pool;
3. const switch_state_handler_table_t *state_handlers[SWITCH_MAX_STATE_HANDLERS];
4. int state_handler_index;
5. FILE *console;
6. uint8_t running;
7. uint32_t flags;
8. char *odbc_dsn;
9. char *dbname;
10. uint32_t debug_level;
11. uint32_t runlevel;
12. char hostname[256];
13....
14.};
15.
16.extern struct switch_runtime runtime;
这里只列出几个重要结构体,其中odbc_dsn和dbname,就是从配置文件switch.conf.xml解析出来的,其它有些成员也是。
1. <!-- <param name="core-db-dsn" value="pgsql://hostaddr=127.0.0.1 dbname=freeswitch user=freeswitch password='' options='-c client_min_messages=NOTICE'" /> -->
2. <!-- <param name="core-db-dsn" value="dsn:username:password" /> -->
3. <!--
4.Allow to specify the sqlite db at a different location (In this example, move it to ramdrive for
5.better performance on most linux distro (note, you loose the data if you reboot))
6. -->
7. <!-- <param name="core-db-name" value="/dev/shm/core.db" /> -->
3.2、子核心初始化
核心会初始化各个子模块,注意,这里是核心的模块,而不是扩展模块mod。一般核心子模块的初始化,都是设置一个全局结构体参数,分析具体该模块的时候再讲。
3.3、解析主配置文件switch.conf.xml
25.//解析全局参数,比如core-db-dsn保存到runtime.odbc_dsn
26. switch_load_core_config("switch.conf");
这个函数就不进去细讲,无非就是解析xml字段。我们只需要明白,全局配置switch.conf在这里解析到全局变量runtime。
4、可加载模块初始化
1.switch_loadable_module_init();//switch_loadable_module.c
2.{
3. char *cf = "modules.conf";
4. char *pcf = "post_load_modules.conf";
5. //载入核心默认模块
6. switch_loadable_module_load_module("", "CORE_SOFTTIMER_MODULE", SWITCH_FALSE, &err);
7. switch_loadable_module_load_module("", "CORE_PCM_MODULE", SWITCH_FALSE, &err);
8. switch_loadable_module_load_module("", "CORE_SPEEX_MODULE", SWITCH_FALSE, &err);
9. //循环解析modules.conf和post_load_modules.conf
10. switch_loadable_module_load_module_ex();
11. switch_loadable_module_runtime();
12. chat_thread_start(1);
13.}
首先加载三个包含在核心的模块,softtimer、pcm、speex,然后根据配置文件modules.conf和post_load_modules.conf加载对应的模块,这里的模块就是mod。如何加载,后面再单独一篇说明。