Asterisk - The Open Source Telephony Project  21.4.1
stasis_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 Stasis Messages and Data Types for Bridge Objects
22  *
23  * \author Kinsey Moore <kmoore@digium.com>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 #include "asterisk/astobj2.h"
33 #include "asterisk/stasis.h"
35 #include "asterisk/channel.h"
36 #include "asterisk/stasis_bridges.h"
37 #include "asterisk/stasis_channels.h"
38 #include "asterisk/bridge.h"
40 
41 /* The container of channel snapshots in a bridge snapshot should always be
42  equivalent to a linked list; otherwise things (like CDRs) that depend on some
43  consistency in the ordering of channels in a bridge will break. */
44 #define SNAPSHOT_CHANNELS_BUCKETS 1
45 
46 /*** DOCUMENTATION
47  <managerEvent language="en_US" name="BlindTransfer">
48  <managerEventInstance class="EVENT_FLAG_CALL">
49  <synopsis>Raised when a blind transfer is complete.</synopsis>
50  <syntax>
51  <parameter name="Result">
52  <para>Indicates if the transfer was successful or if it failed.</para>
53  <enumlist>
54  <enum name="Fail"><para>An internal error occurred.</para></enum>
55  <enum name="Invalid"><para>Invalid configuration for transfer (e.g. Not bridged)</para></enum>
56  <enum name="Not Permitted"><para>Bridge does not permit transfers</para></enum>
57  <enum name="Success"><para>Transfer completed successfully</para></enum>
58  </enumlist>
59  <note><para>A result of <literal>Success</literal> does not necessarily mean that a target was succesfully
60  contacted. It means that a party was succesfully placed into the dialplan at the expected location.</para></note>
61  </parameter>
62  <channel_snapshot prefix="Transferer"/>
63  <channel_snapshot prefix="Transferee"/>
64  <bridge_snapshot/>
65  <parameter name="IsExternal">
66  <para>Indicates if the transfer was performed outside of Asterisk. For instance,
67  a channel protocol native transfer is external. A DTMF transfer is internal.</para>
68  <enumlist>
69  <enum name="Yes" />
70  <enum name="No" />
71  </enumlist>
72  </parameter>
73  <parameter name="Context">
74  <para>Destination context for the blind transfer.</para>
75  </parameter>
76  <parameter name="Extension">
77  <para>Destination extension for the blind transfer.</para>
78  </parameter>
79  </syntax>
80  <see-also>
81  <ref type="manager">BlindTransfer</ref>
82  </see-also>
83  </managerEventInstance>
84  </managerEvent>
85  <managerEvent language="en_US" name="AttendedTransfer">
86  <managerEventInstance class="EVENT_FLAG_CALL">
87  <synopsis>Raised when an attended transfer is complete.</synopsis>
88  <syntax>
89  <xi:include xpointer="xpointer(docs/managerEvent[@name='BlindTransfer']/managerEventInstance/syntax/parameter[@name='Result'])" />
90  <channel_snapshot prefix="OrigTransferer"/>
91  <bridge_snapshot prefix="Orig"/>
92  <channel_snapshot prefix="SecondTransferer"/>
93  <bridge_snapshot prefix="Second"/>
94  <parameter name="DestType">
95  <para>Indicates the method by which the attended transfer completed.</para>
96  <enumlist>
97  <enum name="Bridge"><para>The transfer was accomplished by merging two bridges into one.</para></enum>
98  <enum name="App"><para>The transfer was accomplished by having a channel or bridge run a dialplan application.</para></enum>
99  <enum name="Link"><para>The transfer was accomplished by linking two bridges together using a local channel pair.</para></enum>
100  <enum name="Threeway"><para>The transfer was accomplished by placing all parties into a threeway call.</para></enum>
101  <enum name="Fail"><para>The transfer failed.</para></enum>
102  </enumlist>
103  </parameter>
104  <parameter name="DestBridgeUniqueid">
105  <para>Indicates the surviving bridge when bridges were merged to complete the transfer</para>
106  <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Bridge</literal> or <literal>Threeway</literal></para></note>
107  </parameter>
108  <parameter name="DestApp">
109  <para>Indicates the application that is running when the transfer completes</para>
110  <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>App</literal></para></note>
111  </parameter>
112  <channel_snapshot prefix="LocalOne"/>
113  <channel_snapshot prefix="LocalTwo"/>
114  <parameter name="DestTransfererChannel">
115  <para>The name of the surviving transferer channel when a transfer results in a threeway call</para>
116  <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Threeway</literal></para></note>
117  </parameter>
118  <channel_snapshot prefix="Transferee" />
119  </syntax>
120  <description>
121  <para>The headers in this event attempt to describe all the major details of the attended transfer. The two transferer channels
122  and the two bridges are determined based on their chronological establishment. So consider that Alice calls Bob, and then Alice
123  transfers the call to Voicemail. The transferer and bridge headers would be arranged as follows:</para>
124  <para> <replaceable>OrigTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
125  <para> <replaceable>OrigBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
126  <para> <replaceable>SecondTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
127  <para> <replaceable>SecondBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
128  <para>Now consider if the order were reversed; instead of having Alice call Bob and transfer him to Voicemail, Alice instead
129  calls her Voicemail and transfers that to Bob. The transferer and bridge headers would be arranged as follows:</para>
130  <para> <replaceable>OrigTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
131  <para> <replaceable>OrigBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
132  <para> <replaceable>SecondTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
133  <para> <replaceable>SecondBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
134  </description>
135  <see-also>
136  <ref type="manager">AtxFer</ref>
137  </see-also>
138  </managerEventInstance>
139  </managerEvent>
140  ***/
141 
142 static struct ast_json *attended_transfer_to_json(struct stasis_message *msg,
143  const struct stasis_message_sanitizer *sanitize);
144 static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_message *message);
145 static struct ast_json *blind_transfer_to_json(struct stasis_message *msg,
146  const struct stasis_message_sanitizer *sanitize);
147 static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *message);
148 static struct ast_json *ast_channel_entered_bridge_to_json(
149  struct stasis_message *msg,
150  const struct stasis_message_sanitizer *sanitize);
151 static struct ast_json *ast_channel_left_bridge_to_json(
152  struct stasis_message *msg,
153  const struct stasis_message_sanitizer *sanitize);
154 static struct ast_json *ast_bridge_merge_message_to_json(
155  struct stasis_message *msg,
156  const struct stasis_message_sanitizer *sanitize);
157 
158 static struct stasis_topic *bridge_topic_all;
159 static struct stasis_topic_pool *bridge_topic_pool;
160 
161 /*!
162  * @{ \brief Define bridge message types.
163  */
164 STASIS_MESSAGE_TYPE_DEFN(ast_bridge_snapshot_type);
165 STASIS_MESSAGE_TYPE_DEFN(ast_bridge_merge_message_type,
166  .to_json = ast_bridge_merge_message_to_json);
167 STASIS_MESSAGE_TYPE_DEFN(ast_channel_entered_bridge_type,
168  .to_json = ast_channel_entered_bridge_to_json);
169 STASIS_MESSAGE_TYPE_DEFN(ast_channel_left_bridge_type,
170  .to_json = ast_channel_left_bridge_to_json);
171 STASIS_MESSAGE_TYPE_DEFN(ast_blind_transfer_type,
172  .to_json = blind_transfer_to_json,
173  .to_ami = blind_transfer_to_ami);
174 STASIS_MESSAGE_TYPE_DEFN(ast_attended_transfer_type,
175  .to_json = attended_transfer_to_json,
176  .to_ami = attended_transfer_to_ami);
177 /*! @} */
178 
180 {
181  return bridge_topic_all;
182 }
183 
184 struct stasis_topic *ast_bridge_topic(struct ast_bridge *bridge)
185 {
186  if (!bridge) {
187  return ast_bridge_topic_all();
188  }
189 
190  return bridge->topic;
191 }
192 
193 /*! \brief Destructor for bridge snapshots */
194 static void bridge_snapshot_dtor(void *obj)
195 {
196  struct ast_bridge_snapshot *snapshot = obj;
198  ao2_cleanup(snapshot->channels);
199  snapshot->channels = NULL;
200 }
201 
203 {
204  struct ast_bridge_snapshot *snapshot;
205  struct ast_bridge_channel *bridge_channel;
206 
207  if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
208  return NULL;
209  }
210 
211  snapshot = ao2_alloc_options(sizeof(*snapshot), bridge_snapshot_dtor,
213  if (!snapshot) {
214  return NULL;
215  }
216 
217  if (ast_string_field_init(snapshot, 128)) {
218  ao2_ref(snapshot, -1);
219 
220  return NULL;
221  }
222 
223  snapshot->channels = ast_str_container_alloc(SNAPSHOT_CHANNELS_BUCKETS);
224  if (!snapshot->channels) {
225  ao2_ref(snapshot, -1);
226 
227  return NULL;
228  }
229 
230  AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
231  if (ast_str_container_add(snapshot->channels,
232  ast_channel_uniqueid(bridge_channel->chan))) {
233  ao2_ref(snapshot, -1);
234 
235  return NULL;
236  }
237  }
238 
239  ast_string_field_set(snapshot, uniqueid, bridge->uniqueid);
240  ast_string_field_set(snapshot, technology, bridge->technology->name);
241  ast_string_field_set(snapshot, subclass, bridge->v_table->name);
242  ast_string_field_set(snapshot, creator, bridge->creator);
243  ast_string_field_set(snapshot, name, bridge->name);
244 
245  snapshot->feature_flags = bridge->feature_flags;
246  snapshot->capabilities = bridge->technology->capabilities;
247  snapshot->num_channels = bridge->num_channels;
248  snapshot->num_active = bridge->num_active;
249  snapshot->creationtime = bridge->creationtime;
250  snapshot->video_mode = bridge->softmix.video_mode.mode;
252  && bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc) {
253  ast_string_field_set(snapshot, video_source_id,
254  ast_channel_uniqueid(bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc));
255  } else if (snapshot->video_mode == AST_BRIDGE_VIDEO_MODE_TALKER_SRC
256  && bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc) {
257  ast_string_field_set(snapshot, video_source_id,
258  ast_channel_uniqueid(bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc));
259  }
260 
261  return snapshot;
262 }
263 
264 static void bridge_snapshot_update_dtor(void *obj)
265 {
266  struct ast_bridge_snapshot_update *update = obj;
267 
268  ast_debug(3, "Update: %p Old: %s New: %s\n", update,
269  update->old_snapshot ? update->old_snapshot->uniqueid : "<none>",
270  update->new_snapshot ? update->new_snapshot->uniqueid : "<none>");
271  ao2_cleanup(update->old_snapshot);
272  ao2_cleanup(update->new_snapshot);
273 }
274 
275 static struct ast_bridge_snapshot_update *bridge_snapshot_update_create(
276  struct ast_bridge_snapshot *old, struct ast_bridge_snapshot *new)
277 {
278  struct ast_bridge_snapshot_update *update;
279 
280  update = ao2_alloc_options(sizeof(*update), bridge_snapshot_update_dtor,
282  if (!update) {
283  return NULL;
284  }
285  update->old_snapshot = ao2_bump(old);
286  update->new_snapshot = ao2_bump(new);
287 
288  ast_debug(3, "Update: %p Old: %s New: %s\n", update,
289  update->old_snapshot ? update->old_snapshot->uniqueid : "<none>",
290  update->new_snapshot ? update->new_snapshot->uniqueid : "<none>");
291 
292  return update;
293 }
294 
295 int bridge_topics_init(struct ast_bridge *bridge)
296 {
297  char *topic_name;
298  int ret;
299 
300  if (ast_strlen_zero(bridge->uniqueid)) {
301  ast_log(LOG_ERROR, "Bridge id initialization required\n");
302  return -1;
303  }
304 
305  ret = ast_asprintf(&topic_name, "bridge:%s", bridge->uniqueid);
306  if (ret < 0) {
307  return -1;
308  }
309 
310  bridge->topic = stasis_topic_pool_get_topic(bridge_topic_pool, topic_name);
311  ast_free(topic_name);
312  if (!bridge->topic) {
313  return -1;
314  }
315 
316  return 0;
317 }
318 
319 void bridge_topics_destroy(struct ast_bridge *bridge)
320 {
321  struct ast_bridge_snapshot_update *update;
322  struct stasis_message *msg;
323 
324  ast_assert(bridge != NULL);
325 
326  if (!bridge->current_snapshot) {
328  if (!bridge->current_snapshot) {
329  return;
330  }
331  }
332 
333  update = bridge_snapshot_update_create(bridge->current_snapshot, NULL);
334  if (!update) {
335  return;
336  }
337 
338  msg = stasis_message_create(ast_bridge_snapshot_type(), update);
339  ao2_ref(update, -1);
340  if (!msg) {
341  return;
342  }
343 
344  stasis_publish(ast_bridge_topic(bridge), msg);
345  ao2_ref(msg, -1);
346 
348 }
349 
351 {
352  struct ast_bridge_snapshot *new_snapshot;
353  struct ast_bridge_snapshot_update *update;
354  struct stasis_message *msg;
355 
356  ast_assert(bridge != NULL);
357 
358  new_snapshot = ast_bridge_snapshot_create(bridge);
359  if (!new_snapshot) {
360  return;
361  }
362 
363  update = bridge_snapshot_update_create(bridge->current_snapshot, new_snapshot);
364  /* There may not have been an old snapshot */
365  ao2_cleanup(bridge->current_snapshot);
366  bridge->current_snapshot = new_snapshot;
367  if (!update) {
368  return;
369  }
370 
371  msg = stasis_message_create(ast_bridge_snapshot_type(), update);
372  ao2_ref(update, -1);
373  if (!msg) {
374  return;
375  }
376 
377  stasis_publish(ast_bridge_topic(bridge), msg);
378  ao2_ref(msg, -1);
379 }
380 
381 static void bridge_publish_state_from_blob(struct ast_bridge *bridge,
382  struct ast_bridge_blob *obj)
383 {
384  struct ast_bridge_snapshot_update *update;
385  struct stasis_message *msg;
386 
387  ast_assert(obj != NULL);
388 
389  update = bridge_snapshot_update_create(bridge->current_snapshot, obj->bridge);
390  ao2_cleanup(bridge->current_snapshot);
391  bridge->current_snapshot = ao2_bump(obj->bridge);
392  if (!update) {
393  return;
394  }
395 
396  msg = stasis_message_create(ast_bridge_snapshot_type(), update);
397  ao2_ref(update, -1);
398  if (!msg) {
399  return;
400  }
401 
402  stasis_publish(ast_bridge_topic(bridge), msg);
403  ao2_ref(msg, -1);
404 }
405 
406 /*! \brief Destructor for bridge merge messages */
407 static void bridge_merge_message_dtor(void *obj)
408 {
409  struct ast_bridge_merge_message *msg = obj;
410 
411  ao2_cleanup(msg->to);
412  msg->to = NULL;
413  ao2_cleanup(msg->from);
414  msg->from = NULL;
415 }
416 
417 /*! \brief Bridge merge message creation helper */
419 {
420  struct ast_bridge_merge_message *msg;
421 
422  msg = ao2_alloc(sizeof(*msg), bridge_merge_message_dtor);
423  if (!msg) {
424  return NULL;
425  }
426 
427  msg->to = ast_bridge_snapshot_create(to);
428  msg->from = ast_bridge_snapshot_create(from);
429  if (!msg->to || !msg->from) {
430  ao2_ref(msg, -1);
431 
432  return NULL;
433  }
434 
435  return msg;
436 }
437 
438 static struct ast_json *ast_bridge_merge_message_to_json(
439  struct stasis_message *msg,
440  const struct stasis_message_sanitizer *sanitize)
441 {
442  struct ast_bridge_merge_message *merge = stasis_message_data(msg);
443  struct ast_json *json_bridge_to = ast_bridge_snapshot_to_json(merge->to, sanitize);
444  struct ast_json *json_bridge_from = ast_bridge_snapshot_to_json(merge->from, sanitize);
445 
446  if (!json_bridge_to || !json_bridge_from) {
447  ast_json_unref(json_bridge_to);
448  ast_json_unref(json_bridge_from);
449 
450  return NULL;
451  }
452 
453  return ast_json_pack("{s: s, s: o, s: o, s: o}",
454  "type", "BridgeMerged",
455  "timestamp", ast_json_timeval(*stasis_message_timestamp(msg), NULL),
456  "bridge", json_bridge_to,
457  "bridge_from", json_bridge_from);
458 }
459 
460 void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
461 {
462  struct ast_bridge_merge_message *merge_msg;
463  struct stasis_message *msg;
464 
465  if (!ast_bridge_merge_message_type()) {
466  return;
467  }
468 
469  ast_assert(to != NULL);
470  ast_assert(from != NULL);
471  ast_assert(ast_test_flag(&to->feature_flags, AST_BRIDGE_FLAG_INVISIBLE) == 0);
472  ast_assert(ast_test_flag(&from->feature_flags, AST_BRIDGE_FLAG_INVISIBLE) == 0);
473 
474  merge_msg = bridge_merge_message_create(to, from);
475  if (!merge_msg) {
476  return;
477  }
478 
479  msg = stasis_message_create(ast_bridge_merge_message_type(), merge_msg);
480  ao2_ref(merge_msg, -1);
481  if (!msg) {
482  return;
483  }
484 
486  ao2_ref(msg, -1);
487 }
488 
489 static void bridge_blob_dtor(void *obj)
490 {
491  struct ast_bridge_blob *event = obj;
492  ao2_cleanup(event->bridge);
493  event->bridge = NULL;
494  ao2_cleanup(event->channel);
495  event->channel = NULL;
496  ast_json_unref(event->blob);
497  event->blob = NULL;
498 }
499 
501  struct stasis_message_type *message_type,
502  struct ast_bridge *bridge,
503  struct ast_channel *chan,
504  struct ast_json *blob)
505 {
506  struct ast_bridge_blob *obj;
507  struct stasis_message *msg;
508 
509  if (!message_type) {
510  return NULL;
511  }
512 
513  obj = ao2_alloc(sizeof(*obj), bridge_blob_dtor);
514  if (!obj) {
515  return NULL;
516  }
517 
518  if (bridge) {
519  obj->bridge = ast_bridge_snapshot_create(bridge);
520  if (obj->bridge == NULL) {
521  ao2_ref(obj, -1);
522 
523  return NULL;
524  }
525  }
526 
527  if (chan) {
528  obj->channel = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
529  if (obj->channel == NULL) {
530  ao2_ref(obj, -1);
531 
532  return NULL;
533  }
534  }
535 
536  if (blob) {
537  obj->blob = ast_json_ref(blob);
538  }
539 
540  msg = stasis_message_create(message_type, obj);
541  ao2_ref(obj, -1);
542 
543  return msg;
544 }
545 
547  struct stasis_message_type *message_type,
548  struct ast_bridge_snapshot *bridge_snapshot,
549  struct ast_channel_snapshot *chan_snapshot,
550  struct ast_json *blob)
551 {
552  struct ast_bridge_blob *obj;
553  struct stasis_message *msg;
554 
555  if (!message_type) {
556  return NULL;
557  }
558 
559  obj = ao2_alloc(sizeof(*obj), bridge_blob_dtor);
560  if (!obj) {
561  return NULL;
562  }
563 
564  if (bridge_snapshot) {
565  obj->bridge = ao2_bump(bridge_snapshot);
566  }
567 
568  if (chan_snapshot) {
569  obj->channel = ao2_bump(chan_snapshot);
570  }
571 
572  if (blob) {
573  obj->blob = ast_json_ref(blob);
574  }
575 
576  msg = stasis_message_create(message_type, obj);
577  ao2_ref(obj, -1);
578 
579  return msg;
580 }
581 
582 void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan,
583  struct ast_channel *swap)
584 {
585  struct stasis_message *msg;
586  struct ast_json *blob = NULL;
587 
588  if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
589  return;
590  }
591 
592  if (swap) {
593  blob = ast_json_pack("{s: s}", "swap", ast_channel_uniqueid(swap));
594  if (!blob) {
595  return;
596  }
597  }
598 
599  msg = ast_bridge_blob_create(ast_channel_entered_bridge_type(), bridge, chan, blob);
600  ast_json_unref(blob);
601  if (!msg) {
602  return;
603  }
604 
605  /* enter blob first, then state */
606  stasis_publish(ast_bridge_topic(bridge), msg);
607  bridge_publish_state_from_blob(bridge, stasis_message_data(msg));
608  ao2_ref(msg, -1);
609 }
610 
611 void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *chan)
612 {
613  struct stasis_message *msg;
614 
615  if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
616  return;
617  }
618  msg = ast_bridge_blob_create(ast_channel_left_bridge_type(), bridge, chan, NULL);
619  if (!msg) {
620  return;
621  }
622 
623  /* state first, then leave blob (opposite of enter, preserves nesting of events) */
624  bridge_publish_state_from_blob(bridge, stasis_message_data(msg));
625  stasis_publish(ast_bridge_topic(bridge), msg);
626  ao2_ref(msg, -1);
627 }
628 
629 static struct ast_json *simple_bridge_channel_event(
630  const char *type,
631  struct ast_bridge_snapshot *bridge_snapshot,
632  struct ast_channel_snapshot *channel_snapshot,
633  const struct timeval *tv,
634  const struct stasis_message_sanitizer *sanitize)
635 {
636  struct ast_json *json_bridge = ast_bridge_snapshot_to_json(bridge_snapshot, sanitize);
637  struct ast_json *json_channel = ast_channel_snapshot_to_json(channel_snapshot, sanitize);
638 
639  if (!json_bridge || !json_channel) {
640  ast_json_unref(json_bridge);
641  ast_json_unref(json_channel);
642 
643  return NULL;
644  }
645 
646  return ast_json_pack("{s: s, s: o, s: o, s: o}",
647  "type", type,
648  "timestamp", ast_json_timeval(*tv, NULL),
649  "bridge", json_bridge,
650  "channel", json_channel);
651 }
652 
653 struct ast_json *ast_channel_entered_bridge_to_json(
654  struct stasis_message *msg,
655  const struct stasis_message_sanitizer *sanitize)
656 {
657  struct ast_bridge_blob *obj = stasis_message_data(msg);
658 
659  return simple_bridge_channel_event("ChannelEnteredBridge", obj->bridge,
660  obj->channel, stasis_message_timestamp(msg), sanitize);
661 }
662 
663 struct ast_json *ast_channel_left_bridge_to_json(
664  struct stasis_message *msg,
665  const struct stasis_message_sanitizer *sanitize)
666 {
667  struct ast_bridge_blob *obj = stasis_message_data(msg);
668 
669  return simple_bridge_channel_event("ChannelLeftBridge", obj->bridge,
670  obj->channel, stasis_message_timestamp(msg), sanitize);
671 }
672 
673 static struct ast_json *container_to_json_array(struct ao2_container *items,
674  const struct stasis_message_sanitizer *sanitize)
675 {
676  struct ast_json *json_items = ast_json_array_create();
677  char *item;
678  struct ao2_iterator it;
679 
680  if (!json_items) {
681  return NULL;
682  }
683 
684  for (it = ao2_iterator_init(items, 0);
685  (item = ao2_iterator_next(&it)); ao2_cleanup(item)) {
686  if (sanitize && sanitize->channel_id && sanitize->channel_id(item)) {
687  continue;
688  }
689 
690  if (ast_json_array_append(json_items, ast_json_string_create(item))) {
691  ao2_cleanup(item);
693  ast_json_unref(json_items);
694 
695  return NULL;
696  }
697  }
699 
700  return json_items;
701 }
702 
703 static const char *capability2str(uint32_t capabilities)
704 {
705  if (capabilities & AST_BRIDGE_CAPABILITY_HOLDING) {
706  return "holding";
707  } else {
708  return "mixing";
709  }
710 }
711 
713  const struct ast_bridge_snapshot *snapshot,
714  const struct stasis_message_sanitizer *sanitize)
715 {
716  struct ast_json *json_bridge;
717  struct ast_json *json_channels;
718 
719  if (snapshot == NULL) {
720  return NULL;
721  }
722 
723  json_channels = container_to_json_array(snapshot->channels, sanitize);
724  if (!json_channels) {
725  return NULL;
726  }
727 
728  json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: o, s: o, s: s}",
729  "id", snapshot->uniqueid,
730  "technology", snapshot->technology,
731  "bridge_type", capability2str(snapshot->capabilities),
732  "bridge_class", snapshot->subclass,
733  "creator", snapshot->creator,
734  "name", snapshot->name,
735  "channels", json_channels,
736  "creationtime", ast_json_timeval(snapshot->creationtime, NULL),
737  "video_mode", ast_bridge_video_mode_to_string(snapshot->video_mode));
738  if (!json_bridge) {
739  return NULL;
740  }
741 
742  if (snapshot->video_mode != AST_BRIDGE_VIDEO_MODE_NONE
743  && !ast_strlen_zero(snapshot->video_source_id)) {
744  ast_json_object_set(json_bridge, "video_source_id",
746  }
747 
748  return json_bridge;
749 }
750 
751 /*!
752  * \internal
753  * \brief Allocate the fields of an \ref ast_bridge_channel_snapshot_pair.
754  *
755  * \param channel, bridge A bridge and channel to get snapshots of
756  * \param[out] snapshot_pair An allocated snapshot pair.
757  * \retval 0 Success
758  * \retval non-zero Failure
759  */
760 static int bridge_channel_snapshot_pair_init(struct ast_channel *channel, struct ast_bridge *bridge,
761  struct ast_bridge_channel_snapshot_pair *snapshot_pair)
762 {
763  if (bridge) {
764  ast_bridge_lock(bridge);
765  snapshot_pair->bridge_snapshot = ast_bridge_snapshot_create(bridge);
766  ast_bridge_unlock(bridge);
767  if (!snapshot_pair->bridge_snapshot) {
768  return -1;
769  }
770  }
771 
772  snapshot_pair->channel_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(channel));
773  if (!snapshot_pair->channel_snapshot) {
774  return -1;
775  }
776 
777  return 0;
778 }
779 
780 /*!
781  * \internal
782  * \brief Free the fields of an \ref ast_bridge_channel_snapshot_pair.
783  *
784  * \param pair The snapshot pair whose fields are to be cleaned up
785  */
786 static void bridge_channel_snapshot_pair_cleanup(struct ast_bridge_channel_snapshot_pair *pair)
787 {
788  ao2_cleanup(pair->bridge_snapshot);
789  ao2_cleanup(pair->channel_snapshot);
790 }
791 
792 static const char *result_strs[] = {
793  [AST_BRIDGE_TRANSFER_FAIL] = "Fail",
794  [AST_BRIDGE_TRANSFER_INVALID] = "Invalid",
795  [AST_BRIDGE_TRANSFER_NOT_PERMITTED] = "Not Permitted",
796  [AST_BRIDGE_TRANSFER_SUCCESS] = "Success",
797 };
798 
799 static struct ast_json *blind_transfer_to_json(struct stasis_message *msg,
800  const struct stasis_message_sanitizer *sanitize)
801 {
802  struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
803  struct ast_json *json_transferer;
804  struct ast_json *json_transferee = NULL;
805  struct ast_json *out;
806  struct ast_json *json_replace = NULL;
807  const struct timeval *tv = stasis_message_timestamp(msg);
808 
809  json_transferer = ast_channel_snapshot_to_json(transfer_msg->transferer, sanitize);
810  if (!json_transferer) {
811  return NULL;
812  }
813 
814  if (transfer_msg->transferee) {
815  json_transferee = ast_channel_snapshot_to_json(transfer_msg->transferee, sanitize);
816  if (!json_transferee) {
817  ast_json_unref(json_transferer);
818  return NULL;
819  }
820  }
821 
822  if (transfer_msg->replace_channel) {
823  json_replace = ast_channel_snapshot_to_json(transfer_msg->replace_channel, sanitize);
824  if (!json_replace) {
825  ast_json_unref(json_transferee);
826  ast_json_unref(json_transferer);
827  return NULL;
828  }
829  }
830 
831  out = ast_json_pack("{s: s, s: o, s: o, s: s, s: s, s: s, s: o}",
832  "type", "BridgeBlindTransfer",
833  "timestamp", ast_json_timeval(*tv, NULL),
834  "channel", json_transferer,
835  "exten", transfer_msg->exten,
836  "context", transfer_msg->context,
837  "result", result_strs[transfer_msg->result],
838  "is_external", ast_json_boolean(transfer_msg->is_external));
839 
840  if (!out) {
841  ast_json_unref(json_transferee);
842  ast_json_unref(json_replace);
843  return NULL;
844  }
845 
846  if (json_transferee && ast_json_object_set(out, "transferee", json_transferee)) {
847  ast_json_unref(out);
848  ast_json_unref(json_replace);
849  return NULL;
850  }
851 
852  if (json_replace && ast_json_object_set(out, "replace_channel", json_replace)) {
853  ast_json_unref(out);
854  return NULL;
855  }
856 
857  if (transfer_msg->bridge) {
858  struct ast_json *json_bridge = ast_bridge_snapshot_to_json(
859  transfer_msg->bridge, sanitize);
860 
861  if (!json_bridge || ast_json_object_set(out, "bridge", json_bridge)) {
862  ast_json_unref(out);
863  return NULL;
864  }
865  }
866 
867  return out;
868 }
869 
870 static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *msg)
871 {
872  RAII_VAR(struct ast_str *, transferer_state, NULL, ast_free_ptr);
873  RAII_VAR(struct ast_str *, bridge_state, NULL, ast_free_ptr);
874  RAII_VAR(struct ast_str *, transferee_state, NULL, ast_free_ptr);
875  struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
876 
877  if (!transfer_msg) {
878  return NULL;
879  }
880 
882  transfer_msg->transferer, "Transferer");
883  if (!transferer_state) {
884  return NULL;
885  }
886 
887  if (transfer_msg->bridge) {
888  bridge_state = ast_manager_build_bridge_state_string(transfer_msg->bridge);
889  if (!bridge_state) {
890  return NULL;
891  }
892  }
893 
894  if (transfer_msg->transferee) {
896  transfer_msg->transferee, "Transferee");
897  if (!transferee_state) {
898  return NULL;
899  }
900  }
901 
902  return ast_manager_event_blob_create(EVENT_FLAG_CALL, "BlindTransfer",
903  "Result: %s\r\n"
904  "%s"
905  "%s"
906  "%s"
907  "IsExternal: %s\r\n"
908  "Context: %s\r\n"
909  "Extension: %s\r\n",
910  result_strs[transfer_msg->result],
911  ast_str_buffer(transferer_state),
912  transferee_state ? ast_str_buffer(transferee_state) : "",
913  bridge_state ? ast_str_buffer(bridge_state) : "",
914  transfer_msg->is_external ? "Yes" : "No",
915  transfer_msg->context,
916  transfer_msg->exten);
917 }
918 
919 static void blind_transfer_dtor(void *obj)
920 {
921  struct ast_blind_transfer_message *msg = obj;
922 
923  ao2_cleanup(msg->transferer);
924  ao2_cleanup(msg->bridge);
925  ao2_cleanup(msg->transferee);
926  ao2_cleanup(msg->replace_channel);
927 }
928 
930  struct ast_channel *transferer, const char *exten, const char *context)
931 {
932  struct ast_blind_transfer_message *msg;
933 
934  msg = ao2_alloc(sizeof(*msg), blind_transfer_dtor);
935  if (!msg) {
936  return NULL;
937  }
938 
939  msg->transferer = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferer));
940  if (!msg->transferer) {
941  ao2_cleanup(msg);
942  return NULL;
943  }
944 
945  msg->is_external = is_external;
946  ast_copy_string(msg->context, context, sizeof(msg->context));
947  ast_copy_string(msg->exten, exten, sizeof(msg->exten));
948 
949  return msg;
950 }
951 
952 
954 {
955  struct stasis_message *stasis;
956 
957  stasis = stasis_message_create(ast_blind_transfer_type(), transfer_message);
958  if (!stasis) {
959  return;
960  }
961 
963 
964  ao2_cleanup(stasis);
965 }
966 
967 static struct ast_json *attended_transfer_to_json(struct stasis_message *msg,
968  const struct stasis_message_sanitizer *sanitize)
969 {
970  struct ast_attended_transfer_message *transfer_msg = stasis_message_data(msg);
971  RAII_VAR(struct ast_json *, out, NULL, ast_json_unref);
972  struct ast_json *json_transferer1, *json_transferer2, *json_bridge, *json_channel;
973  struct ast_json *json_transferee = NULL, *json_target = NULL;
974  const struct timeval *tv = stasis_message_timestamp(msg);
975  int res = 0;
976 
977  json_transferer1 = ast_channel_snapshot_to_json(transfer_msg->to_transferee.channel_snapshot, sanitize);
978  if (!json_transferer1) {
979  return NULL;
980  }
981 
982  json_transferer2 = ast_channel_snapshot_to_json(transfer_msg->to_transfer_target.channel_snapshot, sanitize);
983  if (!json_transferer2) {
984  ast_json_unref(json_transferer1);
985  return NULL;
986  }
987 
988  if (transfer_msg->transferee) {
989  json_transferee = ast_channel_snapshot_to_json(transfer_msg->transferee, sanitize);
990  if (!json_transferee) {
991  ast_json_unref(json_transferer2);
992  ast_json_unref(json_transferer1);
993  return NULL;
994  }
995  }
996 
997  if (transfer_msg->target) {
998  json_target = ast_channel_snapshot_to_json(transfer_msg->target, sanitize);
999  if (!json_target) {
1000  ast_json_unref(json_transferee);
1001  ast_json_unref(json_transferer2);
1002  ast_json_unref(json_transferer1);
1003  return NULL;
1004  }
1005  }
1006 
1007  out = ast_json_pack("{s: s, s: o, s: o, s: o, s: s, s: o}",
1008  "type", "BridgeAttendedTransfer",
1009  "timestamp", ast_json_timeval(*tv, NULL),
1010  "transferer_first_leg", json_transferer1,
1011  "transferer_second_leg", json_transferer2,
1012  "result", result_strs[transfer_msg->result],
1013  "is_external", ast_json_boolean(transfer_msg->is_external));
1014  if (!out) {
1015  ast_json_unref(json_target);
1016  ast_json_unref(json_transferee);
1017  return NULL;
1018  }
1019  if (json_transferee && ast_json_object_set(out, "transferee", json_transferee)) {
1020  ast_json_unref(json_target);
1021  return NULL;
1022  }
1023  if (json_target && ast_json_object_set(out, "transfer_target", json_target)) {
1024  return NULL;
1025  }
1026 
1027  if (transfer_msg->to_transferee.bridge_snapshot) {
1028  json_bridge = ast_bridge_snapshot_to_json(transfer_msg->to_transferee.bridge_snapshot, sanitize);
1029 
1030  if (!json_bridge) {
1031  return NULL;
1032  }
1033 
1034  res |= ast_json_object_set(out, "transferer_first_leg_bridge", json_bridge);
1035  }
1036 
1037  if (transfer_msg->to_transfer_target.bridge_snapshot) {
1038  json_bridge = ast_bridge_snapshot_to_json(transfer_msg->to_transfer_target.bridge_snapshot, sanitize);
1039 
1040  if (!json_bridge) {
1041  return NULL;
1042  }
1043 
1044  res |= ast_json_object_set(out, "transferer_second_leg_bridge", json_bridge);
1045  }
1046 
1047  switch (transfer_msg->dest_type) {
1048  case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
1049  res |= ast_json_object_set(out, "destination_type", ast_json_string_create("bridge"));
1050  res |= ast_json_object_set(out, "destination_bridge", ast_json_string_create(transfer_msg->dest.bridge));
1051  break;
1052  case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
1053  res |= ast_json_object_set(out, "replace_channel", ast_channel_snapshot_to_json(transfer_msg->replace_channel, sanitize));
1054  /* fallthrough */
1055  case AST_ATTENDED_TRANSFER_DEST_APP:
1056  res |= ast_json_object_set(out, "destination_type", ast_json_string_create("application"));
1057  res |= ast_json_object_set(out, "destination_application", ast_json_string_create(transfer_msg->dest.app));
1058  break;
1059  case AST_ATTENDED_TRANSFER_DEST_LINK:
1060  res |= ast_json_object_set(out, "destination_type", ast_json_string_create("link"));
1061 
1062  json_channel = ast_channel_snapshot_to_json(transfer_msg->dest.links[0], sanitize);
1063  if (!json_channel) {
1064  return NULL;
1065  }
1066  res |= ast_json_object_set(out, "destination_link_first_leg", json_channel);
1067 
1068  json_channel = ast_channel_snapshot_to_json(transfer_msg->dest.links[1], sanitize);
1069  if (!json_channel) {
1070  return NULL;
1071  }
1072  res |= ast_json_object_set(out, "destination_link_second_leg", json_channel);
1073 
1074  break;
1075  case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
1076  res |= ast_json_object_set(out, "destination_type", ast_json_string_create("threeway"));
1077 
1078  json_channel = ast_channel_snapshot_to_json(transfer_msg->dest.threeway.channel_snapshot, sanitize);
1079  if (!json_channel) {
1080  return NULL;
1081  }
1082  res |= ast_json_object_set(out, "destination_threeway_channel", json_channel);
1083 
1084  json_bridge = ast_bridge_snapshot_to_json(transfer_msg->dest.threeway.bridge_snapshot, sanitize);
1085  if (!json_bridge) {
1086  return NULL;
1087  }
1088  res |= ast_json_object_set(out, "destination_threeway_bridge", json_bridge);
1089 
1090  break;
1091  case AST_ATTENDED_TRANSFER_DEST_FAIL:
1092  res |= ast_json_object_set(out, "destination_type", ast_json_string_create("fail"));
1093  break;
1094  }
1095 
1096  if (res) {
1097  return NULL;
1098  }
1099 
1100  return ast_json_ref(out);
1101 }
1102 
1103 static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_message *msg)
1104 {
1105  RAII_VAR(struct ast_str *, variable_data, ast_str_create(64), ast_free_ptr);
1106  RAII_VAR(struct ast_str *, transferer1_state, NULL, ast_free_ptr);
1107  RAII_VAR(struct ast_str *, bridge1_state, NULL, ast_free_ptr);
1108  RAII_VAR(struct ast_str *, transferer2_state, NULL, ast_free_ptr);
1109  RAII_VAR(struct ast_str *, bridge2_state, NULL, ast_free_ptr);
1110  RAII_VAR(struct ast_str *, local1_state, NULL, ast_free_ptr);
1111  RAII_VAR(struct ast_str *, local2_state, NULL, ast_free_ptr);
1112  RAII_VAR(struct ast_str *, transferee_state, NULL, ast_free_ptr);
1113  RAII_VAR(struct ast_str *, target_state, NULL, ast_free_ptr);
1114  struct ast_attended_transfer_message *transfer_msg = stasis_message_data(msg);
1115 
1116  if (!variable_data) {
1117  return NULL;
1118  }
1119 
1120  transferer1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transferee.channel_snapshot, "OrigTransferer");
1121  transferer2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transfer_target.channel_snapshot, "SecondTransferer");
1122  if (!transferer1_state || !transferer2_state) {
1123  return NULL;
1124  }
1125  if (transfer_msg->transferee) {
1126  transferee_state = ast_manager_build_channel_state_string_prefix(transfer_msg->transferee, "Transferee");
1127  if (!transferee_state) {
1128  return NULL;
1129  }
1130  }
1131 
1132  if (transfer_msg->target) {
1133  target_state = ast_manager_build_channel_state_string_prefix(transfer_msg->target, "TransferTarget");
1134  if (!target_state) {
1135  return NULL;
1136  }
1137  }
1138 
1139  if (transfer_msg->to_transferee.bridge_snapshot) {
1141  transfer_msg->to_transferee.bridge_snapshot, "Orig");
1142  if (!bridge1_state) {
1143  return NULL;
1144  }
1145  }
1146 
1147  if (transfer_msg->to_transfer_target.bridge_snapshot) {
1149  transfer_msg->to_transfer_target.bridge_snapshot, "Second");
1150  if (!bridge2_state) {
1151  return NULL;
1152  }
1153  }
1154 
1155  switch (transfer_msg->dest_type) {
1156  case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
1157  ast_str_append(&variable_data, 0, "DestType: Bridge\r\n");
1158  ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.bridge);
1159  break;
1160  case AST_ATTENDED_TRANSFER_DEST_APP:
1161  case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
1162  ast_str_append(&variable_data, 0, "DestType: App\r\n");
1163  ast_str_append(&variable_data, 0, "DestApp: %s\r\n", transfer_msg->dest.app);
1164  break;
1165  case AST_ATTENDED_TRANSFER_DEST_LINK:
1166  local1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[0], "LocalOne");
1167  local2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[1], "LocalTwo");
1168  if (!local1_state || !local2_state) {
1169  return NULL;
1170  }
1171  ast_str_append(&variable_data, 0, "DestType: Link\r\n");
1172  ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local1_state));
1173  ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local2_state));
1174  break;
1175  case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
1176  ast_str_append(&variable_data, 0, "DestType: Threeway\r\n");
1177  ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.threeway.bridge_snapshot->uniqueid);
1178  ast_str_append(&variable_data, 0, "DestTransfererChannel: %s\r\n", transfer_msg->dest.threeway.channel_snapshot->base->name);
1179  break;
1180  case AST_ATTENDED_TRANSFER_DEST_FAIL:
1181  ast_str_append(&variable_data, 0, "DestType: Fail\r\n");
1182  break;
1183  }
1184 
1185  return ast_manager_event_blob_create(EVENT_FLAG_CALL, "AttendedTransfer",
1186  "Result: %s\r\n"
1187  "%s"
1188  "%s"
1189  "%s"
1190  "%s"
1191  "%s"
1192  "%s"
1193  "IsExternal: %s\r\n"
1194  "%s",
1195  result_strs[transfer_msg->result],
1196  ast_str_buffer(transferer1_state),
1197  bridge1_state ? ast_str_buffer(bridge1_state) : "",
1198  ast_str_buffer(transferer2_state),
1199  bridge2_state ? ast_str_buffer(bridge2_state) : "",
1200  transferee_state ? ast_str_buffer(transferee_state) : "",
1201  target_state ? ast_str_buffer(target_state) : "",
1202  transfer_msg->is_external ? "Yes" : "No",
1203  ast_str_buffer(variable_data));
1204 }
1205 
1206 static void attended_transfer_dtor(void *obj)
1207 {
1208  struct ast_attended_transfer_message *msg = obj;
1209  int i;
1210 
1211  bridge_channel_snapshot_pair_cleanup(&msg->to_transferee);
1212  bridge_channel_snapshot_pair_cleanup(&msg->to_transfer_target);
1213  ao2_cleanup(msg->replace_channel);
1214  ao2_cleanup(msg->transferee);
1215  ao2_cleanup(msg->target);
1216 
1217  if (msg->dest_type != AST_ATTENDED_TRANSFER_DEST_LINK) {
1218  return;
1219  }
1220 
1221  for (i = 0; i < ARRAY_LEN(msg->dest.links); ++i) {
1222  ao2_cleanup(msg->dest.links[i]);
1223  }
1224 }
1225 
1227  struct ast_channel *to_transferee, struct ast_bridge *transferee_bridge,
1228  struct ast_channel *to_transfer_target, struct ast_bridge *target_bridge,
1229  struct ast_channel *transferee, struct ast_channel *transfer_target)
1230 {
1231  struct ast_attended_transfer_message *transfer_msg;
1232 
1233  transfer_msg = ao2_alloc(sizeof(*transfer_msg), attended_transfer_dtor);
1234  if (!transfer_msg) {
1235  return NULL;
1236  }
1237 
1238  if (bridge_channel_snapshot_pair_init(to_transferee, transferee_bridge, &transfer_msg->to_transferee) ||
1239  bridge_channel_snapshot_pair_init(to_transfer_target, target_bridge, &transfer_msg->to_transfer_target)) {
1240  ao2_cleanup(transfer_msg);
1241  return NULL;
1242  }
1243 
1244  if (transferee) {
1245  transfer_msg->transferee = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferee));
1246  if (!transfer_msg->transferee) {
1247  ao2_cleanup(transfer_msg);
1248  return NULL;
1249  }
1250  } else if (transferee_bridge) {
1251  transferee = ast_bridge_peer(transferee_bridge, to_transferee);
1252  if (transferee) {
1253  transfer_msg->transferee = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferee));
1254  ao2_cleanup(transferee);
1255  if (!transfer_msg->transferee) {
1256  ao2_cleanup(transfer_msg);
1257  return NULL;
1258  }
1259  }
1260  }
1261 
1262  if (transfer_target) {
1263  transfer_msg->target = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transfer_target));
1264  if (!transfer_msg->target) {
1265  ao2_cleanup(transfer_msg);
1266  return NULL;
1267  }
1268  } else if (target_bridge) {
1269  transfer_target = ast_bridge_peer(target_bridge, to_transfer_target);
1270  if (transfer_target) {
1271  transfer_msg->target = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transfer_target));
1272  ao2_cleanup(transfer_target);
1273  if (!transfer_msg->target) {
1274  ao2_cleanup(transfer_msg);
1275  return NULL;
1276  }
1277  }
1278  }
1279 
1280  return transfer_msg;
1281 }
1282 
1284  struct ast_bridge *final_bridge)
1285 {
1286  transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE;
1287  ast_copy_string(transfer_msg->dest.bridge, final_bridge->uniqueid,
1288  sizeof(transfer_msg->dest.bridge));
1289 
1290  return 0;
1291 }
1292 
1294  struct ast_channel *survivor_channel, struct ast_bridge *survivor_bridge)
1295 {
1296  transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_THREEWAY;
1297 
1298  if (!strcmp(ast_channel_uniqueid(survivor_channel), transfer_msg->to_transferee.channel_snapshot->base->uniqueid)) {
1299  transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transferee.channel_snapshot;
1300  } else {
1301  transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transfer_target.channel_snapshot;
1302  }
1303 
1304  if (!strcmp(survivor_bridge->uniqueid, transfer_msg->to_transferee.bridge_snapshot->uniqueid)) {
1305  transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transferee.bridge_snapshot;
1306  } else {
1307  transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transfer_target.bridge_snapshot;
1308  }
1309 
1310  return 0;
1311 }
1312 
1314  const char *app, struct ast_channel *replace_channel)
1315 {
1316  transfer_msg->dest_type = replace_channel ? AST_ATTENDED_TRANSFER_DEST_LOCAL_APP : AST_ATTENDED_TRANSFER_DEST_APP;
1317 
1318  if (replace_channel) {
1319  transfer_msg->replace_channel = ast_channel_snapshot_get_latest(ast_channel_uniqueid(replace_channel));
1320  if (!transfer_msg->replace_channel) {
1321  return -1;
1322  }
1323  }
1324 
1325  ast_copy_string(transfer_msg->dest.app, app, sizeof(transfer_msg->dest.app));
1326 
1327  return 0;
1328 }
1329 
1331  struct ast_channel *locals[2])
1332 {
1333  int i;
1334 
1335  transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_LINK;
1336  for (i = 0; i < 2; ++i) {
1337  transfer_msg->dest.links[i] = ast_channel_snapshot_get_latest(ast_channel_uniqueid(locals[i]));
1338  if (!transfer_msg->dest.links[i]) {
1339  return -1;
1340  }
1341  }
1342 
1343  return 0;
1344 }
1345 
1347 {
1348  struct stasis_message *msg;
1349 
1350  msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
1351  if (!msg) {
1352  return;
1353  }
1354 
1356  ao2_ref(msg, -1);
1357 }
1358 
1360 {
1361  struct ast_bridge *bridge;
1362  struct ast_bridge_snapshot *snapshot;
1363 
1364  ast_assert(!ast_strlen_zero(uniqueid));
1365 
1366  bridge = ast_bridge_find_by_id(uniqueid);
1367  if (!bridge) {
1368  return NULL;
1369  }
1370  ast_bridge_lock(bridge);
1371  snapshot = ao2_bump(bridge->current_snapshot);
1372  ast_bridge_unlock(bridge);
1373  ao2_ref(bridge, -1);
1374 
1375  return snapshot;
1376 }
1377 
1379 {
1380  struct ast_bridge_snapshot *snapshot;
1381 
1382  if (!bridge) {
1383  return NULL;
1384  }
1385  ast_bridge_lock(bridge);
1386  snapshot = ao2_bump(bridge->current_snapshot);
1387  ast_bridge_unlock(bridge);
1388 
1389  return snapshot;
1390 }
1391 
1392 static void stasis_bridging_cleanup(void)
1393 {
1394  STASIS_MESSAGE_TYPE_CLEANUP(ast_bridge_snapshot_type);
1395  STASIS_MESSAGE_TYPE_CLEANUP(ast_bridge_merge_message_type);
1396  STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_entered_bridge_type);
1397  STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_left_bridge_type);
1398  STASIS_MESSAGE_TYPE_CLEANUP(ast_blind_transfer_type);
1399  STASIS_MESSAGE_TYPE_CLEANUP(ast_attended_transfer_type);
1400 
1401  ao2_cleanup(bridge_topic_pool);
1402  bridge_topic_pool = NULL;
1403  ao2_cleanup(bridge_topic_all);
1404  bridge_topic_all = NULL;
1405 }
1406 
1407 int ast_stasis_bridging_init(void)
1408 {
1409  int res = 0;
1410 
1411  ast_register_cleanup(stasis_bridging_cleanup);
1412 
1413  bridge_topic_all = stasis_topic_create("bridge:all");
1414  if (!bridge_topic_all) {
1415  return -1;
1416  }
1417  bridge_topic_pool = stasis_topic_pool_create(bridge_topic_all);
1418  if (!bridge_topic_pool) {
1419  return -1;
1420  }
1421 
1422  res |= STASIS_MESSAGE_TYPE_INIT(ast_bridge_snapshot_type);
1423  res |= STASIS_MESSAGE_TYPE_INIT(ast_bridge_merge_message_type);
1424  res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_entered_bridge_type);
1425  res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_left_bridge_type);
1426  res |= STASIS_MESSAGE_TYPE_INIT(ast_blind_transfer_type);
1427  res |= STASIS_MESSAGE_TYPE_INIT(ast_attended_transfer_type);
1428 
1429  return res;
1430 }
struct ast_blind_transfer_message * ast_blind_transfer_message_create(int is_external, struct ast_channel *transferer, const char *exten, const char *context)
Create a blind transfer message to be published.
Struct containing info for an AMI event to send out.
Definition: manager.h:502
struct ao2_container * channels
Definition: bridge.h:331
Main Channel structure associated with a channel.
Caching pattern for Stasis Message Bus API topics.
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
struct timeval creationtime
Definition: bridge.h:343
struct ast_channel_snapshot_base * base
Asterisk main include file. File version handling, generic pbx functions.
struct ast_flags feature_flags
Definition: bridge.h:369
const ast_string_field uniqueid
Definition: bridge.h:401
unsigned int num_active
Definition: bridge.h:375
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
static struct ast_bridge_merge_message * bridge_merge_message_create(struct ast_bridge *to, struct ast_bridge *from)
Bridge merge message creation helper.
int ast_attended_transfer_message_add_app(struct ast_attended_transfer_message *transfer_msg, const char *app, struct ast_channel *replace_channel)
Add details for an attended transfer to an application.
Message representing attended transfer.
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
char exten[AST_MAX_EXTENSION]
Message published during a blind transfer.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *uniqueid)
Returns the current snapshot for the bridge.
void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *chan)
Publish a bridge channel leave event.
void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap)
Publish a bridge channel enter event.
const char * name
Definition: bridge.h:259
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
int(* channel_id)(const char *channel_id)
Callback which determines whether a channel should be sanitized from a message based on the channel's...
Definition: stasis.h:210
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
void ast_bridge_publish_attended_transfer(struct ast_attended_transfer_message *transfer_msg)
Publish an attended transfer.
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
struct ast_bridge_video_mode video_mode
Definition: bridge.h:279
void ast_bridge_publish_blind_transfer(struct ast_blind_transfer_message *transfer_message)
Publish a blind transfer event.
const ast_string_field name
Definition: bridge.h:401
const ast_string_field video_source_id
Definition: bridge.h:328
Structure representing a snapshot of channel state.
struct stasis_message * ast_bridge_blob_create_from_snapshots(struct stasis_message_type *message_type, struct ast_bridge_snapshot *bridge_snapshot, struct ast_channel_snapshot *chan_snapshot, struct ast_json *blob)
Creates a ast_bridge_blob message from snapshots.
struct ast_channel * chan_vsrc
Definition: bridge.h:116
#define ast_str_container_alloc(buckets)
Allocates a hash container for bare strings.
Definition: strings.h:1365
struct ast_str * ast_manager_build_channel_state_string_prefix(const struct ast_channel_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a channel snapshot.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
struct ast_json * blob
struct ast_channel_snapshot * target
Definition: astman.c:222
const ast_string_field uniqueid
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 ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
struct stasis_topic * stasis_topic_pool_get_topic(struct stasis_topic_pool *pool, const char *topic_name)
Find or create a topic in the pool.
Definition: stasis.c:1884
char bridge[AST_UUID_STR_LEN]
void ast_free_ptr(void *ptr)
free() wrapper
Definition: main/astmm.c:1739
struct ast_bridge_softmix softmix
Definition: bridge.h:367
int ast_attended_transfer_message_add_merge(struct ast_attended_transfer_message *transfer_msg, struct ast_bridge *final_bridge)
Add details for a bridge merge to an attended transfer message.
struct ast_bridge_channel_snapshot_pair to_transferee
struct ast_channel * ast_bridge_peer(struct ast_bridge *bridge, struct ast_channel *chan)
Get the channel's bridge peer only if the bridge is two-party.
Definition: bridge.c:4075
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
Structure containing callbacks for Stasis message sanitization.
Definition: stasis.h:200
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:414
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
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.
struct stasis_topic_pool * stasis_topic_pool_create(struct stasis_topic *pooled_topic)
Create a topic pool that routes messages from dynamically generated topics to the given topic...
Definition: stasis.c:1833
static void bridge_snapshot_dtor(void *obj)
Destructor for bridge snapshots.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
struct ast_bridge_technology * technology
Definition: bridge.h:355
struct ast_bridge_channel_snapshot_pair to_transfer_target
struct ast_bridge_snapshot * bridge
struct ast_attended_transfer_message * ast_attended_transfer_message_create(int is_external, struct ast_channel *to_transferee, struct ast_bridge *transferee_bridge, struct ast_channel *to_transfer_target, struct ast_bridge *target_bridge, struct ast_channel *transferee, struct ast_channel *transfer_target)
Create an Attended transfer message to be published.
enum ast_transfer_result result
uint32_t capabilities
Definition: bridge.h:335
const ast_string_field technology
Definition: bridge.h:328
General Asterisk PBX channel definitions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
Publish a bridge merge.
struct ast_channel_snapshot * links[2]
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:278
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
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_channel_snapshot * transferee
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
Channel Bridging API.
struct ast_channel_snapshot * replace_channel
struct ast_bridge_snapshot * bridge
#define ast_debug(level,...)
Log a DEBUG message.
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition: stasis.c:617
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.
static void bridge_merge_message_dtor(void *obj)
Destructor for bridge merge messages.
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
Definition: json.c:362
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition: json.c:670
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition: json.c:378
enum ast_attended_transfer_dest_type dest_type
const struct ast_bridge_methods * v_table
Definition: bridge.h:351
struct ast_bridge_snapshot * ast_bridge_get_snapshot(struct ast_bridge *bridge)
Returns the current snapshot for the bridge.
void stasis_topic_pool_delete_topic(struct stasis_topic_pool *pool, const char *topic_name)
Delete a topic from the topic pool.
Definition: stasis.c:1864
struct ast_bridge_snapshot * current_snapshot
Definition: bridge.h:406
Structure that contains information about a bridge.
Definition: bridge.h:349
struct ast_channel_snapshot * transferer
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.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
enum ast_bridge_video_mode_type video_mode
Definition: bridge.h:341
const char * stasis_topic_name(const struct stasis_topic *topic)
Return the name of a topic.
Definition: stasis.c:627
char context[AST_MAX_CONTEXT]
struct ast_bridge_channel_snapshot_pair threeway
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
struct timeval creationtime
Definition: bridge.h:408
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition: bridge.h:481
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1511
static const char * stasis
Dialplan application name.
Definition: app_stasis.c:80
struct ast_bridge_snapshot * ast_bridge_snapshot_create(struct ast_bridge *bridge)
Generate a snapshot of the bridge state. This is an ao2 object, so ao2_cleanup() to deallocate...
int ast_attended_transfer_message_add_threeway(struct ast_attended_transfer_message *transfer_msg, struct ast_channel *survivor_channel, struct ast_bridge *survivor_bridge)
Add details for an attended transfer that was resolved as a three-way call.
const ast_string_field uniqueid
Definition: bridge.h:328
struct ast_flags feature_flags
Definition: bridge.h:333
unsigned int num_channels
Definition: bridge.h:337
struct ast_bridge_snapshot * from
struct stasis_topic * ast_bridge_topic(struct ast_bridge *bridge)
A topic which publishes the events for a particular bridge.
#define ast_bridge_lock(bridge)
Lock the bridge.
Definition: bridge.h:470
unsigned int num_active
Definition: bridge.h:339
struct ast_bridge_channels_list channels
Definition: bridge.h:363
Message representing the merge of two bridges.
struct ast_channel * chan
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...
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
struct ast_channel * chan_vsrc
Definition: bridge.h:123
struct stasis_topic * topic
Definition: bridge.h:359
Abstract JSON element (object, array, string, int, ...).
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.
struct ast_json * ast_json_boolean(int value)
Get the JSON boolean corresponding to value.
Definition: json.c:243
int ast_attended_transfer_message_add_link(struct ast_attended_transfer_message *transfer_msg, struct ast_channel *locals[2])
Add details for an attended transfer that has a link between bridges.
Definition: search.h:40
Generic container type.
struct ast_channel_snapshot * transferee
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.
const ast_string_field creator
Definition: bridge.h:401
Bridging API.
struct stasis_message * ast_bridge_blob_create(struct stasis_message_type *message_type, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_json *blob)
Creates a ast_bridge_blob message.
const ast_string_field subclass
Definition: bridge.h:328
STASIS_MESSAGE_TYPE_DEFN(ast_bridge_snapshot_type)
Define bridge message types.
#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
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
enum ast_transfer_result result
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
unsigned int num_channels
Definition: bridge.h:373
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
Definition: strings.c:205
const ast_string_field name
struct ast_channel_snapshot * replace_channel
struct ast_bridge_snapshot * to
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
void ast_bridge_publish_state(struct ast_bridge *bridge)
Publish the state of a bridge.
Pair showing a bridge snapshot and a specific channel snapshot belonging to the bridge.