freeswitch系列3加载模块

  1. 可加载模块数据结构

可加载模块相关的文件如下

switch_loadable_module.h

switch_loadable_module.c

switch_types.h

switch_module_interfaces.h

在switch_loadable_module.c定义了可加载模块容器和可加载模块对象:

  1. struct switch_loadable_module {  
  2.     char *key;  
  3.     char *filename;  
  4.     int perm;  
  5.     switch_loadable_module_interface_t *module_interface;  
  6.     switch_dso_lib_t lib;  
  7.     switch_module_load_t switch_module_load;  
  8.     switch_module_runtime_t switch_module_runtime;  
  9.     switch_module_shutdown_t switch_module_shutdown;  
  10.     switch_memory_pool_t *pool;  
  11.     switch_status_t status;  
  12.     switch_thread_t *thread;  
  13.     switch_bool_t shutting_down;  
  14. };  
  15.   
  16. struct switch_loadable_module_container {  
  17.     switch_hash_t *module_hash;  
  18.     switch_hash_t *endpoint_hash;  
  19.     switch_hash_t *codec_hash;  
  20.     switch_hash_t *dialplan_hash;  
  21.     switch_hash_t *timer_hash;  
  22.     switch_hash_t *application_hash;  
  23.     switch_hash_t *chat_application_hash;  
  24.     switch_hash_t *api_hash;  
  25.     switch_hash_t *json_api_hash;  
  26.     switch_hash_t *file_hash;  
  27.     switch_hash_t *speech_hash;  
  28.     switch_hash_t *asr_hash;  
  29.     switch_hash_t *directory_hash;  
  30.     switch_hash_t *chat_hash;  
  31.     switch_hash_t *say_hash;  
  32.     switch_hash_t *management_hash;  
  33.     switch_hash_t *limit_hash;  
  34.     switch_hash_t *secondary_recover_hash;  
  35.     switch_mutex_t *mutex;  
  36.     switch_memory_pool_t *pool;  
  37. };  
  38.  
  39. static struct switch_loadable_module_container loadable_modules;

 

switch_loadable_module_container容器,除了模块哈希表module_hash外,还有各种接口哈希表,并且39行定义了一个全局结构体容器loadable_modules。容器管理多个模块对象。

模块对象比较重要的几个参数

key:用户哈希表搜索,本质上就是文件名filename

module_interface:模块接口,每个模块都会有个模块接口,通过模块接口可以获取该模块实现的各种接口,比如端点接口。

load、runtime、shutdown这组是模块可实现的三个默认接口,其中load是必须的,在加载模块后会首先调用。

  1. 模块初始化
  1. switch_loadable_module_init();//switch_loadable_module.c  
  2. {  
  3.     //初始化容器loadable_modules  
  4.     char *cf = "modules.conf";  
  5.     char *pcf = "post_load_modules.conf";  
  6.      //载入核心默认模块  
  7.      switch_loadable_module_load_module("""CORE_SOFTTIMER_MODULE", SWITCH_FALSE, &err);  
  8.      switch_loadable_module_load_module("""CORE_PCM_MODULE", SWITCH_FALSE, &err);  
  9.      switch_loadable_module_load_module("""CORE_SPEEX_MODULE", SWITCH_FALSE, &err);  
  10.        
  11.      //循环解析modules.conf和post_load_modules.conf  
  12.      switch_loadable_module_load_module_ex();  
  13.      switch_loadable_module_runtime();  
  14.      chat_thread_start(1);  

前篇讲到在main函数,会调用模块初始化,首先加载三个核心内部的模块softtimer、pcm、speex,然后根据两个配置modules.conf和post_load_modules.conf,去加载模块。加载模块最终是调用switch_loadable_module_load_module_ex()进行。

 

    1. switch_loadable_module_load_module_ex()
  1. switch_loadable_module_load_module_ex()  
  2. {  
  3.     //如果已加载  
  4.     if (switch_core_hash_find_locked(loadable_modules.module_hash, file, loadable_modules.mutex)) {  
  5.     }  
  6.     //如果未加载,则从模块名对应的文件载入  
  7.     else if(switch_loadable_module_load_file())  
  8.     {  
  9.         //填充模块对象结构体,加入模块容器  
  10.         switch_loadable_module_process();  
  11.         //如果有实现模块runtime函数,创建线程执行  
  12.         if (new_module->switch_module_runtime) {  
  13.             new_module->thread = switch_core_launch_thread(switch_loadable_module_exec, new_module, new_module->pool);  
  14.         }  
  15.     }  
  16. }  

载入模块先判断是否在容器中的模块哈希表,如果未存在,则做三件事

1、调用switch_loadable_module_load_file()从文件加载。

2、处理模块switch_loadable_module_process,主要是把模块加入各个哈希表。

3、如果模块有实现runtime,则新起线程执行之,这个函数不是所有模块都有,先不深入分析。

    1. switch_loadable_module_load_file
  1. static switch_status_t switch_loadable_module_load_file(char *path, char *filename, switch_bool_t global, switch_loadable_module_t **new_module)  
  2. {  
  3.     switch_loadable_module_function_table_t *interface_struct_handle = NULL;  
  4.     switch_loadable_module_function_table_t *mod_interface_functions = NULL;  
  5.     switch_module_load_t load_func_ptr = NULL;  
  6.       
  7.     //每个模块要实现模块函数表,并且命名规则如下,比如mod_sofia模块有sofia_module_interface  
  8.     struct_name = switch_core_sprintf(pool, "%s_module_interface", filename);  
  9.       
  10.     //打开动态链接库  
  11.     switch_dso_open();  
  12.       
  13.     //获取模块函数表指针  
  14.     interface_struct_handle = switch_dso_data_sym(dso, struct_name, &derr)  
  15.       
  16.     if (interface_struct_handle) {  
  17.         mod_interface_functions = interface_struct_handle;  
  18.         //找到模块的load函数指针  
  19.         load_func_ptr = mod_interface_functions->load;  
  20.     }  
  21.       
  22.     //执行该模块的load函数,返回模块接口  
  23.     status = load_func_ptr(&module_interface, pool);  
  24.       
  25.     //申请module数据结构,并填充字段  
  26.     module = switch_core_alloc(pool, sizeof(switch_loadable_module_t);  
  27.     module->pool = pool;  
  28.     module->filename = switch_core_strdup(module->pool, path);  
  29.     module->module_interface = module_interface;  
  30.     module->switch_module_load = load_func_ptr;  
  31. }

 

1、首先打开动态链接库 switch_dso_open,其内部实质使用dlopen。

2、拿到xx_module_interface函数指针,也就是说,每个模块都要以模块名字开头,定义一个函数表。使用switch_dso_data_sym,内部实质使用dlsym。

3、使用函数表,获取load函数;

4、调用load函数,获取模块接口函数module_interface。

    1. switch_loadable_module_process
  1. switch_loadable_module_process(file, new_module)  
  2. {  
  3.     //插入模块容器中的模块哈希表,以文件名作为key  
  4.     switch_core_hash_insert(loadable_modules.module_hash, key, new_module);  
  5.     //如果该模块实现了端点接口  
  6.     if (new_module->module_interface->endpoint_interface) {  
  7.         //插入到模块容器中的端点哈希表  
  8.         switch_core_hash_insert(loadable_modules.endpoint_hash, ptr->interface_name, (const void *) ptr);  
  9.     }  
  10.     ...  
  11.     其它接口判断  
  12. }  

从switch_loadable_module_load_file可以构造一个模块对象,然后插入到模块容器,并且进行一系列接口判断,如果该模块实现某类接口,则添加到该类接口的哈希,这里只列出端点接口的判断,后面各种类型的接口判断省略。

  1. 实现一个模块

在switch_type.h中,有如下定义。

  1. #define SWITCH_MODULE_DEFINITION_EX(name, load, shutdown, runtime, flags)                   \  
  2. static const char modname[] =  #name ;                                                      \  
  3. SWITCH_MOD_DECLARE_DATA switch_loadable_module_function_table_t name##_module_interface = { \  
  4.     SWITCH_API_VERSION,                                                                     \  
  5.     load,                                                                                   \  
  6.     shutdown,                                                                               \  
  7.     runtime,                                                                                \  
  8.     flags                                                                                   \  
  9. }  
  10.   
  11. #define SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)                             \  
  12.         SWITCH_MODULE_DEFINITION_EX(name, load, shutdown, runtime, SMODF_NONE)  

 

通过SWITCH_MODULE_DEFINITION宏,可以定义一个函数表,函数表中有load、shutdown、runtime三个函数,这个函数表的名字,是xxx_module_interface,也就是switch_status_t switch_loadable_module_load_file中的interface_struct_handle。函数表定义如下:

 

  1. //每个模块实现一个函数表,取名如sofia_module_interface  
  2. typedef struct switch_loadable_module_function_table {  
  3.     int switch_api_version;  
  4.     switch_module_load_t load;  
  5.     switch_module_shutdown_t shutdown;  
  6.     switch_module_runtime_t runtime;  
  7.     switch_module_flag_t flags;  
  8. } switch_loadable_module_function_table_t;  

 

    1. 模块接口

使用load函数,可以获取模块接口,也就是switch_status_t switch_loadable_module_load_file中的module_interface,模块接口里面有各种接口的指针,一个模块可以实现一个或多个接口。

  1. struct switch_loadable_module_interface {  
  2.     /*! the name of the module */  
  3.     const char *module_name;  
  4.     /*! the table of endpoints the module has implemented */  
  5.     switch_endpoint_interface_t *endpoint_interface;  
  6.     /*! the table of timers the module has implemented */  
  7.     switch_timer_interface_t *timer_interface;  
  8.     /*! the table of dialplans the module has implemented */  
  9.     switch_dialplan_interface_t *dialplan_interface;  
  10.     /*! the table of codecs the module has implemented */  
  11.     switch_codec_interface_t *codec_interface;  
  12.     /*! the table of applications the module has implemented */  
  13.     switch_application_interface_t *application_interface;  
  14. ...  
  15.     switch_thread_rwlock_t *rwlock;  
  16.     int refs;  
  17.     switch_memory_pool_t *pool;  
  18. };  

 

 

  1. 各种接口
    1. 端点接口
  1. struct switch_endpoint_interface {  
  2.     /*! the interface's name */  
  3.     const char *interface_name;  
  4.   
  5.     /*! channel abstraction methods */  
  6.     switch_io_routines_t *io_routines;  
  7.   
  8.     /*! state machine methods */  
  9.     switch_state_handler_table_t *state_handler;  
  10.   
  11.     /*! private information */  
  12.     void *private_info;  
  13.   
  14.     switch_thread_rwlock_t *rwlock;  
  15.     int refs;  
  16.     switch_mutex_t *reflock;  
  17.   
  18.     /* parent */  
  19.     switch_loadable_module_interface_t *parent;  
  20.   
  21.     /* to facilitate linking */  
  22.     struct switch_endpoint_interface *next;  
  23.   
  24.     switch_core_recover_callback_t recover_callback;  
  25.   
  26. };  

端点是最重要的一类接口,比如sip就是属于端点,下面解释几个重点成员:

interface_name:接口名字

io_routines:数据流IO结构体

state_handler:状态处理回调,后面讲channel状态机会说明。

parent:父指针,指向模块接口

next:短接接口链表

 

      1. IO例程
  1. //io例程  
  2. typedef enum {  
  3.     SWITCH_IO_OUTGOING_CHANNEL,  
  4.     SWITCH_IO_READ_FRAME,  
  5.     SWITCH_IO_WRITE_FRAME,  
  6.     SWITCH_IO_KILL_CHANNEL,  
  7.     SWITCH_IO_SEND_DTMF,  
  8.     SWITCH_IO_RECEIVE_MESSAGE,  
  9.     SWITCH_IO_RECEIVE_EVENT,  
  10.     SWITCH_IO_STATE_CHANGE,  
  11.     SWITCH_IO_READ_VIDEO_FRAME,  
  12.     SWITCH_IO_WRITE_VIDEO_FRAME,  
  13.     SWITCH_IO_GET_JB,  
  14. } switch_io_routine_name_t;  
  15.   
  16. /*! \brief A table of i/o routines that an endpoint interface can implement */  
  17. struct switch_io_routines {  
  18.     /*! creates an outgoing session from given session, caller profile */  
  19.     switch_io_outgoing_channel_t outgoing_channel;  
  20.     /*! read a frame from a session */  
  21.     switch_io_read_frame_t read_frame;  
  22.     /*! write a frame to a session */  
  23.     switch_io_write_frame_t write_frame;  
  24.     /*! send a kill signal to the session's channel */  
  25.     switch_io_kill_channel_t kill_channel;  
  26.     /*! send a string of DTMF digits to a session's channel */  
  27.     switch_io_send_dtmf_t send_dtmf;  
  28.     /*! receive a message from another session */  
  29.     switch_io_receive_message_t receive_message;  
  30.     /*! queue a message for another session */  
  31.     switch_io_receive_event_t receive_event;  
  32.     /*! change a sessions channel state */  
  33.     switch_io_state_change_t state_change;  
  34.     /*! read a video frame from a session */  
  35.     switch_io_read_video_frame_t read_video_frame;  
  36.     /*! write a video frame to a session */  
  37.     switch_io_write_video_frame_t write_video_frame;  
  38.     /*! change a sessions channel run state */  
  39.     switch_io_state_run_t state_run;  
  40.     /*! get sessions jitterbuffer */  
  41.     switch_io_get_jb_t get_jb;  
  42.     void *padding[10];  
  43. };  

io例程主要处理媒体的输入输出,其中最重要的就是读写一帧read_frame、write_frame,其它的后面讲到媒体流再细讲。

      1. 状态机
  1. typedef enum {  
  2.     SWITCH_SHN_ON_INIT,  
  3.     SWITCH_SHN_ON_ROUTING,  
  4.     SWITCH_SHN_ON_EXECUTE,  
  5.     SWITCH_SHN_ON_HANGUP,  
  6.     SWITCH_SHN_ON_EXCHANGE_MEDIA,  
  7.     SWITCH_SHN_ON_SOFT_EXECUTE,  
  8.     SWITCH_SHN_ON_CONSUME_MEDIA,  
  9.     SWITCH_SHN_ON_HIBERNATE,  
  10.     SWITCH_SHN_ON_RESET,  
  11.     SWITCH_SHN_ON_PARK,  
  12.     SWITCH_SHN_ON_REPORTING,  
  13.     SWITCH_SHN_ON_DESTROY  
  14. } switch_state_handler_name_t;  
  15.   
  16. typedef switch_status_t (*switch_state_handler_t) (switch_core_session_t *);  
  17.   
  18. struct switch_state_handler_table {  
  19.     /*! executed when the state changes to init */  
  20.     switch_state_handler_t on_init;  
  21.     /*! executed when the state changes to routing */  
  22.     switch_state_handler_t on_routing;  
  23.     /*! executed when the state changes to execute */  
  24.     switch_state_handler_t on_execute;  
  25.     /*! executed when the state changes to hangup */  
  26.     switch_state_handler_t on_hangup;  
  27.     /*! executed when the state changes to exchange_media */  
  28.     switch_state_handler_t on_exchange_media;  
  29.     /*! executed when the state changes to soft_execute */  
  30.     switch_state_handler_t on_soft_execute;  
  31.     /*! executed when the state changes to consume_media */  
  32.     switch_state_handler_t on_consume_media;  
  33.     /*! executed when the state changes to hibernate */  
  34.     switch_state_handler_t on_hibernate;  
  35.     /*! executed when the state changes to reset */  
  36.     switch_state_handler_t on_reset;  
  37.     /*! executed when the state changes to park */  
  38.     switch_state_handler_t on_park;  
  39.     /*! executed when the state changes to reporting */  
  40.     switch_state_handler_t on_reporting;  
  41.     /*! executed when the state changes to destroy */  
  42.     switch_state_handler_t on_destroy;  
  43.     int flags;  
  44.     void *padding[10];  
  45. };  

 

每建立一个通话channel,都会有若干状态切换,刚开始是init,然后解析拨号规则,进入路由状态,路由规则解析完成后,会进入路由action执行状态。状态函数表switch_state_handler_table中的每个函数,跟状态一一对应。

    1. 应用接口
  1. struct switch_application_interface {  
  2.     /*! the name of the interface */  
  3.     const char *interface_name;  
  4.     /*! function the application implements */  
  5.     switch_application_function_t application_function;  
  6.     /*! the long winded description of the application */  
  7.     const char *long_desc;  
  8.     /*! the short and sweet description of the application */  
  9.     const char *short_desc;  
  10.     /*! an example of the application syntax */  
  11.     const char *syntax;  
  12.     /*! flags to control behaviour */  
  13.     uint32_t flags;  
  14.     switch_thread_rwlock_t *rwlock;  
  15.     int refs;  
  16.     switch_mutex_t *reflock;  
  17.     switch_loadable_module_interface_t *parent;  
  18.     struct switch_application_interface *next;  
  19. };  
  20.   
  21. typedef void (*switch_application_function_t) (switch_core_session_t *, const char *); 

freeswitch里有很多的app,这里不是手机的app,而是freeswitch中的可以实现一个功能的接口,或者可以理解为一个功能函数,应用接口会有个application_function。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值