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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章