我建了一個 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);
- }
- }<pre class="cpp" name="code"></pre>
- <pre></pre>
- <pre class="cpp" name="code"></pre><pre class="cpp" name="code"></pre><pre class="cpp" name="code"></pre><pre class="cpp" name="code"></pre><pre class="cpp" name="code"></pre><pre class="cpp" name="code"></pre><pre class="cpp" name="code"></pre><pre class="cpp" name="code"><pre class="cpp" name="code"></pre>
- <p><br>
- </p>
- <pre style="border-bottom:rgb(60,120,181) 1px solid; border-left:rgb(60,120,181) 1px solid; padding-bottom:0.4em; background-color:rgb(240,240,240); padding-left:0.4em; padding-right:0.4em; border-top:rgb(60,120,181) 1px solid; border-right:rgb(60,120,181) 1px solid; padding-top:0.4em"><pre name="code" class="cpp">編譯: 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狀態回調。。。。
- </pre><br><br></pre>
- <p></p>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- </pre>