[asterisk-commits] mmichelson: branch group/ari-greedy-atxfer r419682 - in /team/group/ari-greed...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Jul 28 13:02:53 CDT 2014


Author: mmichelson
Date: Mon Jul 28 13:02:47 2014
New Revision: 419682

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=419682
Log:
Adding work performed in review 3816 to this branch.

That review added transferee channel and transfer target
channel to blind and attended transfer publications, modified
AMI events to use this information, and modified CEL to use
this information as well.


Modified:
    team/group/ari-greedy-atxfer/apps/app_queue.c
    team/group/ari-greedy-atxfer/include/asterisk/stasis_bridges.h
    team/group/ari-greedy-atxfer/main/bridge.c
    team/group/ari-greedy-atxfer/main/bridge_basic.c
    team/group/ari-greedy-atxfer/main/cel.c
    team/group/ari-greedy-atxfer/main/stasis_bridges.c
    team/group/ari-greedy-atxfer/res/stasis/app.c

Modified: team/group/ari-greedy-atxfer/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/apps/app_queue.c?view=diff&rev=419682&r1=419681&r2=419682
==============================================================================
--- team/group/ari-greedy-atxfer/apps/app_queue.c (original)
+++ team/group/ari-greedy-atxfer/apps/app_queue.c Mon Jul 28 13:02:47 2014
@@ -5614,10 +5614,7 @@
 		struct stasis_message *msg)
 {
 	struct queue_stasis_data *queue_data = userdata;
-	struct ast_bridge_blob *blind_blob = stasis_message_data(msg);
-	struct ast_json *result_blob;
-	struct ast_json *exten_blob;
-	struct ast_json *context_blob;
+	struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
 	const char *exten;
 	const char *context;
 	RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
@@ -5627,19 +5624,14 @@
 		return;
 	}
 
-	result_blob = ast_json_object_get(blind_blob->blob, "result");
-	if (!result_blob) {
+	if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
 		return;
 	}
 
-	if (ast_json_integer_get(result_blob) != AST_BRIDGE_TRANSFER_SUCCESS) {
-		return;
-	}
-
 	ao2_lock(queue_data);
 
 	if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
-			strcmp(queue_data->bridge_uniqueid, blind_blob->bridge->uniqueid)) {
+			strcmp(queue_data->bridge_uniqueid, transfer_msg->to_transferee.bridge_snapshot->uniqueid)) {
 		ao2_unlock(queue_data);
 		return;
 	}
@@ -5649,10 +5641,8 @@
 
 	ao2_unlock(queue_data);
 
-	exten_blob = ast_json_object_get(blind_blob->blob, "exten");
-	exten = exten_blob ? ast_json_string_get(exten_blob) : "<unknown>";
-	context_blob = ast_json_object_get(blind_blob->blob, "context");
-	context = context_blob ? ast_json_string_get(context_blob) : "<unknown>";
+	exten = transfer_msg->exten;
+	context = transfer_msg->context;
 
 	ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
 	ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,

Modified: team/group/ari-greedy-atxfer/include/asterisk/stasis_bridges.h
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/include/asterisk/stasis_bridges.h?view=diff&rev=419682&r1=419681&r2=419682
==============================================================================
--- team/group/ari-greedy-atxfer/include/asterisk/stasis_bridges.h (original)
+++ team/group/ari-greedy-atxfer/include/asterisk/stasis_bridges.h Mon Jul 28 13:02:47 2014
@@ -285,6 +285,24 @@
 struct stasis_message_type *ast_blind_transfer_type(void);
 
 /*!
+ * \brief Message published during a blind transfer
+ */
+struct ast_blind_transfer_message {
+	/*! Result of the transfer */
+	enum ast_transfer_result result;
+	/*! True if the transfer was initiated by an external source (i.e. not DTMF-initiated) */
+	int is_external;
+	/*! Transferer and its bridge */
+	struct ast_bridge_channel_snapshot_pair to_transferee;
+	/*! Destination context */
+	char context[AST_MAX_CONTEXT];
+	/*! Destination extension */
+	char exten[AST_MAX_EXTENSION];
+	/*! Transferee channel. NULL if there were multiple transferee channels */
+	struct ast_channel_snapshot *transferee;
+};
+
+/*!
  * \brief Publish a blind transfer event
  *
  * \pre Bridges involved are locked. Channels involved are not locked.
@@ -294,9 +312,11 @@
  * \param to_transferee The bridge between the transferer and transferee plus the transferer channel
  * \param context The destination context for the blind transfer
  * \param exten The destination extension for the blind transfer
+ * \param transferee_channel If a single channel is being transferred, this is it. If multiple parties are being transferred, this is NULL.
  */
 void ast_bridge_publish_blind_transfer(int is_external, enum ast_transfer_result result,
-		struct ast_bridge_channel_pair *to_transferee, const char *context, const char *exten);
+		struct ast_bridge_channel_pair *to_transferee, const char *context, const char *exten,
+		struct ast_channel *transferee_channel);
 
 enum ast_attended_transfer_dest_type {
 	/*! The transfer failed, so there is no appropriate final state */
@@ -327,6 +347,10 @@
 	struct ast_bridge_channel_snapshot_pair to_transfer_target;
 	/*! Local channel connecting transferee bridge to application */
 	struct ast_channel_snapshot *replace_channel;
+	/*! Transferee channel. Will be NULL if there were multiple channels transferred. */
+	struct ast_channel_snapshot *transferee;
+	/*! Transfer target channel. Will be NULL if there were multiple channels targeted. */
+	struct ast_channel_snapshot *target;
 	/*! Indicates the final state of the transfer */
 	enum ast_attended_transfer_dest_type dest_type;
 	union {
@@ -362,9 +386,12 @@
  * \param result The result of the transfer. Will always be a type of failure.
  * \param transferee The bridge between the transferer and transferees as well as the transferer channel from that bridge
  * \param target The bridge between the transferer and transfer targets as well as the transferer channel from that bridge
+ * \param transferee_channel If a single channel is being transferred, this is it. If multiple parties are being transferred, this is NULL.
+ * \param target_channel If a single channel is being transferred to, this is it. If multiple parties are being transferred to, this is NULL.
  */
 void ast_bridge_publish_attended_transfer_fail(int is_external, enum ast_transfer_result result,
-		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target);
+		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
+		struct ast_channel *transferee_channel, struct ast_channel *target_channel);
 
 /*!
  * \since 12
@@ -386,10 +413,13 @@
  * \param transferee The bridge between the transferer and transferees as well as the transferer channel from that bridge
  * \param target The bridge between the transferer and transfer targets as well as the transferer channel from that bridge
  * \param final_bridge The bridge that the parties end up in. Will be a bridge from the transferee or target pair.
+ * \param transferee_channel If a single channel is being transferred, this is it. If multiple parties are being transferred, this is NULL.
+ * \param target_channel If a single channel is being transferred to, this is it. If multiple parties are being transferred to, this is NULL.
  */
 void ast_bridge_publish_attended_transfer_bridge_merge(int is_external, enum ast_transfer_result result,
 		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
-		struct ast_bridge *final_bridge);
+		struct ast_bridge *final_bridge, struct ast_channel *transferee_channel,
+		struct ast_channel *target_channel);
 
 /*!
  * \since 12
@@ -407,10 +437,13 @@
  * \param transferee The bridge between the transferer and transferees as well as the transferer channel from that bridge
  * \param target The bridge between the transferer and transfer targets as well as the transferer channel from that bridge
  * \param final_pair The bridge that the parties end up in, and the transferer channel that is in this bridge.
+ * \param transferee_channel If a single channel is being transferred, this is it. If multiple parties are being transferred, this is NULL.
+ * \param target_channel If a single channel is being transferred to, this is it. If multiple parties are being transferred to, this is NULL.
  */
 void ast_bridge_publish_attended_transfer_threeway(int is_external, enum ast_transfer_result result,
 		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
-		struct ast_bridge_channel_pair *final_pair);
+		struct ast_bridge_channel_pair *final_pair, struct ast_channel *transferee_channel,
+		struct ast_channel *target_channel);
 
 /*!
  * \since 12
@@ -435,10 +468,15 @@
  *        transferer channel when a local channel is involved
  * \param dest_app The application that the channel or bridge is running upon transfer
  *        completion.
+ * \param transferee_channel If a single channel is being transferred, this is it.
+ *        If multiple parties are being transferred, this is NULL.
+ * \param target_channel If a single channel is being transferred to, this is it.
+ *        If multiple parties are being transferred to, this is NULL.
  */
 void ast_bridge_publish_attended_transfer_app(int is_external, enum ast_transfer_result result,
 		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
-		struct ast_channel *replace_channel, const char *dest_app);
+		struct ast_channel *replace_channel, const char *dest_app,
+		struct ast_channel *transferee_channel, struct ast_channel *target_channel);
 
 /*!
  * \since 12
@@ -460,10 +498,13 @@
  * \param transferee The bridge between the transferer and transferees as well as the transferer channel from that bridge
  * \param target The bridge between the transferer and transfer targets as well as the transferer channel from that bridge
  * \param locals The local channels linking the bridges together.
+ * \param transferee_channel If a single channel is being transferred, this is it. If multiple parties are being transferred, this is NULL.
+ * \param target_channel If a single channel is being transferred to, this is it. If multiple parties are being transferred to, this is NULL.
  */
 void ast_bridge_publish_attended_transfer_link(int is_external, enum ast_transfer_result result,
 		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
-		struct ast_channel *locals[2]);
+		struct ast_channel *locals[2], struct ast_channel *transferee_channel,
+		struct ast_channel *target_channel);
 
 /*!
  * \brief Returns the most recent snapshot for the bridge.

Modified: team/group/ari-greedy-atxfer/main/bridge.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/main/bridge.c?view=diff&rev=419682&r1=419681&r2=419682
==============================================================================
--- team/group/ari-greedy-atxfer/main/bridge.c (original)
+++ team/group/ari-greedy-atxfer/main/bridge.c Mon Jul 28 13:02:47 2014
@@ -3760,12 +3760,50 @@
 	struct ast_bridge_channel_pair to_transfer_target;
 	/* The Local;1 that will replace the transferee bridge transferer channel */
 	struct ast_channel *replace_channel;
+	/* The transferee channel. NULL if there is no transferee channel or if multiple parties are transferred */
+	struct ast_channel *transferee_channel;
+	/* The transfer target channel. NULL if there is no transfer target channel or if multiple parties are transferred */
+	struct ast_channel *target_channel;
 };
+
+/*!
+ * \internal
+ * \brief Get the transferee channel
+ *
+ * This is only applicable to cases where a transfer is occurring on a
+ * two-party bridge. The channels container passed in is expected to only
+ * contain two channels, the transferer and the transferee. The transferer
+ * channel is passed in as a parameter to ensure we don't return it as
+ * the transferee channel.
+ *
+ * \param channels A two-channel container containing the transferer and transferee
+ * \param transferer The party that is transfering the call
+ * \return The party that is being transferred
+ */
+static struct ast_channel *get_transferee(struct ao2_container *channels, struct ast_channel *transferer)
+{
+	struct ao2_iterator channel_iter;
+	struct ast_channel *transferee;
+
+	for (channel_iter = ao2_iterator_init(channels, 0);
+			(transferee = ao2_iterator_next(&channel_iter));
+			ao2_cleanup(transferee)) {
+		if (transferee != transferer) {
+			break;
+		}
+	}
+
+	ao2_iterator_destroy(&channel_iter);
+	return transferee;
+}
+
 
 static void stasis_publish_data_cleanup(struct stasis_attended_transfer_publish_data *publication)
 {
 	ast_channel_unref(publication->to_transferee.channel);
 	ast_channel_unref(publication->to_transfer_target.channel);
+	ast_channel_cleanup(publication->transferee_channel);
+	ast_channel_cleanup(publication->target_channel);
 	ao2_cleanup(publication->to_transferee.bridge);
 	ao2_cleanup(publication->to_transfer_target.bridge);
 	ao2_cleanup(publication->replace_channel);
@@ -3798,6 +3836,9 @@
 		ao2_ref(to_target_bridge, +1);
 		publication->to_transfer_target.bridge = to_target_bridge;
 	}
+
+	publication->transferee_channel = ast_bridge_peer(to_transferee_bridge, to_transferee);
+	publication->target_channel = ast_bridge_peer(to_target_bridge, to_transfer_target);
 }
 
 /*
@@ -3811,7 +3852,8 @@
 		struct ast_bridge *final_bridge)
 {
 	ast_bridge_publish_attended_transfer_bridge_merge(1, AST_BRIDGE_TRANSFER_SUCCESS,
-			&publication->to_transferee, &publication->to_transfer_target, final_bridge);
+			&publication->to_transferee, &publication->to_transfer_target, final_bridge,
+			publication->transferee_channel, publication->target_channel);
 }
 
 /*
@@ -3826,7 +3868,8 @@
 {
 	ast_bridge_publish_attended_transfer_app(1, AST_BRIDGE_TRANSFER_SUCCESS,
 			&publication->to_transferee, &publication->to_transfer_target,
-			publication->replace_channel, app);
+			publication->replace_channel, app,
+			publication->transferee_channel, publication->target_channel);
 }
 
 /*
@@ -3843,7 +3886,8 @@
 	struct ast_channel *locals[2] = { local_channel1, local_channel2 };
 
 	ast_bridge_publish_attended_transfer_link(1, AST_BRIDGE_TRANSFER_SUCCESS,
-			&publication->to_transferee, &publication->to_transfer_target, locals);
+			&publication->to_transferee, &publication->to_transfer_target, locals,
+			publication->transferee_channel, publication->target_channel);
 }
 
 /*
@@ -3857,7 +3901,8 @@
 		enum ast_transfer_result result)
 {
 	ast_bridge_publish_attended_transfer_fail(1, result, &publication->to_transferee,
-			&publication->to_transfer_target);
+			&publication->to_transfer_target, publication->transferee_channel,
+			publication->target_channel);
 }
 
 /*!
@@ -3947,37 +3992,6 @@
 	return AST_BRIDGE_TRANSFER_SUCCESS;
 }
 
-/*!
- * \internal
- * \brief Get the transferee channel
- *
- * This is only applicable to cases where a transfer is occurring on a
- * two-party bridge. The channels container passed in is expected to only
- * contain two channels, the transferer and the transferee. The transferer
- * channel is passed in as a parameter to ensure we don't return it as
- * the transferee channel.
- *
- * \param channels A two-channel container containing the transferer and transferee
- * \param transferer The party that is transfering the call
- * \return The party that is being transferred
- */
-static struct ast_channel *get_transferee(struct ao2_container *channels, struct ast_channel *transferer)
-{
-	struct ao2_iterator channel_iter;
-	struct ast_channel *transferee;
-
-	for (channel_iter = ao2_iterator_init(channels, 0);
-			(transferee = ao2_iterator_next(&channel_iter));
-			ao2_cleanup(transferee)) {
-		if (transferee != transferer) {
-			break;
-		}
-	}
-
-	ao2_iterator_destroy(&channel_iter);
-	return transferee;
-}
-
 static enum ast_transfer_result try_parking(struct ast_channel *transferer,
 	const char *context, const char *exten, transfer_channel_cb new_channel_cb,
 	struct transfer_channel_data *user_data_wrapper)
@@ -4079,7 +4093,7 @@
 
 static void publish_blind_transfer(int is_external, enum ast_transfer_result result,
 		struct ast_channel *transferer, struct ast_bridge *bridge,
-		const char *context, const char *exten)
+		const char *context, const char *exten, struct ast_channel *transferee_channel)
 {
 	struct ast_bridge_channel_pair pair;
 	pair.channel = transferer;
@@ -4087,7 +4101,7 @@
 	if (bridge) {
 		ast_bridge_lock(bridge);
 	}
-	ast_bridge_publish_blind_transfer(is_external, result, &pair, context, exten);
+	ast_bridge_publish_blind_transfer(is_external, result, &pair, context, exten, transferee_channel);
 	if (bridge) {
 		ast_bridge_unlock(bridge);
 	}
@@ -4111,6 +4125,9 @@
 		transfer_result = AST_BRIDGE_TRANSFER_INVALID;
 		goto publish;
 	}
+
+	transferee = ast_bridge_peer(bridge, transferer);
+
 	ast_channel_lock(transferer);
 	bridge_channel = ast_channel_get_bridge_channel(transferer);
 	ast_channel_unlock(transferer);
@@ -4172,7 +4189,6 @@
 
 	/* Reaching this portion means that we're dealing with a two-party bridge */
 
-	transferee = get_transferee(channels, transferer);
 	if (!transferee) {
 		transfer_result = AST_BRIDGE_TRANSFER_FAIL;
 		goto publish;
@@ -4188,7 +4204,7 @@
 	transfer_result = AST_BRIDGE_TRANSFER_SUCCESS;
 
 publish:
-	publish_blind_transfer(is_external, transfer_result, transferer, bridge, context, exten);
+	publish_blind_transfer(is_external, transfer_result, transferer, bridge, context, exten, transferee);
 	return transfer_result;
 }
 

Modified: team/group/ari-greedy-atxfer/main/bridge_basic.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/main/bridge_basic.c?view=diff&rev=419682&r1=419681&r2=419682
==============================================================================
--- team/group/ari-greedy-atxfer/main/bridge_basic.c (original)
+++ team/group/ari-greedy-atxfer/main/bridge_basic.c Mon Jul 28 13:02:47 2014
@@ -1525,9 +1525,85 @@
 }
 
 /*!
+ * \brief Get a desired transfer party for a bridge the transferer is not in.
+ *
+ * \param bridge The bridge to get the party from. May be NULL.
+ * \param[out] party The lone channel in the bridge. Will be set NULL if bridge is NULL or multiple parties are present.
+ */
+static void get_transfer_party_non_transferer_bridge(struct ast_bridge *bridge,
+		struct ast_channel **party)
+{
+	if (bridge && bridge->num_channels == 1) {
+		*party = ast_channel_ref(AST_LIST_FIRST(&bridge->channels)->chan);
+	} else {
+		*party = NULL;
+	}
+}
+
+/*!
+ * \brief Get the transferee and transfer target when the transferer is in a bridge with
+ * one of the desired parties.
+ *
+ * \param transferer_bridge The bridge the transferer is in
+ * \param other_bridge The bridge the transferer is not in. May be NULL.
+ * \param transferer The transferer party
+ * \param[out] transferer_peer The party that is in the bridge with the transferer
+ * \param[out] other_party The party that is in the other_bridge
+ */
+static void get_transfer_parties_transferer_bridge(struct ast_bridge *transferer_bridge,
+		struct ast_bridge *other_bridge, struct ast_channel *transferer,
+		struct ast_channel **transferer_peer, struct ast_channel **other_party)
+{
+	*transferer_peer = ast_bridge_peer(transferer_bridge, transferer);
+	get_transfer_party_non_transferer_bridge(other_bridge, other_party);
+}
+
+/*!
+ * \brief determine transferee and transfer target for an attended transfer
+ *
+ * In builtin attended transfers, there is a single transferer channel that jumps between
+ * the two bridges involved. At the time the attended transfer occurs, the transferer could
+ * be in either bridge, so determining the parties is a bit more complex than normal.
+ *
+ * The method used here is to determine which of the two bridges the transferer is in, and
+ * grabbing the peer from that bridge. The other bridge, if it only has a single channel in it,
+ * has the other desired channel.
+ *
+ * \param transferer The channel performing the transfer
+ * \param transferee_bridge The bridge that the transferee is in
+ * \param target_bridge The bridge that the transfer target is in
+ * \param[out] transferee The transferee channel
+ * \param[out] transfer_target The transfer target channel
+ */
+static void get_transfer_parties(struct ast_channel *transferer, struct ast_bridge *transferee_bridge,
+		struct ast_bridge *target_bridge, struct ast_channel **transferee,
+		struct ast_channel **transfer_target)
+{
+	struct ast_bridge *transferer_bridge;
+
+	ast_channel_lock(transferer);
+	transferer_bridge = ast_channel_get_bridge(transferer);
+	ast_channel_unlock(transferer);
+
+	if (transferer_bridge == transferee_bridge) {
+		get_transfer_parties_transferer_bridge(transferee_bridge, target_bridge,
+				transferer, transferee, transfer_target);
+	} else if (transferer_bridge == target_bridge) {
+		get_transfer_parties_transferer_bridge(target_bridge, transferee_bridge,
+				transferer, transfer_target, transferee);
+	} else {
+		get_transfer_party_non_transferer_bridge(transferee_bridge, transferee);
+		get_transfer_party_non_transferer_bridge(target_bridge, transfer_target);
+	}
+
+	ao2_cleanup(transferer_bridge);
+}
+
+/*!
  * \brief Send a stasis publication for a successful attended transfer
  */
-static void publish_transfer_success(struct attended_transfer_properties *props)
+static void publish_transfer_success(struct attended_transfer_properties *props,
+		struct ast_channel *transferee_channel, struct ast_channel *target_channel)
 {
 	struct ast_bridge_channel_pair transferee = {
 		.channel = props->transferer,
@@ -1547,7 +1623,8 @@
 	}
 
 	ast_bridge_publish_attended_transfer_bridge_merge(0, AST_BRIDGE_TRANSFER_SUCCESS,
-			&transferee, &transfer_target, props->transferee_bridge);
+			&transferee, &transfer_target, props->transferee_bridge, transferee_channel,
+			target_channel);
 
 	if (transferee.bridge) {
 		ast_bridge_unlock(transferee.bridge);
@@ -1560,7 +1637,8 @@
 /*!
  * \brief Send a stasis publication for an attended transfer that ends in a threeway call
  */
-static void publish_transfer_threeway(struct attended_transfer_properties *props)
+static void publish_transfer_threeway(struct attended_transfer_properties *props,
+		struct ast_channel *transferee_channel, struct ast_channel *target_channel)
 {
 	struct ast_bridge_channel_pair transferee = {
 		.channel = props->transferer,
@@ -1584,7 +1662,8 @@
 	}
 
 	ast_bridge_publish_attended_transfer_threeway(0, AST_BRIDGE_TRANSFER_SUCCESS,
-			&transferee, &transfer_target, &threeway);
+			&transferee, &transfer_target, &threeway, transferee_channel,
+			target_channel);
 
 	if (transferee.bridge) {
 		ast_bridge_unlock(transferee.bridge);
@@ -1607,6 +1686,8 @@
 		.channel = props->transferer,
 		.bridge = props->target_bridge,
 	};
+	struct ast_channel *transferee_channel;
+	struct ast_channel *target_channel;
 
 	if (transferee.bridge && transfer_target.bridge) {
 		ast_bridge_lock_both(transferee.bridge, transfer_target.bridge);
@@ -1616,8 +1697,12 @@
 		ast_bridge_lock(transfer_target.bridge);
 	}
 
+	get_transfer_parties(props->transferer, props->transferee_bridge, props->target_bridge,
+			&transferee_channel, &target_channel);
 	ast_bridge_publish_attended_transfer_fail(0, AST_BRIDGE_TRANSFER_FAIL,
-			&transferee, &transfer_target);
+			&transferee, &transfer_target, transferee_channel, target_channel);
+	ast_channel_cleanup(transferee_channel);
+	ast_channel_cleanup(target_channel);
 
 	if (transferee.bridge) {
 		ast_bridge_unlock(transferee.bridge);
@@ -2071,11 +2156,18 @@
 
 static int threeway_enter(struct attended_transfer_properties *props)
 {
+	struct ast_channel *transferee_channel;
+	struct ast_channel *target_channel;
+
+	get_transfer_parties(props->transferer, props->transferee_bridge, props->target_bridge,
+			&transferee_channel, &target_channel);
 	bridge_merge(props->transferee_bridge, props->target_bridge, NULL, 0);
 	play_sound(props->transfer_target, props->xfersound);
 	play_sound(props->transferer, props->xfersound);
-	publish_transfer_threeway(props);
-
+	publish_transfer_threeway(props, transferee_channel, target_channel);
+
+	ast_channel_cleanup(transferee_channel);
+	ast_channel_cleanup(target_channel);
 	return 0;
 }
 
@@ -2177,17 +2269,33 @@
 
 static int complete_enter(struct attended_transfer_properties *props)
 {
+	struct ast_channel *transferee_channel;
+	struct ast_channel *target_channel;
+
+	get_transfer_parties(props->transferer, props->transferee_bridge, props->target_bridge,
+			&transferee_channel, &target_channel);
 	bridge_merge(props->transferee_bridge, props->target_bridge, &props->transferer, 1);
 	play_sound(props->transfer_target, props->xfersound);
-	publish_transfer_success(props);
+	publish_transfer_success(props, transferee_channel, target_channel);
+
+	ast_channel_cleanup(transferee_channel);
+	ast_channel_cleanup(target_channel);
 	return 0;
 }
 
 static int blond_enter(struct attended_transfer_properties *props)
 {
+	struct ast_channel *transferee_channel;
+	struct ast_channel *target_channel;
+
+	get_transfer_parties(props->transferer, props->transferee_bridge, props->target_bridge,
+			&transferee_channel, &target_channel);
 	bridge_merge(props->transferee_bridge, props->target_bridge, &props->transferer, 1);
 	ringing(props->transfer_target);
-	publish_transfer_success(props);
+	publish_transfer_success(props, transferee_channel, target_channel);
+
+	ast_channel_cleanup(transferee_channel);
+	ast_channel_cleanup(target_channel);
 	return 0;
 }
 

Modified: team/group/ari-greedy-atxfer/main/cel.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/main/cel.c?view=diff&rev=419682&r1=419681&r2=419682
==============================================================================
--- team/group/ari-greedy-atxfer/main/cel.c (original)
+++ team/group/ari-greedy-atxfer/main/cel.c Mon Jul 28 13:02:47 2014
@@ -1354,44 +1354,16 @@
 	void *data, struct stasis_subscription *sub,
 	struct stasis_message *message)
 {
-	struct ast_bridge_blob *obj = stasis_message_data(message);
-	struct ast_channel_snapshot *chan_snapshot = obj->channel;
-	struct ast_bridge_snapshot *bridge_snapshot = obj->bridge;
-	struct ast_json *blob = obj->blob;
-	struct ast_json *json_result = ast_json_object_get(blob, "result");
-	struct ast_json *json_exten;
-	struct ast_json *json_context;
+	struct ast_blind_transfer_message *transfer_msg = stasis_message_data(message);
+	struct ast_channel_snapshot *chan_snapshot = transfer_msg->to_transferee.channel_snapshot;
+	struct ast_bridge_snapshot *bridge_snapshot = transfer_msg->to_transferee.bridge_snapshot;
 	struct ast_json *extra;
-	const char *exten;
-	const char *context;
-	enum ast_transfer_result result;
-
-	if (!json_result) {
-		return;
-	}
-
-	result = ast_json_integer_get(json_result);
-	if (result != AST_BRIDGE_TRANSFER_SUCCESS) {
-		return;
-	}
-
-	json_exten = ast_json_object_get(blob, "exten");
-	json_context = ast_json_object_get(blob, "context");
-
-	if (!json_exten || !json_context) {
-		return;
-	}
-
-	exten = ast_json_string_get(json_exten);
-	context = ast_json_string_get(json_context);
-	if (!exten || !context) {
-		return;
-	}
 
 	extra = ast_json_pack("{s: s, s: s, s: s}",
-		"extension", exten,
-		"context", context,
-		"bridge_id", bridge_snapshot->uniqueid);
+		"extension", transfer_msg->exten,
+		"context", transfer_msg->context,
+		"bridge_id", bridge_snapshot->uniqueid,
+		"transferee_channel_name", transfer_msg->transferee ? transfer_msg->transferee->name: "N/A");
 	if (extra) {
 		cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, NULL, extra, NULL);
 		ast_json_unref(extra);
@@ -1427,20 +1399,24 @@
 	case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
 	case AST_ATTENDED_TRANSFER_DEST_LINK:
 	case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
-		extra = ast_json_pack("{s: s, s: s, s: s}",
+		extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
 			"bridge1_id", bridge1->uniqueid,
 			"channel2_name", channel2->name,
-			"bridge2_id", bridge2->uniqueid);
+			"bridge2_id", bridge2->uniqueid,
+			"transferee_channel_name", xfer->transferee ? xfer->transferee->name : "N/A",
+			"transfer_target_channel_name", xfer->target ? xfer->target->name : "N/A");
 		if (!extra) {
 			return;
 		}
 		break;
 	case AST_ATTENDED_TRANSFER_DEST_APP:
 	case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
-		extra = ast_json_pack("{s: s, s: s, s: s}",
+		extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
 			"bridge1_id", bridge1->uniqueid,
 			"channel2_name", channel2->name,
-			"app", xfer->dest.app);
+			"app", xfer->dest.app,
+			"transferee_channel_name", xfer->transferee ? xfer->transferee->name : "N/A",
+			"transfer_target_channel_name", xfer->target ? xfer->target->name : "N/A");
 		if (!extra) {
 			return;
 		}

Modified: team/group/ari-greedy-atxfer/main/stasis_bridges.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/main/stasis_bridges.c?view=diff&rev=419682&r1=419681&r2=419682
==============================================================================
--- team/group/ari-greedy-atxfer/main/stasis_bridges.c (original)
+++ team/group/ari-greedy-atxfer/main/stasis_bridges.c Mon Jul 28 13:02:47 2014
@@ -62,6 +62,7 @@
 					contacted. It means that a party was succesfully placed into the dialplan at the expected location.</para></note>
 				</parameter>
 				<channel_snapshot prefix="Transferer"/>
+				<channel_snapshot prefix="Transferee"/>
 				<bridge_snapshot/>
 				<parameter name="IsExternal">
 					<para>Indicates if the transfer was performed outside of Asterisk. For instance,
@@ -113,6 +114,7 @@
 					<para>The name of the surviving transferer channel when a transfer results in a threeway call</para>
 					<note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Threeway</literal></para></note>
 				</parameter>
+				<channel_snapshot prefix="Transferee" />
 			</syntax>
 			<description>
 				<para>The headers in this event attempt to describe all the major details of the attended transfer. The two transferer channels
@@ -621,30 +623,41 @@
 static struct ast_json *blind_transfer_to_json(struct stasis_message *msg,
 	const struct stasis_message_sanitizer *sanitize)
 {
-	struct ast_bridge_blob *blob = stasis_message_data(msg);
-	struct ast_json *json_channel, *out;
+	struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
+	struct ast_json *json_transferer, *json_transferee, *out;
 	const struct timeval *tv = stasis_message_timestamp(msg);
 
-	json_channel = ast_channel_snapshot_to_json(blob->channel, sanitize);
-	if (!json_channel) {
-		return NULL;
-	}
-
-	out = ast_json_pack("{s: s, s: o, s: o, s: O, s: O, s: s, s: o}",
+	json_transferer = ast_channel_snapshot_to_json(transfer_msg->to_transferee.channel_snapshot, sanitize);
+	if (!json_transferer) {
+		return NULL;
+	}
+
+	if (transfer_msg->transferee) {
+		json_transferee = ast_channel_snapshot_to_json(transfer_msg->transferee, sanitize);
+		if (!json_transferee) {
+			return NULL;
+		}
+	} else {
+		json_transferee = ast_json_null();
+	}
+
+	out = ast_json_pack("{s: s, s: o, s: o, s: o, s: s, s: s, s: s, s: o}",
 		"type", "BridgeBlindTransfer",
 		"timestamp", ast_json_timeval(*tv, NULL),
-		"channel", json_channel,
-		"exten", ast_json_object_get(blob->blob, "exten"),
-		"context", ast_json_object_get(blob->blob, "context"),
-		"result", result_strs[ast_json_integer_get(ast_json_object_get(blob->blob, "result"))],
-		"is_external", ast_json_boolean(ast_json_integer_get(ast_json_object_get(blob->blob, "is_external"))));
+		"transferer", json_transferer,
+		"transferee", json_transferee,
+		"exten", transfer_msg->exten,
+		"context", transfer_msg->context,
+		"result", result_strs[transfer_msg->result],
+		"is_external", ast_json_boolean(transfer_msg->is_external));
 
 	if (!out) {
 		return NULL;
 	}
 
-	if (blob->bridge) {
-		struct ast_json *json_bridge = ast_bridge_snapshot_to_json(blob->bridge, sanitize);
+	if (transfer_msg->to_transferee.bridge_snapshot) {
+		struct ast_json *json_bridge = ast_bridge_snapshot_to_json(
+				transfer_msg->to_transferee.bridge_snapshot, sanitize);
 
 		if (!json_bridge || ast_json_object_set(out, "bridge", json_bridge)) {
 			ast_json_unref(out);
@@ -657,73 +670,96 @@
 
 static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *msg)
 {
-	RAII_VAR(struct ast_str *, channel_state, NULL, ast_free_ptr);
+	RAII_VAR(struct ast_str *, transferer_state, NULL, ast_free_ptr);
 	RAII_VAR(struct ast_str *, bridge_state, NULL, ast_free_ptr);
-	struct ast_bridge_blob *blob = stasis_message_data(msg);
-	const char *exten;
-	const char *context;
-	enum ast_transfer_result result;
-	int is_external;
-
-	if (!blob) {
-		return NULL;
-	}
-
-	channel_state = ast_manager_build_channel_state_string_prefix(blob->channel, "Transferer");
-	if (!channel_state) {
-		return NULL;
-	}
-
-	if (blob->bridge) {
-		bridge_state = ast_manager_build_bridge_state_string(blob->bridge);
+	RAII_VAR(struct ast_str *, transferee_state, NULL, ast_free_ptr);
+	struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
+
+	if (!transfer_msg) {
+		return NULL;
+	}
+
+	transferer_state = ast_manager_build_channel_state_string_prefix(
+			transfer_msg->to_transferee.channel_snapshot, "Transferer");
+	if (!transferer_state) {
+		return NULL;
+	}
+
+	if (transfer_msg->to_transferee.bridge_snapshot) {
+		bridge_state = ast_manager_build_bridge_state_string(transfer_msg->to_transferee.bridge_snapshot);
 		if (!bridge_state) {
 			return NULL;
 		}
 	}
 
-	exten = ast_json_string_get(ast_json_object_get(blob->blob, "exten"));
-	context = ast_json_string_get(ast_json_object_get(blob->blob, "context"));
-	result = ast_json_integer_get(ast_json_object_get(blob->blob, "result"));
-	is_external = ast_json_integer_get(ast_json_object_get(blob->blob, "is_external"));
+	if (transfer_msg->transferee) {
+		transferee_state = ast_manager_build_channel_state_string_prefix(
+				transfer_msg->transferee, "Transferee");
+		if (!transferee_state) {
+			return NULL;
+		}
+	}
 
 	return ast_manager_event_blob_create(EVENT_FLAG_CALL, "BlindTransfer",
 			"Result: %s\r\n"
+			"%s"
 			"%s"
 			"%s"
 			"IsExternal: %s\r\n"
 			"Context: %s\r\n"
 			"Extension: %s\r\n",
-			result_strs[result],
-			ast_str_buffer(channel_state),
+			result_strs[transfer_msg->result],
+			ast_str_buffer(transferer_state),
+			transferee_state ? ast_str_buffer(transferee_state) : "",
 			bridge_state ? ast_str_buffer(bridge_state) : "",
-			is_external ? "Yes" : "No",
-			context,
-			exten);
+			transfer_msg->is_external ? "Yes" : "No",
+			transfer_msg->context,
+			transfer_msg->exten);
+}
+
+static void blind_transfer_dtor(void *obj)
+{
+	struct ast_blind_transfer_message *msg = obj;
+
+	bridge_channel_snapshot_pair_cleanup(&msg->to_transferee);
+	ao2_cleanup(msg->transferee);
 }
 
 void ast_bridge_publish_blind_transfer(int is_external, enum ast_transfer_result result,
-		struct ast_bridge_channel_pair *transferer, const char *context, const char *exten)
-{
-	RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-
-	json_object = ast_json_pack("{s: s, s: s, s: i, s: i}",
-			"context", context, "exten", exten, "result", result, "is_external", is_external);
-
-	if (!json_object) {
-		ast_log(LOG_NOTICE, "Failed to create json bridge blob\n");
-		return;
-	}
-
-	msg = ast_bridge_blob_create(ast_blind_transfer_type(),
-			transferer->bridge, transferer->channel, json_object);
-
-	if (!msg) {
-		ast_log(LOG_NOTICE, "Failed to create blob msg\n");
-		return;
-	}
-
-	stasis_publish(ast_bridge_topic_all(), msg);
+		struct ast_bridge_channel_pair *transferer, const char *context, const char *exten,
+		struct ast_channel *transferee_channel)
+{
+	struct ast_blind_transfer_message *msg;
+	struct stasis_message *stasis;
+
+	msg = ao2_alloc(sizeof(*msg), blind_transfer_dtor);
+	if (!msg) {
+		return;
+	}
+
+	if (bridge_channel_snapshot_pair_init(transferer, &msg->to_transferee)) {
+		ao2_cleanup(msg);
+		return;
+	}
+
+	if (transferee_channel) {
+		msg->transferee = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferee_channel));
+	}
+	msg->is_external = is_external;
+	msg->result = result;
+	ast_copy_string(msg->context, context, sizeof(msg->context));
+	ast_copy_string(msg->exten, exten, sizeof(msg->exten));
+
+	stasis = stasis_message_create(ast_blind_transfer_type(), msg);
+	if (!stasis) {
+		ao2_cleanup(msg);
+		return;
+	}
+
+	stasis_publish(ast_bridge_topic_all(), stasis);
+
+	ao2_cleanup(stasis);
+	ao2_cleanup(msg);
 }
 
 static struct ast_json *attended_transfer_to_json(struct stasis_message *msg,
@@ -731,7 +767,7 @@
 {
 	struct ast_attended_transfer_message *transfer_msg = stasis_message_data(msg);
 	RAII_VAR(struct ast_json *, out, NULL, ast_json_unref);
-	struct ast_json *json_transferer1, *json_transferer2, *json_bridge, *json_channel;
+	struct ast_json *json_transferer1, *json_transferer2, *json_bridge, *json_channel, *json_transferee, *json_target;
 	const struct timeval *tv = stasis_message_timestamp(msg);
 	int res = 0;
 
@@ -746,11 +782,25 @@
 		return NULL;
 	}
 
-	out = ast_json_pack("{s: s, s: o, s: o, s: o, s: s, s: o}",
+	if (transfer_msg->transferee) {
+		json_transferee = ast_channel_snapshot_to_json(transfer_msg->transferee, sanitize);
+	} else {
+		json_transferee = ast_json_null();
+	}
+
+	if (transfer_msg->target) {
+		json_target = ast_channel_snapshot_to_json(transfer_msg->target, sanitize);
+	} else {
+		json_target = ast_json_null();
+	}
+
+	out = ast_json_pack("{s: s, s: o, s: o, s: o, s: o, s: o, s: s, s: o}",
 		"type", "BridgeAttendedTransfer",
 		"timestamp", ast_json_timeval(*tv, NULL),
 		"transferer_first_leg", json_transferer1,
 		"transferer_second_leg", json_transferer2,
+		"transferee", json_transferee,
+		"transfer_target", json_target,
 		"result", result_strs[transfer_msg->result],
 		"is_external", ast_json_boolean(transfer_msg->is_external));
 	if (!out) {
@@ -842,6 +892,8 @@
 	RAII_VAR(struct ast_str *, bridge2_state, NULL, ast_free_ptr);
 	RAII_VAR(struct ast_str *, local1_state, NULL, ast_free_ptr);
 	RAII_VAR(struct ast_str *, local2_state, NULL, ast_free_ptr);
+	RAII_VAR(struct ast_str *, transferee_state, NULL, ast_free_ptr);
+	RAII_VAR(struct ast_str *, target_state, NULL, ast_free_ptr);
 	struct ast_attended_transfer_message *transfer_msg = stasis_message_data(msg);
 
 	if (!variable_data) {
@@ -852,6 +904,19 @@
 	transferer2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transfer_target.channel_snapshot, "SecondTransferer");
 	if (!transferer1_state || !transferer2_state) {
 		return NULL;
+	}
+	if (transfer_msg->transferee) {
+		transferee_state = ast_manager_build_channel_state_string_prefix(transfer_msg->transferee, "Transferee");
+		if (!transferee_state) {
+			return NULL;
+		}
+	}
+
+	if (transfer_msg->target) {
+		target_state = ast_manager_build_channel_state_string_prefix(transfer_msg->target, "TransferTarget");
+		if (!target_state) {
+			return NULL;
+		}
 	}
 
 	if (transfer_msg->to_transferee.bridge_snapshot) {
@@ -906,6 +971,8 @@
 			"%s"
 			"%s"
 			"%s"
+			"%s"
+			"%s"
 			"IsExternal: %s\r\n"
 			"%s",
 			result_strs[transfer_msg->result],
@@ -913,6 +980,8 @@
 			bridge1_state ? ast_str_buffer(bridge1_state) : "",
 			ast_str_buffer(transferer2_state),
 			bridge2_state ? ast_str_buffer(bridge2_state) : "",
+			transferee_state ? ast_str_buffer(transferee_state) : "",
+			target_state ? ast_str_buffer(target_state) : "",
 			transfer_msg->is_external ? "Yes" : "No",
 			ast_str_buffer(variable_data));
 }
@@ -925,6 +994,8 @@
 	bridge_channel_snapshot_pair_cleanup(&msg->to_transferee);
 	bridge_channel_snapshot_pair_cleanup(&msg->to_transfer_target);
 	ao2_cleanup(msg->replace_channel);
+	ao2_cleanup(msg->transferee);
+	ao2_cleanup(msg->target);
 
 	if (msg->dest_type != AST_ATTENDED_TRANSFER_DEST_LINK) {
 		return;

[... 132 lines stripped ...]



More information about the asterisk-commits mailing list