[asterisk-commits] mmichelson: branch mmichelson/atxfer_features r393495 - /team/mmichelson/atxf...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jul 2 16:14:07 CDT 2013


Author: mmichelson
Date: Tue Jul  2 16:14:06 2013
New Revision: 393495

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=393495
Log:
Add debugging and do some rearranging of functions.


Modified:
    team/mmichelson/atxfer_features/main/bridging_basic.c

Modified: team/mmichelson/atxfer_features/main/bridging_basic.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/atxfer_features/main/bridging_basic.c?view=diff&rev=393495&r1=393494&r2=393495
==============================================================================
--- team/mmichelson/atxfer_features/main/bridging_basic.c (original)
+++ team/mmichelson/atxfer_features/main/bridging_basic.c Tue Jul  2 16:14:06 2013
@@ -219,124 +219,6 @@
 		SCOPED_LOCK(lock, iter, ast_bridge_channel_lock, ast_bridge_channel_unlock);
 		ast_bridge_features_remove(iter->features, AST_BRIDGE_HOOK_REMOVE_ON_PERSONALITY_CHANGE);
 	}
-}
-
-/*!
- * \brief Helper function that presents dialtone and grabs extension
- *
- * \retval 0 on success
- * \retval -1 on failure
- */
-static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len, const char *context)
-{
-	int res;
-	int digit_timeout;
-	RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup);
-
-	ast_channel_lock(chan);
-	xfer_cfg = ast_get_chan_features_xfer_config(chan);
-	if (!xfer_cfg) {
-		ast_log(LOG_ERROR, "Unable to get transfer configuration\n");
-		ast_channel_unlock(chan);
-		return -1;
-	}
-	digit_timeout = xfer_cfg->transferdigittimeout;
-	ast_channel_unlock(chan);
-
-	/* Play the simple "transfer" prompt out and wait */
-	res = ast_stream_and_wait(chan, "pbx-transfer", AST_DIGIT_ANY);
-	ast_stopstream(chan);
-	if (res < 0) {
-		/* Hangup or error */
-		return -1;
-	}
-	if (res) {
-		/* Store the DTMF digit that interrupted playback of the file. */
-		exten[0] = res;
-	}
-
-	/* Drop to dialtone so they can enter the extension they want to transfer to */
-	res = ast_app_dtget(chan, context, exten, exten_len, exten_len - 1, digit_timeout);
-	if (res < 0) {
-		/* Hangup or error */
-		res = -1;
-	} else if (!res) {
-		/* 0 for invalid extension dialed. */
-		if (ast_strlen_zero(exten)) {
-			ast_debug(1, "%s dialed no digits.\n", ast_channel_name(chan));
-		} else {
-			ast_debug(1, "%s dialed '%s@%s' does not exist.\n",
-				ast_channel_name(chan), exten, context);
-		}
-		ast_stream_and_wait(chan, "pbx-invalid", AST_DIGIT_NONE);
-		res = -1;
-	} else {
-		/* Dialed extension is valid. */
-		res = 0;
-	}
-	return res;
-}
-
-static void copy_caller_data(struct ast_channel *dest, struct ast_channel *caller)
-{
-	ast_channel_lock_both(caller, dest);
-	ast_connected_line_copy_from_caller(ast_channel_connected(dest), ast_channel_caller(caller));
-	ast_channel_inherit_variables(caller, dest);
-	ast_channel_datastore_inherit(caller, dest);
-	ast_channel_unlock(dest);
-	ast_channel_unlock(caller);
-}
-
-/*! \brief Helper function that creates an outgoing channel and returns it immediately */
-static struct ast_channel *dial_transfer(struct ast_channel *caller, const char *destination)
-{
-	struct ast_channel *chan;
-	int cause;
-
-	/* Now we request a local channel to prepare to call the destination */
-	chan = ast_request("Local", ast_channel_nativeformats(caller), caller, destination,
-		&cause);
-	if (!chan) {
-		return NULL;
-	}
-
-	/* Who is transferring the call. */
-	pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", ast_channel_name(caller));
-
-	/* Before we actually dial out let's inherit appropriate information. */
-	copy_caller_data(chan, caller);
-
-	return chan;
-}
-
-/*!
- * \internal
- * \brief Determine the transfer context to use.
- * \since 12.0.0
- *
- * \param transferer Channel initiating the transfer.
- * \param context User supplied context if available.  May be NULL.
- *
- * \return The context to use for the transfer.
- */
-static const char *get_transfer_context(struct ast_channel *transferer, const char *context)
-{
-	if (!ast_strlen_zero(context)) {
-		return context;
-	}
-	context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
-	if (!ast_strlen_zero(context)) {
-		return context;
-	}
-	context = ast_channel_macrocontext(transferer);
-	if (!ast_strlen_zero(context)) {
-		return context;
-	}
-	context = ast_channel_context(transferer);
-	if (!ast_strlen_zero(context)) {
-		return context;
-	}
-	return "default";
 }
 
 /*!
@@ -963,7 +845,7 @@
 {
 	struct attended_transfer_properties *props = obj;
 
-	ast_log(LOG_NOTICE, "Attended transfer properties destructor\n");
+	ast_debug(1, "Destroy attended transfer properties %p\n", props);
 
 	ao2_cleanup(props->target_bridge);
 	ao2_cleanup(props->transferee_bridge);
@@ -976,6 +858,36 @@
 }
 
 /*!
+ * \internal
+ * \brief Determine the transfer context to use.
+ * \since 12.0.0
+ *
+ * \param transferer Channel initiating the transfer.
+ * \param context User supplied context if available.  May be NULL.
+ *
+ * \return The context to use for the transfer.
+ */
+static const char *get_transfer_context(struct ast_channel *transferer, const char *context)
+{
+	if (!ast_strlen_zero(context)) {
+		return context;
+	}
+	context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
+	if (!ast_strlen_zero(context)) {
+		return context;
+	}
+	context = ast_channel_macrocontext(transferer);
+	if (!ast_strlen_zero(context)) {
+		return context;
+	}
+	context = ast_channel_context(transferer);
+	if (!ast_strlen_zero(context)) {
+		return context;
+	}
+	return "default";
+}
+
+/*!
  * \brief Allocate and initialize attended transfer properties
  *
  * \param transferee_bridge The bridge where the transfer was initiated
@@ -1010,6 +922,7 @@
 	ast_channel_lock(props->transferer);
 	xfer_cfg = ast_get_chan_features_xfer_config(props->transferer);
 	if (!xfer_cfg) {
+		ast_log(LOG_ERROR, "Unable to get transfer configuration from channel %s\n", ast_channel_name(props->transferer));
 		ao2_ref(props, -1);
 		return NULL;
 	}
@@ -1028,6 +941,7 @@
 	tech = ast_strdupa(ast_channel_name(props->transferer));
 	addr = strchr(tech, '/');
 	if (!addr) {
+		ast_log(LOG_ERROR, "Transferer channel name does not follow typical channel naming format (tech/address)\n");
 		ast_channel_unref(props->transferer);
 		return NULL;
 	}
@@ -1041,6 +955,8 @@
 
 	ast_channel_unlock(props->transferer);
 
+	ast_debug(1, "Allocated attended transfer properties %p for transfer from %s\n",
+			props, ast_channel_name(props->transferer));
 	return props;
 }
 
@@ -1065,6 +981,8 @@
  */
 static void attended_transfer_properties_shutdown(struct attended_transfer_properties *props)
 {
+	ast_debug(1, "Shutting down attended transfer %p\n", props);
+
 	if (props->transferee_bridge) {
 		ast_bridge_merge_inhibit(props->transferee_bridge, -1);
 		bridge_basic_change_personality_normal(props->transferee_bridge);
@@ -1082,6 +1000,24 @@
 	clear_stimulus_queue(props);
 
 	ao2_cleanup(props);
+}
+
+static void stimulate_attended_transfer(struct attended_transfer_properties *props,
+		enum attended_transfer_stimulus stimulus)
+{
+	struct stimulus_list *list;
+
+	list = ast_calloc(1, sizeof(*list));
+	if (!list) {
+		ast_log(LOG_ERROR, "Unable to push event to attended transfer queue. Expect transfer to fail\n");
+		return;
+	}
+
+	list->stimulus = stimulus;
+	ast_mutex_lock(&props->lock);
+	AST_LIST_INSERT_TAIL(&props->stimulus_queue, list, next);
+	ast_cond_signal(&props->cond);
+	ast_mutex_unlock(&props->lock);
 }
 
 /*!
@@ -1727,7 +1663,41 @@
 	}
 }
 
-static void recall_callback(struct ast_dial *dial);
+/*!
+ * \brief Dial callback when attempting to recall the original transferer channel
+ *
+ * This is how we can monitor if the recall target has answered or has hung up.
+ * If one of the two is detected, then an appropriate stimulus is sent to the
+ * attended transfer monitor thread.
+ */
+static void recall_callback(struct ast_dial *dial)
+{
+	struct attended_transfer_properties *props = ast_dial_get_user_data(dial);
+
+	switch (ast_dial_state(dial)) {
+	default:
+	case AST_DIAL_RESULT_INVALID:
+	case AST_DIAL_RESULT_FAILED:
+	case AST_DIAL_RESULT_TIMEOUT:
+	case AST_DIAL_RESULT_HANGUP:
+	case AST_DIAL_RESULT_UNANSWERED:
+		/* Failure cases */
+		stimulate_attended_transfer(props, STIMULUS_RECALL_TARGET_HANGUP);
+		break;
+	case AST_DIAL_RESULT_RINGING:
+	case AST_DIAL_RESULT_PROGRESS:
+	case AST_DIAL_RESULT_PROCEEDING:
+	case AST_DIAL_RESULT_TRYING:
+		/* Don't care about these cases */
+		break;
+	case AST_DIAL_RESULT_ANSWERED:
+		/* We struck gold! */
+		props->recall_target = ast_dial_answered_steal(dial);
+		stimulate_attended_transfer(props, STIMULUS_RECALL_TARGET_ANSWER);
+		break;
+	}
+}
+
 
 static int recalling_enter(struct attended_transfer_properties *props)
 {
@@ -1862,12 +1832,6 @@
 	struct ast_format fmt;
 	char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2];
 	int cause;
-
-	if (props->recall_target) {
-		ast_log(LOG_NOTICE, "props->recall_target is non-NULL and its refcount is %d\n", ao2_ref(props->recall_target, 0));
-	} else {
-		ast_log(LOG_NOTICE, "props->recall_target is NULL\n");
-	}
 	
 	if (!cap) {
 		return -1;
@@ -1980,24 +1944,6 @@
 	return 0;
 }
 
-static void stimulate_attended_transfer(struct attended_transfer_properties *props,
-		enum attended_transfer_stimulus stimulus)
-{
-	struct stimulus_list *list;
-
-	list = ast_calloc(1, sizeof(*list));
-	if (!list) {
-		ast_log(LOG_NOTICE, "Unable to push event to attended transfer queue. Expect transfer to fail\n");
-		return;
-	}
-
-	list->stimulus = stimulus;
-	ast_mutex_lock(&props->lock);
-	AST_LIST_INSERT_TAIL(&props->stimulus_queue, list, next);
-	ast_cond_signal(&props->cond);
-	ast_mutex_unlock(&props->lock);
-}
-
 /*!
  * \brief DTMF hook when transferer presses abort sequence.
  *
@@ -2007,6 +1953,7 @@
 {
 	struct attended_transfer_properties *props = hook_pvt;
 
+	ast_debug(1, "Transferer on attended transfer %p pressed abort sequence\n", props);
 	stimulate_attended_transfer(props, STIMULUS_DTMF_ATXFER_ABORT);
 	return 0;
 }
@@ -2020,6 +1967,7 @@
 {
 	struct attended_transfer_properties *props = hook_pvt;
 
+	ast_debug(1, "Transferer on attended transfer %p pressed complete sequence\n", props);
 	stimulate_attended_transfer(props, STIMULUS_DTMF_ATXFER_COMPLETE);
 	return 0;
 }
@@ -2033,6 +1981,7 @@
 {
 	struct attended_transfer_properties *props = hook_pvt;
 
+	ast_debug(1, "Transferer on attended transfer %p pressed threeway sequence\n", props);
 	stimulate_attended_transfer(props, STIMULUS_DTMF_ATXFER_THREEWAY);
 	return 0;
 }
@@ -2046,6 +1995,7 @@
 {
 	struct attended_transfer_properties *props = hook_pvt;
 
+	ast_debug(1, "Transferer on attended transfer %p pressed swap sequence\n", props);
 	stimulate_attended_transfer(props, STIMULUS_DTMF_ATXFER_SWAP);
 	return 0;
 }
@@ -2059,6 +2009,7 @@
 {
 	struct attended_transfer_properties *props = hook_pvt;
 
+	ast_debug(1, "Transferer on attended transfer %p hung up\n", props);
 	stimulate_attended_transfer(props, STIMULUS_TRANSFERER_HANGUP);
 	return 0;
 }
@@ -2085,6 +2036,8 @@
 	if (event == AST_FRAMEHOOK_EVENT_READ &&
 			frame && frame->frametype == AST_FRAME_CONTROL &&
 			frame->subclass.integer == AST_CONTROL_ANSWER) {
+
+		ast_debug(1, "Detected an answer for recall attempt on attended transfer %p\n", props);
 		if (props->superstate == SUPERSTATE_TRANSFER) {
 			stimulate_attended_transfer(props, STIMULUS_TRANSFER_TARGET_ANSWER);
 		} else {
@@ -2101,41 +2054,6 @@
 {
 	struct attended_transfer_properties *props = data;
 	ao2_cleanup(props);
-}
-
-/*!
- * \brief Dial callback when attempting to recall the original transferer channel
- *
- * This is how we can monitor if the recall target has answered or has hung up.
- * If one of the two is detected, then an appropriate stimulus is sent to the
- * attended transfer monitor thread.
- */
-static void recall_callback(struct ast_dial *dial)
-{
-	struct attended_transfer_properties *props = ast_dial_get_user_data(dial);
-
-	switch (ast_dial_state(dial)) {
-	default:
-	case AST_DIAL_RESULT_INVALID:
-	case AST_DIAL_RESULT_FAILED:
-	case AST_DIAL_RESULT_TIMEOUT:
-	case AST_DIAL_RESULT_HANGUP:
-	case AST_DIAL_RESULT_UNANSWERED:
-		/* Failure cases */
-		stimulate_attended_transfer(props, STIMULUS_RECALL_TARGET_HANGUP);
-		break;
-	case AST_DIAL_RESULT_RINGING:
-	case AST_DIAL_RESULT_PROGRESS:
-	case AST_DIAL_RESULT_PROCEEDING:
-	case AST_DIAL_RESULT_TRYING:
-		/* Don't care about these cases */
-		break;
-	case AST_DIAL_RESULT_ANSWERED:
-		/* We struck gold! */
-		props->recall_target = ast_dial_answered_steal(dial);
-		stimulate_attended_transfer(props, STIMULUS_RECALL_TARGET_ANSWER);
-		break;
-	}
 }
 
 static int bridge_personality_atxfer_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
@@ -2294,6 +2212,7 @@
 			if (state_properties[props->state].flags & TRANSFER_STATE_FLAG_TIMER_LOOP_DELAY) {
 				relative_timeout = ast_samp2tv(props->atxferloopdelay, 1000);
 			} else {
+				/* Implied TRANSFER_STATE_FLAG_TIMER_ATXFER_NO_ANSWER */
 				relative_timeout = ast_samp2tv(props->atxfernoanswertimeout, 1000);
 			}
 
@@ -2309,6 +2228,16 @@
 	return list->stimulus;
 }
 
+/*!
+ * \brief The main loop for the attended transfer monitor thread.
+ *
+ * This loop runs continuously until the attended transfer reaches
+ * a terminal state. Stimuli for changes in the attended transfer
+ * state are handled in this thread so that all factors in an
+ * attended transfer can be handled in an orderly fashion.
+ *
+ * \param data The attended transfer properties
+ */
 static void *attended_transfer_monitor_thread(void *data)
 {
 	struct attended_transfer_properties *props = data;
@@ -2316,28 +2245,30 @@
 	for (;;) {
 		enum attended_transfer_stimulus stimulus;
 
-		ast_log(LOG_NOTICE, "About to enter state %s\n", state_properties[props->state].state_name);
+		ast_debug(1, "About to enter state %s for attended transfer %p\n", state_properties[props->state].state_name, props);
 
 		if (state_properties[props->state].enter &&
 				state_properties[props->state].enter(props)) {
-			ast_log(LOG_NOTICE, "State enter function returned an error\n");
+			ast_log(LOG_ERROR, "State %s enter function returned an error for attended transfer %p\n",
+					state_properties[props->state].state_name, props);
 			break;
 		}
 
 		if (state_properties[props->state].flags & TRANSFER_STATE_FLAG_TERMINAL) {
-			ast_log(LOG_NOTICE, "State is a terminal state, so we have left it\n");
+			ast_debug(1, "State %s is a terminal state. Ending attended transfer %p\n",
+					state_properties[props->state].state_name, props);
 			break;
 		}
 
 		stimulus = wait_for_stimulus(props);
 
-		ast_log(LOG_NOTICE, "Received stimulus %s\n", stimulus_strs[stimulus]);
+		ast_debug(1, "Received stimulus %s on attended transfer %p\n", stimulus_strs[stimulus], props);
 		
 		ast_assert(state_properties[props->state].exit != NULL);
 
 		props->state = state_properties[props->state].exit(props, stimulus);
 
-		ast_log(LOG_NOTICE, "Told to enter state %s exit\n", state_properties[props->state].state_name);
+		ast_debug(1, "Told to enter state %s exit on attended transfer %p\n", state_properties[props->state].state_name, props);
 	}
 
 	attended_transfer_properties_shutdown(props);
@@ -2394,6 +2325,94 @@
 		ast_channel_set_bridge_role_option(chan, TRANSFERER_ROLE_NAME, "complete", atxfer_complete) ||
 		ast_channel_set_bridge_role_option(chan, TRANSFERER_ROLE_NAME, "threeway", atxfer_threeway) ||
 		ast_channel_set_bridge_role_option(chan, TRANSFERER_ROLE_NAME, "swap", atxfer_swap);
+}
+
+/*!
+ * \brief Helper function that presents dialtone and grabs extension
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len, const char *context)
+{
+	int res;
+	int digit_timeout;
+	RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup);
+
+	ast_channel_lock(chan);
+	xfer_cfg = ast_get_chan_features_xfer_config(chan);
+	if (!xfer_cfg) {
+		ast_log(LOG_ERROR, "Unable to get transfer configuration\n");
+		ast_channel_unlock(chan);
+		return -1;
+	}
+	digit_timeout = xfer_cfg->transferdigittimeout;
+	ast_channel_unlock(chan);
+
+	/* Play the simple "transfer" prompt out and wait */
+	res = ast_stream_and_wait(chan, "pbx-transfer", AST_DIGIT_ANY);
+	ast_stopstream(chan);
+	if (res < 0) {
+		/* Hangup or error */
+		return -1;
+	}
+	if (res) {
+		/* Store the DTMF digit that interrupted playback of the file. */
+		exten[0] = res;
+	}
+
+	/* Drop to dialtone so they can enter the extension they want to transfer to */
+	res = ast_app_dtget(chan, context, exten, exten_len, exten_len - 1, digit_timeout);
+	if (res < 0) {
+		/* Hangup or error */
+		res = -1;
+	} else if (!res) {
+		/* 0 for invalid extension dialed. */
+		if (ast_strlen_zero(exten)) {
+			ast_debug(1, "%s dialed no digits.\n", ast_channel_name(chan));
+		} else {
+			ast_debug(1, "%s dialed '%s@%s' does not exist.\n",
+				ast_channel_name(chan), exten, context);
+		}
+		ast_stream_and_wait(chan, "pbx-invalid", AST_DIGIT_NONE);
+		res = -1;
+	} else {
+		/* Dialed extension is valid. */
+		res = 0;
+	}
+	return res;
+}
+
+static void copy_caller_data(struct ast_channel *dest, struct ast_channel *caller)
+{
+	ast_channel_lock_both(caller, dest);
+	ast_connected_line_copy_from_caller(ast_channel_connected(dest), ast_channel_caller(caller));
+	ast_channel_inherit_variables(caller, dest);
+	ast_channel_datastore_inherit(caller, dest);
+	ast_channel_unlock(dest);
+	ast_channel_unlock(caller);
+}
+
+/*! \brief Helper function that creates an outgoing channel and returns it immediately */
+static struct ast_channel *dial_transfer(struct ast_channel *caller, const char *destination)
+{
+	struct ast_channel *chan;
+	int cause;
+
+	/* Now we request a local channel to prepare to call the destination */
+	chan = ast_request("Local", ast_channel_nativeformats(caller), caller, destination,
+		&cause);
+	if (!chan) {
+		return NULL;
+	}
+
+	/* Who is transferring the call. */
+	pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", ast_channel_name(caller));
+
+	/* Before we actually dial out let's inherit appropriate information. */
+	copy_caller_data(chan, caller);
+
+	return chan;
 }
 
 /*!




More information about the asterisk-commits mailing list