Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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"
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;
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 
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 
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 
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 
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 
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 {
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)) {
848  ast_json_unref(json_replace);
849  return NULL;
850  }
851 
852  if (json_replace && ast_json_object_set(out, "replace_channel", json_replace)) {
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)) {
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 
958  if (!stasis) {
959  return;
960  }
961 
963 
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) ||
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) {
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) {
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) {
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 
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 
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  }
1418  if (!bridge_topic_pool) {
1419  return -1;
1420  }
1421 
1428 
1429  return res;
1430 }
static const char app[]
Definition: app_adsiprog.c:56
static const char * stasis
Dialplan application name.
Definition: app_stasis.c:80
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
#define ast_free(a)
Definition: astmm.h:180
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1739
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
Bridging API.
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
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition: bridge.h:481
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_bridge * ast_bridge_find_by_id(const char *bridge_id)
Find bridge by id.
Definition: bridge.c:4997
@ AST_BRIDGE_CAPABILITY_HOLDING
Definition: bridge.h:86
@ AST_BRIDGE_TRANSFER_NOT_PERMITTED
Definition: bridge.h:1102
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition: bridge.h:1100
@ AST_BRIDGE_TRANSFER_INVALID
Definition: bridge.h:1104
@ AST_BRIDGE_TRANSFER_FAIL
Definition: bridge.h:1106
@ AST_BRIDGE_VIDEO_MODE_SINGLE_SRC
Definition: bridge.h:102
@ AST_BRIDGE_VIDEO_MODE_TALKER_SRC
Definition: bridge.h:105
@ AST_BRIDGE_VIDEO_MODE_NONE
Definition: bridge.h:100
#define ast_bridge_lock(bridge)
Lock the bridge.
Definition: bridge.h:470
@ AST_BRIDGE_FLAG_INVISIBLE
Channel Bridging API.
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:122
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
static const char type[]
Definition: chan_ooh323.c:109
General Asterisk PBX channel definitions.
const char * ast_channel_uniqueid(const struct ast_channel *chan)
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
static struct ao2_container * locals
Definition: core_local.c:138
static const char name[]
Definition: format_mp3.c:68
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition: json.c:649
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition: json.c:368
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
Definition: json.c:352
struct ast_json * ast_json_boolean(int value)
Get the JSON boolean corresponding to value.
Definition: json.c:243
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
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
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:268
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
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:9760
struct ast_str * ast_manager_build_bridge_state_string(const struct ast_bridge_snapshot *snapshot)
Generate the AMI message body from a bridge snapshot.
#define EVENT_FLAG_CALL
Definition: manager.h:76
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.
struct ast_str * ast_manager_build_bridge_state_string_prefix(const struct ast_bridge_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a bridge snapshot.
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
#define NULL
Definition: resample.c:96
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
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:1866
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:1886
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1513
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition: stasis.c:619
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:1835
const char * stasis_topic_name(const struct stasis_topic *topic)
Return the name of a topic.
Definition: stasis.c:629
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct ast_bridge_snapshot * ast_bridge_get_snapshot(struct ast_bridge *bridge)
Returns the current snapshot for the bridge.
void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
Publish a bridge merge.
static struct ast_json * ast_bridge_merge_message_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize)
void ast_bridge_publish_attended_transfer(struct ast_attended_transfer_message *transfer_msg)
Publish an attended transfer.
void ast_bridge_publish_blind_transfer(struct ast_blind_transfer_message *transfer_message)
Publish a blind transfer event.
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 struct stasis_topic_pool * bridge_topic_pool
static void stasis_bridging_cleanup(void)
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_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.
static struct ast_json * attended_transfer_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.
#define SNAPSHOT_CHANNELS_BUCKETS
static const char * capability2str(uint32_t capabilities)
static void blind_transfer_dtor(void *obj)
int bridge_topics_init(struct ast_bridge *bridge)
void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *chan)
Publish a bridge channel leave event.
static struct ast_json * container_to_json_array(struct ao2_container *items, const struct stasis_message_sanitizer *sanitize)
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.
static struct ast_json * blind_transfer_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize)
static void attended_transfer_dtor(void *obj)
static struct ast_manager_event_blob * blind_transfer_to_ami(struct stasis_message *message)
static struct ast_manager_event_blob * attended_transfer_to_ami(struct stasis_message *message)
static struct stasis_topic * bridge_topic_all
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 stasis_topic * ast_bridge_topic(struct ast_bridge *bridge)
A topic which publishes the events for a particular bridge.
static void bridge_blob_dtor(void *obj)
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 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 int bridge_channel_snapshot_pair_init(struct ast_channel *channel, struct ast_bridge *bridge, struct ast_bridge_channel_snapshot_pair *snapshot_pair)
static void bridge_channel_snapshot_pair_cleanup(struct ast_bridge_channel_snapshot_pair *pair)
void ast_bridge_publish_state(struct ast_bridge *bridge)
Publish the state of a bridge.
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.
static void bridge_snapshot_dtor(void *obj)
Destructor for bridge snapshots.
static void bridge_merge_message_dtor(void *obj)
Destructor for bridge merge messages.
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_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.
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
static const char * result_strs[]
static struct ast_json * ast_channel_entered_bridge_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize)
static void bridge_publish_state_from_blob(struct ast_bridge *bridge, struct ast_bridge_blob *obj)
struct ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *uniqueid)
Returns the current snapshot for the bridge.
STASIS_MESSAGE_TYPE_DEFN(ast_bridge_snapshot_type)
Define bridge message types.
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.
static struct ast_bridge_snapshot_update * bridge_snapshot_update_create(struct ast_bridge_snapshot *old, struct ast_bridge_snapshot *new)
static void bridge_snapshot_update_dtor(void *obj)
int ast_stasis_bridging_init(void)
void bridge_topics_destroy(struct ast_bridge *bridge)
void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap)
Publish a bridge channel enter event.
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 stasis_message_type * ast_blind_transfer_type(void)
Message type for ast_blind_transfer_message.
struct stasis_message_type * ast_bridge_merge_message_type(void)
Message type for ast_bridge_merge_message.
struct stasis_message_type * ast_attended_transfer_type(void)
Message type for ast_attended_transfer_message.
struct stasis_message_type * ast_channel_left_bridge_type(void)
Message type for ast_channel leave bridge blob messages.
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for ast_channel enter bridge blob messages.
struct stasis_message_type * ast_bridge_snapshot_type(void)
Message type for ast_bridge_snapshot.
@ AST_ATTENDED_TRANSFER_DEST_FAIL
@ AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE
@ AST_ATTENDED_TRANSFER_DEST_LOCAL_APP
@ AST_ATTENDED_TRANSFER_DEST_LINK
@ AST_ATTENDED_TRANSFER_DEST_APP
@ AST_ATTENDED_TRANSFER_DEST_THREEWAY
Caching pattern for Stasis Message Bus API topics.
struct ast_json * ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_channel_snapshot.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
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:1117
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:739
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_container_alloc(buckets)
Allocates a hash container for bare strings.
Definition: strings.h:1343
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:640
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:406
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
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Message representing attended transfer.
enum ast_attended_transfer_dest_type dest_type
struct ast_channel_snapshot * replace_channel
struct ast_channel_snapshot * links[2]
struct ast_bridge_channel_snapshot_pair to_transfer_target
union ast_attended_transfer_message::@314 dest
struct ast_channel_snapshot * transferee
struct ast_bridge_channel_snapshot_pair threeway
enum ast_transfer_result result
struct ast_bridge_channel_snapshot_pair to_transferee
char bridge[AST_UUID_STR_LEN]
struct ast_channel_snapshot * target
Message published during a blind transfer.
struct ast_channel_snapshot * replace_channel
char exten[AST_MAX_EXTENSION]
struct ast_bridge_snapshot * bridge
struct ast_channel_snapshot * transferer
struct ast_channel_snapshot * transferee
enum ast_transfer_result result
char context[AST_MAX_CONTEXT]
Blob of data associated with a bridge.
struct ast_bridge_snapshot * bridge
struct ast_channel_snapshot * channel
struct ast_json * blob
Pair showing a bridge snapshot and a specific channel snapshot belonging to the bridge.
struct ast_bridge_snapshot * bridge_snapshot
struct ast_channel_snapshot * channel_snapshot
Structure that contains information regarding a channel in a bridge.
struct ast_bridge * bridge
Bridge this channel is participating in.
struct ast_channel * chan
Message representing the merge of two bridges.
struct ast_bridge_snapshot * from
struct ast_bridge_snapshot * to
const char * name
Definition: bridge.h:259
Structure that contains a snapshot of information about a bridge.
Definition: bridge.h:314
uint32_t capabilities
Definition: bridge.h:335
enum ast_bridge_video_mode_type video_mode
Definition: bridge.h:341
struct timeval creationtime
Definition: bridge.h:343
unsigned int num_active
Definition: bridge.h:339
const ast_string_field video_source_id
Definition: bridge.h:328
const ast_string_field creator
Definition: bridge.h:328
const ast_string_field uniqueid
Definition: bridge.h:328
unsigned int num_channels
Definition: bridge.h:337
const ast_string_field technology
Definition: bridge.h:328
const ast_string_field name
Definition: bridge.h:328
struct ao2_container * channels
Definition: bridge.h:331
const ast_string_field subclass
Definition: bridge.h:328
struct ast_flags feature_flags
Definition: bridge.h:333
struct ast_bridge_video_mode video_mode
Definition: bridge.h:279
struct ast_bridge_video_single_src_data single_src_data
Definition: bridge.h:163
struct ast_bridge_video_talker_src_data talker_src_data
Definition: bridge.h:164
enum ast_bridge_video_mode_type mode
Definition: bridge.h:160
union ast_bridge_video_mode::@217 mode_data
struct ast_channel * chan_vsrc
Definition: bridge.h:116
struct ast_channel * chan_vsrc
Definition: bridge.h:123
Structure that contains information about a bridge.
Definition: bridge.h:349
struct stasis_topic * topic
Definition: bridge.h:359
struct ast_bridge_softmix softmix
Definition: bridge.h:367
struct timeval creationtime
Definition: bridge.h:408
const struct ast_bridge_methods * v_table
Definition: bridge.h:351
unsigned int num_active
Definition: bridge.h:375
const ast_string_field creator
Definition: bridge.h:401
const ast_string_field uniqueid
Definition: bridge.h:401
struct ast_bridge_channels_list channels
Definition: bridge.h:363
struct ast_bridge_snapshot * current_snapshot
Definition: bridge.h:406
unsigned int num_channels
Definition: bridge.h:373
struct ast_bridge_technology * technology
Definition: bridge.h:355
const ast_string_field name
Definition: bridge.h:401
struct ast_flags feature_flags
Definition: bridge.h:369
const ast_string_field uniqueid
const ast_string_field name
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_base * base
Main Channel structure associated with a channel.
Abstract JSON element (object, array, string, int, ...).
Struct containing info for an AMI event to send out.
Definition: manager.h:490
Support for dynamic strings.
Definition: strings.h:604
Definition: search.h:40
Definition: astman.c:222
Structure containing callbacks for Stasis message sanitization.
Definition: stasis.h:200
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
static struct aco_type item
Definition: test_config.c:1463
FILE * out
Definition: utils/frame.c:33
#define ast_test_flag(p, flag)
Definition: utils.h:63
#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:936
#define ast_assert(a)
Definition: utils.h:734
#define ARRAY_LEN(a)
Definition: utils.h:661