Asterisk - The Open Source Telephony Project GIT-master-6144b6b
Loading...
Searching...
No Matches
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/json.h"
34#include "asterisk/stasis.h"
36#include "asterisk/channel.h"
39#include "asterisk/bridge.h"
41
42/* The container of channel snapshots in a bridge snapshot should always be
43 equivalent to a linked list; otherwise things (like CDRs) that depend on some
44 consistency in the ordering of channels in a bridge will break. */
45#define SNAPSHOT_CHANNELS_BUCKETS 1
46
47/*** DOCUMENTATION
48 <managerEvent language="en_US" name="BlindTransfer">
49 <managerEventInstance class="EVENT_FLAG_CALL">
50 <since>
51 <version>12.0.0</version>
52 </since>
53 <synopsis>Raised when a blind transfer is complete.</synopsis>
54 <syntax>
55 <parameter name="Result">
56 <para>Indicates if the transfer was successful or if it failed.</para>
57 <enumlist>
58 <enum name="Fail"><para>An internal error occurred.</para></enum>
59 <enum name="Invalid"><para>Invalid configuration for transfer (e.g. Not bridged)</para></enum>
60 <enum name="Not Permitted"><para>Bridge does not permit transfers</para></enum>
61 <enum name="Success"><para>Transfer completed successfully</para></enum>
62 </enumlist>
63 <note><para>A result of <literal>Success</literal> does not necessarily mean that a target was successfully
64 contacted. It means that a party was successfully placed into the dialplan at the expected location.</para></note>
65 </parameter>
66 <channel_snapshot prefix="Transferer"/>
67 <channel_snapshot prefix="Transferee"/>
68 <bridge_snapshot/>
69 <parameter name="IsExternal">
70 <para>Indicates if the transfer was performed outside of Asterisk. For instance,
71 a channel protocol native transfer is external. A DTMF transfer is internal.</para>
72 <enumlist>
73 <enum name="Yes" />
74 <enum name="No" />
75 </enumlist>
76 </parameter>
77 <parameter name="Context">
78 <para>Destination context for the blind transfer.</para>
79 </parameter>
80 <parameter name="Extension">
81 <para>Destination extension for the blind transfer.</para>
82 </parameter>
83 </syntax>
84 <see-also>
85 <ref type="manager">BlindTransfer</ref>
86 </see-also>
87 </managerEventInstance>
88 </managerEvent>
89 <managerEvent language="en_US" name="AttendedTransfer">
90 <managerEventInstance class="EVENT_FLAG_CALL">
91 <since>
92 <version>12.0.0</version>
93 </since>
94 <synopsis>Raised when an attended transfer is complete.</synopsis>
95 <syntax>
96 <xi:include xpointer="xpointer(docs/managerEvent[@name='BlindTransfer']/managerEventInstance/syntax/parameter[@name='Result'])" />
97 <channel_snapshot prefix="OrigTransferer"/>
98 <bridge_snapshot prefix="Orig"/>
99 <channel_snapshot prefix="SecondTransferer"/>
100 <bridge_snapshot prefix="Second"/>
101 <parameter name="DestType">
102 <para>Indicates the method by which the attended transfer completed.</para>
103 <enumlist>
104 <enum name="Bridge"><para>The transfer was accomplished by merging two bridges into one.</para></enum>
105 <enum name="App"><para>The transfer was accomplished by having a channel or bridge run a dialplan application.</para></enum>
106 <enum name="Link"><para>The transfer was accomplished by linking two bridges together using a local channel pair.</para></enum>
107 <enum name="Threeway"><para>The transfer was accomplished by placing all parties into a threeway call.</para></enum>
108 <enum name="Fail"><para>The transfer failed.</para></enum>
109 </enumlist>
110 </parameter>
111 <parameter name="DestBridgeUniqueid">
112 <para>Indicates the surviving bridge when bridges were merged to complete the transfer</para>
113 <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Bridge</literal> or <literal>Threeway</literal></para></note>
114 </parameter>
115 <parameter name="DestApp">
116 <para>Indicates the application that is running when the transfer completes</para>
117 <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>App</literal></para></note>
118 </parameter>
119 <channel_snapshot prefix="LocalOne"/>
120 <channel_snapshot prefix="LocalTwo"/>
121 <parameter name="DestTransfererChannel">
122 <para>The name of the surviving transferer channel when a transfer results in a threeway call</para>
123 <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Threeway</literal></para></note>
124 </parameter>
125 <channel_snapshot prefix="Transferee" />
126 <channel_snapshot prefix="TransferTarget" />
127 </syntax>
128 <description>
129 <para>The headers in this event attempt to describe all the major details of the attended transfer. The two transferer channels
130 and the two bridges are determined based on their chronological establishment. So consider that Alice calls Bob, and then Alice
131 transfers the call to Voicemail. The transferer and bridge headers would be arranged as follows:</para>
132 <para> <replaceable>OrigTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
133 <para> <replaceable>OrigBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
134 <para> <replaceable>SecondTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
135 <para> <replaceable>SecondBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
136 <para>Now consider if the order were reversed; instead of having Alice call Bob and transfer him to Voicemail, Alice instead
137 calls her Voicemail and transfers that to Bob. The transferer and bridge headers would be arranged as follows:</para>
138 <para> <replaceable>OrigTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
139 <para> <replaceable>OrigBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
140 <para> <replaceable>SecondTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
141 <para> <replaceable>SecondBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
142 </description>
143 <see-also>
144 <ref type="manager">AtxFer</ref>
145 </see-also>
146 </managerEventInstance>
147 </managerEvent>
148 ***/
149
150static struct ast_json *attended_transfer_to_json(struct stasis_message *msg,
151 const struct stasis_message_sanitizer *sanitize);
153static struct ast_json *blind_transfer_to_json(struct stasis_message *msg,
154 const struct stasis_message_sanitizer *sanitize);
157 struct stasis_message *msg,
158 const struct stasis_message_sanitizer *sanitize);
160 struct stasis_message *msg,
161 const struct stasis_message_sanitizer *sanitize);
163 struct stasis_message *msg,
164 const struct stasis_message_sanitizer *sanitize);
165
168
169/*!
170 * @{ \brief Define bridge message types.
171 */
180 .to_json = blind_transfer_to_json,
183 .to_json = attended_transfer_to_json,
185/*! @} */
186
188{
189 return bridge_topic_all;
190}
191
193{
194 if (!bridge) {
195 return ast_bridge_topic_all();
196 }
197
198 return bridge->topic;
199}
200
201int ast_bridge_topic_exists(const char *uniqueid)
202{
203 char *topic_name;
204 int ret;
205
206 if (ast_strlen_zero(uniqueid)) {
207 return 0;
208 }
209
210 ret = ast_asprintf(&topic_name, "bridge:%s", uniqueid);
211 if (ret < 0) {
212 return 0;
213 }
215 ast_free(topic_name);
216
217 return ret;
218}
219
220
221/*! \brief Destructor for bridge snapshots */
222static void bridge_snapshot_dtor(void *obj)
223{
224 struct ast_bridge_snapshot *snapshot = obj;
226 ao2_cleanup(snapshot->channels);
227 snapshot->channels = NULL;
229 snapshot->bridgevars = NULL;
230}
231
233{
234 struct ast_bridge_snapshot *snapshot;
235 struct ast_bridge_channel *bridge_channel;
236
238 return NULL;
239 }
240
241 snapshot = ao2_alloc_options(sizeof(*snapshot), bridge_snapshot_dtor,
243 if (!snapshot) {
244 return NULL;
245 }
246
247 if (ast_string_field_init(snapshot, 128)) {
248 ao2_ref(snapshot, -1);
249
250 return NULL;
251 }
252
254 if (!snapshot->channels) {
255 ao2_ref(snapshot, -1);
256
257 return NULL;
258 }
259
260 AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
261 if (ast_str_container_add(snapshot->channels,
262 ast_channel_uniqueid(bridge_channel->chan))) {
263 ao2_ref(snapshot, -1);
264
265 return NULL;
266 }
267 }
268
269 ast_string_field_set(snapshot, uniqueid, bridge->uniqueid);
270 ast_string_field_set(snapshot, technology, bridge->technology->name);
271 ast_string_field_set(snapshot, subclass, bridge->v_table->name);
272 ast_string_field_set(snapshot, creator, bridge->creator);
274
277 snapshot->num_channels = bridge->num_channels;
278 snapshot->num_active = bridge->num_active;
279 snapshot->creationtime = bridge->creationtime;
283 ast_string_field_set(snapshot, video_source_id,
285 } else if (snapshot->video_mode == AST_BRIDGE_VIDEO_MODE_TALKER_SRC
287 ast_string_field_set(snapshot, video_source_id,
289 }
290
292
293 return snapshot;
294}
295
296static void bridge_snapshot_update_dtor(void *obj)
297{
299
300 ast_debug(3, "Update: %p Old: %s New: %s\n", update,
301 update->old_snapshot ? update->old_snapshot->uniqueid : "<none>",
302 update->new_snapshot ? update->new_snapshot->uniqueid : "<none>");
303 ao2_cleanup(update->old_snapshot);
304 ao2_cleanup(update->new_snapshot);
305}
306
308 struct ast_bridge_snapshot *old, struct ast_bridge_snapshot *new)
309{
311
314 if (!update) {
315 return NULL;
316 }
317 update->old_snapshot = ao2_bump(old);
318 update->new_snapshot = ao2_bump(new);
319
320 ast_debug(3, "Update: %p Old: %s New: %s\n", update,
321 update->old_snapshot ? update->old_snapshot->uniqueid : "<none>",
322 update->new_snapshot ? update->new_snapshot->uniqueid : "<none>");
323
324 return update;
325}
326
328{
329 char *topic_name;
330 int ret;
331
332 if (ast_strlen_zero(bridge->uniqueid)) {
333 ast_log(LOG_ERROR, "Bridge id initialization required\n");
334 return -1;
335 }
336
337 ret = ast_asprintf(&topic_name, "bridge:%s", bridge->uniqueid);
338 if (ret < 0) {
339 return -1;
340 }
341
343 ast_free(topic_name);
344 if (!bridge->topic) {
345 return -1;
346 }
347 ao2_bump(bridge->topic);
348
349 return 0;
350}
351
353{
355 struct stasis_message *msg;
356
357 ast_assert(bridge != NULL);
358 ast_debug(1, "Bridge " BRIDGE_PRINTF_SPEC ": destroying topics\n",
359 BRIDGE_PRINTF_VARS(bridge));
360
361 if (!bridge->topic) {
362 ast_log(LOG_WARNING, "Bridge " BRIDGE_PRINTF_SPEC " topic is NULL\n",
363 BRIDGE_PRINTF_VARS(bridge));
364 return;
365 }
366
367 if (!bridge->current_snapshot) {
369 if (!bridge->current_snapshot) {
370 return;
371 }
372 }
373
375 if (!update) {
376 return;
377 }
378
380 ao2_ref(update, -1);
381 if (!msg) {
382 return;
383 }
384
385 stasis_publish(ast_bridge_topic(bridge), msg);
386 ao2_ref(msg, -1);
387
389 ao2_cleanup(bridge->topic);
390 bridge->topic = NULL;
391}
392
394{
395 struct ast_bridge_snapshot *new_snapshot;
397 struct stasis_message *msg;
398
399 ast_assert(bridge != NULL);
400
401 new_snapshot = ast_bridge_snapshot_create(bridge);
402 if (!new_snapshot) {
403 return;
404 }
405
407 /* There may not have been an old snapshot */
409 bridge->current_snapshot = new_snapshot;
410 if (!update) {
411 return;
412 }
413
415 ao2_ref(update, -1);
416 if (!msg) {
417 return;
418 }
419
420 stasis_publish(ast_bridge_topic(bridge), msg);
421 ao2_ref(msg, -1);
422}
423
425 struct ast_bridge_blob *obj)
426{
428 struct stasis_message *msg;
429
430 ast_assert(obj != NULL);
431
434 bridge->current_snapshot = ao2_bump(obj->bridge);
435 if (!update) {
436 return;
437 }
438
440 ao2_ref(update, -1);
441 if (!msg) {
442 return;
443 }
444
445 stasis_publish(ast_bridge_topic(bridge), msg);
446 ao2_ref(msg, -1);
447}
448
449/*! \brief Destructor for bridge merge messages */
450static void bridge_merge_message_dtor(void *obj)
451{
452 struct ast_bridge_merge_message *msg = obj;
453
454 ao2_cleanup(msg->to);
455 msg->to = NULL;
456 ao2_cleanup(msg->from);
457 msg->from = NULL;
458}
459
460/*! \brief Bridge merge message creation helper */
462{
463 struct ast_bridge_merge_message *msg;
464
465 msg = ao2_alloc(sizeof(*msg), bridge_merge_message_dtor);
466 if (!msg) {
467 return NULL;
468 }
469
472 if (!msg->to || !msg->from) {
473 ao2_ref(msg, -1);
474
475 return NULL;
476 }
477
478 return msg;
479}
480
482 struct stasis_message *msg,
483 const struct stasis_message_sanitizer *sanitize)
484{
486 struct ast_json *json_bridge_to = ast_bridge_snapshot_to_json(merge->to, sanitize);
487 struct ast_json *json_bridge_from = ast_bridge_snapshot_to_json(merge->from, sanitize);
488
489 if (!json_bridge_to || !json_bridge_from) {
490 ast_json_unref(json_bridge_to);
491 ast_json_unref(json_bridge_from);
492
493 return NULL;
494 }
495
496 return ast_json_pack("{s: s, s: o, s: o, s: o}",
497 "type", "BridgeMerged",
499 "bridge", json_bridge_to,
500 "bridge_from", json_bridge_from);
501}
502
503void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
504{
505 struct ast_bridge_merge_message *merge_msg;
506 struct stasis_message *msg;
507
509 return;
510 }
511
512 ast_assert(to != NULL);
513 ast_assert(from != NULL);
516
517 merge_msg = bridge_merge_message_create(to, from);
518 if (!merge_msg) {
519 return;
520 }
521
523 ao2_ref(merge_msg, -1);
524 if (!msg) {
525 return;
526 }
527
529 ao2_ref(msg, -1);
530}
531
532static void bridge_blob_dtor(void *obj)
533{
534 struct ast_bridge_blob *event = obj;
535 ao2_cleanup(event->bridge);
536 event->bridge = NULL;
537 ao2_cleanup(event->channel);
538 event->channel = NULL;
539 ast_json_unref(event->blob);
540 event->blob = NULL;
541}
542
544 struct stasis_message_type *message_type,
545 struct ast_bridge *bridge,
546 struct ast_channel *chan,
547 struct ast_json *blob)
548{
549 struct ast_bridge_blob *obj;
550 struct stasis_message *msg;
551
552 if (!message_type) {
553 return NULL;
554 }
555
556 obj = ao2_alloc(sizeof(*obj), bridge_blob_dtor);
557 if (!obj) {
558 return NULL;
559 }
560
561 if (bridge) {
562 obj->bridge = ast_bridge_snapshot_create(bridge);
563 if (obj->bridge == NULL) {
564 ao2_ref(obj, -1);
565
566 return NULL;
567 }
568 }
569
570 if (chan) {
572 if (obj->channel == NULL) {
573 ao2_ref(obj, -1);
574
575 return NULL;
576 }
577 }
578
579 if (blob) {
580 obj->blob = ast_json_ref(blob);
581 }
582
583 msg = stasis_message_create(message_type, obj);
584 ao2_ref(obj, -1);
585
586 return msg;
587}
588
590 struct stasis_message_type *message_type,
591 struct ast_bridge_snapshot *bridge_snapshot,
592 struct ast_channel_snapshot *chan_snapshot,
593 struct ast_json *blob)
594{
595 struct ast_bridge_blob *obj;
596 struct stasis_message *msg;
597
598 if (!message_type) {
599 return NULL;
600 }
601
602 obj = ao2_alloc(sizeof(*obj), bridge_blob_dtor);
603 if (!obj) {
604 return NULL;
605 }
606
607 if (bridge_snapshot) {
608 obj->bridge = ao2_bump(bridge_snapshot);
609 }
610
611 if (chan_snapshot) {
612 obj->channel = ao2_bump(chan_snapshot);
613 }
614
615 if (blob) {
616 obj->blob = ast_json_ref(blob);
617 }
618
619 msg = stasis_message_create(message_type, obj);
620 ao2_ref(obj, -1);
621
622 return msg;
623}
624
625void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan,
626 struct ast_channel *swap)
627{
628 struct stasis_message *msg;
629 struct ast_json *blob = NULL;
630
632 return;
633 }
634
635 if (swap) {
636 blob = ast_json_pack("{s: s}", "swap", ast_channel_uniqueid(swap));
637 if (!blob) {
638 return;
639 }
640 }
641
642 msg = ast_bridge_blob_create(ast_channel_entered_bridge_type(), bridge, chan, blob);
643 ast_json_unref(blob);
644 if (!msg) {
645 return;
646 }
647
648 /* enter blob first, then state */
649 stasis_publish(ast_bridge_topic(bridge), msg);
651 ao2_ref(msg, -1);
652}
653
654void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *chan)
655{
656 struct stasis_message *msg;
657
659 return;
660 }
662 if (!msg) {
663 return;
664 }
665
666 /* state first, then leave blob (opposite of enter, preserves nesting of events) */
668 stasis_publish(ast_bridge_topic(bridge), msg);
669 ao2_ref(msg, -1);
670}
671
673 const char *type,
674 struct ast_bridge_snapshot *bridge_snapshot,
675 struct ast_channel_snapshot *channel_snapshot,
676 const struct timeval *tv,
677 const struct stasis_message_sanitizer *sanitize)
678{
679 struct ast_json *json_bridge = ast_bridge_snapshot_to_json(bridge_snapshot, sanitize);
680 struct ast_json *json_channel = ast_channel_snapshot_to_json(channel_snapshot, sanitize);
681
682 if (!json_bridge || !json_channel) {
683 ast_json_unref(json_bridge);
684 ast_json_unref(json_channel);
685
686 return NULL;
687 }
688
689 return ast_json_pack("{s: s, s: o, s: o, s: o}",
690 "type", type,
691 "timestamp", ast_json_timeval(*tv, NULL),
692 "bridge", json_bridge,
693 "channel", json_channel);
694}
695
697 struct stasis_message *msg,
698 const struct stasis_message_sanitizer *sanitize)
699{
700 struct ast_bridge_blob *obj = stasis_message_data(msg);
701
702 return simple_bridge_channel_event("ChannelEnteredBridge", obj->bridge,
703 obj->channel, stasis_message_timestamp(msg), sanitize);
704}
705
707 struct stasis_message *msg,
708 const struct stasis_message_sanitizer *sanitize)
709{
710 struct ast_bridge_blob *obj = stasis_message_data(msg);
711
712 return simple_bridge_channel_event("ChannelLeftBridge", obj->bridge,
713 obj->channel, stasis_message_timestamp(msg), sanitize);
714}
715
716static struct ast_json *container_to_json_array(struct ao2_container *items,
717 const struct stasis_message_sanitizer *sanitize)
718{
719 struct ast_json *json_items = ast_json_array_create();
720 char *item;
721 struct ao2_iterator it;
722
723 if (!json_items) {
724 return NULL;
725 }
726
727 for (it = ao2_iterator_init(items, 0);
729 if (sanitize && sanitize->channel_id && sanitize->channel_id(item)) {
730 continue;
731 }
732
736 ast_json_unref(json_items);
737
738 return NULL;
739 }
740 }
742
743 return json_items;
744}
745
746static const char *capability2str(uint32_t capabilities)
747{
748 if (capabilities & AST_BRIDGE_CAPABILITY_HOLDING) {
749 return "holding";
750 } else {
751 return "mixing";
752 }
753}
754
756 const struct ast_bridge_snapshot *snapshot,
757 const struct stasis_message_sanitizer *sanitize)
758{
759 struct ast_json *json_bridge;
760 struct ast_json *json_channels;
761
762 if (snapshot == NULL) {
763 return NULL;
764 }
765
766 json_channels = container_to_json_array(snapshot->channels, sanitize);
767 if (!json_channels) {
768 return NULL;
769 }
770
771 json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: o, s: o, s: s}",
772 "id", snapshot->uniqueid,
773 "technology", snapshot->technology,
774 "bridge_type", capability2str(snapshot->capabilities),
775 "bridge_class", snapshot->subclass,
776 "creator", snapshot->creator,
777 "name", snapshot->name,
778 "channels", json_channels,
779 "creationtime", ast_json_timeval(snapshot->creationtime, NULL),
780 "video_mode", ast_bridge_video_mode_to_string(snapshot->video_mode));
781 if (!json_bridge) {
782 return NULL;
783 }
784
786 && !ast_strlen_zero(snapshot->video_source_id)) {
787 ast_json_object_set(json_bridge, "video_source_id",
789 }
790
791 if (snapshot->bridgevars && !AST_LIST_EMPTY(snapshot->bridgevars)) {
792 ast_json_object_set(json_bridge, "bridgevars",
794 }
795
796 return json_bridge;
797}
798
799/*!
800 * \internal
801 * \brief Allocate the fields of an \ref ast_bridge_channel_snapshot_pair.
802 *
803 * \param channel, bridge A bridge and channel to get snapshots of
804 * \param[out] snapshot_pair An allocated snapshot pair.
805 * \retval 0 Success
806 * \retval non-zero Failure
807 */
808static int bridge_channel_snapshot_pair_init(struct ast_channel *channel, struct ast_bridge *bridge,
809 struct ast_bridge_channel_snapshot_pair *snapshot_pair)
810{
811 if (bridge) {
812 ast_bridge_lock(bridge);
813 snapshot_pair->bridge_snapshot = ast_bridge_snapshot_create(bridge);
814 ast_bridge_unlock(bridge);
815 if (!snapshot_pair->bridge_snapshot) {
816 return -1;
817 }
818 }
819
821 if (!snapshot_pair->channel_snapshot) {
822 return -1;
823 }
824
825 return 0;
826}
827
828/*!
829 * \internal
830 * \brief Free the fields of an \ref ast_bridge_channel_snapshot_pair.
831 *
832 * \param pair The snapshot pair whose fields are to be cleaned up
833 */
835{
836 ao2_cleanup(pair->bridge_snapshot);
837 ao2_cleanup(pair->channel_snapshot);
838}
839
840static const char *result_strs[] = {
841 [AST_BRIDGE_TRANSFER_FAIL] = "Fail",
842 [AST_BRIDGE_TRANSFER_INVALID] = "Invalid",
843 [AST_BRIDGE_TRANSFER_NOT_PERMITTED] = "Not Permitted",
844 [AST_BRIDGE_TRANSFER_SUCCESS] = "Success",
845};
846
848 const struct stasis_message_sanitizer *sanitize)
849{
850 struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
851 struct ast_json *json_transferer;
852 struct ast_json *json_transferee = NULL;
853 struct ast_json *out;
854 struct ast_json *json_replace = NULL;
855 const struct timeval *tv = stasis_message_timestamp(msg);
856
857 json_transferer = ast_channel_snapshot_to_json(transfer_msg->transferer, sanitize);
858 if (!json_transferer) {
859 return NULL;
860 }
861
862 if (transfer_msg->transferee) {
863 json_transferee = ast_channel_snapshot_to_json(transfer_msg->transferee, sanitize);
864 if (!json_transferee) {
865 ast_json_unref(json_transferer);
866 return NULL;
867 }
868 }
869
870 if (transfer_msg->replace_channel) {
871 json_replace = ast_channel_snapshot_to_json(transfer_msg->replace_channel, sanitize);
872 if (!json_replace) {
873 ast_json_unref(json_transferee);
874 ast_json_unref(json_transferer);
875 return NULL;
876 }
877 }
878
879 out = ast_json_pack("{s: s, s: o, s: o, s: s, s: s, s: s, s: o}",
880 "type", "BridgeBlindTransfer",
881 "timestamp", ast_json_timeval(*tv, NULL),
882 "channel", json_transferer,
883 "exten", transfer_msg->exten,
884 "context", transfer_msg->context,
885 "result", result_strs[transfer_msg->result],
886 "is_external", ast_json_boolean(transfer_msg->is_external));
887
888 if (!out) {
889 ast_json_unref(json_transferee);
890 ast_json_unref(json_replace);
891 return NULL;
892 }
893
894 if (json_transferee && ast_json_object_set(out, "transferee", json_transferee)) {
896 ast_json_unref(json_replace);
897 return NULL;
898 }
899
900 if (json_replace && ast_json_object_set(out, "replace_channel", json_replace)) {
902 return NULL;
903 }
904
905 if (transfer_msg->bridge) {
906 struct ast_json *json_bridge = ast_bridge_snapshot_to_json(
907 transfer_msg->bridge, sanitize);
908
909 if (!json_bridge || ast_json_object_set(out, "bridge", json_bridge)) {
911 return NULL;
912 }
913 }
914
915 return out;
916}
917
919{
920 RAII_VAR(struct ast_str *, transferer_state, NULL, ast_free_ptr);
921 RAII_VAR(struct ast_str *, bridge_state, NULL, ast_free_ptr);
922 RAII_VAR(struct ast_str *, transferee_state, NULL, ast_free_ptr);
923 struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
924
925 if (!transfer_msg) {
926 return NULL;
927 }
928
930 transfer_msg->transferer, "Transferer");
931 if (!transferer_state) {
932 return NULL;
933 }
934
935 if (transfer_msg->bridge) {
936 bridge_state = ast_manager_build_bridge_state_string(transfer_msg->bridge);
937 if (!bridge_state) {
938 return NULL;
939 }
940 }
941
942 if (transfer_msg->transferee) {
944 transfer_msg->transferee, "Transferee");
945 if (!transferee_state) {
946 return NULL;
947 }
948 }
949
950 return ast_manager_event_blob_create(EVENT_FLAG_CALL, "BlindTransfer",
951 "Result: %s\r\n"
952 "%s"
953 "%s"
954 "%s"
955 "IsExternal: %s\r\n"
956 "Context: %s\r\n"
957 "Extension: %s\r\n",
958 result_strs[transfer_msg->result],
959 ast_str_buffer(transferer_state),
960 transferee_state ? ast_str_buffer(transferee_state) : "",
961 bridge_state ? ast_str_buffer(bridge_state) : "",
962 transfer_msg->is_external ? "Yes" : "No",
963 transfer_msg->context,
964 transfer_msg->exten);
965}
966
967static void blind_transfer_dtor(void *obj)
968{
969 struct ast_blind_transfer_message *msg = obj;
970
972 ao2_cleanup(msg->bridge);
975}
976
978 struct ast_channel *transferer, const char *exten, const char *context)
979{
980 struct ast_blind_transfer_message *msg;
981
982 msg = ao2_alloc(sizeof(*msg), blind_transfer_dtor);
983 if (!msg) {
984 return NULL;
985 }
986
988 if (!msg->transferer) {
989 ao2_cleanup(msg);
990 return NULL;
991 }
992
994 ast_copy_string(msg->context, context, sizeof(msg->context));
995 ast_copy_string(msg->exten, exten, sizeof(msg->exten));
996
997 return msg;
998}
999
1000
1002{
1003 struct stasis_message *stasis;
1004
1006 if (!stasis) {
1007 return;
1008 }
1009
1011
1013}
1014
1016 const struct stasis_message_sanitizer *sanitize)
1017{
1018 struct ast_attended_transfer_message *transfer_msg = stasis_message_data(msg);
1020 struct ast_json *json_transferer1, *json_transferer2, *json_bridge, *json_channel;
1021 struct ast_json *json_transferee = NULL, *json_target = NULL;
1022 const struct timeval *tv = stasis_message_timestamp(msg);
1023 int res = 0;
1024
1025 json_transferer1 = ast_channel_snapshot_to_json(transfer_msg->to_transferee.channel_snapshot, sanitize);
1026 if (!json_transferer1) {
1027 return NULL;
1028 }
1029
1030 json_transferer2 = ast_channel_snapshot_to_json(transfer_msg->to_transfer_target.channel_snapshot, sanitize);
1031 if (!json_transferer2) {
1032 ast_json_unref(json_transferer1);
1033 return NULL;
1034 }
1035
1036 if (transfer_msg->transferee) {
1037 json_transferee = ast_channel_snapshot_to_json(transfer_msg->transferee, sanitize);
1038 if (!json_transferee) {
1039 ast_json_unref(json_transferer2);
1040 ast_json_unref(json_transferer1);
1041 return NULL;
1042 }
1043 }
1044
1045 if (transfer_msg->target) {
1046 json_target = ast_channel_snapshot_to_json(transfer_msg->target, sanitize);
1047 if (!json_target) {
1048 ast_json_unref(json_transferee);
1049 ast_json_unref(json_transferer2);
1050 ast_json_unref(json_transferer1);
1051 return NULL;
1052 }
1053 }
1054
1055 out = ast_json_pack("{s: s, s: o, s: o, s: o, s: s, s: o}",
1056 "type", "BridgeAttendedTransfer",
1057 "timestamp", ast_json_timeval(*tv, NULL),
1058 "transferer_first_leg", json_transferer1,
1059 "transferer_second_leg", json_transferer2,
1060 "result", result_strs[transfer_msg->result],
1061 "is_external", ast_json_boolean(transfer_msg->is_external));
1062 if (!out) {
1063 ast_json_unref(json_target);
1064 ast_json_unref(json_transferee);
1065 return NULL;
1066 }
1067 if (json_transferee && ast_json_object_set(out, "transferee", json_transferee)) {
1068 ast_json_unref(json_target);
1069 return NULL;
1070 }
1071 if (json_target && ast_json_object_set(out, "transfer_target", json_target)) {
1072 return NULL;
1073 }
1074
1075 if (transfer_msg->to_transferee.bridge_snapshot) {
1076 json_bridge = ast_bridge_snapshot_to_json(transfer_msg->to_transferee.bridge_snapshot, sanitize);
1077
1078 if (!json_bridge) {
1079 return NULL;
1080 }
1081
1082 res |= ast_json_object_set(out, "transferer_first_leg_bridge", json_bridge);
1083 }
1084
1085 if (transfer_msg->to_transfer_target.bridge_snapshot) {
1086 json_bridge = ast_bridge_snapshot_to_json(transfer_msg->to_transfer_target.bridge_snapshot, sanitize);
1087
1088 if (!json_bridge) {
1089 return NULL;
1090 }
1091
1092 res |= ast_json_object_set(out, "transferer_second_leg_bridge", json_bridge);
1093 }
1094
1095 switch (transfer_msg->dest_type) {
1097 res |= ast_json_object_set(out, "destination_type", ast_json_string_create("bridge"));
1098 res |= ast_json_object_set(out, "destination_bridge", ast_json_string_create(transfer_msg->dest.bridge));
1099 break;
1101 res |= ast_json_object_set(out, "replace_channel", ast_channel_snapshot_to_json(transfer_msg->replace_channel, sanitize));
1102 /* fallthrough */
1104 res |= ast_json_object_set(out, "destination_type", ast_json_string_create("application"));
1105 res |= ast_json_object_set(out, "destination_application", ast_json_string_create(transfer_msg->dest.app));
1106 break;
1108 res |= ast_json_object_set(out, "destination_type", ast_json_string_create("link"));
1109
1110 json_channel = ast_channel_snapshot_to_json(transfer_msg->dest.links[0], sanitize);
1111 if (!json_channel) {
1112 return NULL;
1113 }
1114 res |= ast_json_object_set(out, "destination_link_first_leg", json_channel);
1115
1116 json_channel = ast_channel_snapshot_to_json(transfer_msg->dest.links[1], sanitize);
1117 if (!json_channel) {
1118 return NULL;
1119 }
1120 res |= ast_json_object_set(out, "destination_link_second_leg", json_channel);
1121
1122 break;
1124 res |= ast_json_object_set(out, "destination_type", ast_json_string_create("threeway"));
1125
1126 json_channel = ast_channel_snapshot_to_json(transfer_msg->dest.threeway.channel_snapshot, sanitize);
1127 if (!json_channel) {
1128 return NULL;
1129 }
1130 res |= ast_json_object_set(out, "destination_threeway_channel", json_channel);
1131
1132 json_bridge = ast_bridge_snapshot_to_json(transfer_msg->dest.threeway.bridge_snapshot, sanitize);
1133 if (!json_bridge) {
1134 return NULL;
1135 }
1136 res |= ast_json_object_set(out, "destination_threeway_bridge", json_bridge);
1137
1138 break;
1140 res |= ast_json_object_set(out, "destination_type", ast_json_string_create("fail"));
1141 break;
1142 }
1143
1144 if (res) {
1145 return NULL;
1146 }
1147
1148 return ast_json_ref(out);
1149}
1150
1152{
1153 RAII_VAR(struct ast_str *, variable_data, ast_str_create(64), ast_free_ptr);
1154 RAII_VAR(struct ast_str *, transferer1_state, NULL, ast_free_ptr);
1155 RAII_VAR(struct ast_str *, bridge1_state, NULL, ast_free_ptr);
1156 RAII_VAR(struct ast_str *, transferer2_state, NULL, ast_free_ptr);
1157 RAII_VAR(struct ast_str *, bridge2_state, NULL, ast_free_ptr);
1158 RAII_VAR(struct ast_str *, local1_state, NULL, ast_free_ptr);
1159 RAII_VAR(struct ast_str *, local2_state, NULL, ast_free_ptr);
1160 RAII_VAR(struct ast_str *, transferee_state, NULL, ast_free_ptr);
1161 RAII_VAR(struct ast_str *, target_state, NULL, ast_free_ptr);
1162 struct ast_attended_transfer_message *transfer_msg = stasis_message_data(msg);
1163
1164 if (!variable_data) {
1165 return NULL;
1166 }
1167
1168 transferer1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transferee.channel_snapshot, "OrigTransferer");
1169 transferer2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transfer_target.channel_snapshot, "SecondTransferer");
1170 if (!transferer1_state || !transferer2_state) {
1171 return NULL;
1172 }
1173 if (transfer_msg->transferee) {
1174 transferee_state = ast_manager_build_channel_state_string_prefix(transfer_msg->transferee, "Transferee");
1175 if (!transferee_state) {
1176 return NULL;
1177 }
1178 }
1179
1180 if (transfer_msg->target) {
1181 target_state = ast_manager_build_channel_state_string_prefix(transfer_msg->target, "TransferTarget");
1182 if (!target_state) {
1183 return NULL;
1184 }
1185 }
1186
1187 if (transfer_msg->to_transferee.bridge_snapshot) {
1189 transfer_msg->to_transferee.bridge_snapshot, "Orig");
1190 if (!bridge1_state) {
1191 return NULL;
1192 }
1193 }
1194
1195 if (transfer_msg->to_transfer_target.bridge_snapshot) {
1197 transfer_msg->to_transfer_target.bridge_snapshot, "Second");
1198 if (!bridge2_state) {
1199 return NULL;
1200 }
1201 }
1202
1203 switch (transfer_msg->dest_type) {
1205 ast_str_append(&variable_data, 0, "DestType: Bridge\r\n");
1206 ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.bridge);
1207 break;
1210 ast_str_append(&variable_data, 0, "DestType: App\r\n");
1211 ast_str_append(&variable_data, 0, "DestApp: %s\r\n", transfer_msg->dest.app);
1212 break;
1214 local1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[0], "LocalOne");
1215 local2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[1], "LocalTwo");
1216 if (!local1_state || !local2_state) {
1217 return NULL;
1218 }
1219 ast_str_append(&variable_data, 0, "DestType: Link\r\n");
1220 ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local1_state));
1221 ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local2_state));
1222 break;
1224 ast_str_append(&variable_data, 0, "DestType: Threeway\r\n");
1225 ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.threeway.bridge_snapshot->uniqueid);
1226 ast_str_append(&variable_data, 0, "DestTransfererChannel: %s\r\n", transfer_msg->dest.threeway.channel_snapshot->base->name);
1227 break;
1229 ast_str_append(&variable_data, 0, "DestType: Fail\r\n");
1230 break;
1231 }
1232
1233 return ast_manager_event_blob_create(EVENT_FLAG_CALL, "AttendedTransfer",
1234 "Result: %s\r\n"
1235 "%s"
1236 "%s"
1237 "%s"
1238 "%s"
1239 "%s"
1240 "%s"
1241 "IsExternal: %s\r\n"
1242 "%s",
1243 result_strs[transfer_msg->result],
1244 ast_str_buffer(transferer1_state),
1245 bridge1_state ? ast_str_buffer(bridge1_state) : "",
1246 ast_str_buffer(transferer2_state),
1247 bridge2_state ? ast_str_buffer(bridge2_state) : "",
1248 transferee_state ? ast_str_buffer(transferee_state) : "",
1249 target_state ? ast_str_buffer(target_state) : "",
1250 transfer_msg->is_external ? "Yes" : "No",
1251 ast_str_buffer(variable_data));
1252}
1253
1254static void attended_transfer_dtor(void *obj)
1255{
1256 struct ast_attended_transfer_message *msg = obj;
1257 int i;
1258
1262 ao2_cleanup(msg->transferee);
1263 ao2_cleanup(msg->target);
1264
1266 return;
1267 }
1268
1269 for (i = 0; i < ARRAY_LEN(msg->dest.links); ++i) {
1270 ao2_cleanup(msg->dest.links[i]);
1271 }
1272}
1273
1275 struct ast_channel *to_transferee, struct ast_bridge *transferee_bridge,
1276 struct ast_channel *to_transfer_target, struct ast_bridge *target_bridge,
1277 struct ast_channel *transferee, struct ast_channel *transfer_target)
1278{
1279 struct ast_attended_transfer_message *transfer_msg;
1280
1281 transfer_msg = ao2_alloc(sizeof(*transfer_msg), attended_transfer_dtor);
1282 if (!transfer_msg) {
1283 return NULL;
1284 }
1285
1286 if (bridge_channel_snapshot_pair_init(to_transferee, transferee_bridge, &transfer_msg->to_transferee) ||
1288 ao2_cleanup(transfer_msg);
1289 return NULL;
1290 }
1291
1292 if (transferee) {
1294 if (!transfer_msg->transferee) {
1295 ao2_cleanup(transfer_msg);
1296 return NULL;
1297 }
1298 } else if (transferee_bridge) {
1299 transferee = ast_bridge_peer(transferee_bridge, to_transferee);
1300 if (transferee) {
1303 if (!transfer_msg->transferee) {
1304 ao2_cleanup(transfer_msg);
1305 return NULL;
1306 }
1307 }
1308 }
1309
1310 if (transfer_target) {
1311 transfer_msg->target = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transfer_target));
1312 if (!transfer_msg->target) {
1313 ao2_cleanup(transfer_msg);
1314 return NULL;
1315 }
1316 } else if (target_bridge) {
1317 transfer_target = ast_bridge_peer(target_bridge, to_transfer_target);
1318 if (transfer_target) {
1319 transfer_msg->target = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transfer_target));
1320 ao2_cleanup(transfer_target);
1321 if (!transfer_msg->target) {
1322 ao2_cleanup(transfer_msg);
1323 return NULL;
1324 }
1325 }
1326 }
1327
1328 return transfer_msg;
1329}
1330
1332 struct ast_bridge *final_bridge)
1333{
1335 ast_copy_string(transfer_msg->dest.bridge, final_bridge->uniqueid,
1336 sizeof(transfer_msg->dest.bridge));
1337
1338 return 0;
1339}
1340
1342 struct ast_channel *survivor_channel, struct ast_bridge *survivor_bridge)
1343{
1345
1346 if (!strcmp(ast_channel_uniqueid(survivor_channel), transfer_msg->to_transferee.channel_snapshot->base->uniqueid)) {
1347 transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transferee.channel_snapshot;
1348 } else {
1350 }
1351
1352 if (!strcmp(survivor_bridge->uniqueid, transfer_msg->to_transferee.bridge_snapshot->uniqueid)) {
1353 transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transferee.bridge_snapshot;
1354 } else {
1355 transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transfer_target.bridge_snapshot;
1356 }
1357
1358 return 0;
1359}
1360
1362 const char *app, struct ast_channel *replace_channel)
1363{
1365
1366 if (replace_channel) {
1368 if (!transfer_msg->replace_channel) {
1369 return -1;
1370 }
1371 }
1372
1373 ast_copy_string(transfer_msg->dest.app, app, sizeof(transfer_msg->dest.app));
1374
1375 return 0;
1376}
1377
1379 struct ast_channel *locals[2])
1380{
1381 int i;
1382
1384 for (i = 0; i < 2; ++i) {
1386 if (!transfer_msg->dest.links[i]) {
1387 return -1;
1388 }
1389 }
1390
1391 return 0;
1392}
1393
1395{
1396 struct stasis_message *msg;
1397
1399 if (!msg) {
1400 return;
1401 }
1402
1404 ao2_ref(msg, -1);
1405}
1406
1408{
1409 struct ast_bridge *bridge;
1410 struct ast_bridge_snapshot *snapshot;
1411
1413
1415 if (!bridge) {
1416 return NULL;
1417 }
1418 ast_bridge_lock(bridge);
1419 snapshot = ao2_bump(bridge->current_snapshot);
1420 ast_bridge_unlock(bridge);
1421 ao2_ref(bridge, -1);
1422
1423 return snapshot;
1424}
1425
1427{
1428 struct ast_bridge_snapshot *snapshot;
1429
1430 if (!bridge) {
1431 return NULL;
1432 }
1433 ast_bridge_lock(bridge);
1434 snapshot = ao2_bump(bridge->current_snapshot);
1435 ast_bridge_unlock(bridge);
1436
1437 return snapshot;
1438}
1439
1454
static const char app[]
static const char * stasis
Dialplan application name.
Definition app_stasis.c:85
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:491
struct varshead * ast_bridge_get_ari_reportable_variables(struct ast_bridge *bridge)
Get a list of variables that should be included in ARI events for this bridge.
Definition bridge.c:1385
@ 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:5221
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:4284
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:4160
@ AST_BRIDGE_TRANSFER_NOT_PERMITTED
Definition bridge.h:1163
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition bridge.h:1161
@ AST_BRIDGE_TRANSFER_INVALID
Definition bridge.h:1165
@ AST_BRIDGE_TRANSFER_FAIL
Definition bridge.h:1167
@ 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:480
#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[]
General Asterisk PBX channel definitions.
const char * ast_channel_uniqueid(const struct ast_channel *chan)
void ast_var_list_destroy(struct varshead *head)
Definition chanvars.c:109
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
Asterisk JSON abstraction layer.
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
struct ast_json * ast_json_channel_vars(struct varshead *channelvars)
Construct a JSON object from a ast_var_t list.
Definition json.c:941
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
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:10198
#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:1960
const char * stasis_topic_name(const struct stasis_topic *topic)
Return the name of a topic.
Definition stasis.c:694
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition stasis.h:1546
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:1996
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition stasis.c:684
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition stasis.h:1524
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:2139
#define STASIS_MESSAGE_TYPE_DEFN(name,...)
Boiler-plate messaging macro for defining public message types.
Definition stasis.h:1471
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:1929
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition stasis.c:1589
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.
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.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
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
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
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
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
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
union ast_attended_transfer_message::@303 dest
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
struct ast_bridge_channel::@201 entry
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
struct varshead * bridgevars
Definition bridge.h:349
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::@198 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:355
struct stasis_topic * topic
Definition bridge.h:365
struct ast_bridge_softmix softmix
Definition bridge.h:373
struct timeval creationtime
Definition bridge.h:414
const struct ast_bridge_methods * v_table
Definition bridge.h:357
unsigned int num_active
Definition bridge.h:381
const ast_string_field creator
Definition bridge.h:407
const ast_string_field uniqueid
Definition bridge.h:407
struct ast_bridge_channels_list channels
Definition bridge.h:369
struct ast_bridge_snapshot * current_snapshot
Definition bridge.h:412
unsigned int num_channels
Definition bridge.h:379
struct ast_bridge_technology * technology
Definition bridge.h:361
const ast_string_field name
Definition bridge.h:407
struct ast_flags feature_flags
Definition bridge.h:375
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:504
Support for dynamic strings.
Definition strings.h:623
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
FILE * out
Definition utils/frame.c:33
#define ast_test_flag(p, flag)
Definition utils.h:64
#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:981
#define ast_assert(a)
Definition utils.h:779
#define ARRAY_LEN(a)
Definition utils.h:706