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
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容