[svn-commits] mmichelson: branch mmichelson/atxfer_features r393495 - /team/mmichelson/atxf...
SVN commits to the Digium repositories
svn-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 svn-commits
mailing list