Asterisk - The Open Source Telephony Project  21.4.1
manager_bridges.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  * Kinsey Moore <kmoore@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 The Asterisk Management Interface - AMI (bridge event handling)
22  *
23  * \author Kinsey Moore <kmoore@digium.com>
24  */
25 
26 #include "asterisk.h"
27 
28 #include "asterisk/stasis_bridges.h"
29 #include "asterisk/stasis_channels.h"
30 #include "asterisk/manager.h"
31 #include "asterisk/stasis_message_router.h"
32 
33 /*! \brief Message router for cached bridge state snapshot updates */
35 
36 /*** DOCUMENTATION
37  <managerEvent language="en_US" name="BridgeCreate">
38  <managerEventInstance class="EVENT_FLAG_CALL">
39  <synopsis>Raised when a bridge is created.</synopsis>
40  <syntax>
41  <bridge_snapshot/>
42  </syntax>
43  <see-also>
44  <ref type="managerEvent">BridgeDestroy</ref>
45  <ref type="managerEvent">BridgeEnter</ref>
46  <ref type="managerEvent">BridgeLeave</ref>
47  </see-also>
48  </managerEventInstance>
49  </managerEvent>
50  <managerEvent language="en_US" name="BridgeDestroy">
51  <managerEventInstance class="EVENT_FLAG_CALL">
52  <synopsis>Raised when a bridge is destroyed.</synopsis>
53  <syntax>
54  <bridge_snapshot/>
55  </syntax>
56  <see-also>
57  <ref type="managerEvent">BridgeCreate</ref>
58  <ref type="managerEvent">BridgeEnter</ref>
59  <ref type="managerEvent">BridgeLeave</ref>
60  </see-also>
61  </managerEventInstance>
62  </managerEvent>
63  <managerEvent language="en_US" name="BridgeEnter">
64  <managerEventInstance class="EVENT_FLAG_CALL">
65  <synopsis>Raised when a channel enters a bridge.</synopsis>
66  <syntax>
67  <bridge_snapshot/>
68  <channel_snapshot/>
69  <parameter name="SwapUniqueid">
70  <para>The uniqueid of the channel being swapped out of the bridge</para>
71  </parameter>
72  </syntax>
73  <see-also>
74  <ref type="managerEvent">BridgeCreate</ref>
75  <ref type="managerEvent">BridgeDestroy</ref>
76  <ref type="managerEvent">BridgeLeave</ref>
77  </see-also>
78  </managerEventInstance>
79  </managerEvent>
80  <managerEvent language="en_US" name="BridgeLeave">
81  <managerEventInstance class="EVENT_FLAG_CALL">
82  <synopsis>Raised when a channel leaves a bridge.</synopsis>
83  <syntax>
84  <bridge_snapshot/>
85  <channel_snapshot/>
86  </syntax>
87  <see-also>
88  <ref type="managerEvent">BridgeCreate</ref>
89  <ref type="managerEvent">BridgeDestroy</ref>
90  <ref type="managerEvent">BridgeEnter</ref>
91  </see-also>
92  </managerEventInstance>
93  </managerEvent>
94  <managerEvent language="en_US" name="BridgeVideoSourceUpdate">
95  <managerEventInstance class="EVENT_FLAG_CALL">
96  <synopsis>Raised when the channel that is the source of video in a bridge changes.</synopsis>
97  <syntax>
98  <bridge_snapshot/>
99  <parameter name="BridgePreviousVideoSource">
100  <para>The unique ID of the channel that was the video source.</para>
101  </parameter>
102  </syntax>
103  <see-also>
104  <ref type="managerEvent">BridgeCreate</ref>
105  <ref type="managerEvent">BridgeDestroy</ref>
106  </see-also>
107  </managerEventInstance>
108  </managerEvent>
109  <manager name="BridgeList" language="en_US">
110  <synopsis>
111  Get a list of bridges in the system.
112  </synopsis>
113  <syntax>
114  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
115  <parameter name="BridgeType">
116  <para>Optional type for filtering the resulting list of bridges.</para>
117  </parameter>
118  </syntax>
119  <description>
120  <para>Returns a list of bridges, optionally filtering on a bridge type.</para>
121  </description>
122  <see-also>
123  <ref type="manager">Bridge</ref>
124  <ref type="manager">BridgeDestroy</ref>
125  <ref type="manager">BridgeInfo</ref>
126  <ref type="manager">BridgeKick</ref>
127  </see-also>
128  </manager>
129  <manager name="BridgeInfo" language="en_US">
130  <synopsis>
131  Get information about a bridge.
132  </synopsis>
133  <syntax>
134  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
135  <parameter name="BridgeUniqueid" required="true">
136  <para>The unique ID of the bridge about which to retrieve information.</para>
137  </parameter>
138  </syntax>
139  <description>
140  <para>Returns detailed information about a bridge and the channels in it.</para>
141  </description>
142  <see-also>
143  <ref type="manager">Bridge</ref>
144  <ref type="manager">BridgeDestroy</ref>
145  <ref type="manager">BridgeKick</ref>
146  <ref type="manager">BridgeList</ref>
147  </see-also>
148  <responses>
149  <list-elements>
150  <managerEvent language="en_US" name="BridgeInfoChannel">
151  <managerEventInstance class="EVENT_FLAG_COMMAND">
152  <synopsis>Information about a channel in a bridge.</synopsis>
153  <syntax>
154  <channel_snapshot/>
155  </syntax>
156  </managerEventInstance>
157  </managerEvent>
158  </list-elements>
159  <managerEvent language="en_US" name="BridgeInfoComplete">
160  <managerEventInstance class="EVENT_FLAG_COMMAND">
161  <synopsis>Information about a bridge.</synopsis>
162  <syntax>
163  <bridge_snapshot/>
164  </syntax>
165  </managerEventInstance>
166  </managerEvent>
167  </responses>
168  </manager>
169  <manager name="BridgeDestroy" language="en_US">
170  <synopsis>
171  Destroy a bridge.
172  </synopsis>
173  <syntax>
174  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
175  <parameter name="BridgeUniqueid" required="true">
176  <para>The unique ID of the bridge to destroy.</para>
177  </parameter>
178  </syntax>
179  <description>
180  <para>Deletes the bridge, causing channels to continue or hang up.</para>
181  </description>
182  <see-also>
183  <ref type="manager">Bridge</ref>
184  <ref type="manager">BridgeInfo</ref>
185  <ref type="manager">BridgeKick</ref>
186  <ref type="manager">BridgeList</ref>
187  <ref type="managerEvent">BridgeDestroy</ref>
188  </see-also>
189  </manager>
190  <manager name="BridgeKick" language="en_US">
191  <synopsis>
192  Kick a channel from a bridge.
193  </synopsis>
194  <syntax>
195  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
196  <parameter name="BridgeUniqueid" required="false">
197  <para>The unique ID of the bridge containing the channel to
198  destroy. This parameter can be omitted, or supplied to insure
199  that the channel is not removed from the wrong bridge.</para>
200  </parameter>
201  <parameter name="Channel" required="true">
202  <para>The channel to kick out of a bridge.</para>
203  </parameter>
204  </syntax>
205  <description>
206  <para>The channel is removed from the bridge.</para>
207  </description>
208  <see-also>
209  <ref type="manager">Bridge</ref>
210  <ref type="manager">BridgeDestroy</ref>
211  <ref type="manager">BridgeInfo</ref>
212  <ref type="manager">BridgeList</ref>
213  <ref type="managerEvent">BridgeLeave</ref>
214  </see-also>
215  </manager>
216  ***/
217 
218 /*! \brief The \ref stasis subscription returned by the forwarding of the channel topic
219  * to the manager topic
220  */
222 
224  const struct ast_bridge_snapshot *snapshot,
225  const char *prefix)
226 {
227  struct ast_str *out = ast_str_create(128);
228  int res;
229 
230  if (!out) {
231  return NULL;
232  }
233 
234  res = ast_str_set(&out, 0,
235  "%sBridgeUniqueid: %s\r\n"
236  "%sBridgeType: %s\r\n"
237  "%sBridgeTechnology: %s\r\n"
238  "%sBridgeCreator: %s\r\n"
239  "%sBridgeName: %s\r\n"
240  "%sBridgeNumChannels: %u\r\n"
241  "%sBridgeVideoSourceMode: %s\r\n",
242  prefix, snapshot->uniqueid,
243  prefix, snapshot->subclass,
244  prefix, snapshot->technology,
245  prefix, ast_strlen_zero(snapshot->creator) ? "<unknown>": snapshot->creator,
246  prefix, ast_strlen_zero(snapshot->name) ? "<unknown>": snapshot->name,
247  prefix, snapshot->num_channels,
248  prefix, ast_bridge_video_mode_to_string(snapshot->video_mode));
249  if (!res) {
250  ast_free(out);
251  return NULL;
252  }
253 
254  if (snapshot->video_mode != AST_BRIDGE_VIDEO_MODE_NONE
255  && !ast_strlen_zero(snapshot->video_source_id)) {
256  res = ast_str_append(&out, 0, "%sBridgeVideoSource: %s\r\n",
257  prefix, snapshot->video_source_id);
258  if (!res) {
259  ast_free(out);
260  return NULL;
261  }
262  }
263 
264  return out;
265 }
266 
268  const struct ast_bridge_snapshot *snapshot)
269 {
271 }
272 
273 /*! \brief Typedef for callbacks that get called on channel snapshot updates */
274 typedef struct ast_manager_event_blob *(*bridge_snapshot_monitor)(
275  struct ast_bridge_snapshot *old_snapshot,
276  struct ast_bridge_snapshot *new_snapshot);
277 
278 /*! \brief Handle bridge creation */
280  struct ast_bridge_snapshot *old_snapshot,
281  struct ast_bridge_snapshot *new_snapshot)
282 {
283  if (!new_snapshot || old_snapshot) {
284  return NULL;
285  }
286 
288  EVENT_FLAG_CALL, "BridgeCreate", NO_EXTRA_FIELDS);
289 }
290 
291 /*! \brief Handle video source updates */
293  struct ast_bridge_snapshot *old_snapshot,
294  struct ast_bridge_snapshot *new_snapshot)
295 {
296  if (!new_snapshot || !old_snapshot) {
297  return NULL;
298  }
299 
300  if (!strcmp(old_snapshot->video_source_id, new_snapshot->video_source_id)) {
301  return NULL;
302  }
303 
305  EVENT_FLAG_CALL, "BridgeVideoSourceUpdate",
306  "BridgePreviousVideoSource: %s\r\n",
307  old_snapshot->video_source_id);
308 }
309 
310 /*! \brief Handle bridge destruction */
312  struct ast_bridge_snapshot *old_snapshot,
313  struct ast_bridge_snapshot *new_snapshot)
314 {
315  if (new_snapshot || !old_snapshot) {
316  return NULL;
317  }
318 
320  EVENT_FLAG_CALL, "BridgeDestroy", NO_EXTRA_FIELDS);
321 }
322 
323 bridge_snapshot_monitor bridge_monitors[] = {
327 };
328 
329 static void bridge_snapshot_update(void *data, struct stasis_subscription *sub,
330  struct stasis_message *message)
331 {
332  RAII_VAR(struct ast_str *, bridge_event_string, NULL, ast_free);
333  struct ast_bridge_snapshot_update *update;
334  size_t i;
335 
336  update = stasis_message_data(message);
337 
338  for (i = 0; i < ARRAY_LEN(bridge_monitors); ++i) {
339  RAII_VAR(struct ast_manager_event_blob *, event, NULL, ao2_cleanup);
340 
341  event = bridge_monitors[i](update->old_snapshot, update->new_snapshot);
342  if (!event) {
343  continue;
344  }
345 
346  /* If we haven't already, build the channel event string */
347  if (!bridge_event_string) {
348  bridge_event_string =
350  update->new_snapshot ? update->new_snapshot : update->old_snapshot);
351  if (!bridge_event_string) {
352  return;
353  }
354  }
355 
356  manager_event(event->event_flags, event->manager_event, "%s%s",
357  ast_str_buffer(bridge_event_string),
358  event->extra_fields);
359  }
360 }
361 
362 static void bridge_merge_cb(void *data, struct stasis_subscription *sub,
363  struct stasis_message *message)
364 {
365  struct ast_bridge_merge_message *merge_msg = stasis_message_data(message);
366  RAII_VAR(struct ast_str *, to_text, NULL, ast_free);
367  RAII_VAR(struct ast_str *, from_text, NULL, ast_free);
368 
369  ast_assert(merge_msg->to != NULL);
370  ast_assert(merge_msg->from != NULL);
371 
372  to_text = ast_manager_build_bridge_state_string_prefix(merge_msg->to, "To");
373  from_text = ast_manager_build_bridge_state_string_prefix(merge_msg->from, "From");
374  if (!to_text || !from_text) {
375  return;
376  }
377 
378  /*** DOCUMENTATION
379  <managerEvent language="en_US" name="BridgeMerge">
380  <managerEventInstance class="EVENT_FLAG_CALL">
381  <synopsis>Raised when two bridges are merged.</synopsis>
382  <syntax>
383  <bridge_snapshot prefix="To"/>
384  <bridge_snapshot prefix="From"/>
385  </syntax>
386  </managerEventInstance>
387  </managerEvent>
388  ***/
389  manager_event(EVENT_FLAG_CALL, "BridgeMerge",
390  "%s"
391  "%s",
392  ast_str_buffer(to_text),
393  ast_str_buffer(from_text));
394 }
395 
396 static void channel_enter_cb(void *data, struct stasis_subscription *sub,
397  struct stasis_message *message)
398 {
399  static const char *swap_name = "SwapUniqueid: ";
400  struct ast_bridge_blob *blob = stasis_message_data(message);
401  RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
402  RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
403  const char *swap_id;
404 
405  bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
406  channel_text = ast_manager_build_channel_state_string(blob->channel);
407  if (!bridge_text || !channel_text) {
408  return;
409  }
410 
411  swap_id = ast_json_string_get(ast_json_object_get(blob->blob, "swap"));
412 
413  manager_event(EVENT_FLAG_CALL, "BridgeEnter",
414  "%s"
415  "%s"
416  "%s%s%s",
417  ast_str_buffer(bridge_text),
418  ast_str_buffer(channel_text),
419  swap_id ? swap_name : "",
420  S_OR(swap_id, ""),
421  swap_id ? "\r\n" : "");
422 }
423 
424 static void channel_leave_cb(void *data, struct stasis_subscription *sub,
425  struct stasis_message *message)
426 {
427  struct ast_bridge_blob *blob = stasis_message_data(message);
428  RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
429  RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
430 
431  bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
432  channel_text = ast_manager_build_channel_state_string(blob->channel);
433  if (!bridge_text || !channel_text) {
434  return;
435  }
436 
437  manager_event(EVENT_FLAG_CALL, "BridgeLeave",
438  "%s"
439  "%s",
440  ast_str_buffer(bridge_text),
441  ast_str_buffer(channel_text));
442 }
443 
445  struct ast_str *id_text;
446  const char *type_filter;
447  int count;
448 };
449 
450 static int send_bridge_list_item_cb(void *obj, void *arg, void *data, int flags)
451 {
452  struct ast_bridge *bridge = obj;
453  RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_get_snapshot(bridge), ao2_cleanup);
454  struct mansession *s = arg;
455  struct bridge_list_data *list_data = data;
456  struct ast_str * bridge_info;
457 
458  if (!snapshot) {
459  return 0;
460  }
461 
462  if (!ast_strlen_zero(list_data->type_filter)
463  && strcmp(list_data->type_filter, snapshot->technology)) {
464  return 0;
465  }
466 
467  bridge_info = ast_manager_build_bridge_state_string(snapshot);
468  if (!bridge_info) {
469  return 0;
470  }
471 
472  astman_append(s,
473  "Event: BridgeListItem\r\n"
474  "%s"
475  "%s"
476  "\r\n",
477  ast_str_buffer(list_data->id_text),
478  ast_str_buffer(bridge_info));
479  ++list_data->count;
480 
481  ast_free(bridge_info);
482 
483  return 0;
484 }
485 
486 static int manager_bridges_list(struct mansession *s, const struct message *m)
487 {
488  const char *id = astman_get_header(m, "ActionID");
489  const char *type_filter = astman_get_header(m, "BridgeType");
490  struct ao2_container *bridges;
491  struct bridge_list_data list_data = { 0 };
492 
493  bridges = ast_bridges();
494  if (!bridges) {
495  astman_send_error(s, m, "Internal error");
496  return -1;
497  }
498 
499  list_data.id_text = ast_str_create(128);
500  if (!list_data.id_text) {
501  ao2_ref(bridges, -1);
502  astman_send_error(s, m, "Internal error");
503  return -1;
504  }
505 
506  if (!ast_strlen_zero(id)) {
507  ast_str_set(&list_data.id_text, 0, "ActionID: %s\r\n", id);
508  }
509  list_data.type_filter = type_filter;
510 
511  astman_send_listack(s, m, "Bridge listing will follow", "start");
512 
513  ao2_callback_data(bridges, OBJ_NODATA, send_bridge_list_item_cb, s, &list_data);
514 
515  astman_send_list_complete_start(s, m, "BridgeListComplete", list_data.count);
517 
518  ast_free(list_data.id_text);
519  ao2_ref(bridges, -1);
520 
521  return 0;
522 }
523 
524 static int send_bridge_info_item_cb(void *obj, void *arg, void *data, int flags)
525 {
526  char *uniqueid = obj;
527  struct mansession *s = arg;
528  struct bridge_list_data *list_data = data;
529  RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
530  RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
531 
532  snapshot = ast_channel_snapshot_get_latest(uniqueid);
533  if (!snapshot) {
534  return 0;
535  }
536 
537  if (snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL) {
538  return 0;
539  }
540 
541  channel_text = ast_manager_build_channel_state_string(snapshot);
542  if (!channel_text) {
543  return 0;
544  }
545 
546  astman_append(s,
547  "Event: BridgeInfoChannel\r\n"
548  "%s"
549  "%s"
550  "\r\n",
551  ast_str_buffer(list_data->id_text),
552  ast_str_buffer(channel_text));
553  ++list_data->count;
554  return 0;
555 }
556 
557 static int manager_bridge_info(struct mansession *s, const struct message *m)
558 {
559  const char *id = astman_get_header(m, "ActionID");
560  const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
561  RAII_VAR(struct ast_str *, bridge_info, NULL, ast_free);
562  RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
563  struct bridge_list_data list_data = { 0 };
564 
565  if (ast_strlen_zero(bridge_uniqueid)) {
566  astman_send_error(s, m, "BridgeUniqueid must be provided");
567  return 0;
568  }
569 
570  snapshot = ast_bridge_get_snapshot_by_uniqueid(bridge_uniqueid);
571  if (!snapshot) {
572  astman_send_error(s, m, "Specified BridgeUniqueid not found");
573  return 0;
574  }
575 
576  bridge_info = ast_manager_build_bridge_state_string(snapshot);
577  if (!bridge_info) {
578  astman_send_error(s, m, "Internal error");
579  return -1;
580  }
581 
582  list_data.id_text = ast_str_create(128);
583  if (!list_data.id_text) {
584  astman_send_error(s, m, "Internal error");
585  return -1;
586  }
587 
588  if (!ast_strlen_zero(id)) {
589  ast_str_set(&list_data.id_text, 0, "ActionID: %s\r\n", id);
590  }
591 
592  astman_send_listack(s, m, "Bridge channel listing will follow", "start");
593 
594  ao2_callback_data(snapshot->channels, OBJ_NODATA, send_bridge_info_item_cb, s, &list_data);
595 
596  astman_send_list_complete_start(s, m, "BridgeInfoComplete", list_data.count);
597  if (!ast_strlen_zero(ast_str_buffer(bridge_info))) {
598  astman_append(s, "%s", ast_str_buffer(bridge_info));
599  }
601  ast_free(list_data.id_text);
602 
603  return 0;
604 }
605 
606 static int manager_bridge_destroy(struct mansession *s, const struct message *m)
607 {
608  const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
609  struct ast_bridge *bridge;
610 
611  if (ast_strlen_zero(bridge_uniqueid)) {
612  astman_send_error(s, m, "BridgeUniqueid must be provided");
613  return 0;
614  }
615 
616  bridge = ast_bridge_find_by_id(bridge_uniqueid);
617  if (!bridge) {
618  astman_send_error(s, m, "Specified BridgeUniqueid not found");
619  return 0;
620  }
621  ast_bridge_destroy(bridge, 0);
622 
623  astman_send_ack(s, m, "Bridge has been destroyed");
624 
625  return 0;
626 }
627 
628 static int manager_bridge_kick(struct mansession *s, const struct message *m)
629 {
630  const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
631  const char *channel_name = astman_get_header(m, "Channel");
632  RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
633  RAII_VAR(struct ast_channel *, channel, NULL, ao2_cleanup);
634 
635  if (ast_strlen_zero(channel_name)) {
636  astman_send_error(s, m, "Channel must be provided");
637  return 0;
638  }
639 
640  channel = ast_channel_get_by_name(channel_name);
641  if (!channel) {
642  astman_send_error(s, m, "Channel does not exist");
643  return 0;
644  }
645 
646  if (ast_strlen_zero(bridge_uniqueid)) {
647  /* get the bridge from the channel */
648  ast_channel_lock(channel);
649  bridge = ast_channel_get_bridge(channel);
650  ast_channel_unlock(channel);
651  if (!bridge) {
652  astman_send_error(s, m, "Channel is not in a bridge");
653  return 0;
654  }
655  } else {
656  bridge = ast_bridge_find_by_id(bridge_uniqueid);
657  if (!bridge || ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
658  astman_send_error(s, m, "Bridge not found");
659  return 0;
660  }
661  }
662 
663  if (ast_bridge_kick(bridge, channel)) {
664  astman_send_error(s, m, "Channel kick from bridge failed");
665  return 0;
666  }
667 
668  astman_send_ack(s, m, "Channel has been kicked");
669  return 0;
670 }
671 
672 static void manager_bridging_cleanup(void)
673 {
674  stasis_forward_cancel(topic_forwarder);
675  topic_forwarder = NULL;
676 
677  ast_manager_unregister("BridgeList");
678  ast_manager_unregister("BridgeInfo");
679  ast_manager_unregister("BridgeDestroy");
680  ast_manager_unregister("BridgeKick");
681 }
682 
684 {
685  int ret = 0;
686  struct stasis_topic *manager_topic;
687  struct stasis_topic *bridge_topic;
688 
689  if (bridge_state_router) {
690  /* Already initialized */
691  return 0;
692  }
693 
694  ast_register_cleanup(manager_bridging_cleanup);
695 
696  manager_topic = ast_manager_get_topic();
697  if (!manager_topic) {
698  return -1;
699  }
700 
701  bridge_topic = ast_bridge_topic_all();
702  if (!bridge_topic) {
703  return -1;
704  }
705 
706  topic_forwarder = stasis_forward_all(bridge_topic, manager_topic);
707  if (!topic_forwarder) {
708  return -1;
709  }
710 
711  bridge_state_router = ast_manager_get_message_router();
712  if (!bridge_state_router) {
713  return -1;
714  }
715 
716  ret |= stasis_message_router_add(bridge_state_router,
717  ast_bridge_snapshot_type(), bridge_snapshot_update, NULL);
718 
719  ret |= stasis_message_router_add(bridge_state_router,
720  ast_bridge_merge_message_type(), bridge_merge_cb, NULL);
721 
722  ret |= stasis_message_router_add(bridge_state_router,
723  ast_channel_entered_bridge_type(), channel_enter_cb, NULL);
724 
725  ret |= stasis_message_router_add(bridge_state_router,
726  ast_channel_left_bridge_type(), channel_leave_cb, NULL);
727 
728  ret |= ast_manager_register_xml_core("BridgeList", 0, manager_bridges_list);
729  ret |= ast_manager_register_xml_core("BridgeInfo", 0, manager_bridge_info);
730  ret |= ast_manager_register_xml_core("BridgeDestroy", 0, manager_bridge_destroy);
731  ret |= ast_manager_register_xml_core("BridgeKick", 0, manager_bridge_kick);
732 
733  /* If somehow we failed to add any routes, just shut down the whole
734  * thing and fail it.
735  */
736  if (ret) {
737  manager_bridging_cleanup();
738  return -1;
739  }
740 
741  return 0;
742 }
Struct containing info for an AMI event to send out.
Definition: manager.h:502
Main Channel structure associated with a channel.
struct ao2_container * ast_bridges(void)
Returns the global bridges container.
Definition: bridge.c:174
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3310
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:971
Asterisk main include file. File version handling, generic pbx functions.
struct ast_flags feature_flags
Definition: bridge.h:369
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.
struct ast_channel_snapshot * channel
struct ast_bridge * ast_bridge_find_by_id(const char *bridge_id)
Find bridge by id.
Definition: bridge.c:5012
struct ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *uniqueid)
Returns the current snapshot for the bridge.
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3467
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
Structure that contains a snapshot of information about a bridge.
Definition: bridge.h:314
const ast_string_field video_source_id
Definition: bridge.h:328
int manager_bridging_init(void)
Initialize support for AMI channel events.
Structure representing a snapshot of channel state.
struct ast_json * blob
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
Definition: bridge.c:944
Definition: astman.c:222
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3421
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition: manager.c:1644
#define ast_manager_register_xml_core(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:202
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:10563
const ast_string_field creator
Definition: bridge.h:328
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3050
static struct ast_manager_event_blob * bridge_create(struct ast_bridge_snapshot *old_snapshot, struct ast_bridge_snapshot *new_snapshot)
Handle bridge creation.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
struct ast_bridge_snapshot * bridge
struct ast_bridge * ast_channel_get_bridge(const struct ast_channel *chan)
Get the bridge associated with a channel.
Definition: channel.c:10534
const ast_string_field technology
Definition: bridge.h:328
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3475
const char * ast_bridge_video_mode_to_string(enum ast_bridge_video_mode_type video_mode)
Converts an enum representation of a bridge video mode to string.
Definition: bridge.c:3951
struct ast_str * ast_manager_build_bridge_state_string(const struct ast_bridge_snapshot *snapshot)
Generate the AMI message body from a bridge snapshot.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1785
#define NO_EXTRA_FIELDS
Definition: manager.h:533
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
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.
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8057
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
struct ast_bridge_snapshot * ast_bridge_get_snapshot(struct ast_bridge *bridge)
Returns the current snapshot for the bridge.
Structure that contains information about a bridge.
Definition: bridge.h:349
Support for dynamic strings.
Definition: strings.h:623
const ast_string_field name
Definition: bridge.h:328
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
enum ast_bridge_video_mode_type video_mode
Definition: bridge.h:341
struct stasis_message_router * ast_manager_get_message_router(void)
Get the stasis_message_router for AMI.
Definition: manager.c:1885
static struct ao2_container * bridges
Definition: bridge.c:123
int ast_bridge_kick(struct ast_bridge *bridge, struct ast_channel *chan)
Kick a channel from a bridge.
Definition: bridge.c:1979
struct ast_manager_event_blob *(* bridge_snapshot_monitor)(struct ast_bridge_snapshot *old_snapshot, struct ast_bridge_snapshot *new_snapshot)
Typedef for callbacks that get called on channel snapshot updates.
const ast_string_field uniqueid
Definition: bridge.h:328
unsigned int num_channels
Definition: bridge.h:337
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1880
struct ast_bridge_snapshot * from
Message representing the merge of two bridges.
static struct ast_manager_event_blob * bridge_video_update(struct ast_bridge_snapshot *old_snapshot, struct ast_bridge_snapshot *new_snapshot)
Handle video source updates.
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...
static struct ast_manager_event_blob * bridge_destroy(struct ast_bridge_snapshot *old_snapshot, struct ast_bridge_snapshot *new_snapshot)
Handle bridge destruction.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
static struct stasis_message_router * bridge_state_router
Message router for cached bridge state snapshot updates.
Forwarding information.
Definition: stasis.c:1531
struct ast_str * ast_manager_build_bridge_state_string_prefix(const struct ast_bridge_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a bridge snapshot.
static struct stasis_forward * topic_forwarder
The Stasis Message Bus API subscription returned by the forwarding of the channel topic to the manage...
Generic container type.
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition: stasis.c:1578
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:253
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3389
const ast_string_field subclass
Definition: bridge.h:328
#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:941
struct ast_bridge_snapshot * to
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3431