2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2013, Digium, Inc.
6 * Kinsey Moore <kmoore@digium.com>
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.
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.
21 * \brief Stasis Messages and Data Types for Bridge Objects
23 * \author Kinsey Moore <kmoore@digium.com>
27 <support_level>core</support_level>
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34 #include "asterisk/astobj2.h"
35 #include "asterisk/stasis.h"
36 #include "asterisk/stasis_cache_pattern.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/stasis_bridges.h"
39 #include "asterisk/stasis_channels.h"
40 #include "asterisk/bridge.h"
41 #include "asterisk/bridge_technology.h"
43 /* The container of channel snapshots in a bridge snapshot should always be
44 equivalent to a linked list; otherwise things (like CDRs) that depend on some
45 consistency in the ordering of channels in a bridge will break. */
46 #define SNAPSHOT_CHANNELS_BUCKETS 1
49 <managerEvent language="en_US" name="BlindTransfer">
50 <managerEventInstance class="EVENT_FLAG_CALL">
51 <synopsis>Raised when a blind transfer is complete.</synopsis>
53 <parameter name="Result">
54 <para>Indicates if the transfer was successful or if it failed.</para>
56 <enum name="Fail"><para>An internal error occurred.</para></enum>
57 <enum name="Invalid"><para>Invalid configuration for transfer (e.g. Not bridged)</para></enum>
58 <enum name="Not Permitted"><para>Bridge does not permit transfers</para></enum>
59 <enum name="Success"><para>Transfer completed successfully</para></enum>
61 <note><para>A result of <literal>Success</literal> does not necessarily mean that a target was succesfully
62 contacted. It means that a party was succesfully placed into the dialplan at the expected location.</para></note>
64 <channel_snapshot prefix="Transferer"/>
66 <parameter name="IsExternal">
67 <para>Indicates if the transfer was performed outside of Asterisk. For instance,
68 a channel protocol native transfer is external. A DTMF transfer is internal.</para>
74 <parameter name="Context">
75 <para>Destination context for the blind transfer.</para>
77 <parameter name="Extension">
78 <para>Destination extension for the blind transfer.</para>
81 </managerEventInstance>
83 <managerEvent language="en_US" name="AttendedTransfer">
84 <managerEventInstance class="EVENT_FLAG_CALL">
85 <synopsis>Raised when an attended transfer is complete.</synopsis>
87 <xi:include xpointer="xpointer(docs/managerEvent[@name='BlindTransfer']/managerEventInstance/syntax/parameter[@name='Result'])" />
88 <channel_snapshot prefix="OrigTransferer"/>
89 <bridge_snapshot prefix="Orig"/>
90 <channel_snapshot prefix="SecondTransferer"/>
91 <bridge_snapshot prefix="Second"/>
92 <parameter name="DestType">
93 <para>Indicates the method by which the attended transfer completed.</para>
95 <enum name="Bridge"><para>The transfer was accomplished by merging two bridges into one.</para></enum>
96 <enum name="App"><para>The transfer was accomplished by having a channel or bridge run a dialplan application.</para></enum>
97 <enum name="Link"><para>The transfer was accomplished by linking two bridges together using a local channel pair.</para></enum>
98 <enum name="Threeway"><para>The transfer was accomplished by placing all parties into a threeway call.</para></enum>
99 <enum name="Fail"><para>The transfer failed.</para></enum>
102 <parameter name="DestBridgeUniqueid">
103 <para>Indicates the surviving bridge when bridges were merged to complete the transfer</para>
104 <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Bridge</literal> or <literal>Threeway</literal></para></note>
106 <parameter name="DestApp">
107 <para>Indicates the application that is running when the transfer completes</para>
108 <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>App</literal></para></note>
110 <channel_snapshot prefix="LocalOne"/>
111 <channel_snapshot prefix="LocalTwo"/>
112 <parameter name="DestTransfererChannel">
113 <para>The name of the surviving transferer channel when a transfer results in a threeway call</para>
114 <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Threeway</literal></para></note>
118 <para>The headers in this event attempt to describe all the major details of the attended transfer. The two transferer channels
119 and the two bridges are determined based on their chronological establishment. So consider that Alice calls Bob, and then Alice
120 transfers the call to Voicemail. The transferer and bridge headers would be arranged as follows:</para>
121 <para> <replaceable>OrigTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
122 <para> <replaceable>OrigBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
123 <para> <replaceable>SecondTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
124 <para> <replaceable>SecondBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
125 <para>Now consider if the order were reversed; instead of having Alice call Bob and transfer him to Voicemail, Alice instead
126 calls her Voicemail and transfers that to Bob. The transferer and bridge headers would be arranged as follows:</para>
127 <para> <replaceable>OrigTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
128 <para> <replaceable>OrigBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
129 <para> <replaceable>SecondTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
130 <para> <replaceable>SecondBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
132 </managerEventInstance>
136 static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_message *message);
137 static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *message);
138 static struct ast_json *ast_channel_entered_bridge_to_json(
139 struct stasis_message *msg,
140 const struct stasis_message_sanitizer *sanitize);
141 static struct ast_json *ast_channel_left_bridge_to_json(
142 struct stasis_message *msg,
143 const struct stasis_message_sanitizer *sanitize);
144 static struct ast_json *ast_bridge_merge_message_to_json(
145 struct stasis_message *msg,
146 const struct stasis_message_sanitizer *sanitize);
148 static struct stasis_cp_all *bridge_cache_all;
151 * @{ \brief Define bridge message types.
153 STASIS_MESSAGE_TYPE_DEFN(ast_bridge_snapshot_type);
154 STASIS_MESSAGE_TYPE_DEFN(ast_bridge_merge_message_type,
155 .to_json = ast_bridge_merge_message_to_json);
156 STASIS_MESSAGE_TYPE_DEFN(ast_channel_entered_bridge_type,
157 .to_json = ast_channel_entered_bridge_to_json);
158 STASIS_MESSAGE_TYPE_DEFN(ast_channel_left_bridge_type,
159 .to_json = ast_channel_left_bridge_to_json);
160 STASIS_MESSAGE_TYPE_DEFN(ast_blind_transfer_type, .to_ami = blind_transfer_to_ami);
161 STASIS_MESSAGE_TYPE_DEFN(ast_attended_transfer_type, .to_ami = attended_transfer_to_ami);
164 struct stasis_cache *ast_bridge_cache(void)
166 return stasis_cp_all_cache(bridge_cache_all);
169 struct stasis_topic *ast_bridge_topic_all(void)
171 return stasis_cp_all_topic(bridge_cache_all);
174 struct stasis_topic *ast_bridge_topic_all_cached(void)
176 return stasis_cp_all_topic_cached(bridge_cache_all);
179 int bridge_topics_init(struct ast_bridge *bridge)
181 if (ast_strlen_zero(bridge->uniqueid)) {
182 ast_log(LOG_ERROR, "Bridge id initialization required\n");
185 bridge->topics = stasis_cp_single_create(bridge_cache_all,
187 if (!bridge->topics) {
193 struct stasis_topic *ast_bridge_topic(struct ast_bridge *bridge)
196 return ast_bridge_topic_all();
199 return stasis_cp_single_topic(bridge->topics);
202 struct stasis_topic *ast_bridge_topic_cached(struct ast_bridge *bridge)
205 return ast_bridge_topic_all_cached();
208 return stasis_cp_single_topic_cached(bridge->topics);
211 /*! \brief Destructor for bridge snapshots */
212 static void bridge_snapshot_dtor(void *obj)
214 struct ast_bridge_snapshot *snapshot = obj;
215 ast_string_field_free_memory(snapshot);
216 ao2_cleanup(snapshot->channels);
217 snapshot->channels = NULL;
220 struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge)
222 RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
223 struct ast_bridge_channel *bridge_channel;
225 snapshot = ao2_alloc(sizeof(*snapshot), bridge_snapshot_dtor);
226 if (!snapshot || ast_string_field_init(snapshot, 128)) {
230 snapshot->channels = ast_str_container_alloc(SNAPSHOT_CHANNELS_BUCKETS);
231 if (!snapshot->channels) {
235 AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
236 if (ast_str_container_add(snapshot->channels,
237 ast_channel_uniqueid(bridge_channel->chan))) {
242 ast_string_field_set(snapshot, uniqueid, bridge->uniqueid);
243 ast_string_field_set(snapshot, technology, bridge->technology->name);
244 ast_string_field_set(snapshot, subclass, bridge->v_table->name);
246 snapshot->feature_flags = bridge->feature_flags;
247 snapshot->capabilities = bridge->technology->capabilities;
248 snapshot->num_channels = bridge->num_channels;
249 snapshot->num_active = bridge->num_active;
251 ao2_ref(snapshot, +1);
255 void ast_bridge_publish_state(struct ast_bridge *bridge)
257 RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
258 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
260 ast_assert(bridge != NULL);
262 snapshot = ast_bridge_snapshot_create(bridge);
267 msg = stasis_message_create(ast_bridge_snapshot_type(), snapshot);
272 stasis_publish(ast_bridge_topic(bridge), msg);
275 static void bridge_publish_state_from_blob(struct ast_bridge *bridge,
276 struct ast_bridge_blob *obj)
278 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
280 ast_assert(obj != NULL);
282 msg = stasis_message_create(ast_bridge_snapshot_type(), obj->bridge);
287 stasis_publish(ast_bridge_topic(bridge), msg);
290 /*! \brief Destructor for bridge merge messages */
291 static void bridge_merge_message_dtor(void *obj)
293 struct ast_bridge_merge_message *msg = obj;
295 ao2_cleanup(msg->to);
297 ao2_cleanup(msg->from);
301 /*! \brief Bridge merge message creation helper */
302 static struct ast_bridge_merge_message *bridge_merge_message_create(struct ast_bridge *to, struct ast_bridge *from)
304 RAII_VAR(struct ast_bridge_merge_message *, msg, NULL, ao2_cleanup);
306 msg = ao2_alloc(sizeof(*msg), bridge_merge_message_dtor);
311 msg->to = ast_bridge_snapshot_create(to);
316 msg->from = ast_bridge_snapshot_create(from);
325 static struct ast_json *ast_bridge_merge_message_to_json(
326 struct stasis_message *msg,
327 const struct stasis_message_sanitizer *sanitize)
329 struct ast_bridge_merge_message *merge = stasis_message_data(msg);
330 RAII_VAR(struct ast_json *, json_bridge_to,
331 ast_bridge_snapshot_to_json(merge->to, sanitize), ast_json_unref);
332 RAII_VAR(struct ast_json *, json_bridge_from,
333 ast_bridge_snapshot_to_json(merge->from, sanitize), ast_json_unref);
335 if (!json_bridge_to || !json_bridge_from) {
339 return ast_json_pack("{s: s, s: o, s: O, s: O}",
340 "type", "BridgeMerged",
341 "timestamp", ast_json_timeval(*stasis_message_timestamp(msg), NULL),
342 "bridge", json_bridge_to,
343 "bridge_from", json_bridge_from);
346 void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
348 RAII_VAR(struct ast_bridge_merge_message *, merge_msg, NULL, ao2_cleanup);
349 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
351 ast_assert(to != NULL);
352 ast_assert(from != NULL);
354 merge_msg = bridge_merge_message_create(to, from);
359 msg = stasis_message_create(ast_bridge_merge_message_type(), merge_msg);
364 stasis_publish(ast_bridge_topic_all(), msg);
367 static void bridge_blob_dtor(void *obj)
369 struct ast_bridge_blob *event = obj;
370 ao2_cleanup(event->bridge);
371 event->bridge = NULL;
372 ao2_cleanup(event->channel);
373 event->channel = NULL;
374 ast_json_unref(event->blob);
378 struct stasis_message *ast_bridge_blob_create(
379 struct stasis_message_type *message_type,
380 struct ast_bridge *bridge,
381 struct ast_channel *chan,
382 struct ast_json *blob)
384 RAII_VAR(struct ast_bridge_blob *, obj, NULL, ao2_cleanup);
385 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
387 obj = ao2_alloc(sizeof(*obj), bridge_blob_dtor);
393 obj->bridge = ast_bridge_snapshot_create(bridge);
394 if (obj->bridge == NULL) {
400 obj->channel = ast_channel_snapshot_create(chan);
401 if (obj->channel == NULL) {
407 obj->blob = ast_json_ref(blob);
410 msg = stasis_message_create(message_type, obj);
419 void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan,
420 struct ast_channel *swap)
422 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
423 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
426 blob = ast_json_pack("{s: s}", "swap", ast_channel_uniqueid(swap));
432 msg = ast_bridge_blob_create(ast_channel_entered_bridge_type(), bridge, chan, blob);
437 /* enter blob first, then state */
438 stasis_publish(ast_bridge_topic(bridge), msg);
439 bridge_publish_state_from_blob(bridge, stasis_message_data(msg));
442 void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *chan)
444 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
446 msg = ast_bridge_blob_create(ast_channel_left_bridge_type(), bridge, chan, NULL);
451 /* state first, then leave blob (opposite of enter, preserves nesting of events) */
452 bridge_publish_state_from_blob(bridge, stasis_message_data(msg));
453 stasis_publish(ast_bridge_topic(bridge), msg);
456 static struct ast_json *simple_bridge_channel_event(
458 struct ast_bridge_snapshot *bridge_snapshot,
459 struct ast_channel_snapshot *channel_snapshot,
460 const struct timeval *tv,
461 const struct stasis_message_sanitizer *sanitize)
463 RAII_VAR(struct ast_json *, json_bridge,
464 ast_bridge_snapshot_to_json(bridge_snapshot, sanitize), ast_json_unref);
465 RAII_VAR(struct ast_json *, json_channel,
466 ast_channel_snapshot_to_json(channel_snapshot, sanitize), ast_json_unref);
468 if (!json_bridge || !json_channel) {
472 return ast_json_pack("{s: s, s: o, s: O, s: O}",
474 "timestamp", ast_json_timeval(*tv, NULL),
475 "bridge", json_bridge,
476 "channel", json_channel);
479 struct ast_json *ast_channel_entered_bridge_to_json(
480 struct stasis_message *msg,
481 const struct stasis_message_sanitizer *sanitize)
483 struct ast_bridge_blob *obj = stasis_message_data(msg);
485 return simple_bridge_channel_event("ChannelEnteredBridge", obj->bridge,
486 obj->channel, stasis_message_timestamp(msg), sanitize);
489 struct ast_json *ast_channel_left_bridge_to_json(
490 struct stasis_message *msg,
491 const struct stasis_message_sanitizer *sanitize)
493 struct ast_bridge_blob *obj = stasis_message_data(msg);
495 return simple_bridge_channel_event("ChannelLeftBridge", obj->bridge,
496 obj->channel, stasis_message_timestamp(msg), sanitize);
499 static struct ast_json *container_to_json_array(struct ao2_container *items,
500 const struct stasis_message_sanitizer *sanitize)
502 RAII_VAR(struct ast_json *, json_items, ast_json_array_create(), ast_json_unref);
504 struct ao2_iterator it;
509 for (it = ao2_iterator_init(items, 0);
510 (item = ao2_iterator_next(&it)); ao2_cleanup(item)) {
511 if (sanitize && sanitize->channel_id && sanitize->channel_id(item)) {
515 if (ast_json_array_append(json_items, ast_json_string_create(item))) {
517 ao2_iterator_destroy(&it);
521 ao2_iterator_destroy(&it);
523 return ast_json_ref(json_items);
526 static const char *capability2str(uint32_t capabilities)
528 if (capabilities & AST_BRIDGE_CAPABILITY_HOLDING) {
535 struct ast_json *ast_bridge_snapshot_to_json(
536 const struct ast_bridge_snapshot *snapshot,
537 const struct stasis_message_sanitizer *sanitize)
539 RAII_VAR(struct ast_json *, json_bridge, NULL, ast_json_unref);
540 struct ast_json *json_channels;
542 if (snapshot == NULL) {
546 json_channels = container_to_json_array(snapshot->channels, sanitize);
547 if (!json_channels) {
551 json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: o}",
552 "id", snapshot->uniqueid,
553 "technology", snapshot->technology,
554 "bridge_type", capability2str(snapshot->capabilities),
555 "bridge_class", snapshot->subclass,
556 "channels", json_channels);
561 return ast_json_ref(json_bridge);
566 * \brief Allocate the fields of an \ref ast_bridge_channel_snapshot_pair.
568 * \param pair A bridge and channel to get snapshots of
569 * \param[out] snapshot_pair An allocated snapshot pair.
571 * \retval non-zero Failure
573 static int bridge_channel_snapshot_pair_init(struct ast_bridge_channel_pair *pair, struct ast_bridge_channel_snapshot_pair *snapshot_pair)
576 snapshot_pair->bridge_snapshot = ast_bridge_snapshot_create(pair->bridge);
577 if (!snapshot_pair->bridge_snapshot) {
582 snapshot_pair->channel_snapshot = ast_channel_snapshot_create(pair->channel);
583 if (!snapshot_pair->channel_snapshot) {
592 * \brief Free the fields of an \ref ast_bridge_channel_snapshot_pair.
594 * \param pair The snapshot pair whose fields are to be cleaned up
596 static void bridge_channel_snapshot_pair_cleanup(struct ast_bridge_channel_snapshot_pair *pair)
598 ao2_cleanup(pair->bridge_snapshot);
599 ao2_cleanup(pair->channel_snapshot);
602 static const char *result_strs[] = {
603 [AST_BRIDGE_TRANSFER_FAIL] = "Fail",
604 [AST_BRIDGE_TRANSFER_INVALID] = "Invalid",
605 [AST_BRIDGE_TRANSFER_NOT_PERMITTED] = "Not Permitted",
606 [AST_BRIDGE_TRANSFER_SUCCESS] = "Success",
609 static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *msg)
611 RAII_VAR(struct ast_str *, channel_state, NULL, ast_free_ptr);
612 RAII_VAR(struct ast_str *, bridge_state, NULL, ast_free_ptr);
613 struct ast_bridge_blob *blob = stasis_message_data(msg);
616 enum ast_transfer_result result;
623 channel_state = ast_manager_build_channel_state_string_prefix(blob->channel, "Transferer");
624 if (!channel_state) {
629 bridge_state = ast_manager_build_bridge_state_string(blob->bridge);
635 exten = ast_json_string_get(ast_json_object_get(blob->blob, "exten"));
636 context = ast_json_string_get(ast_json_object_get(blob->blob, "context"));
637 result = ast_json_integer_get(ast_json_object_get(blob->blob, "result"));
638 is_external = ast_json_integer_get(ast_json_object_get(blob->blob, "is_external"));
640 return ast_manager_event_blob_create(EVENT_FLAG_CALL, "BlindTransfer",
648 ast_str_buffer(channel_state),
649 bridge_state ? ast_str_buffer(bridge_state) : "",
650 is_external ? "Yes" : "No",
655 void ast_bridge_publish_blind_transfer(int is_external, enum ast_transfer_result result,
656 struct ast_bridge_channel_pair *transferer, const char *context, const char *exten)
658 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
659 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
661 json_object = ast_json_pack("{s: s, s: s, s: i, s: i}",
662 "context", context, "exten", exten, "result", result, "is_external", is_external);
665 ast_log(LOG_NOTICE, "Failed to create json bridge blob\n");
669 msg = ast_bridge_blob_create(ast_blind_transfer_type(),
670 transferer->bridge, transferer->channel, json_object);
673 ast_log(LOG_NOTICE, "Failed to create blob msg\n");
677 stasis_publish(ast_bridge_topic_all(), msg);
680 static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_message *msg)
682 RAII_VAR(struct ast_str *, variable_data, ast_str_create(64), ast_free_ptr);
683 RAII_VAR(struct ast_str *, transferer1_state, NULL, ast_free_ptr);
684 RAII_VAR(struct ast_str *, bridge1_state, NULL, ast_free_ptr);
685 RAII_VAR(struct ast_str *, transferer2_state, NULL, ast_free_ptr);
686 RAII_VAR(struct ast_str *, bridge2_state, NULL, ast_free_ptr);
687 RAII_VAR(struct ast_str *, local1_state, NULL, ast_free_ptr);
688 RAII_VAR(struct ast_str *, local2_state, NULL, ast_free_ptr);
689 struct ast_attended_transfer_message *transfer_msg = stasis_message_data(msg);
691 if (!variable_data) {
695 transferer1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transferee.channel_snapshot, "OrigTransferer");
696 transferer2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transfer_target.channel_snapshot, "SecondTransferer");
697 if (!transferer1_state || !transferer2_state) {
701 if (transfer_msg->to_transferee.bridge_snapshot) {
702 bridge1_state = ast_manager_build_bridge_state_string_prefix(
703 transfer_msg->to_transferee.bridge_snapshot, "Orig");
704 if (!bridge1_state) {
709 if (transfer_msg->to_transfer_target.bridge_snapshot) {
710 bridge2_state = ast_manager_build_bridge_state_string_prefix(
711 transfer_msg->to_transfer_target.bridge_snapshot, "Second");
712 if (!bridge2_state) {
717 switch (transfer_msg->dest_type) {
718 case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
719 ast_str_append(&variable_data, 0, "DestType: Bridge\r\n");
720 ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.bridge);
722 case AST_ATTENDED_TRANSFER_DEST_APP:
723 ast_str_append(&variable_data, 0, "DestType: App\r\n");
724 ast_str_append(&variable_data, 0, "DestApp: %s\r\n", transfer_msg->dest.app);
726 case AST_ATTENDED_TRANSFER_DEST_LINK:
727 local1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[0], "LocalOne");
728 local2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[1], "LocalTwo");
729 if (!local1_state || !local2_state) {
732 ast_str_append(&variable_data, 0, "DestType: Link\r\n");
733 ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local1_state));
734 ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local2_state));
736 case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
737 ast_str_append(&variable_data, 0, "DestType: Threeway\r\n");
738 ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.threeway.bridge_snapshot->uniqueid);
739 ast_str_append(&variable_data, 0, "DestTransfererChannel: %s\r\n", transfer_msg->dest.threeway.channel_snapshot->name);
741 case AST_ATTENDED_TRANSFER_DEST_FAIL:
742 ast_str_append(&variable_data, 0, "DestType: Fail\r\n");
746 return ast_manager_event_blob_create(EVENT_FLAG_CALL, "AttendedTransfer",
754 result_strs[transfer_msg->result],
755 ast_str_buffer(transferer1_state),
756 bridge1_state ? ast_str_buffer(bridge1_state) : "",
757 ast_str_buffer(transferer2_state),
758 bridge2_state ? ast_str_buffer(bridge2_state) : "",
759 transfer_msg->is_external ? "Yes" : "No",
760 ast_str_buffer(variable_data));
763 static void attended_transfer_dtor(void *obj)
765 struct ast_attended_transfer_message *msg = obj;
768 bridge_channel_snapshot_pair_cleanup(&msg->to_transferee);
769 bridge_channel_snapshot_pair_cleanup(&msg->to_transfer_target);
771 if (msg->dest_type != AST_ATTENDED_TRANSFER_DEST_LINK) {
775 for (i = 0; i < ARRAY_LEN(msg->dest.links); ++i) {
776 ao2_cleanup(msg->dest.links[i]);
780 static struct ast_attended_transfer_message *attended_transfer_message_create(int is_external, enum ast_transfer_result result,
781 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target)
783 RAII_VAR(struct ast_attended_transfer_message *, msg, NULL, ao2_cleanup);
785 msg = ao2_alloc(sizeof(*msg), attended_transfer_dtor);
790 if (bridge_channel_snapshot_pair_init(transferee, &msg->to_transferee) ||
791 bridge_channel_snapshot_pair_init(target, &msg->to_transfer_target)) {
795 msg->is_external = is_external;
796 msg->result = result;
802 void ast_bridge_publish_attended_transfer_fail(int is_external, enum ast_transfer_result result,
803 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target)
805 RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
806 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
808 transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
813 transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_FAIL;
815 msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
820 stasis_publish(ast_bridge_topic_all(), msg);
823 void ast_bridge_publish_attended_transfer_bridge_merge(int is_external, enum ast_transfer_result result,
824 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
825 struct ast_bridge *final_bridge)
827 RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
828 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
830 transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
835 transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE;
836 ast_copy_string(transfer_msg->dest.bridge, final_bridge->uniqueid,
837 sizeof(transfer_msg->dest.bridge));
839 msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
844 stasis_publish(ast_bridge_topic_all(), msg);
847 void ast_bridge_publish_attended_transfer_threeway(int is_external, enum ast_transfer_result result,
848 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
849 struct ast_bridge_channel_pair *final_pair)
851 RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
852 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
854 transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
859 transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_THREEWAY;
860 if (final_pair->channel == transferee->channel) {
861 transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transferee.channel_snapshot;
863 transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transfer_target.channel_snapshot;
866 if (final_pair->bridge == transferee->bridge) {
867 transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transferee.bridge_snapshot;
869 transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transfer_target.bridge_snapshot;
872 msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
877 stasis_publish(ast_bridge_topic_all(), msg);
880 void ast_bridge_publish_attended_transfer_app(int is_external, enum ast_transfer_result result,
881 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
882 const char *dest_app)
884 RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
885 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
887 transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
892 transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_APP;
893 ast_copy_string(transfer_msg->dest.app, dest_app, sizeof(transfer_msg->dest.app));
895 msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
900 stasis_publish(ast_bridge_topic_all(), msg);
903 void ast_bridge_publish_attended_transfer_link(int is_external, enum ast_transfer_result result,
904 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
905 struct ast_channel *locals[2])
907 RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
908 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
911 transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
916 transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_LINK;
917 for (i = 0; i < 2; ++i) {
918 transfer_msg->dest.links[i] = ast_channel_snapshot_create(locals[i]);
919 if (!transfer_msg->dest.links[i]) {
924 msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
929 stasis_publish(ast_bridge_topic_all(), msg);
932 struct ast_bridge_snapshot *ast_bridge_snapshot_get_latest(const char *uniqueid)
934 RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
935 struct ast_bridge_snapshot *snapshot;
937 ast_assert(!ast_strlen_zero(uniqueid));
939 message = stasis_cache_get(ast_bridge_cache(),
940 ast_bridge_snapshot_type(),
946 snapshot = stasis_message_data(message);
950 ao2_ref(snapshot, +1);
954 /*! \brief snapshot ID getter for caching topic */
955 static const char *bridge_snapshot_get_id(struct stasis_message *msg)
957 struct ast_bridge_snapshot *snapshot;
958 if (stasis_message_type(msg) != ast_bridge_snapshot_type()) {
961 snapshot = stasis_message_data(msg);
962 return snapshot->uniqueid;
965 static void stasis_bridging_cleanup(void)
967 STASIS_MESSAGE_TYPE_CLEANUP(ast_bridge_snapshot_type);
968 STASIS_MESSAGE_TYPE_CLEANUP(ast_bridge_merge_message_type);
969 STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_entered_bridge_type);
970 STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_left_bridge_type);
971 STASIS_MESSAGE_TYPE_CLEANUP(ast_blind_transfer_type);
972 STASIS_MESSAGE_TYPE_CLEANUP(ast_attended_transfer_type);
974 ao2_cleanup(bridge_cache_all);
975 bridge_cache_all = NULL;
978 int ast_stasis_bridging_init(void)
982 ast_register_cleanup(stasis_bridging_cleanup);
984 bridge_cache_all = stasis_cp_all_create("ast_bridge_topic_all",
985 bridge_snapshot_get_id);
987 if (!bridge_cache_all) {
991 res |= STASIS_MESSAGE_TYPE_INIT(ast_bridge_snapshot_type);
992 res |= STASIS_MESSAGE_TYPE_INIT(ast_bridge_merge_message_type);
993 res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_entered_bridge_type);
994 res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_left_bridge_type);
995 res |= STASIS_MESSAGE_TYPE_INIT(ast_blind_transfer_type);
996 res |= STASIS_MESSAGE_TYPE_INIT(ast_attended_transfer_type);