eb1b58e1554bd53ce25718eb3d438651abc088f4
[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/bridge.h"
32 #include "asterisk/stasis.h"
33 #include "asterisk/stasis_channels.h"
34 #include "asterisk/stasis_bridges.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                                 <bridge_snapshot/>
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                                 <bridge_snapshot/>
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                                 <bridge_snapshot/>
78                                 <channel_snapshot/>
79                                 <parameter name="Admin">
80                                         <para>Identifies this user as an admin user.</para>
81                                         <enumlist>
82                                                 <enum name="Yes"/>
83                                                 <enum name="No"/>
84                                         </enumlist>
85                                 </parameter>
86                         </syntax>
87                         <see-also>
88                                 <ref type="managerEvent">ConfbridgeLeave</ref>
89                                 <ref type="application">ConfBridge</ref>
90                         </see-also>
91                 </managerEventInstance>
92         </managerEvent>
93         <managerEvent language="en_US" name="ConfbridgeLeave">
94                 <managerEventInstance class="EVENT_FLAG_CALL">
95                         <synopsis>Raised when a channel leaves a Confbridge conference.</synopsis>
96                         <syntax>
97                                 <parameter name="Conference">
98                                         <para>The name of the Confbridge conference.</para>
99                                 </parameter>
100                                 <bridge_snapshot/>
101                                 <channel_snapshot/>
102                                 <parameter name="Admin">
103                                         <para>Identifies this user as an admin user.</para>
104                                         <enumlist>
105                                                 <enum name="Yes"/>
106                                                 <enum name="No"/>
107                                         </enumlist>
108                                 </parameter>
109                         </syntax>
110                         <see-also>
111                                 <ref type="managerEvent">ConfbridgeJoin</ref>
112                                 <ref type="application">ConfBridge</ref>
113                         </see-also>
114                 </managerEventInstance>
115         </managerEvent>
116         <managerEvent language="en_US" name="ConfbridgeRecord">
117                 <managerEventInstance class="EVENT_FLAG_CALL">
118                         <synopsis>Raised when a conference starts recording.</synopsis>
119                         <syntax>
120                                 <parameter name="Conference">
121                                         <para>The name of the Confbridge conference.</para>
122                                 </parameter>
123                                 <bridge_snapshot/>
124                         </syntax>
125                         <see-also>
126                                 <ref type="managerEvent">ConfbridgeStopRecord</ref>
127                                 <ref type="application">ConfBridge</ref>
128                         </see-also>
129                 </managerEventInstance>
130         </managerEvent>
131         <managerEvent language="en_US" name="ConfbridgeStopRecord">
132                 <managerEventInstance class="EVENT_FLAG_CALL">
133                         <synopsis>Raised when a conference that was recording stops recording.</synopsis>
134                         <syntax>
135                                 <parameter name="Conference">
136                                         <para>The name of the Confbridge conference.</para>
137                                 </parameter>
138                                 <bridge_snapshot/>
139                         </syntax>
140                         <see-also>
141                                 <ref type="managerEvent">ConfbridgeRecord</ref>
142                                 <ref type="application">ConfBridge</ref>
143                         </see-also>
144                 </managerEventInstance>
145         </managerEvent>
146         <managerEvent language="en_US" name="ConfbridgeMute">
147                 <managerEventInstance class="EVENT_FLAG_CALL">
148                         <synopsis>Raised when a Confbridge participant mutes.</synopsis>
149                         <syntax>
150                                 <parameter name="Conference">
151                                         <para>The name of the Confbridge conference.</para>
152                                 </parameter>
153                                 <bridge_snapshot/>
154                                 <channel_snapshot/>
155                                 <parameter name="Admin">
156                                         <para>Identifies this user as an admin user.</para>
157                                         <enumlist>
158                                                 <enum name="Yes"/>
159                                                 <enum name="No"/>
160                                         </enumlist>
161                                 </parameter>
162                         </syntax>
163                         <see-also>
164                                 <ref type="managerEvent">ConfbridgeUnmute</ref>
165                                 <ref type="application">ConfBridge</ref>
166                         </see-also>
167                 </managerEventInstance>
168         </managerEvent>
169         <managerEvent language="en_US" name="ConfbridgeUnmute">
170                 <managerEventInstance class="EVENT_FLAG_CALL">
171                         <synopsis>Raised when a confbridge participant unmutes.</synopsis>
172                         <syntax>
173                                 <parameter name="Conference">
174                                         <para>The name of the Confbridge conference.</para>
175                                 </parameter>
176                                 <bridge_snapshot/>
177                                 <channel_snapshot/>
178                                 <parameter name="Admin">
179                                         <para>Identifies this user as an admin user.</para>
180                                         <enumlist>
181                                                 <enum name="Yes"/>
182                                                 <enum name="No"/>
183                                         </enumlist>
184                                 </parameter>
185                         </syntax>
186                         <see-also>
187                                 <ref type="managerEvent">ConfbridgeMute</ref>
188                                 <ref type="application">ConfBridge</ref>
189                         </see-also>
190                 </managerEventInstance>
191         </managerEvent>
192         <managerEvent language="en_US" name="ConfbridgeTalking">
193                 <managerEventInstance class="EVENT_FLAG_CALL">
194                         <synopsis>Raised when a confbridge participant unmutes.</synopsis>
195                         <syntax>
196                                 <parameter name="Conference">
197                                         <para>The name of the Confbridge conference.</para>
198                                 </parameter>
199                                 <bridge_snapshot/>
200                                 <channel_snapshot/>
201                                 <parameter name="TalkingStatus">
202                                         <enumlist>
203                                                 <enum name="on"/>
204                                                 <enum name="off"/>
205                                         </enumlist>
206                                 </parameter>
207                                 <parameter name="Admin">
208                                         <para>Identifies this user as an admin user.</para>
209                                         <enumlist>
210                                                 <enum name="Yes"/>
211                                                 <enum name="No"/>
212                                         </enumlist>
213                                 </parameter>
214                         </syntax>
215                         <see-also>
216                                 <ref type="application">ConfBridge</ref>
217                         </see-also>
218                 </managerEventInstance>
219         </managerEvent>
220 ***/
221
222 static struct stasis_message_router *bridge_state_router;
223 static struct stasis_message_router *channel_state_router;
224
225 static void confbridge_publish_manager_event(
226         struct stasis_message *message,
227         const char *event,
228         struct ast_str *extra_text)
229 {
230         struct ast_bridge_blob *blob = stasis_message_data(message);
231         const char *conference_name;
232         RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
233         RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
234
235         ast_assert(blob != NULL);
236         ast_assert(event != NULL);
237
238         bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
239         if (!bridge_text) {
240                 return;
241         }
242
243         conference_name = ast_json_string_get(ast_json_object_get(blob->blob, "conference"));
244         ast_assert(conference_name != NULL);
245
246         if (blob->channel) {
247                 channel_text = ast_manager_build_channel_state_string(blob->channel);
248         }
249
250         manager_event(EVENT_FLAG_CALL, event,
251                 "Conference: %s\r\n"
252                 "%s"
253                 "%s"
254                 "%s",
255                 conference_name,
256                 ast_str_buffer(bridge_text),
257                 S_COR(channel_text, ast_str_buffer(channel_text), ""),
258                 S_COR(extra_text, ast_str_buffer(extra_text), ""));
259 }
260
261 static int get_admin_header(struct ast_str **extra_text, struct stasis_message *message)
262 {
263         const struct ast_bridge_blob *blob = stasis_message_data(message);
264         const struct ast_json *admin = ast_json_object_get(blob->blob, "admin");
265         if (!admin) {
266                 return -1;
267         }
268
269         return ast_str_append_event_header(extra_text, "Admin",
270                 S_COR(ast_json_is_true(admin), "Yes", "No"));
271 }
272
273 static void confbridge_start_cb(void *data, struct stasis_subscription *sub,
274         struct stasis_message *message)
275 {
276         confbridge_publish_manager_event(message, "ConfbridgeStart", NULL);
277 }
278
279 static void confbridge_end_cb(void *data, struct stasis_subscription *sub,
280         struct stasis_message *message)
281 {
282         confbridge_publish_manager_event(message, "ConfbridgeEnd", NULL);
283 }
284
285 static void confbridge_leave_cb(void *data, struct stasis_subscription *sub,
286         struct stasis_message *message)
287 {
288         struct ast_str *extra_text = NULL;
289
290         if (!get_admin_header(&extra_text, message)) {
291                 confbridge_publish_manager_event(message, "ConfbridgeLeave", extra_text);
292         }
293         ast_free(extra_text);
294 }
295
296 static void confbridge_join_cb(void *data, struct stasis_subscription *sub,
297         struct stasis_message *message)
298 {
299         struct ast_str *extra_text = NULL;
300
301         if (!get_admin_header(&extra_text, message)) {
302                 confbridge_publish_manager_event(message, "ConfbridgeJoin", extra_text);
303         }
304         ast_free(extra_text);
305 }
306
307 static void confbridge_start_record_cb(void *data, struct stasis_subscription *sub,
308         struct stasis_message *message)
309 {
310         confbridge_publish_manager_event(message, "ConfbridgeRecord", NULL);
311 }
312
313 static void confbridge_stop_record_cb(void *data, struct stasis_subscription *sub,
314         struct stasis_message *message)
315 {
316         confbridge_publish_manager_event(message, "ConfbridgeStopRecord", NULL);
317 }
318
319 static void confbridge_mute_cb(void *data, struct stasis_subscription *sub,
320         struct stasis_message *message)
321 {
322         struct ast_str *extra_text = NULL;
323
324         if (!get_admin_header(&extra_text, message)) {
325                 confbridge_publish_manager_event(message, "ConfbridgeMute", extra_text);
326         }
327         ast_free(extra_text);
328 }
329
330 static void confbridge_unmute_cb(void *data, struct stasis_subscription *sub,
331         struct stasis_message *message)
332 {
333         struct ast_str *extra_text = NULL;
334
335         if (!get_admin_header(&extra_text, message)) {
336                 confbridge_publish_manager_event(message, "ConfbridgeUnmute", extra_text);
337         }
338         ast_free(extra_text);
339 }
340
341 static void confbridge_talking_cb(void *data, struct stasis_subscription *sub,
342         struct stasis_message *message)
343 {
344         RAII_VAR(struct ast_str *, extra_text, NULL, ast_free);
345         const struct ast_bridge_blob *blob = stasis_message_data(message);
346         const char *talking_status = ast_json_string_get(ast_json_object_get(blob->blob, "talking_status"));
347         if (!talking_status) {
348                 return;
349         }
350
351         ast_str_append_event_header(&extra_text, "TalkingStatus", talking_status);
352         if (!extra_text) {
353                 return;
354         }
355
356         if (!get_admin_header(&extra_text, message)) {
357                 confbridge_publish_manager_event(message, "ConfbridgeTalking", extra_text);
358         }
359 }
360
361 STASIS_MESSAGE_TYPE_DEFN(confbridge_start_type);
362 STASIS_MESSAGE_TYPE_DEFN(confbridge_end_type);
363 STASIS_MESSAGE_TYPE_DEFN(confbridge_join_type);
364 STASIS_MESSAGE_TYPE_DEFN(confbridge_leave_type);
365 STASIS_MESSAGE_TYPE_DEFN(confbridge_start_record_type);
366 STASIS_MESSAGE_TYPE_DEFN(confbridge_stop_record_type);
367 STASIS_MESSAGE_TYPE_DEFN(confbridge_mute_type);
368 STASIS_MESSAGE_TYPE_DEFN(confbridge_unmute_type);
369 STASIS_MESSAGE_TYPE_DEFN(confbridge_talking_type);
370
371 void manager_confbridge_shutdown(void) {
372         STASIS_MESSAGE_TYPE_CLEANUP(confbridge_start_type);
373         STASIS_MESSAGE_TYPE_CLEANUP(confbridge_end_type);
374         STASIS_MESSAGE_TYPE_CLEANUP(confbridge_join_type);
375         STASIS_MESSAGE_TYPE_CLEANUP(confbridge_leave_type);
376         STASIS_MESSAGE_TYPE_CLEANUP(confbridge_start_record_type);
377         STASIS_MESSAGE_TYPE_CLEANUP(confbridge_stop_record_type);
378         STASIS_MESSAGE_TYPE_CLEANUP(confbridge_mute_type);
379         STASIS_MESSAGE_TYPE_CLEANUP(confbridge_unmute_type);
380         STASIS_MESSAGE_TYPE_CLEANUP(confbridge_talking_type);
381
382         if (bridge_state_router) {
383                 stasis_message_router_unsubscribe(bridge_state_router);
384                 bridge_state_router = NULL;
385         }
386
387         if (channel_state_router) {
388                 stasis_message_router_unsubscribe(channel_state_router);
389                 channel_state_router = NULL;
390         }
391 }
392
393 int manager_confbridge_init(void)
394 {
395         STASIS_MESSAGE_TYPE_INIT(confbridge_start_type);
396         STASIS_MESSAGE_TYPE_INIT(confbridge_end_type);
397         STASIS_MESSAGE_TYPE_INIT(confbridge_join_type);
398         STASIS_MESSAGE_TYPE_INIT(confbridge_leave_type);
399         STASIS_MESSAGE_TYPE_INIT(confbridge_start_record_type);
400         STASIS_MESSAGE_TYPE_INIT(confbridge_stop_record_type);
401         STASIS_MESSAGE_TYPE_INIT(confbridge_mute_type);
402         STASIS_MESSAGE_TYPE_INIT(confbridge_unmute_type);
403         STASIS_MESSAGE_TYPE_INIT(confbridge_talking_type);
404
405         bridge_state_router = stasis_message_router_create(
406                 ast_bridge_topic_all_cached());
407
408         if (!bridge_state_router) {
409                 return -1;
410         }
411
412         if (stasis_message_router_add(bridge_state_router,
413                         confbridge_start_type(),
414                         confbridge_start_cb,
415                         NULL)) {
416                 manager_confbridge_shutdown();
417                 return -1;
418         }
419         if (stasis_message_router_add(bridge_state_router,
420                         confbridge_end_type(),
421                         confbridge_end_cb,
422                         NULL)) {
423                 manager_confbridge_shutdown();
424                 return -1;
425         }
426         if (stasis_message_router_add(bridge_state_router,
427                         confbridge_join_type(),
428                         confbridge_join_cb,
429                         NULL)) {
430                 manager_confbridge_shutdown();
431                 return -1;
432         }
433         if (stasis_message_router_add(bridge_state_router,
434                         confbridge_leave_type(),
435                         confbridge_leave_cb,
436                         NULL)) {
437                 manager_confbridge_shutdown();
438                 return -1;
439         }
440         if (stasis_message_router_add(bridge_state_router,
441                         confbridge_start_record_type(),
442                         confbridge_start_record_cb,
443                         NULL)) {
444                 manager_confbridge_shutdown();
445                 return -1;
446         }
447         if (stasis_message_router_add(bridge_state_router,
448                         confbridge_stop_record_type(),
449                         confbridge_stop_record_cb,
450                         NULL)) {
451                 manager_confbridge_shutdown();
452                 return -1;
453         }
454         if (stasis_message_router_add(bridge_state_router,
455                         confbridge_mute_type(),
456                         confbridge_mute_cb,
457                         NULL)) {
458                 manager_confbridge_shutdown();
459                 return -1;
460         }
461         if (stasis_message_router_add(bridge_state_router,
462                         confbridge_unmute_type(),
463                         confbridge_unmute_cb,
464                         NULL)) {
465                 manager_confbridge_shutdown();
466                 return -1;
467         }
468         if (stasis_message_router_add(bridge_state_router,
469                         confbridge_talking_type(),
470                         confbridge_talking_cb,
471                         NULL)) {
472                 manager_confbridge_shutdown();
473                 return -1;
474         }
475
476         channel_state_router = stasis_message_router_create(
477                 ast_channel_topic_all_cached());
478
479         if (!channel_state_router) {
480                 manager_confbridge_shutdown();
481                 return -1;
482         }
483
484         if (stasis_message_router_add(channel_state_router,
485                         confbridge_start_type(),
486                         confbridge_start_cb,
487                         NULL)) {
488                 manager_confbridge_shutdown();
489                 return -1;
490         }
491         if (stasis_message_router_add(channel_state_router,
492                         confbridge_end_type(),
493                         confbridge_end_cb,
494                         NULL)) {
495                 manager_confbridge_shutdown();
496                 return -1;
497         }
498         if (stasis_message_router_add(channel_state_router,
499                         confbridge_join_type(),
500                         confbridge_join_cb,
501                         NULL)) {
502                 manager_confbridge_shutdown();
503                 return -1;
504         }
505         if (stasis_message_router_add(channel_state_router,
506                         confbridge_leave_type(),
507                         confbridge_leave_cb,
508                         NULL)) {
509                 manager_confbridge_shutdown();
510                 return -1;
511         }
512         if (stasis_message_router_add(channel_state_router,
513                         confbridge_start_record_type(),
514                         confbridge_start_record_cb,
515                         NULL)) {
516                 manager_confbridge_shutdown();
517                 return -1;
518         }
519         if (stasis_message_router_add(channel_state_router,
520                         confbridge_stop_record_type(),
521                         confbridge_stop_record_cb,
522                         NULL)) {
523                 manager_confbridge_shutdown();
524                 return -1;
525         }
526         if (stasis_message_router_add(channel_state_router,
527                         confbridge_mute_type(),
528                         confbridge_mute_cb,
529                         NULL)) {
530                 manager_confbridge_shutdown();
531                 return -1;
532         }
533         if (stasis_message_router_add(channel_state_router,
534                         confbridge_unmute_type(),
535                         confbridge_unmute_cb,
536                         NULL)) {
537                 manager_confbridge_shutdown();
538                 return -1;
539         }
540         if (stasis_message_router_add(channel_state_router,
541                         confbridge_talking_type(),
542                         confbridge_talking_cb,
543                         NULL)) {
544                 manager_confbridge_shutdown();
545                 return -1;
546         }
547
548         return 0;
549 }