FreeSWITCH模块开发

参考:https://freeswitch.org/confluence/display/FREESWITCH/Creating+New+Modules
参考:https://freeswitch.org/confluence/display/FREESWITCH/mod_skel

1、新模块文件清单

Makefile.am   # 参考autotools的Makefile.am语法
*.c           # c源码

1.1、模块的Makefile.am

# 默认
include $(top_srcdir)/build/modmake.rulesam
# 模块名称,对应模块的文件夹名称
MODNAME=mod_event_redis
# 模块编译后lib文件名称
mod_LTLIBRARIES = mod_event_redis.la
# 模块入口资源文件
mod_event_redis_la_SOURCES  = mod_event_redis.c
# 默认
mod_event_redis_la_CFLAGS   = $(AM_CFLAGS)
mod_event_redis_la_LIBADD   = $(switch_builddir)/libfreeswitch.la
mod_event_redis_la_LDFLAGS  = -avoid-version -module -no-undefined -shared

2、模块接口

// 使用这个宏定义了模块的加载函数,在这个函数中你应该初始化任何全局结构,连接任何事件或状态处理程序等。如果你返回除了 SWITCH_STATUS_SUCCESS 以外的任何东西,模块将不会继续被加载。
SWITCH_MODULE_LOAD_FUNCTION(load);

// 这是模块的运行时循环,从这里你可以监听套接字,产生新的线程来处理请求。等等
SWITCH_MODULE_RUNTIME_FUNCTION(runtime);

// 这是您为卸载或重新加载模块进行任何清理的地方,您应该释放状态处理程序、事件保留等。您还应该与关闭运行时线程同步(通常使用类似于关闭函数的共享“运行”变量设置为运行时函数注意到的某个值,设置为第三个值,然后退出)。
SWITCH_MODULE_SHUTDOWN_FUNCTION(shutdown);

// 模块定义(模块name,load函数,shutdown函数,runtime函数)
SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime);

// 实现加载模块时被调函数的逻辑
SWITCH_MODULE_LOAD_FUNCTION(load) 
{

}

// 实现模块运行时被调函数的逻辑
SWITCH_MODULE_RUNTIME_FUNCTION(runtime)
{

}

// 实现模块停止时被调函数的逻辑
SWITCH_MODULE_SHUTDOWN_FUNCTION(shutdown)
{

}

3、基础函数

3.1、XML API

3.1.1、switch_xml_free(switch_xml_t xml)

释放switch_xml_t 类型内存

3.1.2、switch_xml_locate_domain (const char *domain_name, switch_event_t *params, switch_xml_t *root, switch_xml_t *domain)

获取domian信息,返回switch_status_t

3.1.3、switch_xml_locate_user(const char *key, const char *user_name, const char *domain_name, const char *ip, switch_xml_t *root, switch_xml_t *domain, switch_xml_t *user, switch_event_t *params)

获取用户信息,返回switch_status_t

3.1.4、switch_xml_open_cfg(const char *file_path, switch_xml_t *node, switch_event_t *params)

获取对应xml配置文件,返回switch_xml_t

file_path:配置部分的名称,例如 modules.conf
node:一个指针,如果找到,则指向该节点
params:可选的 URL 格式的参数传递给外部网关

3.2、绑定事件

3.2.1、订阅事件


switch_event_bind(const char *id, switch_event_types_t event, const char *subclass_name, switch_event_callback_t callback, void *user_data);

// id 是活页夹的标识符标记,使用您的模块名称
// event 是您想要接收的事件 SWITCH_EVENT_ALL 事件类型和 SWITCH_EVENT_SUBCLASS_ANY 子类
// subclass_name 显然是子类的名称
// user_data 是一个指针,它将在回调时传回给您叫做

// e.g.
static void event_handler(switch_event_t *event) {

}

// 绑定事件,并且回调指定的函数 event_handler()
if (switch_event_bind(modname, SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY, event_handler, NULL) != SWITCH_STATUS_SUCCESS) {

}

3.2.2、根据通道状态订阅事件


// Globally 全局变量
switch_core_add_state_handler(const switch_state_handler_table_t *state_handler);
switch_core_remove_state_handler(const switch_state_handler_table_t *state_handler);

// On a specific channel 具体的通道
switch_channel_add_state_handler(switch_channel_t *channel, const switch_state_handler_table_t *state_handler);
switch_channel_clear_state_handler(switch_channel_t *channel, const switch_state_handler_table_t *state_handler);

// e.g.
switch_status_t on_my_callback(switch_core_session_t *session)
{

}

struct switch_state_handler_table_t state_handlers = {
       /*switch_state_handler_t on_init;*/           NULL,
       /*switch_state_handler_t on_routing;*/        NULL,
       /*switch_state_handler_t on_execute;*/        NULL,
       /*switch_state_handler_t on_hangup;*/         NULL,
       /*switch_state_handler_t on_exchange_media;*/ NULL,
       /*switch_state_handler_t on_soft_execute;*/   NULL,
       /*switch_state_handler_t on_consume_media;*/  NULL,
       /*switch_state_handler_t on_hibernate;*/      NULL,
       /*switch_state_handler_t on_reset;*/          NULL,
       /*switch_state_handler_t on_park;*/           NULL,
       /*switch_state_handler_t on_reporting;*/      NULL,
       /*switch_state_handler_t on_destroy;*/        on_my_callback
 };

switch_core_add_state_handler(&state_handlers);

3.3、拨打电话相关

FreeSWITCH 调用分析
(谈论通话状态、会话、频道、私人数据等)

3.3.1、****从您的模块中拨打电话****

Below is my current understanding. I'm not core developer, so all is guessed --Sathieu 11:14, 18 February 2010 (UTC)

When originate your_module/dest vmain is called from the console:

your_io_routines.outgoing_channel is called
        create a new session (with switch_core_session_request())
        parse outbound_profile->destination_number to get called number
        qualify the session, attached channel and attached private data
        The channel is currently in CS_NEW
        Change channel state to CS_INIT
        Make the phone ring (and call switch_channel_mark_ring_ready())
your_state_handler.on_init is called
        Change channel state to CS_ROUTING
your_state_handler.on_routing is called
        What to do here?
The call is answered
        switch_channel_mark_answered(channel)

3.3.2、通话****Session对象****

switch_core_session_t *session;
  if ((session = switch_core_session_locate(uuid_here))) {
          /* do stuff with session */
          switch_core_session_rwunlock(session);
  }

// NOTE: switch_core_session_locate() will automatically lock the session. When you are done with the session object it is MANDATORY to call switch_core_session_rwunlock() or bad things will happen.
// 注意:switch_core_session_locate() 将自动锁定会话。 完成会话对象后,必须调用 switch_core_session_rwunlock() 否则会发生坏事。

3.4、Macros (宏)

3.4.1、****SWITCH_DECLARE_GLOBAL_STRING_FUNC****

这个宏允许你定义一个动态的全局字符串(它实际上是你的模块的静态)设置函数。 宏将释放先前的值(如果有),然后将新值 strdup 到其中。 第一个值是要定义的函数的名称,第二个参数是 char * 指针,用于存储指向已分配字符串的指针。

3.4.2、****switch_malloc****

用于尝试常规 malloc() 的宏,它将 abort() 进程(例如,使用 SIGABRT 退出),将错误消息打印到 stderr,其中包含发生错误的文件名和行号。

#define switch_malloc(ptr, len) (void)( (!!(ptr = malloc(len))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%s", __FILE__, __LINE__),abort(), 0), ptr )

3.4.3、****switch_zmalloc****

根据 #switch_malloc,但使用 calloc() 以便缓冲区的内容在使用前用字节值零填充。

#define switch_zmalloc(ptr, len) (void)( (!!(ptr = calloc(1, (len)))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%s", __FILE__, __LINE__),abort(), 0), ptr)

3.4.4、****switch_strdup****

与#switch_malloc 类似,如果strdup() 返回一个空指针,宏将中止()(因为strdup() 在内部只是一个malloc() 和一个strcpy())。

#define switch_strdup(ptr, s) (void)( (!!(ptr = strdup(s))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%s", __FILE__, __LINE__),abort(), 0), ptr)

3.4.5、****switch_safe_free****

避免释放空指针的宏。 指针在 free()'ing 之后设置为 null 以避免指向过时的缓冲区。

#define switch_safe_free(it) if (it) {free(it);it=NULL;}

4、新模块清单

1、新建Makefile.am文件
2、将模块添加到 FS configure.ac
3、将模块添加到 build/modules.conf.in(注释掉)
4、在模块顶部的注释中尽可能详细地描述模块

5、demo参考:https://github.com/Atoms-Cat/freeswitch

# 模块目录: src/mod/event_handlers/mod_event_redis
# 实现把 channel 信息缓存到 redis
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容