[asterisk-commits] mmichelson: branch mmichelson/transfer r386326 - in /team/mmichelson/transfer...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Apr 22 16:01:42 CDT 2013


Author: mmichelson
Date: Mon Apr 22 16:01:38 2013
New Revision: 386326

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386326
Log:
Implement a naive blind transfer.

I call it "naive" because I wrote this in the way that I think it needs
to work. This might work just fine, or it might totally fail! Neat!

Currently, the frame hook that is passed in is unused.


Modified:
    team/mmichelson/transfer/include/asterisk/bridging.h
    team/mmichelson/transfer/include/asterisk/bridging_features.h
    team/mmichelson/transfer/main/bridging.c

Modified: team/mmichelson/transfer/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/transfer/include/asterisk/bridging.h?view=diff&rev=386326&r1=386325&r2=386326
==============================================================================
--- team/mmichelson/transfer/include/asterisk/bridging.h (original)
+++ team/mmichelson/transfer/include/asterisk/bridging.h Mon Apr 22 16:01:38 2013
@@ -1214,13 +1214,13 @@
 
 enum ast_transfer_result {
     /*! The transfer completed successfully */
-    AST_TRANSFER_SUCCESS,
+    AST_BRIDGE_TRANSFER_SUCCESS,
     /*! A bridge involved does not permit transferring */
-    AST_TRANSFER_NOT_PERMITTED,
+    AST_BRIDGE_TRANSFER_NOT_PERMITTED,
     /*! The current bridge setup makes transferring an invalid operation */
-    AST_TRANSFER_INVALID,
+    AST_BRIDGE_TRANSFER_INVALID,
     /*! The transfer operation failed for a miscellaneous reason */
-    AST_TRANSFER_FAIL,
+    AST_BRIDGE_TRANSFER_FAIL,
 };
 
 /*!
@@ -1242,7 +1242,7 @@
  * \return The success or failure result of the blind transfer
  */
 enum ast_transfer_result ast_bridge_blind_transfer(struct ast_channel *transferer,
-		const char *exten, const char *context, struct ast_framehook *hook)
+		const char *exten, const char *context, struct ast_framehook *hook);
 
 /*!
  * \brief Attended transfer
@@ -1262,7 +1262,7 @@
  * \return The success or failure of the attended transfer
  */
 enum ast_transfer_result ast_bridge_attended_transfer(struct ast_channel *to_transferee,
-		struct ast_channel *to_transfer_target, struct ast_framehook *hook)
+		struct ast_channel *to_transfer_target, struct ast_framehook *hook);
 /*!
  * \brief Set channel to goto specific location after the bridge.
  * \since 12.0.0

Modified: team/mmichelson/transfer/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/transfer/include/asterisk/bridging_features.h?view=diff&rev=386326&r1=386325&r2=386326
==============================================================================
--- team/mmichelson/transfer/include/asterisk/bridging_features.h (original)
+++ team/mmichelson/transfer/include/asterisk/bridging_features.h Mon Apr 22 16:01:38 2013
@@ -42,6 +42,10 @@
 	AST_BRIDGE_FLAG_MERGE_INHIBIT_TO = (1 << 4),
 	/*! Bridge channels can be moved to another bridge only by masquerade (ConfBridge) */
 	AST_BRIDGE_FLAG_MASQUERADE_ONLY = (1 << 5),
+	/*! Bridge does not allow transfers of channels out */
+	AST_BRIDGE_FLAG_TRANSFER_PROHIBITED = (1 << 6),
+	/*! Bridge transfers require transfer of entire bridge rather than individual channels */
+	AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY = (1 << 7),
 };
 
 /*! \brief Flags used for per bridge channel features */

Modified: team/mmichelson/transfer/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/transfer/main/bridging.c?view=diff&rev=386326&r1=386325&r2=386326
==============================================================================
--- team/mmichelson/transfer/main/bridging.c (original)
+++ team/mmichelson/transfer/main/bridging.c Mon Apr 22 16:01:38 2013
@@ -4189,32 +4189,108 @@
 	ast_bridge_unlock(bridge);
 }
 
+/*!
+ * \internal
+ * \brief Accomplish a transfer by swapping a Local channel with an existing channel
+ *
+ * This, in a sense, blind transfers an entire bridge to an extension and context. It
+ * works by creating a local channel to dial out and swapping the called local channel
+ * with the transferring channel. By doing so, all participants in the bridge are
+ * privy to the goings-on of the blind transfer.
+ *
+ * While this means of transferring would work for both two-party and multi-party
+ * bridges, this method is only used for multi-party bridges since this method would
+ * be less efficient for two-party bridges.
+ *
+ * \param transferer The channel performing a transfer
+ * \param bridge The bridge where the transfer is being performed
+ * \param exten The destination extension for the blind transfer
+ * \param context The destination context for the blind transfer
+ * \return The success or failure of the operation
+ */
+static enum ast_transfer_result local_channel_swap_transfer(struct ast_channel *transferer, 
+		struct ast_bridge *bridge, const char *exten, const char *context)
+{
+	struct ast_channel *local;
+	char chan_name[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2]; 
+	int cause;
+
+	snprintf(chan_name, sizeof(chan_name), "%s@%s\n", exten, context);
+	local = ast_request("Local", ast_channel_nativeformats(transferer),
+			transferer, chan_name, &cause);
+	if (!local) {
+		return AST_BRIDGE_TRANSFER_FAIL;
+	}
+	if (ast_call(local, chan_name, 0)) {
+		ast_hangup(local);
+		return AST_BRIDGE_TRANSFER_FAIL;
+	}
+	if (ast_bridge_impart(bridge, local, transferer, NULL, 1)) {
+		ast_hangup(local);
+		return AST_BRIDGE_TRANSFER_FAIL;
+	}
+	return AST_BRIDGE_TRANSFER_SUCCESS;
+}
+
 enum ast_transfer_result ast_bridge_blind_transfer(struct ast_channel *transferer,
 		const char *exten, const char *context, struct ast_framehook *hook)
 {
-	/* First, ensure that the transferer is actually in a bridge. If not, return AST_TRANSFER_INVALID.
-	 * Second, ensure that the bridge the transferer is in is capable of transfers. If not, return AST_TRANSFER_NOT_PERMITTED
-	 * Third, check if the bridge in use requires transferring the bridge.
-	 *     If the bridge requires it, then perform the local channel swap method of blind transferring
-	 *     If the bridge does not require it, then check the number of bridged participants.
-	 *         If there is only one participant, then use an ast_async_goto() on the bridged participant
-	 *         If there are multiple participants, then perform the local channel swap method of blind transferring
-	 * If any of the steps above fails, then return AST_TRANSFER_FAIL
-	 * Otherwise, return AST_TRANSFER_SUCCESS.
+	RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
+	struct ast_channel *bridged_channel;
+	int do_bridge_transfer;
+	int transfer_prohibited;
+
+	ast_channel_lock(transferer);
+	bridge = ast_channel_internal_bridge(transferer);
+	if (!bridge) {
+		ast_channel_unlock(transferer);
+		return AST_BRIDGE_TRANSFER_INVALID;
+	}
+	ao2_ref(bridge, +1);
+	ast_channel_unlock(transferer);
+
+	ast_bridge_lock(bridge);
+	transfer_prohibited = ast_test_flag(&bridge->feature_flags,
+			AST_BRIDGE_FLAG_TRANSFER_PROHIBITED);
+	do_bridge_transfer = ast_test_flag(&bridge->feature_flags, 
+			AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY) ||
+			bridge->num_channels > 2;
+	ast_bridge_unlock(bridge);
+
+	if (transfer_prohibited) {
+		return AST_BRIDGE_TRANSFER_NOT_PERMITTED;
+	}
+
+	if (do_bridge_transfer) {
+		return local_channel_swap_transfer(transferer, bridge, exten, context);
+	}
+
+	ast_channel_lock(transferer);
+	bridged_channel = ast_bridged_channel(transferer);
+	if (!bridged_channel) {
+		ast_channel_unlock(transferer);
+		return AST_BRIDGE_TRANSFER_FAIL;
+	}
+	ast_channel_ref(bridged_channel);
+	ast_channel_unlock(transferer);
+
+	/* XXX I don't know if the ast_bridge_remove() call is necessary
+	 * here since ast_async_goto will set the AST_SOFTHANGUP_GOTO flag
+	 * on the channel that is being redirected
 	 */
-
-	/* XXX STUB */
-	return AST_TRANSFER_SUCCESS;
+	ast_bridge_remove(bridge, bridged_channel);
+	return ast_async_goto(bridged_channel, context, exten, 1) == 0 ?
+		AST_BRIDGE_TRANSFER_SUCCESS : AST_BRIDGE_TRANSFER_FAIL;
 }
 
 enum ast_transfer_result ast_bridge_attended_transfer(struct ast_channel *to_transferee,
 		struct ast_channel *to_transfer_target, struct ast_framehook *hook)
 {
-	/* First, check the validity of scenario. If invalid, return AST_TRANSFER_INVALID. The following are invalid:
+	/* First, check the validity of scenario. If invalid, return AST_BRIDGE_TRANSFER_INVALID. The following are invalid:
 	 *     1) atxfer of an unbridged call to an unbridged call
 	 *     2) atxfer of an unbridged call to a multi-party (n > 2) bridge
 	 *     3) atxfer of a multi-party (n > 2) bridge to an unbridged call
-	 * Second, check that the bridge(s) involved allows transfers. If not, return AST_TRANSFER_NOT_PERMITTED.
+	 * Second, check that the bridge(s) involved allows transfers. If not, return AST_BRIDGE_TRANSFER_NOT_PERMITTED.
 	 * Third, break into different scenarios for different bridge situations:
 	 * If both channels are bridged, perform a bridge merge. Direction of the merge is TBD.
 	 * If channel A is bridged, and channel B is not (e.g. transferring to IVR or blond transfer)
@@ -4228,7 +4304,7 @@
 	 */
 
 	/* XXX STUB */
-	return AST_TRANSFER_SUCCESS;
+	return AST_BRIDGE_TRANSFER_SUCCESS;
 }
 
 /*!




More information about the asterisk-commits mailing list