freeswitch 内核模块开发

我建了一个 Freeswitch 内核研究 交流群, 45211986, 欢迎加入, 另外,提供基于SIP的通信服务器及客户端解决方案。

这里以模块 helloworld 为例。

1. 创建模块目录 freeswitch/src/mod/applications/mod_helloworld

2. 把模块名放在freeswitch/modules.conf文件中,make时 根据此文件选择编译哪些模块并生成相应模块的makefile文件

3. 如果你的模块以依赖第三方库,则需要在makefile中指定头文件以及库的路径,一个例子:

LOCAL_CFLAGS=-I$(switch_srcdir)/libs/libteletone/src
LOCAL_LDFLAGS=$(switch_srcdir)/libs/libteletone/libteletone.la


4.如果你的模块包含多个文件则需要 指定文件列表:

LOCAL_OBJS=file.c file2.c file3.c 
local_depend: $(LOCAL_OBJS)


5.编写模块接口


freeswitch中 每个模块从加载->运行->关闭 流程由三个宏实现,实际编写模块过程为几个宏的填写。具体业务逻辑在宏内部实现。

SWITCH_MODULE_LOAD_FUNCTION (mod_name)

实际展开即为函数,load function 负责系统启动时或运行时加载模块,模块的全局数据结构,钩子设置,事件handler 一般在此处实现。

SWITCH_MODULE_RUNTIME_FUNCTION

系统运行时loop, 这里可以启动线程处理请求,监听socket 等等。

SWITCH_MODULE_SHUTDOWN_FUNCTION

模块卸载,这里负责清除全局数据结构,释放资源。

SWITCH_MODULE_DEFINITION 模块的定义


mod_helloworld.c 代码:


#include <switch.h>

/*  initialize any global structures, hook up any event or state handlers ,etc  */
SWITCH_MODULE_LOAD_FUNCTION(mod_helloworld_load);

 /*  the runtime loop of the module, from here you can listen on sockets, 
  *  spawn new threads to handle requests. etc.
  */
SWITCH_MODULE_RUNTIME_FUNCTION(mod_helloworld_runtime);

 /*
  *   This is where you do any cleanup for unloading or reloading the module, 
  *     you should release state handlers, event reservations, etc. 
  *      You should also synchronize with shutting down the runtime thread (usually using something like a shared 'running' variable that the shutdown function 
  *    sets to some value that the runtime function notices, sets to a third value and then exits).
  */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_helloworld_shutdown);

SWITCH_MODULE_DEFINITION(mod_helloworld, mod_helloworld_load, mod_helloworld_shutdown, NULL);


SWITCH_STANDARD_API(helloworld_function)
{
    return SWITCH_STATUS_SUCCESS;
}
static switch_status_t parse_config(switch_bool_t reload)
{
	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "parse config\n");

	return SWITCH_STATUS_SUCCESS;
}

/*
    Macro expands to: switch_status_t  mod_helloworld_load(switch_loadable_module_interface_t **module_interface, 
    		switch_memory_pool_t *pool) 
*/
SWITCH_MODULE_LOAD_FUNCTION(mod_helloworld_load)
{
	switch_api_interface_t *api_interface;
	/* connect my internal structure to the blank pointer passed to me */
	*module_interface = switch_loadable_module_create_module_interface(pool, modname);

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Hello World!\n");

	parse_config(SWITCH_FALSE);

	SWITCH_ADD_API(api_interface, "helloworld", "Hello World API", helloworld_function, "syntax");

	/* indicate that the module should continue to be loaded */
	return SWITCH_STATUS_SUCCESS;
	
}

SWITCH_MODULE_RUNTIME_FUNCTION(mod_helloworld_runtime)
{
	while(1) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Hello World!\n");
		switch_yield(10000);
	}
}




编译: sudo make mod_helloworld
安装   sudo make mod_helloworld-install
dialplan里试一试 function  helloworld.
-----------------------------------
高级:
1.模块加载函数内可以加载自定义xml配置文件.
例子:
<configuration name="mymodule.conf" description="MyModule configuration">
   <settings>
    <param name="key" value="value"/>
    ...
   </settings>
 </configuration>
You could do the following:

 switch_xml_t xml = NULL, x_lists = NULL, x_list = NULL, cfg = NULL;
 if ((xml = switch_xml_open_cfg("mymodule.conf", &cfg, NULL))) {
   if ((x_lists = switch_xml_child(cfg, "settings"))) {
     for (x_list = switch_xml_child(x_lists, "param"); x_list; x_list = x_list->next) {
       const char *name = switch_xml_attr(x_list, "name"); // This needs to be const 
       const char *value = switch_xml_attr(x_list, "value");
 
       // Ignore empty/missing attributes
       if (switch_strlen_zero(name)) {
         continue;
       }
       
       if (switch_strlen_zero(value)) {
         continue;
       }
 
       if (!strcmp(name, "myattribute")) {
         // Do something with value
       } else if (!strcmp(name, "myotherattribute")) {
         // ...
       } else {
         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown attribute %s\n", name);
       }
     }
   }
 } else {
   switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load MyModule's config!\n");
 }

2. 订阅事件
模块可以向系统订阅自己感兴趣的事件,只需一个函数,指定一个你自己的事件回调。
例子:订阅所有事件
if (switch_event_bind("mod_mymodule", SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY, mymodule_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
   switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot bind to event handler!\n");
 }

接下来就是编写你的回调函数 
void mymodule_event_handler(switch_event_t *event);
void mymodule_event_handler(switch_event_t *event) 
 {
 	switch_assert(event); // Just a sanity check
 	
 	switch(event->event_id) {
 		case SWITCH_EVENT_CHANNEL_CREATE:
 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "A new channel is born, its called \"%s\"\n", 
 				switch_event_get_header_nil(event, "channel-name")); // This function isnt case-sensitive 
 			break;
 		case SWITCH_EVENT_CHANNEL_DESTROY:
 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "A channel named \"%s\" has been destroyed\n"
 				switch_event_get_header_nil(event, "channel-name"));
 			break;
 	}
 }

3.在模块内 发起呼叫,定义channle状态回调。。。。












你可能感兴趣的:(switch)