[svn-commits] mmichelson: branch mmichelson/transfer_stasis r391315 - in /team/mmichelson/t...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Jun 10 18:03:49 CDT 2013


Author: mmichelson
Date: Mon Jun 10 18:03:47 2013
New Revision: 391315

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=391315
Log:
Add functions to be able to publish attended transfer events.

Attended transfers are more complicated than blind transfers, and as such
can be accomplished in many different ways. In order to not make the API
too confusing, there are four separate ways that attended transfers may
be published. All four result in the same stasis message type being published.


Modified:
    team/mmichelson/transfer_stasis/include/asterisk/stasis_bridging.h
    team/mmichelson/transfer_stasis/main/bridging.c
    team/mmichelson/transfer_stasis/main/stasis_bridging.c

Modified: team/mmichelson/transfer_stasis/include/asterisk/stasis_bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/transfer_stasis/include/asterisk/stasis_bridging.h?view=diff&rev=391315&r1=391314&r2=391315
==============================================================================
--- team/mmichelson/transfer_stasis/include/asterisk/stasis_bridging.h (original)
+++ team/mmichelson/transfer_stasis/include/asterisk/stasis_bridging.h Mon Jun 10 18:03:47 2013
@@ -29,6 +29,7 @@
 #include "asterisk/linkedlists.h"
 #include "asterisk/channel.h"
 #include "asterisk/bridging.h"
+#include "asterisk/pbx.h"
 
 /*!
  * \brief Structure that contains a snapshot of information about a bridge
@@ -207,11 +208,19 @@
 struct ast_json *ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *snapshot);
 
 /*!
+ * \brief Pair showing a bridge snapshot and a specific channel snapshot belonging to the bridge
+ */
+struct ast_bridge_channel_snapshot_pair {
+	struct ast_bridge_snapshot *bridge_snapshot;
+	struct ast_channel_snapshot *channel_snapshot;
+};
+
+/*!
  * \brief Pair showing a bridge and a specific channel belonging to the bridge
  */
 struct ast_bridge_channel_pair {
-	struct ast_bridge_snapshot *bridge;
-	struct ast_channel_snapshot *channel;
+	struct ast_bridge *bridge;
+	struct ast_channel *channel;
 };
 
 /*!
@@ -229,7 +238,7 @@
 	/*! If 0, was core DTMF transfer, otherwise was a native transfer */
 	int is_native;
 	/*! The transferer and its bridge before starting the transfer*/
-	struct ast_bridge_channel_pair transferer;
+	struct ast_bridge_channel_snapshot_pair transferer;
 };
 
 /*!
@@ -245,16 +254,16 @@
  *
  * \param is_native Whether the blind transfer is a native blind transfer
  * \param result The success or failure of the transfer
- * \param transferer The channel performing the transfer
- * \param original_bridge The bridge between the transferer and transferee channels
+ * \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
  */
 void ast_bridge_publish_blind_transfer(int is_native, enum ast_transfer_result result,
-		struct ast_channel *transferer, struct ast_bridge *original_bridge,
-		const char *context, const char *exten);
+		struct ast_bridge_channel_pair *to_transferee, const char *context, const char *exten);
 
 enum ast_attended_transfer_dest_type {
+	/*! The transfer failed, so there is no appropriate final state */
+	AST_ATTENDED_TRANSFER_DEST_FAIL,
 	/*! The transfer results in a single bridge remaining due to a merge or swap */
 	AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE,
 	/*! The transfer results in a channel or bridge running an application */
@@ -267,28 +276,120 @@
  * \brief Message representing attended transfer
  */
 struct ast_attended_transfer_message {
+	/*! Result of the blind transfer */
+	enum ast_transfer_result result;
 	/*! Indicates if the transfer was performed using a native protocol */
 	int is_native;
 	/*! Bridge between transferer <-> transferee and the transferer channel in that bridge. May be NULL */
-	struct ast_bridge_channel_pair to_transferee;
+	struct ast_bridge_channel_snapshot_pair to_transferee;
 	/*! Bridge between transferer <-> transfer target and the transferer channel in that bridge. May be NULL */
-	struct ast_bridge_channel_pair to_transfer_target;
+	struct ast_bridge_channel_snapshot_pair to_transfer_target;
 	/*! Indicates the final state of the transfer */
 	enum ast_attended_transfer_dest_type dest_type;	
 	union {
 		/*! ID of the surviving bridge. Applicable for AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE */
-		const char *bridge_id;
+		char bridge[AST_UUID_STR_LEN];
 		/*! Destination application of transfer. Applicable for AST_ATTENDED_TRANSFER_DEST_APP */
-		const char *app;
+		char app[AST_MAX_APP];
 		/*! Pair of local channels and the bridge to which they belong. Applicable for AST_ATTENDED_TRANSFER_DEST_LINK */
 		struct {
 			/*! Local channel unique ID */
 			const char *channel;
 			/*! Bridge unique ID to which the local channel belongs */
-			const char *bridge;
+			char bridge[AST_UUID_STR_LEN];
 		} links[2];
 	} dest;
 };
+
+/*!
+ * \since 12
+ * \brief Message type for \ref ast_attended_transfer_message.
+ *
+ * \retval Message type for \ref ast_attended_transfer_message.
+ */
+struct stasis_message_type *ast_attended_transfer_type(void);
+
+/*!
+ * \since 12
+ * \brief Publish an attended transfer failure
+ *
+ * Publish an \ref ast_attended_transfer_message with the dest_type set to
+ * \c AST_ATTENDED_TRANSFER_DEST_FAIL.
+ *
+ * \param is_native Indicates if the transfer was performed natively
+ * \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
+ */
+void ast_bridge_publish_attended_transfer_failure(int is_native, enum ast_transfer_result result,
+		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target);
+
+/*!
+ * \since 12
+ * \brief Publish an attended transfer that results in two bridges becoming one.
+ *
+ * Publish an \ref ast_attended_transfer_message with the dest_type set to
+ * \c AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE. This type of attended transfer results from
+ * having two bridges involved and either
+ *
+ * \li Merging the two bridges together
+ * \li Moving a channel from one bridge to the other, thus emptying a bridge
+ *
+ * In either case, two bridges enter, one leaves.
+ *
+ * \param is_native Indicates if the transfer was performed natively
+ * \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 final_bridge The bridge that the parties end up in. Will be a bridge from the transferee or target pair.
+ */
+void ast_bridge_publish_attended_transfer_bridge_merge(int is_native, enum ast_transfer_result result,
+		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
+		struct ast_bridge *final_bridge);
+
+/*!
+ * \since 12
+ * \brief Publish an attended transfer failure
+ *
+ * Publish an \ref ast_attended_transfer_message with the dest_type set to
+ * \c AST_ATTENDED_TRANSFER_DEST_APP. This occurs when an attended transfer
+ * results in either:
+ *
+ * \li A transferee channel leaving a bridge to run an app
+ * \li A bridge of transferees running an app (via a local channel)
+ *
+ * \param is_native Indicates if the transfer was performed natively
+ * \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 dest_app The application that the channel or bridge is running upon transfer completion.
+ */
+void ast_bridge_publish_attended_transfer_app(int is_native, enum ast_transfer_result result,
+		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
+		const char *dest_app);
+
+/*!
+ * \since 12
+ * \brief Publish an attended transfer failure
+ *
+ * Publish an \ref ast_attended_transfer_message with the dest_type set to
+ * \c AST_ATTENDED_TRANSFER_DEST_LINK. This occurs when two bridges are involved
+ * in an attended transfer, but their properties do not allow for the bridges to
+ * merge or to have channels moved off of the bridge. An example of this occurs when
+ * attempting to transfer a ConfBridge to another bridge.
+ *
+ * When this type of transfer occurs, the two bridges continue to exist after the
+ * transfer and a local channel is used to link the two bridges together.
+ *
+ * \param is_native Indicates if the transfer was performed natively
+ * \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 locals The local channels linking the bridges together along with the bridge that each local channel belongs to.
+ */
+void ast_bridge_publish_attended_transfer_link(int is_native, enum ast_transfer_result result,
+		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
+		struct ast_bridge_channel_pair *locals[2]);
 
 /*!
  * \brief Initialize the stasis bridging topic and message types

Modified: team/mmichelson/transfer_stasis/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/transfer_stasis/main/bridging.c?view=diff&rev=391315&r1=391314&r2=391315
==============================================================================
--- team/mmichelson/transfer_stasis/main/bridging.c (original)
+++ team/mmichelson/transfer_stasis/main/bridging.c Mon Jun 10 18:03:47 2013
@@ -5846,6 +5846,16 @@
 	return bridge;
 }
 
+static void publish_blind_transfer(int is_native, enum ast_transfer_result result,
+		struct ast_channel *transferer, struct ast_bridge *bridge,
+		const char *context, const char *exten)
+{
+	struct ast_bridge_channel_pair pair;
+	pair.channel = transferer;
+	pair.bridge = bridge;
+	ast_bridge_publish_blind_transfer(1, result, &pair, context, exten);
+}
+
 enum ast_transfer_result ast_bridge_transfer_blind(struct ast_channel *transferer,
 		const char *exten, const char *context,
 		transfer_channel_cb new_channel_cb, void *user_data)
@@ -5939,7 +5949,7 @@
 
 publish:
 	/* XXX is_native parameter cannot be determined with current API */
-	ast_bridge_publish_blind_transfer(1, transfer_result, transferer, bridge, context, exten);
+	publish_blind_transfer(1, transfer_result, transferer, bridge, context, exten);
 	return transfer_result;
 }
 

Modified: team/mmichelson/transfer_stasis/main/stasis_bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/transfer_stasis/main/stasis_bridging.c?view=diff&rev=391315&r1=391314&r2=391315
==============================================================================
--- team/mmichelson/transfer_stasis/main/stasis_bridging.c (original)
+++ team/mmichelson/transfer_stasis/main/stasis_bridging.c Mon Jun 10 18:03:47 2013
@@ -49,6 +49,7 @@
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_entered_bridge_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_left_bridge_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_blind_transfer_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_attended_transfer_type);
 /*! @} */
 
 /*! \brief Aggregate topic for bridge messages */
@@ -311,18 +312,55 @@
 	return ast_json_ref(json_chan);
 }
 
+/*!
+ * \internal
+ * \brief Allocate the fields of an \ref ast_bridge_channel_snapshot_pair.
+ *
+ * \param pair A bridge and channel to get snapshots of
+ * \param[out] snapshot_pair An allocated snapshot pair.
+ * \retval 0 Success
+ * \retval non-zero Failure
+ */
+static int bridge_channel_snapshot_pair_init(struct ast_bridge_channel_pair *pair, struct ast_bridge_channel_snapshot_pair *snapshot_pair)
+{
+	if (pair->bridge) {
+		snapshot_pair->bridge_snapshot = ast_bridge_snapshot_create(pair->bridge);
+		if (!snapshot_pair->bridge_snapshot) {
+			return -1;
+		}
+	}
+
+	snapshot_pair->channel_snapshot = ast_channel_snapshot_create(pair->channel);
+	if (!snapshot_pair->channel_snapshot) {
+		return -1;
+	}
+
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Free the fields of an \ref ast_bridge_channel_snapshot_pair.
+ *
+ * \param pair The snapshot pair whose fields are to be cleaned up
+ */
+static void bridge_channel_snapshot_pair_cleanup(struct ast_bridge_channel_snapshot_pair *pair)
+{
+	ao2_cleanup(pair->bridge_snapshot);
+	ao2_cleanup(pair->channel_snapshot);
+}
+
 static void blind_transfer_dtor(void *obj)
 {
 	struct ast_blind_transfer_message *msg = obj;
 
 	ast_string_field_free_memory(msg);
-	ao2_cleanup(msg->transferer.bridge);
-	ao2_cleanup(msg->transferer.channel);
+	bridge_channel_snapshot_pair_cleanup(&msg->transferer);
 }
 
 static struct ast_blind_transfer_message *blind_transfer_message_create(int is_native,
-		enum ast_transfer_result result, struct ast_channel *transferer,
-		struct ast_bridge *original_bridge, const char *context, const char *exten)
+		enum ast_transfer_result result, struct ast_bridge_channel_pair *transferer,
+		const char *context, const char *exten)
 {
 	RAII_VAR(struct ast_blind_transfer_message *, msg, NULL, ao2_cleanup);
 
@@ -331,15 +369,7 @@
 		return NULL;
 	}
 
-	if (original_bridge) {
-		msg->transferer.bridge = ast_bridge_snapshot_create(original_bridge);
-		if (!msg->transferer.bridge) {
-			return NULL;
-		}
-	}
-
-	msg->transferer.channel = ast_channel_snapshot_create(transferer);
-	if (!msg->transferer.channel) {
+	if (bridge_channel_snapshot_pair_init(transferer, &msg->transferer)) {
 		return NULL;
 	}
 
@@ -353,18 +383,155 @@
 }
 
 void ast_bridge_publish_blind_transfer(int is_native, enum ast_transfer_result result,
-		struct ast_channel *transferer, struct ast_bridge *original_bridge,
-		const char *context, const char *exten)
+		struct ast_bridge_channel_pair *transferer, const char *context, const char *exten)
 {
 	RAII_VAR(struct ast_blind_transfer_message *, transfer_msg, NULL, ao2_cleanup);
 	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
 
-	transfer_msg = blind_transfer_message_create(is_native, result, transferer, original_bridge, context, exten);
+	transfer_msg = blind_transfer_message_create(is_native, result, transferer, context, exten);
 	if (!transfer_msg) {
 		return;
 	}
 
 	msg = stasis_message_create(ast_blind_transfer_type(), transfer_msg);
+	if (!msg) {
+		return;
+	}
+
+	stasis_publish(ast_bridge_topic_all(), msg);
+}
+
+static void attended_transfer_dtor(void *obj)
+{
+	struct ast_attended_transfer_message *msg = obj;
+	int i;
+
+	bridge_channel_snapshot_pair_cleanup(&msg->to_transferee);
+	bridge_channel_snapshot_pair_cleanup(&msg->to_transfer_target);
+
+	if (msg->dest_type != AST_ATTENDED_TRANSFER_DEST_LINK) {
+		return;
+	}
+
+	for (i = 0; i < ARRAY_LEN(msg->dest.links); ++i) {
+		ast_free((char *) msg->dest.links[i].channel);
+	}
+}
+
+static struct ast_attended_transfer_message *attended_transfer_message_create(int is_native, enum ast_transfer_result result,
+		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target)
+{
+	RAII_VAR(struct ast_attended_transfer_message *, msg, NULL, ao2_cleanup);
+
+	msg = ao2_alloc(sizeof(*msg), attended_transfer_dtor);
+	if (!msg) {
+		return NULL;
+	}
+
+	if (bridge_channel_snapshot_pair_init(transferee, &msg->to_transferee) ||
+			bridge_channel_snapshot_pair_init(target, &msg->to_transfer_target)) {
+		return NULL;
+	}
+
+	msg->is_native = is_native;
+	msg->result = result;
+
+	ao2_ref(msg, +1);
+	return msg;
+}
+
+void ast_bridge_publish_attended_transfer_failure(int is_native, enum ast_transfer_result result,
+		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target)
+{
+	RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+
+	transfer_msg = attended_transfer_message_create(is_native, result, transferee, target);
+	if (!transfer_msg) {
+		return;
+	}
+
+	transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_FAIL;
+
+	msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
+	if (!msg) {
+		return;
+	}
+
+	stasis_publish(ast_bridge_topic_all(), msg);
+}
+
+void ast_bridge_publish_attended_transfer_bridge_merge(int is_native, enum ast_transfer_result result,
+		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
+		struct ast_bridge *final_bridge)
+{
+	RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+
+	transfer_msg = attended_transfer_message_create(is_native, result, transferee, target);
+	if (!transfer_msg) {
+		return;
+	}
+
+	transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE;
+	ast_copy_string(transfer_msg->dest.bridge, final_bridge->uniqueid,
+			sizeof(transfer_msg->dest.bridge));
+
+	msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
+	if (!msg) {
+		return;
+	}
+
+	stasis_publish(ast_bridge_topic_all(), msg);
+}
+
+void ast_bridge_publish_attended_transfer_app(int is_native, enum ast_transfer_result result,
+		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
+		const char *dest_app)
+{
+	RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+
+	transfer_msg = attended_transfer_message_create(is_native, result, transferee, target);
+	if (!transfer_msg) {
+		return;
+	}
+
+	transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_APP;
+	ast_copy_string(transfer_msg->dest.app, dest_app, sizeof(transfer_msg->dest.app));
+
+	msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
+	if (!msg) {
+		return;
+	}
+
+	stasis_publish(ast_bridge_topic_all(), msg);
+}
+
+void ast_bridge_publish_attended_transfer_link(int is_native, enum ast_transfer_result result,
+		struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
+		struct ast_bridge_channel_pair *locals[2])
+{
+	RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+	int i;
+
+	transfer_msg = attended_transfer_message_create(is_native, result, transferee, target);
+	if (!transfer_msg) {
+		return;
+	}
+
+	transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_LINK;
+	for (i = 0; i < ARRAY_LEN(locals); ++i) {
+		transfer_msg->dest.links[i].channel = ast_strdup(ast_channel_uniqueid(locals[i]->channel));
+		if (!transfer_msg->dest.links[i].channel) {
+			return;
+		}
+		ast_copy_string(transfer_msg->dest.links[i].bridge, locals[i]->bridge->uniqueid,
+			sizeof(transfer_msg->dest.links[i].bridge));
+	}
+
+	msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
 	if (!msg) {
 		return;
 	}
@@ -386,6 +553,7 @@
 	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_entered_bridge_type);
 	STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_left_bridge_type);
 	STASIS_MESSAGE_TYPE_CLEANUP(ast_blind_transfer_type);
+	STASIS_MESSAGE_TYPE_CLEANUP(ast_attended_transfer_type);
 }
 
 /*! \brief snapshot ID getter for caching topic */
@@ -412,10 +580,10 @@
 	xfer_msg = stasis_message_data(msg);
 
 	ast_log(LOG_NOTICE, "Blind transfer to %s@%s by %s\n", xfer_msg->exten,
-			xfer_msg->context, xfer_msg->transferer.channel->name);
+			xfer_msg->context, xfer_msg->transferer.channel_snapshot->name);
 	if (xfer_msg->result == AST_TRANSFER_SUCCESS) {
 		ast_log(LOG_NOTICE, "Transfer from bridge %s was successful\n",
-				xfer_msg->transferer.bridge->uniqueid);
+				xfer_msg->transferer.bridge_snapshot->uniqueid);
 	} else {
 		ast_log(LOG_NOTICE, "Transfer was unsuccessful\n");
 	}
@@ -430,6 +598,7 @@
 	STASIS_MESSAGE_TYPE_INIT(ast_channel_entered_bridge_type);
 	STASIS_MESSAGE_TYPE_INIT(ast_channel_left_bridge_type);
 	STASIS_MESSAGE_TYPE_INIT(ast_blind_transfer_type);
+	STASIS_MESSAGE_TYPE_INIT(ast_attended_transfer_type);
 	bridge_topic_all = stasis_topic_create("ast_bridge_topic_all");
 	bridge_topic_all_cached = stasis_caching_topic_create(bridge_topic_all, bridge_snapshot_get_id);
 	bridge_topic_pool = stasis_topic_pool_create(bridge_topic_all);




More information about the svn-commits mailing list