From 84395ff04239e3864b1e1cee69b87690a235477a Mon Sep 17 00:00:00 2001 From: Jonathan Rose Date: Fri, 28 Jun 2013 19:19:15 +0000 Subject: features: call pickup stasis refactoring (issue ASTERISK-21544) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2588/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393190 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- main/features.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 110 insertions(+), 15 deletions(-) (limited to 'main') diff --git a/main/features.c b/main/features.c index b9d2468e1..577a17655 100644 --- a/main/features.c +++ b/main/features.c @@ -74,6 +74,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/test.h" #include "asterisk/bridging.h" #include "asterisk/bridging_basic.h" +#include "asterisk/stasis.h" +#include "asterisk/stasis_channels.h" #include "asterisk/features_config.h" /* BUGBUG TEST_FRAMEWORK is disabled because parking tests no longer work. */ @@ -320,6 +322,40 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + + + Raised when a call pickup occurs. + + + + A numeric code for the channel's current state, related to TargetChannelStateDesc + + + + + + + + + + + + + + + + + + + + + + + + + + + ***/ #define DEFAULT_PARK_TIME 45000 /*!< ms */ @@ -552,6 +588,13 @@ struct ast_dial_features { struct ast_flags peer_features; }; +static struct ast_manager_event_blob *call_pickup_to_ami(struct stasis_message *message); + +STASIS_MESSAGE_TYPE_DEFN( + ast_call_pickup_type, + .to_ami = call_pickup_to_ami); + + #if defined(ATXFER_NULL_TECH) /*! * \internal @@ -4650,15 +4693,69 @@ int ast_pickup_call(struct ast_channel *chan) return res; } +static struct ast_manager_event_blob *call_pickup_to_ami(struct stasis_message *message) +{ + struct ast_multi_channel_blob *contents = stasis_message_data(message); + struct ast_channel_snapshot *chan; + struct ast_channel_snapshot *target; + struct ast_manager_event_blob *res; + + RAII_VAR(struct ast_str *, channel_str, NULL, ast_free); + RAII_VAR(struct ast_str *, target_str, NULL, ast_free); + + chan = ast_multi_channel_blob_get_channel(contents, "channel"); + target = ast_multi_channel_blob_get_channel(contents, "target"); + + ast_assert(chan != NULL && target != NULL); + + if (!(channel_str = ast_manager_build_channel_state_string(chan))) { + return NULL; + } + + if (!(target_str = ast_manager_build_channel_state_string_prefix(target, "Target"))) { + return NULL; + } + + res = ast_manager_event_blob_create(EVENT_FLAG_CALL, "Pickup", + "%s" + "%s", + ast_str_buffer(channel_str), + ast_str_buffer(target_str)); + + return res; +} + +static int send_call_pickup_stasis_message(struct ast_channel *picking_up, struct ast_channel_snapshot *chan, struct ast_channel_snapshot *target) +{ + RAII_VAR(struct ast_multi_channel_blob *, pickup_payload, NULL, ao2_cleanup); + RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + + if (!(pickup_payload = ast_multi_channel_blob_create(ast_json_null()))) { + return -1; + } + + ast_multi_channel_blob_add_channel(pickup_payload, "channel", chan); + ast_multi_channel_blob_add_channel(pickup_payload, "target", target); + + if (!(msg = stasis_message_create(ast_call_pickup_type(), pickup_payload))) { + return -1; + } + + stasis_publish(ast_channel_topic(picking_up), msg); + return 0; +} + int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target) { struct ast_party_connected_line connected_caller; - struct ast_channel *chans[2] = { chan, target }; struct ast_datastore *ds_pickup; const char *chan_name;/*!< A masquerade changes channel names. */ const char *target_name;/*!< A masquerade changes channel names. */ int res = -1; + RAII_VAR(struct ast_channel_snapshot *, chan_snapshot, NULL, ao2_cleanup); + RAII_VAR(struct ast_channel_snapshot *, target_snapshot, NULL, ao2_cleanup); + target_name = ast_strdupa(ast_channel_name(target)); ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan)); @@ -4707,26 +4804,22 @@ int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target) /* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */ ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE); + if (!(chan_snapshot = ast_channel_snapshot_create(chan))) { + goto pickup_failed; + } + + if (!(target_snapshot = ast_channel_snapshot_create(target))) { + goto pickup_failed; + } + if (ast_channel_move(target, chan)) { ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, target_name); goto pickup_failed; } - /* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */ - /*** DOCUMENTATION - - Raised when a call pickup occurs. - - The name of the channel that initiated the pickup. - The name of the channel that is being picked up. - - - ***/ - ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans, - "Channel: %s\r\n" - "TargetChannel: %s\r\n", - chan_name, target_name); + /* target points to the channel that did the pickup at this point, so use that channel's topic instead of chan */ + send_call_pickup_stasis_message(target, chan_snapshot, target_snapshot); res = 0; @@ -5570,6 +5663,7 @@ static void features_shutdown(void) ast_unregister_application(app_bridge); + STASIS_MESSAGE_TYPE_CLEANUP(ast_call_pickup_type); pthread_cancel(parking_thread); pthread_kill(parking_thread, SIGURG); pthread_join(parking_thread, NULL); @@ -5596,6 +5690,7 @@ int ast_features_init(void) ast_cli_unregister_multiple(cli_features, ARRAY_LEN(cli_features)); return -1; } + STASIS_MESSAGE_TYPE_INIT(ast_call_pickup_type); res |= ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); res |= ast_manager_register_xml_core("Bridge", EVENT_FLAG_CALL, action_bridge); -- cgit v1.2.3