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