Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief Stasis Messages and Data Types for Bridge Objects
22  *
23  * \author Kinsey Moore <[email protected]>
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"
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);
145 static struct ast_json *blind_transfer_to_json(struct stasis_message *msg,
146  const struct stasis_message_sanitizer *sanitize);
149  struct stasis_message *msg,
150  const struct stasis_message_sanitizer *sanitize);
152  struct stasis_message *msg,
153  const struct stasis_message_sanitizer *sanitize);
155  struct stasis_message *msg,
156  const struct stasis_message_sanitizer *sanitize);
157 
160 
161 /*!
162  * @{ \brief Define bridge message types.
163  */
172  .to_json = blind_transfer_to_json,
175  .to_json = attended_transfer_to_json,
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 
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 
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;
253  ast_string_field_set(snapshot, video_source_id,
255  } else if (snapshot->video_mode == AST_BRIDGE_VIDEO_MODE_TALKER_SRC
257  ast_string_field_set(snapshot, video_source_id,
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 
276  struct ast_bridge_snapshot *old, struct ast_bridge_snapshot *new)
277 {
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 {
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 
334  if (!update) {
335  return;
336  }
337 
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;
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 
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 {
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 
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 
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 
466  return;
467  }
468 
469  ast_assert(to != NULL);
470  ast_assert(from != NULL);
473 
474  merge_msg = bridge_merge_message_create(to, from);
475  if (!merge_msg) {
476  return;
477  }
478 
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) {
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 
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);
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 
616  return;
617  }
619  if (!msg) {
620  return;
621  }
622 
623  /* state first, then leave blob (opposite of enter, preserves nesting of events) */
625  stasis_publish(ast_bridge_topic(bridge), msg);
626  ao2_ref(msg, -1);
627 }
628 
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 
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 
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 pair 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  */
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 
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  */
787 {
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 
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);
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 
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 
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) {
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;
1053  res |= ast_json_object_set(out, "replace_channel", ast_channel_snapshot_to_json(transfer_msg->replace_channel, sanitize));
1054  /* fallthrough */
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;
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;
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;
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 
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) {
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;
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;
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;
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;
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 
1214  ao2_cleanup(msg->transferee);
1215  ao2_cleanup(msg->target);
1216 
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) {
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) {
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 {
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 {
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 {
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 
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 {
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 
1408 {
1409  int res = 0;
1410 
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 
1428 
1429  return res;
1430 }
struct stasis_message_type * ast_bridge_snapshot_type(void)
Message type for ast_bridge_snapshot.
struct stasis_message_type * ast_blind_transfer_type(void)
Message type for ast_blind_transfer_message.
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.
static const char type[]
Definition: chan_ooh323.c:109
Struct containing info for an AMI event to send out.
Definition: manager.h:491
struct ao2_container * channels
Definition: bridge.h:339
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
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:351
struct ast_channel_snapshot_base * base
union ast_attended_transfer_message::@324 dest
static void bridge_snapshot_update_dtor(void *obj)
Asterisk main include file. File version handling, generic pbx functions.
struct ast_flags feature_flags
Definition: bridge.h:377
int bridge_topics_init(struct ast_bridge *bridge)
const ast_string_field uniqueid
Definition: bridge.h:409
#define SNAPSHOT_CHANNELS_BUCKETS
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
unsigned int num_active
Definition: bridge.h:383
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
static struct ast_manager_event_blob * attended_transfer_to_ami(struct stasis_message *message)
static struct ast_bridge_merge_message * bridge_merge_message_create(struct ast_bridge *to, struct ast_bridge *from)
Bridge merge message creation helper.
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for channel enter bridge blob messages.
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:5070
#define ast_test_flag(p, flag)
Definition: utils.h:63
char exten[AST_MAX_EXTENSION]
static void update(int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, struct g726_state *state_ptr)
Definition: codec_g726.c:367
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:267
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1501
int(* channel_id)(const char *channel_id)
Callback which determines whether a channel should be sanitized from a message based on the channel&#39;s...
Definition: stasis.h:210
struct stasis_message_type * ast_channel_left_bridge_type(void)
Message type for channel leave bridge blob messages.
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:714
Structure that contains a snapshot of information about a bridge.
Definition: bridge.h:322
struct ast_bridge_video_mode video_mode
Definition: bridge.h:287
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:409
const ast_string_field video_source_id
Definition: bridge.h:336
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:1312
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:1523
struct ast_json * blob
#define EVENT_FLAG_CALL
Definition: manager.h:72
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:1091
static struct aco_type item
Definition: test_config.c:1463
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define ast_assert(a)
Definition: utils.h:695
Definition: muted.c:95
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]
#define NULL
Definition: resample.c:96
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1771
static int bridge_channel_snapshot_pair_init(struct ast_channel *channel, struct ast_bridge *bridge, struct ast_bridge_channel_snapshot_pair *snapshot_pair)
struct ast_bridge_softmix softmix
Definition: bridge.h:375
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.
union ast_bridge_video_mode::@227 mode_data
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&#39;s bridge peer only if the bridge is two-party.
Definition: bridge.c:4142
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:9727
const ast_string_field creator
Definition: bridge.h:336
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:404
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269
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.
#define ast_strlen_zero(foo)
Definition: strings.h:52
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)
Definition: astobj2.h:491
struct ast_bridge_technology * technology
Definition: bridge.h:363
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.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static void blind_transfer_dtor(void *obj)
enum ast_transfer_result result
#define ast_log
Definition: astobj2.c:42
struct stasis_message_type * ast_bridge_merge_message_type(void)
Message type for ast_bridge_merge_message.
uint32_t capabilities
Definition: bridge.h:343
const ast_string_field technology
Definition: bridge.h:336
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 bridge_topics_destroy(struct ast_bridge *bridge)
void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
Publish a bridge merge.
struct ast_channel_snapshot * links[2]
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:268
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
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:4018
static void attended_transfer_dtor(void *obj)
struct ast_channel_snapshot * transferee
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
Channel Bridging API.
static struct ast_json * simple_bridge_channel_event(const char *type, struct ast_bridge_snapshot *bridge_snapshot, struct ast_channel_snapshot *channel_snapshot, const struct timeval *tv, const struct stasis_message_sanitizer *sanitize)
static struct ast_manager_event_blob * blind_transfer_to_ami(struct stasis_message *message)
struct ast_bridge_video_talker_src_data talker_src_data
Definition: bridge.h:164
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static struct ast_bridge_snapshot_update * bridge_snapshot_update_create(struct ast_bridge_snapshot *old, struct ast_bridge_snapshot *new)
struct ast_channel_snapshot * replace_channel
static struct ast_json * ast_bridge_merge_message_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize)
struct ast_bridge_snapshot * bridge
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition: stasis.c:618
struct ast_bridge_video_single_src_data single_src_data
Definition: bridge.h:163
struct ast_str * ast_manager_build_bridge_state_string(const struct ast_bridge_snapshot *snapshot)
Generate the AMI message body from a bridge snapshot.
struct ast_bridge_snapshot * old_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:352
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition: json.c:649
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition: json.c:368
const char * ast_channel_uniqueid(const struct ast_channel *chan)
enum ast_attended_transfer_dest_type dest_type
int ast_stasis_bridging_init(void)
const struct ast_bridge_methods * v_table
Definition: bridge.h:359
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:414
Structure that contains information about a bridge.
Definition: bridge.h:357
struct ast_channel_snapshot * transferer
struct ast_channel_snapshot * channel_snapshot
#define LOG_ERROR
Definition: logger.h:285
static void bridge_channel_snapshot_pair_cleanup(struct ast_bridge_channel_snapshot_pair *pair)
static struct stasis_topic_pool * bridge_topic_pool
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
const ast_string_field name
Definition: bridge.h:336
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:349
static struct stasis_topic * bridge_topic_all
const char * stasis_topic_name(const struct stasis_topic *topic)
Return the name of a topic.
Definition: stasis.c:628
char context[AST_MAX_CONTEXT]
static struct ast_json * blind_transfer_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize)
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
struct ast_bridge_channel_snapshot_pair threeway
struct stasis_message_type * ast_attended_transfer_type(void)
Message type for ast_attended_transfer_message.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct ast_bridge_snapshot * bridge_snapshot
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.
struct timeval creationtime
Definition: bridge.h:416
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition: bridge.h:493
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
static struct ast_json * container_to_json_array(struct ao2_container *items, const struct stasis_message_sanitizer *sanitize)
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...
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
static struct ast_json * ast_channel_left_bridge_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize)
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.
static void bridge_publish_state_from_blob(struct ast_bridge *bridge, struct ast_bridge_blob *obj)
const ast_string_field uniqueid
Definition: bridge.h:336
struct ast_bridge_snapshot * new_snapshot
static void bridge_blob_dtor(void *obj)
struct ast_flags feature_flags
Definition: bridge.h:341
unsigned int num_channels
Definition: bridge.h:345
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:480
unsigned int num_active
Definition: bridge.h:347
struct ast_bridge_channels_list channels
Definition: bridge.h:371
Message representing the merge of two bridges.
struct ast_channel * chan
Structure that contains information regarding a channel in a bridge.
FILE * out
Definition: utils/frame.c:33
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:1841
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
struct ast_channel * chan_vsrc
Definition: bridge.h:123
static const char * result_strs[]
static void stasis_bridging_cleanup(void)
struct stasis_topic * topic
Definition: bridge.h:367
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.
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
struct ast_channel_snapshot * transferee
static struct ao2_container * locals
Definition: core_local.c:138
const ast_string_field creator
Definition: bridge.h:409
Bridging API.
static const char app[]
Definition: app_mysql.c:62
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:336
STASIS_MESSAGE_TYPE_DEFN(ast_bridge_snapshot_type)
Define bridge message types.
static struct ast_json * attended_transfer_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize)
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
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:381
enum ast_bridge_video_mode_type mode
Definition: bridge.h:160
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:206
static const char * capability2str(uint32_t capabilities)
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&#39;ed dynamic length string.
Definition: strings.h:620
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
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.
static struct ast_json * ast_channel_entered_bridge_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize)