Asterisk - The Open Source Telephony Project  18.5.0
confbridge_manager.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Jonathan Rose <[email protected]>
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 <[email protected]>
24  */
25 
26 #include "asterisk.h"
27 
28 #include "asterisk/channel.h"
29 #include "asterisk/bridge.h"
30 #include "asterisk/stasis.h"
33 #include "asterisk/manager.h"
35 #include "include/confbridge.h"
36 #include "asterisk/message.h"
37 #include "asterisk/stream.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  <parameter name="Muted">
87  <para>The joining mute status.</para>
88  <enumlist>
89  <enum name="Yes"/>
90  <enum name="No"/>
91  </enumlist>
92  </parameter>
93  </syntax>
94  <see-also>
95  <ref type="managerEvent">ConfbridgeLeave</ref>
96  <ref type="application">ConfBridge</ref>
97  </see-also>
98  </managerEventInstance>
99  </managerEvent>
100  <managerEvent language="en_US" name="ConfbridgeLeave">
101  <managerEventInstance class="EVENT_FLAG_CALL">
102  <synopsis>Raised when a channel leaves a Confbridge conference.</synopsis>
103  <syntax>
104  <parameter name="Conference">
105  <para>The name of the Confbridge conference.</para>
106  </parameter>
107  <bridge_snapshot/>
108  <channel_snapshot/>
109  <parameter name="Admin">
110  <para>Identifies this user as an admin user.</para>
111  <enumlist>
112  <enum name="Yes"/>
113  <enum name="No"/>
114  </enumlist>
115  </parameter>
116  </syntax>
117  <see-also>
118  <ref type="managerEvent">ConfbridgeJoin</ref>
119  <ref type="application">ConfBridge</ref>
120  </see-also>
121  </managerEventInstance>
122  </managerEvent>
123  <managerEvent language="en_US" name="ConfbridgeRecord">
124  <managerEventInstance class="EVENT_FLAG_CALL">
125  <synopsis>Raised when a conference starts recording.</synopsis>
126  <syntax>
127  <parameter name="Conference">
128  <para>The name of the Confbridge conference.</para>
129  </parameter>
130  <bridge_snapshot/>
131  </syntax>
132  <see-also>
133  <ref type="managerEvent">ConfbridgeStopRecord</ref>
134  <ref type="application">ConfBridge</ref>
135  </see-also>
136  </managerEventInstance>
137  </managerEvent>
138  <managerEvent language="en_US" name="ConfbridgeStopRecord">
139  <managerEventInstance class="EVENT_FLAG_CALL">
140  <synopsis>Raised when a conference that was recording stops recording.</synopsis>
141  <syntax>
142  <parameter name="Conference">
143  <para>The name of the Confbridge conference.</para>
144  </parameter>
145  <bridge_snapshot/>
146  </syntax>
147  <see-also>
148  <ref type="managerEvent">ConfbridgeRecord</ref>
149  <ref type="application">ConfBridge</ref>
150  </see-also>
151  </managerEventInstance>
152  </managerEvent>
153  <managerEvent language="en_US" name="ConfbridgeMute">
154  <managerEventInstance class="EVENT_FLAG_CALL">
155  <synopsis>Raised when a Confbridge participant mutes.</synopsis>
156  <syntax>
157  <parameter name="Conference">
158  <para>The name of the Confbridge conference.</para>
159  </parameter>
160  <bridge_snapshot/>
161  <channel_snapshot/>
162  <parameter name="Admin">
163  <para>Identifies this user as an admin user.</para>
164  <enumlist>
165  <enum name="Yes"/>
166  <enum name="No"/>
167  </enumlist>
168  </parameter>
169  </syntax>
170  <see-also>
171  <ref type="managerEvent">ConfbridgeUnmute</ref>
172  <ref type="application">ConfBridge</ref>
173  </see-also>
174  </managerEventInstance>
175  </managerEvent>
176  <managerEvent language="en_US" name="ConfbridgeUnmute">
177  <managerEventInstance class="EVENT_FLAG_CALL">
178  <synopsis>Raised when a confbridge participant unmutes.</synopsis>
179  <syntax>
180  <parameter name="Conference">
181  <para>The name of the Confbridge conference.</para>
182  </parameter>
183  <bridge_snapshot/>
184  <channel_snapshot/>
185  <parameter name="Admin">
186  <para>Identifies this user as an admin user.</para>
187  <enumlist>
188  <enum name="Yes"/>
189  <enum name="No"/>
190  </enumlist>
191  </parameter>
192  </syntax>
193  <see-also>
194  <ref type="managerEvent">ConfbridgeMute</ref>
195  <ref type="application">ConfBridge</ref>
196  </see-also>
197  </managerEventInstance>
198  </managerEvent>
199  <managerEvent language="en_US" name="ConfbridgeTalking">
200  <managerEventInstance class="EVENT_FLAG_CALL">
201  <synopsis>Raised when a confbridge participant begins or ends talking.</synopsis>
202  <syntax>
203  <parameter name="Conference">
204  <para>The name of the Confbridge conference.</para>
205  </parameter>
206  <bridge_snapshot/>
207  <channel_snapshot/>
208  <parameter name="TalkingStatus">
209  <enumlist>
210  <enum name="on"/>
211  <enum name="off"/>
212  </enumlist>
213  </parameter>
214  <parameter name="Admin">
215  <para>Identifies this user as an admin user.</para>
216  <enumlist>
217  <enum name="Yes"/>
218  <enum name="No"/>
219  </enumlist>
220  </parameter>
221  </syntax>
222  <see-also>
223  <ref type="application">ConfBridge</ref>
224  </see-also>
225  </managerEventInstance>
226  </managerEvent>
227 ***/
228 
231 
241 /*
242  * The welcome message is defined here but is only sent
243  * to participants and only when events are enabled.
244  * At the current time, no actual stasis or AMI events
245  * are generated for this type.
246  */
248 
250 {
251  if (event_type == confbridge_start_type()) {
252  return "ConfbridgeStart";
253  } else if (event_type == confbridge_end_type()) {
254  return "ConfbridgeEnd";
255  } else if (event_type == confbridge_join_type()) {
256  return "ConfbridgeJoin";
257  } else if (event_type == confbridge_leave_type()) {
258  return "ConfbridgeLeave";
259  } else if (event_type == confbridge_start_record_type()) {
260  return "ConfbridgeRecord";
261  } else if (event_type == confbridge_stop_record_type()) {
262  return "ConfbridgeStopRecord";
263  } else if (event_type == confbridge_mute_type()) {
264  return "ConfbridgeMute";
265  } else if (event_type == confbridge_unmute_type()) {
266  return "ConfbridgeUnmute";
267  } else if (event_type == confbridge_talking_type()) {
268  return "ConfbridgeTalking";
269  } else if (event_type == confbridge_welcome_type()) {
270  return "ConfbridgeWelcome";
271  } else {
272  return "unknown";
273  }
274 }
275 
276 static struct ast_json *channel_to_json(struct ast_channel_snapshot *channel_snapshot,
277  struct ast_json *conf_blob, struct ast_json *labels_blob)
278 {
279  struct ast_json *json_channel = ast_channel_snapshot_to_json(channel_snapshot, NULL);
280 
281  if (!json_channel) {
282  return NULL;
283  }
284 
285  /* These items are removed for privacy reasons. */
286  ast_json_object_del(json_channel, "dialplan");
287  ast_json_object_del(json_channel, "connected");
288  ast_json_object_del(json_channel, "accountcode");
289 
290  /* conf_blob contains flags such as talking, admin, mute, etc. */
291  if (conf_blob) {
292  struct ast_json *conf_copy = ast_json_copy(conf_blob);
293 
294  if (!conf_copy) {
295  ast_json_unref(json_channel);
296  return NULL;
297  }
298  ast_json_object_del(conf_copy, "conference");
299  ast_json_object_update(json_channel, conf_copy);
300  ast_json_unref(conf_copy);
301  }
302 
303  /* labels_blob contains the msid labels to correlate to streams. */
304  if (labels_blob) {
305  ast_json_object_update(json_channel, labels_blob);
306  }
307 
308  return json_channel;
309 }
310 
311 static struct ast_json *bridge_to_json(struct ast_bridge_snapshot *bridge_snapshot)
312 {
313  struct ast_json *json_bridge = ast_bridge_snapshot_to_json(bridge_snapshot, NULL);
314 
315  if (!json_bridge) {
316  return NULL;
317  }
318 
319  /* These items have no use in the context of bridge participant info. */
320  ast_json_object_del(json_bridge, "technology");
321  ast_json_object_del(json_bridge, "bridge_type");
322  ast_json_object_del(json_bridge, "bridge_class");
323  ast_json_object_del(json_bridge, "creator");
324  ast_json_object_del(json_bridge, "channels");
325 
326  return json_bridge;
327 }
328 
330  struct ast_json *json_bridge, struct ast_json *json_channels,
331  struct stasis_message * msg)
332 {
333  const struct timeval *tv = stasis_message_timestamp(msg);
334  const char *msg_name = confbridge_event_type_to_string(stasis_message_type(msg));
335  const char *fmt = ast_json_typeof(json_channels) == AST_JSON_ARRAY ?
336  "{s: s, s: o, s: o, s: o }" : "{s: s, s: o, s: o, s: [ o ] }";
337 
338  return ast_json_pack(fmt,
339  "type", msg_name,
340  "timestamp", ast_json_timeval(*tv, NULL),
341  "bridge", json_bridge,
342  "channels", json_channels);
343 }
344 
345 static struct ast_json *pack_snapshots( struct ast_bridge_snapshot *bridge_snapshot,
346  struct ast_channel_snapshot *channel_snapshot, struct ast_json *conf_blob,
347  struct ast_json *labels_blob, struct stasis_message * msg)
348 {
349  struct ast_json *json_bridge;
350  struct ast_json *json_channel;
351 
352  json_bridge = bridge_to_json(bridge_snapshot);
353  json_channel = channel_to_json(channel_snapshot, conf_blob, labels_blob);
354 
355  return pack_bridge_and_channels(json_bridge, json_channel, msg);
356 }
357 
358 static void send_message(const char *msg_name, char *conf_name, struct ast_json *json_object,
359  struct ast_channel *chan)
360 {
361  struct ast_msg_data *data_msg;
362  struct ast_msg_data_attribute attrs[] = {
363  { .type = AST_MSG_DATA_ATTR_FROM, conf_name },
364  { .type = AST_MSG_DATA_ATTR_CONTENT_TYPE, .value = "application/x-asterisk-confbridge-event+json"},
365  { .type = AST_MSG_DATA_ATTR_BODY, },
366  };
367  char *json;
368  int rc = 0;
369  struct ast_frame f;
370  RAII_VAR(struct ast_bridge_channel *, bridge_chan, NULL, ao2_cleanup);
371 
372  bridge_chan = ast_channel_get_bridge_channel(chan);
373  if (!bridge_chan) {
374  /* Don't complain if we can't get the bridge_chan. The channel is probably gone. */
375  return;
376  }
377 
378  json = ast_json_dump_string_format(json_object, AST_JSON_PRETTY);
379  if (!json) {
380  ast_log(LOG_ERROR, "Unable to convert json_object for %s message to string\n", msg_name);
381  return;
382  }
383  attrs[2].value = json;
384 
386  if (!data_msg) {
387  ast_log(LOG_ERROR, "Unable to create %s message for channel '%s'\n", msg_name,
388  ast_channel_name(chan));
389  ast_json_free(json);
390  return;
391  }
392 
393  memset(&f, 0, sizeof(f));
395  f.data.ptr = data_msg;
396  f.datalen = ast_msg_data_get_length(data_msg);
397 
398  rc = ast_bridge_channel_queue_frame(bridge_chan, &f);
399  ast_free(data_msg);
400  if (rc != 0) {
401  /* Don't complain if we can't send a leave message. The channel is probably gone. */
402  if (strcmp(confbridge_event_type_to_string(confbridge_leave_type()), msg_name) != 0) {
403  ast_log(LOG_ERROR, "Failed to queue %s message to '%s'\n%s\n", msg_name,
404  ast_channel_name(chan), json);
405  }
406  ast_json_free(json);
407  return;
408  }
409 
410  ast_debug(3, "Queued %s message to '%s'\n%s\n", msg_name, ast_channel_name(chan), json);
411  ast_json_free(json);
412 }
413 
415  struct ast_channel *chan, struct stasis_message *msg)
416 {
417  struct ast_bridge_blob *obj = stasis_message_data(msg);
418  struct ast_json *extras = obj->blob;
419  struct user_profile u_profile = {{0}};
420  int source_send_events = 0;
421  int source_echo_events = 0;
422  struct ast_json* json_channels = NULL;
423  struct confbridge_user *user;
424  const char *msg_name = confbridge_event_type_to_string(stasis_message_type(msg));
425 
426  ast_debug(3, "Distributing %s event to participants\n", msg_name);
427 
428  /* This could be a channel level event or a bridge level event */
429  if (chan) {
430  if (!conf_find_user_profile(chan, NULL, &u_profile)) {
431  ast_log(LOG_ERROR, "Unable to retrieve user profile for channel '%s'\n",
432  ast_channel_name(chan));
433  return;
434  }
435  source_send_events = ast_test_flag(&u_profile, USER_OPT_SEND_EVENTS);
436  source_echo_events = ast_test_flag(&u_profile, USER_OPT_ECHO_EVENTS);
437  ast_debug(3, "send_events: %d echo_events: %d for profile %s\n",
438  source_send_events, source_echo_events, u_profile.name);
439  }
440 
441  /* Now send a message to the participants with the json string. */
442  ao2_lock(conference);
443  AST_LIST_TRAVERSE(&conference->active_list, user, list) {
444  struct ast_json *json_object;
445 
446  /*
447  * If the msg type is join, we need to capture all targets channel info so we can
448  * send a welcome message to the source channel with all current participants.
449  */
450  if (source_send_events && stasis_message_type(msg) == confbridge_join_type()) {
451  struct ast_channel_snapshot *target_snapshot;
452  struct ast_json *target_json_channel;
453 
455  if (!target_snapshot) {
456  ast_log(LOG_ERROR, "Unable to get a channel snapshot for '%s'\n",
457  ast_channel_name(user->chan));
458  continue;
459  }
460 
461  target_json_channel = channel_to_json(target_snapshot, extras, NULL);
462  ao2_ref(target_snapshot, -1);
463 
464  if (!json_channels) {
465  json_channels = ast_json_array_create();
466  if (!json_channels) {
467  ast_log(LOG_ERROR, "Unable to allocate json array\n");
468  ast_json_unref(target_json_channel);
469  return;
470  }
471  }
472 
473  ast_json_array_append(json_channels, target_json_channel);
474  }
475 
476  /* Don't send a message to the user that triggered the event. */
477  if (!source_echo_events && user->chan == chan) {
478  ast_debug(3, "Skipping queueing %s message to '%s'. Same channel.\n", msg_name,
479  ast_channel_name(user->chan));
480  continue;
481  }
482 
483  /* Don't send a message to users in profiles not sending events. */
485  ast_debug(3, "Skipping queueing %s message to '%s'. Not receiving events.\n", msg_name,
486  ast_channel_name(user->chan));
487  continue;
488  }
489 
490  json_object = pack_snapshots(obj->bridge, obj->channel, extras, NULL, msg);
491 
492  if (!json_object) {
493  ast_log(LOG_ERROR, "Unable to convert %s message to json\n", msg_name);
494  continue;
495  }
496 
497  send_message(msg_name, conference->name, json_object, user->chan);
498  ast_json_unref(json_object);
499  }
500  ao2_unlock(conference);
501 
502  /*
503  * If this is a join event, send the welcome message to just the joining user
504  * if it's not audio-only or otherwise restricted.
505  */
506  if (source_send_events && json_channels
508  struct ast_json *json_object;
509  struct ast_json *json_bridge;
510  const char *welcome_msg_name = confbridge_event_type_to_string(confbridge_welcome_type());
511 
512  json_bridge = bridge_to_json(obj->bridge);
513  json_object = pack_bridge_and_channels(json_bridge, json_channels, msg);
514  if (!json_object) {
515  ast_log(LOG_ERROR, "Unable to convert ConfbridgeWelcome message to json\n");
516  return;
517  }
518  ast_json_string_set(ast_json_object_get(json_object, "type"), welcome_msg_name);
519 
520  send_message(welcome_msg_name, conference->name, json_object, chan);
521  ast_json_unref(json_object);
522  }
523 }
524 
526  struct stasis_message *message,
527  struct ast_str *extra_text)
528 {
529  struct ast_bridge_blob *blob = stasis_message_data(message);
530  const char *event = confbridge_event_type_to_string(stasis_message_type(message));
531  const char *conference_name;
532  RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
533  RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
534 
535  ast_assert(blob != NULL);
536  ast_assert(event != NULL);
537 
538  bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
539  if (!bridge_text) {
540  return;
541  }
542 
543  conference_name = ast_json_string_get(ast_json_object_get(blob->blob, "conference"));
544  ast_assert(conference_name != NULL);
545 
546  if (blob->channel) {
547  struct confbridge_conference *conference = conf_find_bridge(conference_name);
548 
549  channel_text = ast_manager_build_channel_state_string(blob->channel);
550  ao2_cleanup(conference);
551  }
552 
554  "Conference: %s\r\n"
555  "%s"
556  "%s"
557  "%s",
558  conference_name,
559  ast_str_buffer(bridge_text),
560  channel_text ? ast_str_buffer(channel_text) : "",
561  extra_text ? ast_str_buffer(extra_text) : "");
562 }
563 
564 static int get_bool_header(struct ast_str **extra_text, struct stasis_message *message,
565  const char *json_key, const char *ami_header)
566 {
567  const struct ast_bridge_blob *blob = stasis_message_data(message);
568  const struct ast_json *obj;
569 
570  obj = ast_json_object_get(blob->blob, json_key);
571  if (!obj) {
572  return -1;
573  }
574 
575  return ast_str_append_event_header(extra_text, ami_header,
577 }
578 
579 static int get_admin_header(struct ast_str **extra_text, struct stasis_message *message)
580 {
581  return get_bool_header(extra_text, message, "admin", "Admin");
582 }
583 
584 static int get_muted_header(struct ast_str **extra_text, struct stasis_message *message)
585 {
586  return get_bool_header(extra_text, message, "muted", "Muted");
587 }
588 
589 static void confbridge_start_cb(void *data, struct stasis_subscription *sub,
590  struct stasis_message *message)
591 {
593 }
594 
595 static void confbridge_end_cb(void *data, struct stasis_subscription *sub,
596  struct stasis_message *message)
597 {
599 }
600 
601 static void confbridge_leave_cb(void *data, struct stasis_subscription *sub,
602  struct stasis_message *message)
603 {
604  struct ast_str *extra_text = NULL;
605 
606  if (!get_admin_header(&extra_text, message)) {
607  confbridge_publish_manager_event(message, extra_text);
608  }
609  ast_free(extra_text);
610 }
611 
612 static void confbridge_join_cb(void *data, struct stasis_subscription *sub,
613  struct stasis_message *message)
614 {
615  struct ast_str *extra_text = NULL;
616 
617  if (!get_admin_header(&extra_text, message)
618  && !get_muted_header(&extra_text, message)) {
619  confbridge_publish_manager_event(message, extra_text);
620  }
621  ast_free(extra_text);
622 }
623 
624 static void confbridge_atxfer_cb(void *data, struct stasis_subscription *sub,
625  struct stasis_message *message)
626 {
627  struct ast_attended_transfer_message *msg = stasis_message_data(message);
628 
629  if (msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
630  return;
631  }
632 
633  /*
634  * This callback will get called for ALL attended transfers
635  * so we need to make sure this transfer belongs to
636  * a conference bridge before trying to handle it.
637  */
639  && strcmp(msg->dest.app, "ConfBridge") == 0) {
641  }
642 }
643 
644 static void confbridge_start_record_cb(void *data, struct stasis_subscription *sub,
645  struct stasis_message *message)
646 {
648 }
649 
650 static void confbridge_stop_record_cb(void *data, struct stasis_subscription *sub,
651  struct stasis_message *message)
652 {
654 }
655 
656 static void confbridge_mute_cb(void *data, struct stasis_subscription *sub,
657  struct stasis_message *message)
658 {
659  struct ast_str *extra_text = NULL;
660 
661  if (!get_admin_header(&extra_text, message)) {
662  confbridge_publish_manager_event(message, extra_text);
663  }
664  ast_free(extra_text);
665 }
666 
667 static void confbridge_unmute_cb(void *data, struct stasis_subscription *sub,
668  struct stasis_message *message)
669 {
670  struct ast_str *extra_text = NULL;
671 
672  if (!get_admin_header(&extra_text, message)) {
673  confbridge_publish_manager_event(message, extra_text);
674  }
675  ast_free(extra_text);
676 }
677 
678 static void confbridge_talking_cb(void *data, struct stasis_subscription *sub,
679  struct stasis_message *message)
680 {
681  RAII_VAR(struct ast_str *, extra_text, NULL, ast_free);
682  const struct ast_bridge_blob *blob = stasis_message_data(message);
683  const char *talking_status = ast_json_string_get(ast_json_object_get(blob->blob, "talking_status"));
684  if (!talking_status) {
685  return;
686  }
687 
688  ast_str_append_event_header(&extra_text, "TalkingStatus", talking_status);
689  if (!extra_text) {
690  return;
691  }
692 
693  if (!get_admin_header(&extra_text, message)) {
694  confbridge_publish_manager_event(message, extra_text);
695  }
696 }
697 
709 
710  if (bridge_state_router) {
711  stasis_message_router_unsubscribe(bridge_state_router);
712  bridge_state_router = NULL;
713  }
714 
715  if (channel_state_router) {
716  stasis_message_router_unsubscribe(channel_state_router);
717  channel_state_router = NULL;
718  }
719 }
720 
722 {
733 
734  bridge_state_router = stasis_message_router_create(
736 
737  if (!bridge_state_router) {
738  return -1;
739  }
740 
741  if (stasis_message_router_add(bridge_state_router,
744  NULL)) {
746  return -1;
747  }
748  if (stasis_message_router_add(bridge_state_router,
751  NULL)) {
753  return -1;
754  }
755  if (stasis_message_router_add(bridge_state_router,
758  NULL)) {
760  return -1;
761  }
762  if (stasis_message_router_add(bridge_state_router,
765  NULL)) {
767  return -1;
768  }
769  if (stasis_message_router_add(bridge_state_router,
772  NULL)) {
774  return -1;
775  }
776  if (stasis_message_router_add(bridge_state_router,
779  NULL)) {
781  return -1;
782  }
783  if (stasis_message_router_add(bridge_state_router,
786  NULL)) {
788  return -1;
789  }
790  if (stasis_message_router_add(bridge_state_router,
793  NULL)) {
795  return -1;
796  }
797  if (stasis_message_router_add(bridge_state_router,
800  NULL)) {
802  return -1;
803  }
804  if (stasis_message_router_add(bridge_state_router,
807  NULL)) {
809  return -1;
810  }
811 
812  channel_state_router = stasis_message_router_create(
814 
815  if (!channel_state_router) {
817  return -1;
818  }
819 
820  if (stasis_message_router_add(channel_state_router,
823  NULL)) {
825  return -1;
826  }
827  if (stasis_message_router_add(channel_state_router,
830  NULL)) {
832  return -1;
833  }
834  if (stasis_message_router_add(channel_state_router,
837  NULL)) {
839  return -1;
840  }
841  if (stasis_message_router_add(channel_state_router,
844  NULL)) {
846  return -1;
847  }
848  if (stasis_message_router_add(channel_state_router,
851  NULL)) {
853  return -1;
854  }
855  if (stasis_message_router_add(channel_state_router,
858  NULL)) {
860  return -1;
861  }
862  if (stasis_message_router_add(channel_state_router,
865  NULL)) {
867  return -1;
868  }
869  if (stasis_message_router_add(channel_state_router,
872  NULL)) {
874  return -1;
875  }
876  if (stasis_message_router_add(channel_state_router,
879  NULL)) {
881  return -1;
882  }
883 
884  /* FYI: confbridge_welcome_type is never routed */
885 
886  return 0;
887 }
static char user[512]
struct stasis_message_type * confbridge_start_record_type(void)
get the confbridge start_record stasis message type
size_t ast_msg_data_get_length(struct ast_msg_data *msg)
Get length of the structure.
Definition: message.c:1513
Main Channel structure associated with a channel.
union ast_attended_transfer_message::@324 dest
Asterisk main include file. File version handling, generic pbx functions.
int manager_confbridge_init(void)
register stasis message routers to handle manager events for confbridge messages
struct stasis_message_type * confbridge_join_type(void)
get the confbridge join stasis message type
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
struct ast_channel * chan
Definition: confbridge.h:277
static int get_admin_header(struct ast_str **extra_text, struct stasis_message *message)
static void confbridge_talking_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
enum ast_msg_data_attribute_type type
Definition: message.h:463
Message representing attended transfer.
struct ast_channel_snapshot * channel
static void confbridge_start_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
#define ast_test_flag(p, flag)
Definition: utils.h:63
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1501
int ast_json_object_update(struct ast_json *object, struct ast_json *other)
Update object with all of the fields of other.
Definition: json.c:416
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
static void confbridge_join_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
int ast_json_object_del(struct ast_json *object, const char *key)
Delete a field from a JSON object.
Definition: json.c:408
void ast_json_free(void *p)
Asterisk&#39;s custom JSON allocator. Exposed for use by unit tests.
Definition: json.c:52
Structure that contains a snapshot of information about a bridge.
Definition: bridge.h:322
const struct user_profile * conf_find_user_profile(struct ast_channel *chan, const char *user_profile_name, struct user_profile *result)
find a user profile given a user profile&#39;s name and store that profile in result structure.
static void confbridge_start_record_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
int ast_json_is_true(const struct ast_json *value)
Check if value is JSON true.
Definition: json.c:253
static void confbridge_stop_record_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
STASIS_MESSAGE_TYPE_DEFN(confbridge_start_type)
Structure representing a snapshot of channel state.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1523
struct ast_json * blob
#define EVENT_FLAG_CALL
Definition: manager.h:72
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
Structure used to transport a message through the frame core.
Definition: message.c:1406
Definition: astman.c:222
#define ast_assert(a)
Definition: utils.h:695
struct ast_msg_data * ast_msg_data_alloc(enum ast_msg_data_source_type source, struct ast_msg_data_attribute attributes[], size_t count)
Allocates an ast_msg_data structure.
Definition: message.c:1418
#define ao2_unlock(a)
Definition: astobj2.h:730
struct confbridge_user::@94 list
void confbridge_handle_atxfer(struct ast_attended_transfer_message *msg)
Create join/leave events for attended transfers.
static int get_muted_header(struct ast_str **extra_text, struct stasis_message *message)
#define NULL
Definition: resample.c:96
struct stasis_message_type * confbridge_start_type(void)
get the confbridge start stasis message type
Out-of-call text message support.
struct confbridge_conference::@90 active_list
Media Stream API.
static void confbridge_mute_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
struct stasis_message_type * confbridge_leave_type(void)
get the confbridge leave stasis message type
struct ast_bridge_snapshot * bridge
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
enum ast_transfer_result result
#define ast_log
Definition: astobj2.c:42
static struct ast_json * pack_snapshots(struct ast_bridge_snapshot *bridge_snapshot, struct ast_channel_snapshot *channel_snapshot, struct ast_json *conf_blob, struct ast_json *labels_blob, struct stasis_message *msg)
General Asterisk PBX channel definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
static void confbridge_atxfer_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
struct ast_str * ast_manager_build_bridge_state_string(const struct ast_bridge_snapshot *snapshot)
Generate the AMI message body from a bridge snapshot.
Blob of data associated with a bridge.
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
char * ast_json_dump_string_format(struct ast_json *root, enum ast_json_encoding_format format)
Encode a JSON value to a string.
Definition: json.c:463
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
Definition: json.c:352
struct stasis_message_type * confbridge_stop_record_type(void)
get the confbridge stop_record stasis message type
#define stasis_message_router_create(topic)
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition: json.c:649
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition: json.c:368
const char * ast_channel_uniqueid(const struct ast_channel *chan)
enum ast_attended_transfer_dest_type dest_type
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define LOG_ERROR
Definition: logger.h:285
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
static void confbridge_end_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message_type * ast_attended_transfer_type(void)
Message type for ast_attended_transfer_message.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
void manager_confbridge_shutdown(void)
unregister stasis message routers to handle manager events for confbridge messages ...
struct ast_json * ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_channel_snapshot.
#define ast_free(a)
Definition: astmm.h:182
enum ast_json_type ast_json_typeof(const struct ast_json *value)
Get the type of value.
Definition: json.c:78
The structure that represents a conference bridge.
Definition: confbridge.h:244
static void confbridge_publish_manager_event(struct stasis_message *message, struct ast_str *extra_text)
const char * confbridge_event_type_to_string(struct stasis_message_type *event_type)
Get the string representation of a confbridge stasis message type.
void conf_send_event_to_participants(struct confbridge_conference *conference, struct ast_channel *chan, struct stasis_message *msg)
Send events to bridge participants.
static struct stasis_message_router * channel_state_router
struct ast_bridge_channel * ast_channel_get_bridge_channel(struct ast_channel *chan)
Get a reference to the channel&#39;s bridge pointer.
Definition: channel.c:10783
static struct stasis_message_router * bridge_state_router
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
struct stasis_message_type * confbridge_end_type(void)
get the confbridge end stasis message type
int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr)
Write a frame to the specified bridge_channel.
#define AST_YESNO(x)
return Yes or No depending on the argument.
Definition: strings.h:139
Structure that contains information regarding a channel in a bridge.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object...
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:397
struct ast_json * ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_bridge_snapshot.
const char * ast_channel_name(const struct ast_channel *chan)
char name[MAX_PROFILE_NAME]
Definition: confbridge.h:153
struct stasis_message_type * confbridge_welcome_type(void)
get the confbridge welcome stasis message type
static struct ast_json * channel_to_json(struct ast_channel_snapshot *channel_snapshot, struct ast_json *conf_blob, struct ast_json *labels_blob)
void stasis_message_router_unsubscribe(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic.
struct confbridge_conference * conf_find_bridge(const char *conference_name)
Find a confbridge by name.
struct stasis_forward * sub
Definition: res_corosync.c:240
Data structure associated with a single frame of data.
struct stasis_message_type * confbridge_talking_type(void)
get the confbridge talking stasis message type
struct stasis_message_type * confbridge_unmute_type(void)
get the confbridge unmute stasis message type
Abstract JSON element (object, array, string, int, ...).
The structure that represents a conference bridge user.
Definition: confbridge.h:271
static struct ast_json * bridge_to_json(struct ast_bridge_snapshot *bridge_snapshot)
union ast_frame::@263 data
enum ast_frame_type frametype
struct stasis_message_type * confbridge_mute_type(void)
get the confbridge mute stasis message type
struct user_profile u_profile
Definition: confbridge.h:274
int ast_json_string_set(struct ast_json *string, const char *value)
Change the value of a JSON string.
Definition: json.c:278
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:248
Bridging API.
char name[MAX_CONF_NAME]
Definition: confbridge.h:245
int ast_str_append_event_header(struct ast_str **fields_string, const char *header, const char *value)
append an event header to an ast string
Definition: manager.c:9705
static struct ast_json * pack_bridge_and_channels(struct ast_json *json_bridge, struct ast_json *json_channels, struct stasis_message *msg)
struct ast_json * ast_json_copy(const struct ast_json *value)
Copy a JSON value, but not its children.
Definition: json.c:616
static void send_message(const char *msg_name, char *conf_name, struct ast_json *json_object, struct ast_channel *chan)
static void confbridge_unmute_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
static int get_bool_header(struct ast_str **extra_text, struct stasis_message *message, const char *json_key, const char *ami_header)
static void confbridge_leave_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)