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