我是靠谱客的博主 疯狂舞蹈,这篇文章主要介绍freeswitch的event事件处理概述通道事件开发环境代码处理编译安装配置启动加载测试总结,现在分享给大家,希望可以做个参考。

概述


之前的文章中,我们讲解了freeswitch的源码基本结构,如何新增一个插件式模块,以及如何在模块中新增一个命令式API接口和APP接口。


freeswitch本身是事件驱动的,它可以并发响应多个事件,也可以广播事件。


freeswitch的事件可以由核心产生,也可以由外部模块或外部源产生。


freeswitch系统中的几乎所有事件都会产生事件消息,这些事件可以被外部实体监听(通过event socket),也可以被内部模块监听。


freeswitch的事件系统是双向的,除了允许外部程序监听事件外,外部程序还可以向freeswitch发送事件。


你可以从自己的程序中实时发送/接收事件。这种组合允许你以几乎任何你能想到的方式使用freeswitch。

通道事件


在freeswitch的事件系统中,有一类以“CHANNEL_“开头的事件,这些事件表示了一个呼叫通道(channel)的状态变化的全部过程,是我们在业务开发中最常用的一类事件。


常见的通道事件:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CHANNEL_ANSWER CHANNEL_APPLICATION CHANNEL_BRIDGE CHANNEL_CALLSTATE CHANNEL_CREATE CHANNEL_DATA CHANNEL_DESTROY CHANNEL_EXECUTE CHANNEL_EXECUTE_COMPLETE CHANNEL_GLOBAL CHANNEL_HANGUP CHANNEL_HANGUP_COMPLETE CHANNEL_HOLD CHANNEL_ORIGINATE CHANNEL_OUTGOING CHANNEL_PARK CHANNEL_PROGRESS CHANNEL_PROGRESS_MEDIA CHANNEL_STATE CHANNEL_UNBRIDGE CHANNEL_UNHOLD CHANNEL_UNPARK CHANNEL_UUID

通道事件可以携带一通呼叫的全部呼叫信息,也可以携带呼叫流程中的自定义信息,这个属性让我们可以很方便的在一通呼叫的不同阶段之间传递自定义参数。


本节我们来介绍如何在模块中增加一个channel event事件处理,并传递一个自定义参数。 

开发环境


centos:CentOS release 7.0 (Final)或以上版本


freeswitch:v1.8.7


GCC:4.8.5

代码处理


新增模块的方法请参考之前的内容,本节内容在模块mod_task的基础上修改。

mod_task.c内容如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <switch.h> SWITCH_MODULE_LOAD_FUNCTION(mod_task_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_task_shutdown); SWITCH_MODULE_DEFINITION(mod_task, mod_task_load, mod_task_shutdown, NULL); SWITCH_STANDARD_API(task_api_function) {     //SWITCH_STANDARD_API have three args: (cmd, session, stream)     char *mycmd = NULL;     int argc = 0;     char *argv[16];     bzero(argv, sizeof(argv));     //split cmd and parse     if (cmd)     {         mycmd = strdup(cmd);         if (!mycmd)         {             stream->write_function(stream, "Out of memoryn");             return SWITCH_STATUS_FALSE;             }                  if (!(argc = switch_split(mycmd, ' ', argv)) || !argv[0])          {             argc = 0;             switch_safe_free(mycmd);             return SWITCH_STATUS_FALSE;         }     }     //parse cmd, brach process     if(0 == strcmp("test1", argv[0]))     {         stream->write_function(stream, "task api test1, cmd:%s, session:%p", cmd, session);     }     else if(0 == strcmp("test2", argv[0]))     {         stream->write_function(stream, "task api test2, cmd:%s, session:%p", cmd, session);     }     else     {         stream->write_function(stream, "unknown cmd, cmd:%s, session:%p", cmd, session);     }         switch_safe_free(mycmd);     return SWITCH_STATUS_SUCCESS; } SWITCH_STANDARD_APP(task_app_function) {     switch_channel_t *pchannel = NULL;     //task_app(session, data);     switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,              "task_app_function start, session=%p, data=%sn", (void*)session, data);     //export variable task_str for hangup event     pchannel = switch_core_session_get_channel(session);     if(NULL != pchannel)     {         switch_channel_export_variable(pchannel, "task_str", "task_app export variable", SWITCH_EXPORT_VARS_VARIABLE);     } } void task_event_channel_hangup_complete(switch_event_t *event) {     const char *uuid = switch_event_get_header(event, "Unique-ID");     const char *call_dir = switch_event_get_header(event, "Call-Direction");     const char* task_str = switch_event_get_header(event, "variable_task_str");     switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,          "task_event_channel_hangup_complete, uuid=%s, call_dir=%s, task_str=%sn",          uuid, call_dir, task_str); } void task_event_handler(switch_event_t *event) {     switch (event->event_id)     {         case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:             task_event_channel_hangup_complete(event);             break;         case SWITCH_EVENT_CHANNEL_ANSWER:         default:             switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,                  "unsupported event. event:%dn", event->event_id);              break;     }     return; } SWITCH_MODULE_LOAD_FUNCTION(mod_task_load) {     switch_api_interface_t* api_interface = NULL;     switch_application_interface_t* app_interface = NULL;     *module_interface = switch_loadable_module_create_module_interface(pool, modname);     switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,              "mod_task_load startn");     // register APP     SWITCH_ADD_APP(app_interface,         "task_app",          "task_app",          "task_app",          task_app_function,          "NULL",          SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);     // register API     SWITCH_ADD_API( api_interface,                      "task",                      "task api",                      task_api_function,                      "<cmd> <args>");          // 注册终端命令自动补全      switch_console_set_complete("add task test1 [args]");     switch_console_set_complete("add task test2 [args]");     ///EVENT INIT     if (SWITCH_STATUS_SUCCESS != switch_event_bind(modname, SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE, SWITCH_EVENT_SUBCLASS_ANY, task_event_handler, NULL)){         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "can't bind eventn");         return SWITCH_STATUS_GENERR;     }     return SWITCH_STATUS_SUCCESS; } SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_task_shutdown) {     switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,              "mod_task_shutdown stopn");     return SWITCH_STATUS_SUCCESS; }

呼叫处理过程中,我们在“task_app_function“函数中通过”switch_channel_export_variable“接口设置了一个自定义通道变量”task_str“的值为”task_app export variable“。


然后在呼叫的挂机事件中,我们又取出了消息头域中“variable_task_str“的值并打印到日志中。


通过这种方式,我们可以在呼叫流程的不同阶段传递任意自定义参数

编译安装


进入task模块目录,编译安装,在Makefile.am文件未变化的情况下,不需要重新config。

复制代码
1
2
cd  $(top_srcdir)/src/mod/applications/mod_task make  install

配置启动


修改dialplan拨号计划

复制代码
1
2
3
4
5
6
7
8
9
10
11
cd /usr/local/freeswitch/conf/dialplan vi public.xml … <include>   <context name="public">     <extension name="test">       <condition>         <action application="task_app" data="${destination_number}"/>       </condition>     </extension> …

启动fs

复制代码
1
2
cd /usr/local/freeswitch/bin/ ./freeswitch –nonat

加载测试


freeswitch启动成功后,在freeswitch命令行中输入API命令加载mod_task模块:

复制代码
1
2
3
4
5
6
7
8
9
10
freeswitch@localhost.localdomain> load mod_task 2021-09-03 11:34:50.954223 [INFO] mod_enum.c:882 ENUM Reloaded 2021-09-03 11:34:50.954223 [INFO] mod_task.c:134 mod_task_load start 2021-09-03 11:34:50.954223 [CONSOLE] switch_loadable_module.c:1540 Successfully Loaded [mod_task] 2021-09-03 11:34:50.954223 [NOTICE] switch_loadable_module.c:292 Adding Application 'task_app' +OK Reloading XML +OK 2021-09-03 11:34:50.954223 [NOTICE] switch_loadable_module.c:338 Adding API Function 'task'

通过其他sip服务器发起invite呼叫到本机的5080端口,在日志中可以查看到:

复制代码
1
2
3
4
5
6
7
8
freeswitch@localhost.localdomain> 2021-09-03 11:34:56.614251 [NOTICE] switch_channel.c:1114 New Channel sofia/external/10011@192.168.0.110 [a34a67c3-2b8d-401f-a16f-1f5ec3e5169f] 2021-09-03 11:34:56.614251 [INFO] mod_dialplan_xml.c:637 Processing 10011 <10011>->10012 in context public 2021-09-03 11:34:56.614251 [INFO] mod_task.c:88 task_app_function start, session=0x7fbb8402fab8, data=10012 2021-09-03 11:34:56.614251 [NOTICE] switch_core_state_machine.c:385 sofia/external/10011@192.168.0.110 has executed the last dialplan instruction, hanging up. 2021-09-03 11:34:56.614251 [NOTICE] switch_core_state_machine.c:387 Hangup sofia/external/10011@192.168.0.110 [CS_EXECUTE] [NORMAL_CLEARING] 2021-09-03 11:34:56.614251 [INFO] mod_task.c:105 task_event_channel_hangup_complete, uuid=a34a67c3-2b8d-401f-a16f-1f5ec3e5169f, call_dir=inbound, task_str=task_app export variable 2021-09-03 11:34:56.614251 [NOTICE] switch_core_session.c:1744 Session 1 (sofia/external/10011@192.168.0.110) Ended 2021-09-03 11:34:56.614251 [NOTICE] switch_core_session.c:1748 Close Channel sofia/external/10011@192.168.0.110 [CS_DESTROY]


在日志中,可以看到“task_app_function start “的信息,同时也可以看到” task_event_channel_hangup_complete “的函数打印中”task_str=task_app export variable “的打印信息,验证了在呼叫中设置的自定义参数传递到挂机事件的后处理的过程

总结


freeswitch的event事件是整个架构体系中非常重要的一环,基础核心层通过event事件将所有呼叫相关的信息异步的通知到应用层,极大的方便了呼叫流程的业务开发。


其中的异步设计思想值得我们多多参考学习。


空空如常

求真得真
 

最后

以上就是疯狂舞蹈最近收集整理的关于freeswitch的event事件处理概述通道事件开发环境代码处理编译安装配置启动加载测试总结的全部内容,更多相关freeswitch内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部