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 #define SNAPSHOT_CHANNELS_BUCKETS 13
46 <managerEvent language="en_US" name="BlindTransfer">
47 <managerEventInstance class="EVENT_FLAG_CALL">
48 <synopsis>Raised when a blind transfer is complete.</synopsis>
50 <parameter name="Result">
51 <para>Indicates if the transfer was successful or if it failed.</para>
53 <enum name="Fail"><para>An internal error occurred.</para></enum>
54 <enum name="Invalid"><para>Invalid configuration for transfer (e.g. Not bridged)</para></enum>
55 <enum name="Not Permitted"><para>Bridge does not permit transfers</para></enum>
56 <enum name="Success"><para>Transfer completed successfully</para></enum>
58 <note><para>A result of <literal>Success</literal> does not necessarily mean that a target was succesfully
59 contacted. It means that a party was succesfully placed into the dialplan at the expected location.</para></note>
61 <channel_snapshot prefix="Transferer"/>
63 <parameter name="IsExternal">
64 <para>Indicates if the transfer was performed outside of Asterisk. For instance,
65 a channel protocol native transfer is external. A DTMF transfer is internal.</para>
71 <parameter name="Context">
72 <para>Destination context for the blind transfer.</para>
74 <parameter name="Extension">
75 <para>Destination extension for the blind transfer.</para>
78 </managerEventInstance>
80 <managerEvent language="en_US" name="AttendedTransfer">
81 <managerEventInstance class="EVENT_FLAG_CALL">
82 <synopsis>Raised when an attended transfer is complete.</synopsis>
84 <xi:include xpointer="xpointer(docs/managerEvent[@name='BlindTransfer']/managerEventInstance/syntax/parameter[@name='Result'])" />
85 <channel_snapshot prefix="OrigTransferer"/>
86 <bridge_snapshot prefix="Orig"/>
87 <channel_snapshot prefix="SecondTransferer"/>
88 <bridge_snapshot prefix="Second"/>
89 <parameter name="DestType">
90 <para>Indicates the method by which the attended transfer completed.</para>
92 <enum name="Bridge"><para>The transfer was accomplished by merging two bridges into one.</para></enum>
93 <enum name="App"><para>The transfer was accomplished by having a channel or bridge run a dialplan application.</para></enum>
94 <enum name="Link"><para>The transfer was accomplished by linking two bridges together using a local channel pair.</para></enum>
95 <enum name="Threeway"><para>The transfer was accomplished by placing all parties into a threeway call.</para></enum>
96 <enum name="Fail"><para>The transfer failed.</para></enum>
99 <parameter name="DestBridgeUniqueid">
100 <para>Indicates the surviving bridge when bridges were merged to complete the transfer</para>
101 <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Bridge</literal> or <literal>Threeway</literal></para></note>
103 <parameter name="DestApp">
104 <para>Indicates the application that is running when the transfer completes</para>
105 <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>App</literal></para></note>
107 <channel_snapshot prefix="LocalOne"/>
108 <channel_snapshot prefix="LocalTwo"/>
109 <parameter name="DestTransfererChannel">
110 <para>The name of the surviving transferer channel when a transfer results in a threeway call</para>
111 <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Threeway</literal></para></note>
115 <para>The headers in this event attempt to describe all the major details of the attended transfer. The two transferer channels
116 and the two bridges are determined based on their chronological establishment. So consider that Alice calls Bob, and then Alice
117 transfers the call to Voicemail. The transferer and bridge headers would be arranged as follows:</para>
118 <para> <replaceable>OrigTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
119 <para> <replaceable>OrigBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
120 <para> <replaceable>SecondTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
121 <para> <replaceable>SecondBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
122 <para>Now consider if the order were reversed; instead of having Alice call Bob and transfer him to Voicemail, Alice instead
123 calls her Voicemail and transfers that to Bob. The transferer and bridge headers would be arranged as follows:</para>
124 <para> <replaceable>OrigTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
125 <para> <replaceable>OrigBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
126 <para> <replaceable>SecondTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
127 <para> <replaceable>SecondBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
129 </managerEventInstance>
133 static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_message *message);
134 static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *message);
135 static struct ast_json *ast_channel_entered_bridge_to_json(struct stasis_message *msg);
136 static struct ast_json *ast_channel_left_bridge_to_json(struct stasis_message *msg);
137 static struct ast_json *ast_bridge_merge_message_to_json(struct stasis_message *msg);
139 static struct stasis_cp_all *bridge_cache_all;
142 * @{ \brief Define bridge message types.
144 STASIS_MESSAGE_TYPE_DEFN(ast_bridge_snapshot_type);
145 STASIS_MESSAGE_TYPE_DEFN(ast_bridge_merge_message_type,
146 .to_json = ast_bridge_merge_message_to_json);
147 STASIS_MESSAGE_TYPE_DEFN(ast_channel_entered_bridge_type,
148 .to_json = ast_channel_entered_bridge_to_json);
149 STASIS_MESSAGE_TYPE_DEFN(ast_channel_left_bridge_type,
150 .to_json = ast_channel_left_bridge_to_json);
151 STASIS_MESSAGE_TYPE_DEFN(ast_blind_transfer_type, .to_ami = blind_transfer_to_ami);
152 STASIS_MESSAGE_TYPE_DEFN(ast_attended_transfer_type, .to_ami = attended_transfer_to_ami);
155 struct stasis_cache *ast_bridge_cache(void)
157 return stasis_cp_all_cache(bridge_cache_all);
160 struct stasis_topic *ast_bridge_topic_all(void)
162 return stasis_cp_all_topic(bridge_cache_all);
165 struct stasis_topic *ast_bridge_topic_all_cached(void)
167 return stasis_cp_all_topic_cached(bridge_cache_all);
170 int bridge_topics_init(struct ast_bridge *bridge)
172 if (ast_strlen_zero(bridge->uniqueid)) {
173 ast_log(LOG_ERROR, "Bridge id initialization required\n");
176 bridge->topics = stasis_cp_single_create(bridge_cache_all,
178 if (!bridge->topics) {
184 struct stasis_topic *ast_bridge_topic(struct ast_bridge *bridge)
187 return ast_bridge_topic_all();
190 return stasis_cp_single_topic(bridge->topics);
193 struct stasis_topic *ast_bridge_topic_cached(struct ast_bridge *bridge)
196 return ast_bridge_topic_all_cached();
199 return stasis_cp_single_topic_cached(bridge->topics);
202 /*! \brief Destructor for bridge snapshots */
203 static void bridge_snapshot_dtor(void *obj)
205 struct ast_bridge_snapshot *snapshot = obj;
206 ast_string_field_free_memory(snapshot);
207 ao2_cleanup(snapshot->channels);
208 snapshot->channels = NULL;
211 struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge)
213 RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
214 struct ast_bridge_channel *bridge_channel;
216 snapshot = ao2_alloc(sizeof(*snapshot), bridge_snapshot_dtor);
217 if (!snapshot || ast_string_field_init(snapshot, 128)) {
221 snapshot->channels = ast_str_container_alloc(SNAPSHOT_CHANNELS_BUCKETS);
222 if (!snapshot->channels) {
226 AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
227 if (ast_str_container_add(snapshot->channels,
228 ast_channel_uniqueid(bridge_channel->chan))) {
233 ast_string_field_set(snapshot, uniqueid, bridge->uniqueid);
234 ast_string_field_set(snapshot, technology, bridge->technology->name);
235 ast_string_field_set(snapshot, subclass, bridge->v_table->name);
237 snapshot->feature_flags = bridge->feature_flags;
238 snapshot->capabilities = bridge->technology->capabilities;
239 snapshot->num_channels = bridge->num_channels;
240 snapshot->num_active = bridge->num_active;
242 ao2_ref(snapshot, +1);
246 void ast_bridge_publish_state(struct ast_bridge *bridge)
248 RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
249 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
251 ast_assert(bridge != NULL);
253 snapshot = ast_bridge_snapshot_create(bridge);
258 msg = stasis_message_create(ast_bridge_snapshot_type(), snapshot);
263 stasis_publish(ast_bridge_topic(bridge), msg);
266 static void bridge_publish_state_from_blob(struct ast_bridge *bridge,
267 struct ast_bridge_blob *obj)
269 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
271 ast_assert(obj != NULL);
273 msg = stasis_message_create(ast_bridge_snapshot_type(), obj->bridge);
278 stasis_publish(ast_bridge_topic(bridge), msg);
281 /*! \brief Destructor for bridge merge messages */
282 static void bridge_merge_message_dtor(void *obj)
284 struct ast_bridge_merge_message *msg = obj;
286 ao2_cleanup(msg->to);
288 ao2_cleanup(msg->from);
292 /*! \brief Bridge merge message creation helper */
293 static struct ast_bridge_merge_message *bridge_merge_message_create(struct ast_bridge *to, struct ast_bridge *from)
295 RAII_VAR(struct ast_bridge_merge_message *, msg, NULL, ao2_cleanup);
297 msg = ao2_alloc(sizeof(*msg), bridge_merge_message_dtor);
302 msg->to = ast_bridge_snapshot_create(to);
307 msg->from = ast_bridge_snapshot_create(from);
316 static struct ast_json *ast_bridge_merge_message_to_json(struct stasis_message *msg)
318 struct ast_bridge_merge_message *merge;
320 merge = stasis_message_data(msg);
322 return ast_json_pack("{s: s, s: o, s: o, s: o}",
323 "type", "BridgeMerged",
324 "timestamp", ast_json_timeval(*stasis_message_timestamp(msg), NULL),
325 "bridge", ast_bridge_snapshot_to_json(merge->to),
326 "bridge_from", ast_bridge_snapshot_to_json(merge->from));
329 void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
331 RAII_VAR(struct ast_bridge_merge_message *, merge_msg, NULL, ao2_cleanup);
332 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
334 ast_assert(to != NULL);
335 ast_assert(from != NULL);
337 merge_msg = bridge_merge_message_create(to, from);
342 msg = stasis_message_create(ast_bridge_merge_message_type(), merge_msg);
347 stasis_publish(ast_bridge_topic_all(), msg);
350 static void bridge_blob_dtor(void *obj)
352 struct ast_bridge_blob *event = obj;
353 ao2_cleanup(event->bridge);
354 event->bridge = NULL;
355 ao2_cleanup(event->channel);
356 event->channel = NULL;
357 ast_json_unref(event->blob);
361 struct stasis_message *ast_bridge_blob_create(
362 struct stasis_message_type *message_type,
363 struct ast_bridge *bridge,
364 struct ast_channel *chan,
365 struct ast_json *blob)
367 RAII_VAR(struct ast_bridge_blob *, obj, NULL, ao2_cleanup);
368 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
370 obj = ao2_alloc(sizeof(*obj), bridge_blob_dtor);
376 obj->bridge = ast_bridge_snapshot_create(bridge);
377 if (obj->bridge == NULL) {
383 obj->channel = ast_channel_snapshot_create(chan);
384 if (obj->channel == NULL) {
390 obj->blob = ast_json_ref(blob);
393 msg = stasis_message_create(message_type, obj);
402 void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan,
403 struct ast_channel *swap)
405 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
406 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
409 blob = ast_json_pack("{s: s}", "swap", ast_channel_uniqueid(swap));
415 msg = ast_bridge_blob_create(ast_channel_entered_bridge_type(), bridge, chan, blob);
420 /* enter blob first, then state */
421 stasis_publish(ast_bridge_topic(bridge), msg);
422 bridge_publish_state_from_blob(bridge, stasis_message_data(msg));
425 void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *chan)
427 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
429 msg = ast_bridge_blob_create(ast_channel_left_bridge_type(), bridge, chan, NULL);
434 /* state first, then leave blob (opposite of enter, preserves nesting of events) */
435 bridge_publish_state_from_blob(bridge, stasis_message_data(msg));
436 stasis_publish(ast_bridge_topic(bridge), msg);
439 static struct ast_json *simple_bridge_channel_event(
441 struct ast_bridge_snapshot *bridge_snapshot,
442 struct ast_channel_snapshot *channel_snapshot,
443 const struct timeval *tv)
445 return ast_json_pack("{s: s, s: o, s: o, s: o}",
447 "timestamp", ast_json_timeval(*tv, NULL),
448 "bridge", ast_bridge_snapshot_to_json(bridge_snapshot),
449 "channel", ast_channel_snapshot_to_json(channel_snapshot));
452 struct ast_json *ast_channel_entered_bridge_to_json(struct stasis_message *msg)
454 struct ast_bridge_blob *obj = stasis_message_data(msg);
456 return simple_bridge_channel_event("ChannelEnteredBridge", obj->bridge,
457 obj->channel, stasis_message_timestamp(msg));
460 struct ast_json *ast_channel_left_bridge_to_json(struct stasis_message *msg)
462 struct ast_bridge_blob *obj = stasis_message_data(msg);
464 return simple_bridge_channel_event("ChannelLeftBridge", obj->bridge,
465 obj->channel, stasis_message_timestamp(msg));
468 typedef struct ast_json *(*json_item_serializer_cb)(void *obj);
470 static struct ast_json *container_to_json_array(struct ao2_container *items, json_item_serializer_cb item_cb)
472 RAII_VAR(struct ast_json *, json_items, ast_json_array_create(), ast_json_unref);
474 struct ao2_iterator it;
479 it = ao2_iterator_init(items, 0);
480 while ((item = ao2_iterator_next(&it))) {
481 if (ast_json_array_append(json_items, item_cb(item))) {
482 ao2_iterator_destroy(&it);
486 ao2_iterator_destroy(&it);
488 return ast_json_ref(json_items);
491 static const char *capability2str(uint32_t capabilities)
493 if (capabilities & AST_BRIDGE_CAPABILITY_HOLDING) {
500 struct ast_json *ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *snapshot)
502 RAII_VAR(struct ast_json *, json_bridge, NULL, ast_json_unref);
503 struct ast_json *json_channels;
505 if (snapshot == NULL) {
509 json_channels = container_to_json_array(snapshot->channels,
510 (json_item_serializer_cb)ast_json_string_create);
511 if (!json_channels) {
515 json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: o}",
516 "id", snapshot->uniqueid,
517 "technology", snapshot->technology,
518 "bridge_type", capability2str(snapshot->capabilities),
519 "bridge_class", snapshot->subclass,
520 "channels", json_channels);
525 return ast_json_ref(json_bridge);
530 * \brief Allocate the fields of an \ref ast_bridge_channel_snapshot_pair.
532 * \param pair A bridge and channel to get snapshots of
533 * \param[out] snapshot_pair An allocated snapshot pair.
535 * \retval non-zero Failure
537 static int bridge_channel_snapshot_pair_init(struct ast_bridge_channel_pair *pair, struct ast_bridge_channel_snapshot_pair *snapshot_pair)
540 snapshot_pair->bridge_snapshot = ast_bridge_snapshot_create(pair->bridge);
541 if (!snapshot_pair->bridge_snapshot) {
546 snapshot_pair->channel_snapshot = ast_channel_snapshot_create(pair->channel);
547 if (!snapshot_pair->channel_snapshot) {
556 * \brief Free the fields of an \ref ast_bridge_channel_snapshot_pair.
558 * \param pair The snapshot pair whose fields are to be cleaned up
560 static void bridge_channel_snapshot_pair_cleanup(struct ast_bridge_channel_snapshot_pair *pair)
562 ao2_cleanup(pair->bridge_snapshot);
563 ao2_cleanup(pair->channel_snapshot);
566 static const char *result_strs[] = {
567 [AST_BRIDGE_TRANSFER_FAIL] = "Fail",
568 [AST_BRIDGE_TRANSFER_INVALID] = "Invalid",
569 [AST_BRIDGE_TRANSFER_NOT_PERMITTED] = "Not Permitted",
570 [AST_BRIDGE_TRANSFER_SUCCESS] = "Success",
573 static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *msg)
575 RAII_VAR(struct ast_str *, channel_state, NULL, ast_free_ptr);
576 RAII_VAR(struct ast_str *, bridge_state, NULL, ast_free_ptr);
577 struct ast_bridge_blob *blob = stasis_message_data(msg);
580 enum ast_transfer_result result;
587 channel_state = ast_manager_build_channel_state_string_prefix(blob->channel, "Transferer");
588 if (!channel_state) {
593 bridge_state = ast_manager_build_bridge_state_string(blob->bridge);
599 exten = ast_json_string_get(ast_json_object_get(blob->blob, "exten"));
600 context = ast_json_string_get(ast_json_object_get(blob->blob, "context"));
601 result = ast_json_integer_get(ast_json_object_get(blob->blob, "result"));
602 is_external = ast_json_integer_get(ast_json_object_get(blob->blob, "is_external"));
604 return ast_manager_event_blob_create(EVENT_FLAG_CALL, "BlindTransfer",
612 ast_str_buffer(channel_state),
613 bridge_state ? ast_str_buffer(bridge_state) : "",
614 is_external ? "Yes" : "No",
619 void ast_bridge_publish_blind_transfer(int is_external, enum ast_transfer_result result,
620 struct ast_bridge_channel_pair *transferer, const char *context, const char *exten)
622 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
623 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
625 json_object = ast_json_pack("{s: s, s: s, s: i, s: i}",
626 "context", context, "exten", exten, "result", result, "is_external", is_external);
629 ast_log(LOG_NOTICE, "Failed to create json bridge blob\n");
633 msg = ast_bridge_blob_create(ast_blind_transfer_type(),
634 transferer->bridge, transferer->channel, json_object);
637 ast_log(LOG_NOTICE, "Failed to create blob msg\n");
641 stasis_publish(ast_bridge_topic_all(), msg);
644 static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_message *msg)
646 RAII_VAR(struct ast_str *, variable_data, ast_str_create(64), ast_free_ptr);
647 RAII_VAR(struct ast_str *, transferer1_state, NULL, ast_free_ptr);
648 RAII_VAR(struct ast_str *, bridge1_state, NULL, ast_free_ptr);
649 RAII_VAR(struct ast_str *, transferer2_state, NULL, ast_free_ptr);
650 RAII_VAR(struct ast_str *, bridge2_state, NULL, ast_free_ptr);
651 RAII_VAR(struct ast_str *, local1_state, NULL, ast_free_ptr);
652 RAII_VAR(struct ast_str *, local2_state, NULL, ast_free_ptr);
653 struct ast_attended_transfer_message *transfer_msg = stasis_message_data(msg);
655 if (!variable_data) {
659 transferer1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transferee.channel_snapshot, "OrigTransferer");
660 transferer2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transfer_target.channel_snapshot, "SecondTransferer");
661 if (!transferer1_state || !transferer2_state) {
665 if (transfer_msg->to_transferee.bridge_snapshot) {
666 bridge1_state = ast_manager_build_bridge_state_string_prefix(
667 transfer_msg->to_transferee.bridge_snapshot, "Orig");
668 if (!bridge1_state) {
673 if (transfer_msg->to_transfer_target.bridge_snapshot) {
674 bridge2_state = ast_manager_build_bridge_state_string_prefix(
675 transfer_msg->to_transfer_target.bridge_snapshot, "Second");
676 if (!bridge2_state) {
681 switch (transfer_msg->dest_type) {
682 case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
683 ast_str_append(&variable_data, 0, "DestType: Bridge\r\n");
684 ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.bridge);
686 case AST_ATTENDED_TRANSFER_DEST_APP:
687 ast_str_append(&variable_data, 0, "DestType: App\r\n");
688 ast_str_append(&variable_data, 0, "DestApp: %s\r\n", transfer_msg->dest.app);
690 case AST_ATTENDED_TRANSFER_DEST_LINK:
691 local1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[0], "LocalOne");
692 local2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[1], "LocalTwo");
693 if (!local1_state || !local2_state) {
696 ast_str_append(&variable_data, 0, "DestType: Link\r\n");
697 ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local1_state));
698 ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local2_state));
700 case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
701 ast_str_append(&variable_data, 0, "DestType: Threeway\r\n");
702 ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.threeway.bridge_snapshot->uniqueid);
703 ast_str_append(&variable_data, 0, "DestTransfererChannel: %s\r\n", transfer_msg->dest.threeway.channel_snapshot->name);
705 case AST_ATTENDED_TRANSFER_DEST_FAIL:
706 ast_str_append(&variable_data, 0, "DestType: Fail\r\n");
710 return ast_manager_event_blob_create(EVENT_FLAG_CALL, "AttendedTransfer",
718 result_strs[transfer_msg->result],
719 ast_str_buffer(transferer1_state),
720 bridge1_state ? ast_str_buffer(bridge1_state) : "",
721 ast_str_buffer(transferer2_state),
722 bridge2_state ? ast_str_buffer(bridge2_state) : "",
723 transfer_msg->is_external ? "Yes" : "No",
724 ast_str_buffer(variable_data));
727 static void attended_transfer_dtor(void *obj)
729 struct ast_attended_transfer_message *msg = obj;
732 bridge_channel_snapshot_pair_cleanup(&msg->to_transferee);
733 bridge_channel_snapshot_pair_cleanup(&msg->to_transfer_target);
735 if (msg->dest_type != AST_ATTENDED_TRANSFER_DEST_LINK) {
739 for (i = 0; i < ARRAY_LEN(msg->dest.links); ++i) {
740 ao2_cleanup(msg->dest.links[i]);
744 static struct ast_attended_transfer_message *attended_transfer_message_create(int is_external, enum ast_transfer_result result,
745 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target)
747 RAII_VAR(struct ast_attended_transfer_message *, msg, NULL, ao2_cleanup);
749 msg = ao2_alloc(sizeof(*msg), attended_transfer_dtor);
754 if (bridge_channel_snapshot_pair_init(transferee, &msg->to_transferee) ||
755 bridge_channel_snapshot_pair_init(target, &msg->to_transfer_target)) {
759 msg->is_external = is_external;
760 msg->result = result;
766 void ast_bridge_publish_attended_transfer_fail(int is_external, enum ast_transfer_result result,
767 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target)
769 RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
770 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
772 transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
777 transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_FAIL;
779 msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
784 stasis_publish(ast_bridge_topic_all(), msg);
787 void ast_bridge_publish_attended_transfer_bridge_merge(int is_external, enum ast_transfer_result result,
788 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
789 struct ast_bridge *final_bridge)
791 RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
792 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
794 transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
799 transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE;
800 ast_copy_string(transfer_msg->dest.bridge, final_bridge->uniqueid,
801 sizeof(transfer_msg->dest.bridge));
803 msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
808 stasis_publish(ast_bridge_topic_all(), msg);
811 void ast_bridge_publish_attended_transfer_threeway(int is_external, enum ast_transfer_result result,
812 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
813 struct ast_bridge_channel_pair *final_pair)
815 RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
816 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
818 transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
823 transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_THREEWAY;
824 if (final_pair->channel == transferee->channel) {
825 transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transferee.channel_snapshot;
827 transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transfer_target.channel_snapshot;
830 if (final_pair->bridge == transferee->bridge) {
831 transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transferee.bridge_snapshot;
833 transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transfer_target.bridge_snapshot;
836 msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
841 stasis_publish(ast_bridge_topic_all(), msg);
844 void ast_bridge_publish_attended_transfer_app(int is_external, enum ast_transfer_result result,
845 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
846 const char *dest_app)
848 RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
849 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
851 transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
856 transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_APP;
857 ast_copy_string(transfer_msg->dest.app, dest_app, sizeof(transfer_msg->dest.app));
859 msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
864 stasis_publish(ast_bridge_topic_all(), msg);
867 void ast_bridge_publish_attended_transfer_link(int is_external, enum ast_transfer_result result,
868 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
869 struct ast_channel *locals[2])
871 RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
872 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
875 transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
880 transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_LINK;
881 for (i = 0; i < 2; ++i) {
882 transfer_msg->dest.links[i] = ast_channel_snapshot_create(locals[i]);
883 if (!transfer_msg->dest.links[i]) {
888 msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
893 stasis_publish(ast_bridge_topic_all(), msg);
896 struct ast_bridge_snapshot *ast_bridge_snapshot_get_latest(const char *uniqueid)
898 RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
899 struct ast_bridge_snapshot *snapshot;
901 ast_assert(!ast_strlen_zero(uniqueid));
903 message = stasis_cache_get(ast_bridge_cache(),
904 ast_bridge_snapshot_type(),
910 snapshot = stasis_message_data(message);
914 ao2_ref(snapshot, +1);
918 /*! \brief snapshot ID getter for caching topic */
919 static const char *bridge_snapshot_get_id(struct stasis_message *msg)
921 struct ast_bridge_snapshot *snapshot;
922 if (stasis_message_type(msg) != ast_bridge_snapshot_type()) {
925 snapshot = stasis_message_data(msg);
926 return snapshot->uniqueid;
929 static void stasis_bridging_cleanup(void)
931 STASIS_MESSAGE_TYPE_CLEANUP(ast_bridge_snapshot_type);
932 STASIS_MESSAGE_TYPE_CLEANUP(ast_bridge_merge_message_type);
933 STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_entered_bridge_type);
934 STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_left_bridge_type);
935 STASIS_MESSAGE_TYPE_CLEANUP(ast_blind_transfer_type);
936 STASIS_MESSAGE_TYPE_CLEANUP(ast_attended_transfer_type);
938 ao2_cleanup(bridge_cache_all);
939 bridge_cache_all = NULL;
942 int ast_stasis_bridging_init(void)
946 ast_register_cleanup(stasis_bridging_cleanup);
948 bridge_cache_all = stasis_cp_all_create("ast_bridge_topic_all",
949 bridge_snapshot_get_id);
951 if (!bridge_cache_all) {
955 res |= STASIS_MESSAGE_TYPE_INIT(ast_bridge_snapshot_type);
956 res |= STASIS_MESSAGE_TYPE_INIT(ast_bridge_merge_message_type);
957 res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_entered_bridge_type);
958 res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_left_bridge_type);
959 res |= STASIS_MESSAGE_TYPE_INIT(ast_blind_transfer_type);
960 res |= STASIS_MESSAGE_TYPE_INIT(ast_attended_transfer_type);