vector: Additional string vector definitions.
[asterisk/asterisk.git] / main / bridge_basic.c
index 522a7d4..284d178 100644 (file)
@@ -29,8 +29,6 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include "asterisk/channel.h"
 #include "asterisk/utils.h"
 #include "asterisk/linkedlists.h"
@@ -606,18 +604,17 @@ static int setup_dynamic_feature(void *obj, void *arg, void *data, int flags)
  */
 static int setup_bridge_features_dynamic(struct ast_bridge_features *features, struct ast_channel *chan)
 {
-       RAII_VAR(struct ao2_container *, applicationmap, NULL, ao2_cleanup);
+       struct ao2_container *applicationmap;
        int res = 0;
 
        ast_channel_lock(chan);
        applicationmap = ast_get_chan_applicationmap(chan);
        ast_channel_unlock(chan);
-       if (!applicationmap) {
-               return 0;
+       if (applicationmap) {
+               ao2_callback_data(applicationmap, 0, setup_dynamic_feature, features, &res);
+               ao2_ref(applicationmap, -1);
        }
 
-       ao2_callback_data(applicationmap, 0, setup_dynamic_feature, features, &res);
-
        return res;
 }
 
@@ -1297,8 +1294,6 @@ struct attended_transfer_properties {
                AST_STRING_FIELD(exten);
                /*! Context of transfer target */
                AST_STRING_FIELD(context);
-               /*! Sound to play on failure */
-               AST_STRING_FIELD(failsound);
                /*! Sound to play when transfer completes */
                AST_STRING_FIELD(xfersound);
                /*! The channel technology of the transferer channel */
@@ -1418,16 +1413,25 @@ static struct attended_transfer_properties *attended_transfer_properties_alloc(
        char *tech;
        char *addr;
        char *serial;
-       RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup);
+       struct ast_features_xfer_config *xfer_cfg;
        struct ast_flags *transferer_features;
 
        props = ao2_alloc(sizeof(*props), attended_transfer_properties_destructor);
-       if (!props || ast_string_field_init(props, 64)) {
+       if (!props) {
+               ast_log(LOG_ERROR, "Unable to create props - channel %s, context %s\n",
+                       ast_channel_name(transferer), context);
                return NULL;
        }
 
        ast_cond_init(&props->cond, NULL);
 
+       if (ast_string_field_init(props, 64)) {
+               ast_log(LOG_ERROR, "Unable to initialize prop fields - channel %s, context %s\n",
+                       ast_channel_name(transferer), context);
+               ao2_ref(props, -1);
+               return NULL;
+       }
+
        props->target_framehook_id = -1;
        props->transferer = ast_channel_ref(transferer);
 
@@ -1448,8 +1452,8 @@ static struct attended_transfer_properties *attended_transfer_properties_alloc(
        props->atxfernoanswertimeout = xfer_cfg->atxfernoanswertimeout;
        props->atxferloopdelay = xfer_cfg->atxferloopdelay;
        ast_string_field_set(props, context, get_transfer_context(transferer, context));
-       ast_string_field_set(props, failsound, xfer_cfg->xferfailsound);
        ast_string_field_set(props, xfersound, xfer_cfg->xfersound);
+       ao2_ref(xfer_cfg, -1);
 
        /*
         * Save the transferee's party information for any recall calls.
@@ -1543,6 +1547,23 @@ static void stimulate_attended_transfer(struct attended_transfer_properties *pro
        ao2_unlock(props);
 }
 
+static void remove_attended_transfer_stimulus(struct attended_transfer_properties *props,
+               enum attended_transfer_stimulus stimulus)
+{
+       struct stimulus_list *list;
+
+       ao2_lock(props);
+       AST_LIST_TRAVERSE_SAFE_BEGIN(&props->stimulus_queue, list, next) {
+               if (list->stimulus == stimulus) {
+                       AST_LIST_REMOVE_CURRENT(next);
+                       ast_free(list);
+                       break;
+               }
+       }
+       AST_LIST_TRAVERSE_SAFE_END;
+       ao2_unlock(props);
+}
+
 /*!
  * \brief Get a desired transfer party for a bridge the transferer is not in.
  *
@@ -1695,17 +1716,54 @@ static void publish_transfer_fail(struct attended_transfer_properties *props)
  */
 static void play_sound(struct ast_channel *chan, const char *sound)
 {
-       RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+       struct ast_bridge_channel *bridge_channel;
 
        ast_channel_lock(chan);
        bridge_channel = ast_channel_get_bridge_channel(chan);
        ast_channel_unlock(chan);
 
-       if (!bridge_channel) {
-               return;
+       if (bridge_channel) {
+               ast_bridge_channel_queue_playfile(bridge_channel, NULL, sound, NULL);
+               ao2_ref(bridge_channel, -1);
+       }
+}
+
+/*!
+ * \brief Helper method to play a fail sound on a channel in a bridge
+ *
+ * \param chan The channel to play the fail sound to
+ */
+static void play_failsound(struct ast_channel *chan)
+{
+       char *sound;
+
+       ast_channel_lock(chan);
+       sound = ast_get_chan_features_xferfailsound(chan);
+       ast_channel_unlock(chan);
+
+       if (sound) {
+               play_sound(chan, sound);
+               ast_free(sound);
        }
+}
+
+/*!
+ * \brief Helper method to stream a fail sound on a channel
+ *
+ * \param chan The channel to stream the fail sound to
+ */
+static void stream_failsound(struct ast_channel *chan)
+{
+       char *sound;
 
-       ast_bridge_channel_queue_playfile(bridge_channel, NULL, sound, NULL);
+       ast_channel_lock(chan);
+       sound = ast_get_chan_features_xferfailsound(chan);
+       ast_channel_unlock(chan);
+
+       if (sound) {
+               ast_stream_and_wait(chan, sound, AST_DIGIT_NONE);
+               ast_free(sound);
+       }
 }
 
 /*!
@@ -1713,16 +1771,19 @@ static void play_sound(struct ast_channel *chan, const char *sound)
  */
 static void hold(struct ast_channel *chan)
 {
-       RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+       struct ast_bridge_channel *bridge_channel;
 
-       if (chan) {
-               ast_channel_lock(chan);
-               bridge_channel = ast_channel_get_bridge_channel(chan);
-               ast_channel_unlock(chan);
+       if (!chan) {
+               return;
+       }
 
-               ast_assert(bridge_channel != NULL);
+       ast_channel_lock(chan);
+       bridge_channel = ast_channel_get_bridge_channel(chan);
+       ast_channel_unlock(chan);
 
+       if (bridge_channel) {
                ast_bridge_channel_write_hold(bridge_channel, NULL);
+               ao2_ref(bridge_channel, -1);
        }
 }
 
@@ -1731,15 +1792,20 @@ static void hold(struct ast_channel *chan)
  */
 static void unhold(struct ast_channel *chan)
 {
-       RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+       struct ast_bridge_channel *bridge_channel;
+
+       if (!chan) {
+               return;
+       }
 
        ast_channel_lock(chan);
        bridge_channel = ast_channel_get_bridge_channel(chan);
        ast_channel_unlock(chan);
 
-       ast_assert(bridge_channel != NULL);
-
-       ast_bridge_channel_write_unhold(bridge_channel);
+       if (bridge_channel) {
+               ast_bridge_channel_write_unhold(bridge_channel);
+               ao2_ref(bridge_channel, -1);
+       }
 }
 
 /*!
@@ -1747,15 +1813,16 @@ static void unhold(struct ast_channel *chan)
  */
 static void ringing(struct ast_channel *chan)
 {
-       RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+       struct ast_bridge_channel *bridge_channel;
 
        ast_channel_lock(chan);
        bridge_channel = ast_channel_get_bridge_channel(chan);
        ast_channel_unlock(chan);
 
-       ast_assert(bridge_channel != NULL);
-
-       ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_RINGING, NULL, 0);
+       if (bridge_channel) {
+               ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_RINGING, NULL, 0);
+               ao2_ref(bridge_channel, -1);
+       }
 }
 
 /*!
@@ -1800,10 +1867,9 @@ static void bridge_unhold(struct ast_bridge *bridge)
 /*!
  * \brief Wrapper for \ref bridge_do_move
  */
-static int bridge_move(struct ast_bridge *dest, struct ast_bridge *src, struct ast_channel *channel, struct ast_channel *swap)
+static void bridge_move(struct ast_bridge *dest, struct ast_bridge *src, struct ast_channel *channel, struct ast_channel *swap)
 {
-       int res;
-       RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+       struct ast_bridge_channel *bridge_channel;
 
        ast_bridge_lock_both(src, dest);
 
@@ -1811,18 +1877,18 @@ static int bridge_move(struct ast_bridge *dest, struct ast_bridge *src, struct a
        bridge_channel = ast_channel_get_bridge_channel(channel);
        ast_channel_unlock(channel);
 
-       ast_assert(bridge_channel != NULL);
+       if (bridge_channel) {
+               ao2_lock(bridge_channel);
+               bridge_channel->swap = swap;
+               ao2_unlock(bridge_channel);
 
-       ao2_lock(bridge_channel);
-       bridge_channel->swap = swap;
-       ao2_unlock(bridge_channel);
-
-       res = bridge_do_move(dest, bridge_channel, 1, 0);
+               bridge_do_move(dest, bridge_channel, 1, 0);
+       }
 
        ast_bridge_unlock(dest);
        ast_bridge_unlock(src);
 
-       return res;
+       ao2_cleanup(bridge_channel);
 }
 
 /*!
@@ -2033,7 +2099,8 @@ static const struct attended_transfer_state_properties state_properties[] = {
 
 static int calling_target_enter(struct attended_transfer_properties *props)
 {
-       return bridge_move(props->target_bridge, props->transferee_bridge, props->transferer, NULL);
+       bridge_move(props->target_bridge, props->transferee_bridge, props->transferer, NULL);
+       return 0;
 }
 
 static enum attended_transfer_state calling_target_exit(struct attended_transfer_properties *props,
@@ -2041,7 +2108,7 @@ static enum attended_transfer_state calling_target_exit(struct attended_transfer
 {
        switch (stimulus) {
        case STIMULUS_TRANSFEREE_HANGUP:
-               play_sound(props->transferer, props->failsound);
+               play_failsound(props->transferer);
                publish_transfer_fail(props);
                return TRANSFER_FAIL;
        case STIMULUS_DTMF_ATXFER_COMPLETE:
@@ -2053,7 +2120,7 @@ static enum attended_transfer_state calling_target_exit(struct attended_transfer
        case STIMULUS_TRANSFER_TARGET_HANGUP:
        case STIMULUS_TIMEOUT:
        case STIMULUS_DTMF_ATXFER_ABORT:
-               play_sound(props->transferer, props->failsound);
+               play_failsound(props->transferer);
                return TRANSFER_REBRIDGE;
        case STIMULUS_DTMF_ATXFER_THREEWAY:
                bridge_unhold(props->transferee_bridge);
@@ -2072,10 +2139,7 @@ static enum attended_transfer_state calling_target_exit(struct attended_transfer
 
 static int hesitant_enter(struct attended_transfer_properties *props)
 {
-       if (bridge_move(props->transferee_bridge, props->target_bridge, props->transferer, NULL)) {
-               return -1;
-       }
-
+       bridge_move(props->transferee_bridge, props->target_bridge, props->transferer, NULL);
        unhold(props->transferer);
        return 0;
 }
@@ -2085,7 +2149,7 @@ static enum attended_transfer_state hesitant_exit(struct attended_transfer_prope
 {
        switch (stimulus) {
        case STIMULUS_TRANSFEREE_HANGUP:
-               play_sound(props->transferer, props->failsound);
+               play_failsound(props->transferer);
                publish_transfer_fail(props);
                return TRANSFER_FAIL;
        case STIMULUS_DTMF_ATXFER_COMPLETE:
@@ -2096,7 +2160,7 @@ static enum attended_transfer_state hesitant_exit(struct attended_transfer_prope
        case STIMULUS_TRANSFER_TARGET_HANGUP:
        case STIMULUS_TIMEOUT:
        case STIMULUS_DTMF_ATXFER_ABORT:
-               play_sound(props->transferer, props->failsound);
+               play_failsound(props->transferer);
                return TRANSFER_RESUME;
        case STIMULUS_DTMF_ATXFER_THREEWAY:
                return TRANSFER_THREEWAY;
@@ -2115,11 +2179,7 @@ static enum attended_transfer_state hesitant_exit(struct attended_transfer_prope
 
 static int rebridge_enter(struct attended_transfer_properties *props)
 {
-       if (bridge_move(props->transferee_bridge, props->target_bridge,
-                       props->transferer, NULL)) {
-               return -1;
-       }
-
+       bridge_move(props->transferee_bridge, props->target_bridge, props->transferer, NULL);
        unhold(props->transferer);
        return 0;
 }
@@ -2162,7 +2222,7 @@ static enum attended_transfer_state consulting_exit(struct attended_transfer_pro
                 * a sound to the transferer to indicate the transferee is gone.
                 */
                bridge_basic_change_personality(props->target_bridge, BRIDGE_BASIC_PERSONALITY_NORMAL, NULL);
-               play_sound(props->transferer, props->failsound);
+               play_failsound(props->transferer);
                ast_bridge_merge_inhibit(props->target_bridge, -1);
                /* These next two lines are here to ensure that our reference to the target bridge
                 * is cleaned up properly and that the target bridge is not destroyed when the
@@ -2177,8 +2237,9 @@ static enum attended_transfer_state consulting_exit(struct attended_transfer_pro
                bridge_unhold(props->transferee_bridge);
                return TRANSFER_COMPLETE;
        case STIMULUS_TRANSFER_TARGET_HANGUP:
+               return TRANSFER_REBRIDGE;
        case STIMULUS_DTMF_ATXFER_ABORT:
-               play_sound(props->transferer, props->failsound);
+               play_failsound(props->transferer);
                return TRANSFER_REBRIDGE;
        case STIMULUS_DTMF_ATXFER_THREEWAY:
                bridge_unhold(props->transferee_bridge);
@@ -2210,7 +2271,7 @@ static enum attended_transfer_state double_checking_exit(struct attended_transfe
 {
        switch (stimulus) {
        case STIMULUS_TRANSFEREE_HANGUP:
-               play_sound(props->transferer, props->failsound);
+               play_failsound(props->transferer);
                publish_transfer_fail(props);
                return TRANSFER_FAIL;
        case STIMULUS_TRANSFERER_HANGUP:
@@ -2220,7 +2281,7 @@ static enum attended_transfer_state double_checking_exit(struct attended_transfe
                return TRANSFER_COMPLETE;
        case STIMULUS_TRANSFER_TARGET_HANGUP:
        case STIMULUS_DTMF_ATXFER_ABORT:
-               play_sound(props->transferer, props->failsound);
+               play_failsound(props->transferer);
                return TRANSFER_RESUME;
        case STIMULUS_DTMF_ATXFER_THREEWAY:
                bridge_unhold(props->target_bridge);
@@ -2295,6 +2356,10 @@ static enum attended_transfer_state blond_nonfinal_exit(struct attended_transfer
                return TRANSFER_RESUME;
        case STIMULUS_TIMEOUT:
                ast_softhangup(props->recall_target, AST_SOFTHANGUP_EXPLICIT);
+               /* It is possible before we hung them up that they queued up a recall target answer
+                * so we remove it if present as it should not exist.
+                */
+               remove_attended_transfer_stimulus(props, STIMULUS_RECALL_TARGET_ANSWER);
        case STIMULUS_RECALL_TARGET_HANGUP:
                props->recall_target = ast_channel_unref(props->recall_target);
                return TRANSFER_RECALLING;
@@ -2759,7 +2824,8 @@ static struct ast_frame *transfer_target_framehook_cb(struct ast_channel *chan,
 
        if (event == AST_FRAMEHOOK_EVENT_READ &&
                        frame && frame->frametype == AST_FRAME_CONTROL &&
-                       frame->subclass.integer == AST_CONTROL_ANSWER) {
+                       frame->subclass.integer == AST_CONTROL_ANSWER &&
+                       !ast_check_hangup(chan)) {
 
                ast_debug(1, "Detected an answer for recall attempt on attended transfer %p\n", props);
                if (props->superstate == SUPERSTATE_TRANSFER) {
@@ -2839,7 +2905,8 @@ static void transfer_pull(struct ast_bridge *self, struct ast_bridge_channel *br
        }
 
        if (self->num_channels == 1) {
-               RAII_VAR(struct ast_bridge_channel *, transferer_bridge_channel, NULL, ao2_cleanup);
+               struct ast_bridge_channel *transferer_bridge_channel;
+               int not_transferer;
 
                ast_channel_lock(props->transferer);
                transferer_bridge_channel = ast_channel_get_bridge_channel(props->transferer);
@@ -2849,7 +2916,9 @@ static void transfer_pull(struct ast_bridge *self, struct ast_bridge_channel *br
                        return;
                }
 
-               if (AST_LIST_FIRST(&self->channels) != transferer_bridge_channel) {
+               not_transferer = AST_LIST_FIRST(&self->channels) != transferer_bridge_channel;
+               ao2_ref(transferer_bridge_channel, -1);
+               if (not_transferer) {
                        return;
                }
        }
@@ -2886,7 +2955,8 @@ static void recall_pull(struct ast_bridge *self, struct ast_bridge_channel *brid
        }
 
        if (self->num_channels == 1) {
-               RAII_VAR(struct ast_bridge_channel *, target_bridge_channel, NULL, ao2_cleanup);
+               struct ast_bridge_channel *target_bridge_channel;
+
                if (!props->recall_target) {
                        /* No recall target means that the pull happened on a transferee. If there's still
                         * a channel left in the bridge, we don't need to send a stimulus
@@ -2898,12 +2968,11 @@ static void recall_pull(struct ast_bridge *self, struct ast_bridge_channel *brid
                target_bridge_channel = ast_channel_get_bridge_channel(props->recall_target);
                ast_channel_unlock(props->recall_target);
 
-               if (!target_bridge_channel) {
-                       return;
-               }
-
-               if (AST_LIST_FIRST(&self->channels) == target_bridge_channel) {
-                       stimulate_attended_transfer(props, STIMULUS_TRANSFEREE_HANGUP);
+               if (target_bridge_channel) {
+                       if (AST_LIST_FIRST(&self->channels) == target_bridge_channel) {
+                               stimulate_attended_transfer(props, STIMULUS_TRANSFEREE_HANGUP);
+                       }
+                       ao2_ref(target_bridge_channel, -1);
                }
        }
 }
@@ -2925,7 +2994,8 @@ static void bridge_personality_atxfer_pull(struct ast_bridge *self, struct ast_b
 
 static enum attended_transfer_stimulus wait_for_stimulus(struct attended_transfer_properties *props)
 {
-       RAII_VAR(struct stimulus_list *, list, NULL, ast_free_ptr);
+       enum attended_transfer_stimulus stimulus;
+       struct stimulus_list *list;
        SCOPED_MUTEX(lock, ao2_object_get_lockaddr(props));
 
        while (!(list = AST_LIST_REMOVE_HEAD(&props->stimulus_queue, next))) {
@@ -2956,7 +3026,9 @@ static enum attended_transfer_stimulus wait_for_stimulus(struct attended_transfe
                        }
                }
        }
-       return list->stimulus;
+       stimulus = list->stimulus;
+       ast_free(list);
+       return stimulus;
 }
 
 /*!
@@ -3036,7 +3108,9 @@ static int attach_framehook(struct attended_transfer_properties *props, struct a
        ao2_ref(props, +1);
        target_interface.data = props;
 
+       ast_channel_lock(channel);
        props->target_framehook_id = ast_framehook_attach(channel, &target_interface);
+       ast_channel_unlock(channel);
        if (props->target_framehook_id == -1) {
                ao2_ref(props, -1);
                return -1;
@@ -3050,7 +3124,7 @@ static int add_transferer_role(struct ast_channel *chan, struct ast_bridge_featu
        const char *atxfer_threeway;
        const char *atxfer_complete;
        const char *atxfer_swap;
-       RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup);
+       struct ast_features_xfer_config *xfer_cfg;
        SCOPED_CHANNELLOCK(lock, chan);
 
        xfer_cfg = ast_get_chan_features_xfer_config(chan);
@@ -3068,6 +3142,7 @@ static int add_transferer_role(struct ast_channel *chan, struct ast_bridge_featu
                atxfer_complete = ast_strdupa(xfer_cfg->atxfercomplete);
                atxfer_swap = ast_strdupa(xfer_cfg->atxferswap);
        }
+       ao2_ref(xfer_cfg, -1);
 
        return ast_channel_add_bridge_role(chan, AST_TRANSFERER_ROLE_NAME) ||
                ast_channel_set_bridge_role_option(chan, AST_TRANSFERER_ROLE_NAME, "abort", atxfer_abort) ||
@@ -3088,14 +3163,15 @@ static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len
        int digit_timeout;
        int attempts = 0;
        int max_attempts;
-       RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup);
+       struct ast_features_xfer_config *xfer_cfg;
        char *retry_sound;
        char *invalid_sound;
 
        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_log(LOG_ERROR, "Channel %s: Unable to get transfer configuration\n",
+                       ast_channel_name(chan));
                ast_channel_unlock(chan);
                return -1;
        }
@@ -3103,6 +3179,7 @@ static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len
        max_attempts = xfer_cfg->transferdialattempts;
        retry_sound = ast_strdupa(xfer_cfg->transferretrysound);
        invalid_sound = ast_strdupa(xfer_cfg->transferinvalidsound);
+       ao2_ref(xfer_cfg, -1);
        ast_channel_unlock(chan);
 
        /* Play the simple "transfer" prompt out and wait */
@@ -3138,9 +3215,9 @@ static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len
                } 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));
+                               ast_verb(3, "Channel %s: Dialed no digits.\n", ast_channel_name(chan));
                        } else {
-                               ast_debug(1, "%s dialed '%s@%s' does not exist.\n",
+                               ast_verb(3, "Channel %s: Dialed '%s@%s' does not exist.\n",
                                        ast_channel_name(chan), exten, context);
                        }
                        if (attempts < max_attempts) {
@@ -3227,9 +3304,12 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
        /* Inhibit the bridge before we do anything else. */
        bridge = ast_bridge_channel_merge_inhibit(bridge_channel, +1);
 
+       ast_verb(3, "Channel %s: Started DTMF attended transfer.\n",
+               ast_channel_name(bridge_channel->chan));
+
        if (strcmp(bridge->v_table->name, "basic")) {
-               ast_log(LOG_ERROR, "Attended transfer attempted on unsupported bridge type '%s'.\n",
-                       bridge->v_table->name);
+               ast_log(LOG_ERROR, "Channel %s: Attended transfer attempted on unsupported bridge type '%s'.\n",
+                       ast_channel_name(bridge_channel->chan), bridge->v_table->name);
                ast_bridge_merge_inhibit(bridge, -1);
                ao2_ref(bridge, -1);
                return 0;
@@ -3251,7 +3331,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
        props = attended_transfer_properties_alloc(bridge_channel->chan,
                attended_transfer ? attended_transfer->context : NULL);
        if (!props) {
-               ast_log(LOG_ERROR, "Unable to allocate control structure for performing attended transfer.\n");
+               ast_log(LOG_ERROR, "Channel %s: Unable to allocate control structure for performing attended transfer.\n",
+                       ast_channel_name(bridge_channel->chan));
                ast_bridge_merge_inhibit(bridge, -1);
                ao2_ref(bridge, -1);
                return 0;
@@ -3260,7 +3341,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
        props->transferee_bridge = bridge;
 
        if (add_transferer_role(props->transferer, attended_transfer)) {
-               ast_log(LOG_ERROR, "Unable to set transferrer bridge role.\n");
+               ast_log(LOG_ERROR, "Channel %s: Unable to set transferrer bridge role.\n",
+                       ast_channel_name(bridge_channel->chan));
                attended_transfer_properties_shutdown(props);
                return 0;
        }
@@ -3269,7 +3351,15 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
 
        /* Grab the extension to transfer to */
        if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), props->context)) {
-               ast_log(LOG_WARNING, "Unable to acquire target extension for attended transfer.\n");
+               /*
+                * XXX The warning here really should be removed.  While the
+                * message is accurate, this is a normal exit for when the user
+                * fails to specify a valid transfer target.  e.g., The user
+                * hungup, didn't dial any digits, or dialed an invalid
+                * extension.
+                */
+               ast_log(LOG_WARNING, "Channel %s: Unable to acquire target extension for attended transfer.\n",
+                       ast_channel_name(bridge_channel->chan));
                ast_bridge_channel_write_unhold(bridge_channel);
                attended_transfer_properties_shutdown(props);
                return 0;
@@ -3280,13 +3370,15 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
        /* Fill the variable with the extension and context we want to call */
        snprintf(destination, sizeof(destination), "%s@%s", props->exten, props->context);
 
-       ast_debug(1, "Attended transfer to '%s'\n", destination);
+       ast_debug(1, "Channel %s: Attended transfer target '%s'\n",
+               ast_channel_name(bridge_channel->chan), destination);
 
        /* Get a channel that is the destination we wish to call */
        props->transfer_target = dial_transfer(bridge_channel->chan, destination);
        if (!props->transfer_target) {
-               ast_log(LOG_ERROR, "Unable to request outbound channel for attended transfer target.\n");
-               ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE);
+               ast_log(LOG_ERROR, "Channel %s: Unable to request outbound channel for attended transfer target.\n",
+                       ast_channel_name(bridge_channel->chan));
+               stream_failsound(props->transferer);
                ast_bridge_channel_write_unhold(bridge_channel);
                attended_transfer_properties_shutdown(props);
                return 0;
@@ -3296,8 +3388,9 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
        /* Create a bridge to use to talk to the person we are calling */
        props->target_bridge = ast_bridge_basic_new();
        if (!props->target_bridge) {
-               ast_log(LOG_ERROR, "Unable to create bridge for attended transfer target.\n");
-               ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE);
+               ast_log(LOG_ERROR, "Channel %s: Unable to create bridge for attended transfer target.\n",
+                       ast_channel_name(bridge_channel->chan));
+               stream_failsound(props->transferer);
                ast_bridge_channel_write_unhold(bridge_channel);
                ast_hangup(props->transfer_target);
                props->transfer_target = NULL;
@@ -3307,8 +3400,9 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
        ast_bridge_merge_inhibit(props->target_bridge, +1);
 
        if (attach_framehook(props, props->transfer_target)) {
-               ast_log(LOG_ERROR, "Unable to attach framehook to transfer target.\n");
-               ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE);
+               ast_log(LOG_ERROR, "Channel %s: Unable to attach framehook to transfer target.\n",
+                       ast_channel_name(bridge_channel->chan));
+               stream_failsound(props->transferer);
                ast_bridge_channel_write_unhold(bridge_channel);
                ast_hangup(props->transfer_target);
                props->transfer_target = NULL;
@@ -3322,8 +3416,9 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
                        BRIDGE_BASIC_PERSONALITY_ATXFER, props);
 
        if (ast_call(props->transfer_target, destination, 0)) {
-               ast_log(LOG_ERROR, "Unable to place outbound call to transfer target.\n");
-               ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE);
+               ast_log(LOG_ERROR, "Channel %s: Unable to place outbound call to transfer target.\n",
+                       ast_channel_name(bridge_channel->chan));
+               stream_failsound(props->transferer);
                ast_bridge_channel_write_unhold(bridge_channel);
                ast_hangup(props->transfer_target);
                props->transfer_target = NULL;
@@ -3338,8 +3433,9 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
        ast_channel_ref(props->transfer_target);
        if (ast_bridge_impart(props->target_bridge, props->transfer_target, NULL, NULL,
                AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
-               ast_log(LOG_ERROR, "Unable to place transfer target into bridge.\n");
-               ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE);
+               ast_log(LOG_ERROR, "Channel %s: Unable to place transfer target into bridge.\n",
+                       ast_channel_name(bridge_channel->chan));
+               stream_failsound(props->transferer);
                ast_bridge_channel_write_unhold(bridge_channel);
                ast_hangup(props->transfer_target);
                props->transfer_target = NULL;
@@ -3348,8 +3444,9 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
        }
 
        if (ast_pthread_create_detached(&thread, NULL, attended_transfer_monitor_thread, props)) {
-               ast_log(LOG_ERROR, "Unable to create monitoring thread for attended transfer.\n");
-               ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE);
+               ast_log(LOG_ERROR, "Channel %s: Unable to create monitoring thread for attended transfer.\n",
+                       ast_channel_name(bridge_channel->chan));
+               stream_failsound(props->transferer);
                ast_bridge_channel_write_unhold(bridge_channel);
                attended_transfer_properties_shutdown(props);
                return 0;
@@ -3374,35 +3471,52 @@ static void blind_transfer_cb(struct ast_channel *new_channel, struct transfer_c
 /*! \brief Internal built in feature for blind transfers */
 static int feature_blind_transfer(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 {
-       char exten[AST_MAX_EXTENSION] = "";
+       char xfer_exten[AST_MAX_EXTENSION] = "";
        struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;
-       const char *context;
+       const char *xfer_context;
        char *goto_on_blindxfr;
 
+       ast_verb(3, "Channel %s: Started DTMF blind transfer.\n",
+               ast_channel_name(bridge_channel->chan));
+
        ast_bridge_channel_write_hold(bridge_channel, NULL);
 
        ast_channel_lock(bridge_channel->chan);
-       context = ast_strdupa(get_transfer_context(bridge_channel->chan,
+       xfer_context = ast_strdupa(get_transfer_context(bridge_channel->chan,
                blind_transfer ? blind_transfer->context : NULL));
        goto_on_blindxfr = ast_strdupa(S_OR(pbx_builtin_getvar_helper(bridge_channel->chan,
                "GOTO_ON_BLINDXFR"), ""));
        ast_channel_unlock(bridge_channel->chan);
 
        /* Grab the extension to transfer to */
-       if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
+       if (grab_transfer(bridge_channel->chan, xfer_exten, sizeof(xfer_exten), xfer_context)) {
                ast_bridge_channel_write_unhold(bridge_channel);
                return 0;
        }
 
+       ast_debug(1, "Channel %s: Blind transfer target '%s@%s'\n",
+               ast_channel_name(bridge_channel->chan), xfer_exten, xfer_context);
+
        if (!ast_strlen_zero(goto_on_blindxfr)) {
-               ast_debug(1, "After transfer, transferer %s goes to %s\n",
-                               ast_channel_name(bridge_channel->chan), goto_on_blindxfr);
-               ast_bridge_set_after_go_on(bridge_channel->chan, NULL, NULL, 0, goto_on_blindxfr);
+               const char *chan_context;
+               const char *chan_exten;
+               int chan_priority;
+
+               ast_debug(1, "Channel %s: After transfer, transferrer goes to %s\n",
+                       ast_channel_name(bridge_channel->chan), goto_on_blindxfr);
+
+               ast_channel_lock(bridge_channel->chan);
+               chan_context = ast_strdupa(ast_channel_context(bridge_channel->chan));
+               chan_exten = ast_strdupa(ast_channel_exten(bridge_channel->chan));
+               chan_priority = ast_channel_priority(bridge_channel->chan);
+               ast_channel_unlock(bridge_channel->chan);
+               ast_bridge_set_after_go_on(bridge_channel->chan,
+                       chan_context, chan_exten, chan_priority, goto_on_blindxfr);
        }
 
-       if (ast_bridge_transfer_blind(0, bridge_channel->chan, exten, context, blind_transfer_cb,
-                       bridge_channel->chan) != AST_BRIDGE_TRANSFER_SUCCESS &&
-                       !ast_strlen_zero(goto_on_blindxfr)) {
+       if (ast_bridge_transfer_blind(0, bridge_channel->chan, xfer_exten, xfer_context,
+               blind_transfer_cb, bridge_channel->chan) != AST_BRIDGE_TRANSFER_SUCCESS
+               && !ast_strlen_zero(goto_on_blindxfr)) {
                ast_bridge_discard_after_goto(bridge_channel->chan);
        }
 
@@ -3548,4 +3662,3 @@ void ast_bridging_init_basic(void)
        ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, feature_attended_transfer, NULL);
        ast_bridge_features_register(AST_BRIDGE_BUILTIN_BLINDTRANSFER, feature_blind_transfer, NULL);
 }
-