56fedb98e834d30f3e6fc0fec2efcbf8f09ebe61
[asterisk/asterisk.git] / apps / confbridge / confbridge_manager.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Jonathan Rose <jrose@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Confbridge manager events for stasis messages
22  *
23  * \author Jonathan Rose <jrose@digium.com>
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include "asterisk/channel.h"
31 #include "asterisk/bridging.h"
32 #include "asterisk/stasis.h"
33 #include "asterisk/stasis_channels.h"
34 #include "asterisk/stasis_bridging.h"
35 #include "asterisk/manager.h"
36 #include "asterisk/stasis_message_router.h"
37 #include "include/confbridge.h"
38
39 /*** DOCUMENTATION
40         <managerEvent language="en_US" name="ConfbridgeStart">
41                 <managerEventInstance class="EVENT_FLAG_CALL">
42                         <synopsis>Raised when a conference starts.</synopsis>
43                         <syntax>
44                                 <parameter name="Conference">
45                                         <para>The name of the Confbridge conference.</para>
46                                 </parameter>
47                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
48                         </syntax>
49                         <see-also>
50                                 <ref type="managerEvent">ConfbridgeEnd</ref>
51                                 <ref type="application">ConfBridge</ref>
52                         </see-also>
53                 </managerEventInstance>
54         </managerEvent>
55         <managerEvent language="en_US" name="ConfbridgeEnd">
56                 <managerEventInstance class="EVENT_FLAG_CALL">
57                         <synopsis>Raised when a conference ends.</synopsis>
58                         <syntax>
59                                 <parameter name="Conference">
60                                         <para>The name of the Confbridge conference.</para>
61                                 </parameter>
62                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
63                         </syntax>
64                         <see-also>
65                                 <ref type="managerEvent">ConfbridgeStart</ref>
66                                 <ref type="application">ConfBridge</ref>
67                         </see-also>
68                 </managerEventInstance>
69         </managerEvent>
70         <managerEvent language="en_US" name="ConfbridgeJoin">
71                 <managerEventInstance class="EVENT_FLAG_CALL">
72                         <synopsis>Raised when a channel joins a Confbridge conference.</synopsis>
73                         <syntax>
74                                 <parameter name="Conference">
75                                         <para>The name of the Confbridge conference.</para>
76                                 </parameter>
77                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
78                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
79                         </syntax>
80                         <see-also>
81                                 <ref type="managerEvent">ConfbridgeLeave</ref>
82                                 <ref type="application">ConfBridge</ref>
83                         </see-also>
84                 </managerEventInstance>
85         </managerEvent>
86         <managerEvent language="en_US" name="ConfbridgeLeave">
87                 <managerEventInstance class="EVENT_FLAG_CALL">
88                         <synopsis>Raised when a channel leaves a Confbridge conference.</synopsis>
89                         <syntax>
90                                 <parameter name="Conference">
91                                         <para>The name of the Confbridge conference.</para>
92                                 </parameter>
93                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
94                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
95                         </syntax>
96                         <see-also>
97                                 <ref type="managerEvent">ConfbridgeJoin</ref>
98                                 <ref type="application">ConfBridge</ref>
99                         </see-also>
100                 </managerEventInstance>
101         </managerEvent>
102         <managerEvent language="en_US" name="ConfbridgeRecord">
103                 <managerEventInstance class="EVENT_FLAG_CALL">
104                         <synopsis>Raised when a conference starts recording.</synopsis>
105                         <syntax>
106                                 <parameter name="Conference">
107                                         <para>The name of the Confbridge conference.</para>
108                                 </parameter>
109                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
110                         </syntax>
111                         <see-also>
112                                 <ref type="managerEvent">ConfbridgeStopRecord</ref>
113                                 <ref type="application">ConfBridge</ref>
114                         </see-also>
115                 </managerEventInstance>
116         </managerEvent>
117         <managerEvent language="en_US" name="ConfbridgeStopRecord">
118                 <managerEventInstance class="EVENT_FLAG_CALL">
119                         <synopsis>Raised when a conference that was recording stops recording.</synopsis>
120                         <syntax>
121                                 <parameter name="Conference">
122                                         <para>The name of the Confbridge conference.</para>
123                                 </parameter>
124                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
125                         </syntax>
126                         <see-also>
127                                 <ref type="managerEvent">ConfbridgeRecord</ref>
128                                 <ref type="application">ConfBridge</ref>
129                         </see-also>
130                 </managerEventInstance>
131         </managerEvent>
132         <managerEvent language="en_US" name="ConfbridgeMute">
133                 <managerEventInstance class="EVENT_FLAG_CALL">
134                         <synopsis>Raised when a Confbridge participant mutes.</synopsis>
135                         <syntax>
136                                 <parameter name="Conference">
137                                         <para>The name of the Confbridge conference.</para>
138                                 </parameter>
139                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
140                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
141                         </syntax>
142                         <see-also>
143                                 <ref type="managerEvent">ConfbridgeUnmute</ref>
144                                 <ref type="application">ConfBridge</ref>
145                         </see-also>
146                 </managerEventInstance>
147         </managerEvent>
148         <managerEvent language="en_US" name="ConfbridgeUnmute">
149                 <managerEventInstance class="EVENT_FLAG_CALL">
150                         <synopsis>Raised when a confbridge participant unmutes.</synopsis>
151                         <syntax>
152                                 <parameter name="Conference">
153                                         <para>The name of the Confbridge conference.</para>
154                                 </parameter>
155                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
156                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
157                         </syntax>
158                         <see-also>
159                                 <ref type="managerEvent">ConfbridgeMute</ref>
160                                 <ref type="application">ConfBridge</ref>
161                         </see-also>
162                 </managerEventInstance>
163         </managerEvent>
164
165         <managerEvent language="en_US" name="ConfbridgeTalking">
166                 <managerEventInstance class="EVENT_FLAG_CALL">
167                         <synopsis>Raised when a confbridge participant unmutes.</synopsis>
168                         <syntax>
169                                 <parameter name="Conference">
170                                         <para>The name of the Confbridge conference.</para>
171                                 </parameter>
172                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
173                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
174                                 <parameter name="TalkingStatus">
175                                         <enumlist>
176                                                 <enum name="on"/>
177                                                 <enum name="off"/>
178                                         </enumlist>
179                                 </parameter>
180                         </syntax>
181                         <see-also>
182                                 <ref type="application">ConfBridge</ref>
183                         </see-also>
184                 </managerEventInstance>
185         </managerEvent>
186 ***/
187
188 static struct stasis_message_router *bridge_state_router;
189 static struct stasis_message_router *channel_state_router;
190
191 static void append_event_header(struct ast_str **fields_string,
192                                         const char *header, const char *value)
193 {
194         struct ast_str *working_str = *fields_string;
195
196         if (!working_str) {
197                 working_str = ast_str_create(128);
198                 if (!working_str) {
199                         return;
200                 }
201                 *fields_string = working_str;
202         }
203
204         ast_str_append(&working_str, 0,
205                 "%s: %s\r\n",
206                 header, value);
207 }
208
209 static void stasis_confbridge_cb(void *data, struct stasis_subscription *sub,
210                                         struct stasis_topic *topic,
211                                         struct stasis_message *message)
212 {
213         struct ast_bridge_blob *blob = stasis_message_data(message);
214         const char *type = ast_bridge_blob_json_type(blob);
215         const char *conference_name;
216         RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
217         RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
218         RAII_VAR(struct ast_str *, extra_text, NULL, ast_free);
219         char *event;
220
221         if (!blob || !type) {
222                 ast_assert(0);
223                 return;
224         }
225
226         if (!strcmp("confbridge_start", type)) {
227                 event = "ConfbridgeStart";
228         } else if (!strcmp("confbridge_end", type)) {
229                 event = "ConfbridgeEnd";
230         } else if (!strcmp("confbridge_leave", type)) {
231                 event = "ConfbridgeLeave";
232         } else if (!strcmp("confbridge_join", type)) {
233                 event = "ConfbridgeJoin";
234         } else if (!strcmp("confbridge_record", type)) {
235                 event = "ConfbridgeRecord";
236         } else if (!strcmp("confbridge_stop_record", type)) {
237                 event = "ConfbridgeStopRecord";
238         } else if (!strcmp("confbridge_mute", type)) {
239                 event = "ConfbridgeMute";
240         } else if (!strcmp("confbridge_unmute", type)) {
241                 event = "ConfbridgeUnmute";
242         } else if (!strcmp("confbridge_talking", type)) {
243                 const char *talking_status = ast_json_string_get(ast_json_object_get(blob->blob, "talking_status"));
244                 event = "ConfbridgeTalking";
245
246                 if (!talking_status) {
247                         return;
248                 }
249
250                 append_event_header(&extra_text, "TalkingStatus", talking_status);
251
252         } else {
253                 return;
254         }
255
256         conference_name = ast_json_string_get(ast_json_object_get(blob->blob, "conference"));
257
258         if (!conference_name) {
259                 ast_assert(0);
260                 return;
261         }
262
263         bridge_text = ast_manager_build_bridge_state_string(blob->bridge, "");
264         if (blob->channel) {
265                 channel_text = ast_manager_build_channel_state_string(blob->channel);
266         }
267
268         manager_event(EVENT_FLAG_CALL, event,
269                 "Conference: %s\r\n"
270                 "%s"
271                 "%s"
272                 "%s",
273                 conference_name,
274                 ast_str_buffer(bridge_text),
275                 channel_text ? ast_str_buffer(channel_text) : "",
276                 extra_text ? ast_str_buffer(extra_text) : "");
277 }
278
279 static struct stasis_message_type *confbridge_msg_type;
280
281 struct stasis_message_type *confbridge_message_type(void)
282 {
283         return confbridge_msg_type;
284 }
285
286 void manager_confbridge_shutdown(void) {
287         ao2_cleanup(confbridge_msg_type);
288         confbridge_msg_type = NULL;
289
290         if (bridge_state_router) {
291                 stasis_message_router_unsubscribe(bridge_state_router);
292                 bridge_state_router = NULL;
293         }
294
295         if (channel_state_router) {
296                 stasis_message_router_unsubscribe(channel_state_router);
297                 channel_state_router = NULL;
298         }
299 }
300
301 int manager_confbridge_init(void)
302 {
303         if (!(confbridge_msg_type = stasis_message_type_create("confbridge"))) {
304                 return -1;
305         }
306
307         bridge_state_router = stasis_message_router_create(
308                 stasis_caching_get_topic(ast_bridge_topic_all_cached()));
309
310         if (!bridge_state_router) {
311                 return -1;
312         }
313
314         if (stasis_message_router_add(bridge_state_router,
315                                          confbridge_message_type(),
316                                          stasis_confbridge_cb,
317                                          NULL)) {
318                 manager_confbridge_shutdown();
319                 return -1;
320         }
321
322         channel_state_router = stasis_message_router_create(
323                 stasis_caching_get_topic(ast_channel_topic_all_cached()));
324
325         if (!channel_state_router) {
326                 manager_confbridge_shutdown();
327                 return -1;
328         }
329
330         if (stasis_message_router_add(channel_state_router,
331                                          confbridge_message_type(),
332                                          stasis_confbridge_cb,
333                                          NULL)) {
334                 manager_confbridge_shutdown();
335                 return -1;
336         }
337
338         return 0;
339 }