diff --git a/include/asterisk/features_config.h b/include/asterisk/features_config.h index b15759ba6c4c649979d445ac0f12f7361cb798f7..baaff183b3061087ced7edd77021d6ed896ba648 100644 --- a/include/asterisk/features_config.h +++ b/include/asterisk/features_config.h @@ -101,6 +101,21 @@ struct ast_features_xfer_config { */ struct ast_features_xfer_config *ast_get_chan_features_xfer_config(struct ast_channel *chan); +/*! + * \brief Get the transfer configuration option xferfailsound + * + * \note The channel should be locked before calling this function. + * \note The returned value has to be freed. + * + * If no channel is provided, then option is pulled from the global + * transfer configuration. + * + * \param chan The channel to get configuration options for + * \retval NULL Failed to get configuration + * \retval non-NULL The xferfailsound + */ +char *ast_get_chan_features_xferfailsound(struct ast_channel *chan); + /*! * \brief Configuration relating to call pickup */ diff --git a/main/bridge_basic.c b/main/bridge_basic.c index cd19915205a95b3554622e4b1d83f317a336742b..5d8ee49d06ca5fdd6a9e1b50a841b9c5ddf89951 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -1296,8 +1296,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 */ @@ -1421,12 +1419,21 @@ static struct attended_transfer_properties *attended_transfer_properties_alloc( 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); @@ -1447,7 +1454,6 @@ 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); @@ -1707,6 +1713,44 @@ static void play_sound(struct ast_channel *chan, const char *sound) } } +/*! + * \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_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); + } +} + /*! * \brief Helper method to place a channel in a bridge on hold */ @@ -2049,7 +2093,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: @@ -2061,7 +2105,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); @@ -2090,7 +2134,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: @@ -2101,7 +2145,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; @@ -2163,7 +2207,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 @@ -2179,7 +2223,7 @@ static enum attended_transfer_state consulting_exit(struct attended_transfer_pro 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_REBRIDGE; case STIMULUS_DTMF_ATXFER_THREEWAY: bridge_unhold(props->transferee_bridge); @@ -2211,7 +2255,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: @@ -2221,7 +2265,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); @@ -3295,7 +3339,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, 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); + stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); attended_transfer_properties_shutdown(props); return 0; @@ -3306,7 +3350,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, 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); + stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); props->transfer_target = NULL; @@ -3317,7 +3361,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, 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); + stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); props->transfer_target = NULL; @@ -3332,7 +3376,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, 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); + stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); props->transfer_target = NULL; @@ -3348,7 +3392,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, 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); + stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); props->transfer_target = NULL; @@ -3358,7 +3402,7 @@ 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); + stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); attended_transfer_properties_shutdown(props); return 0; diff --git a/main/features_config.c b/main/features_config.c index 3db1a780a4afdc6fa063431a41b33892f7e4df05..58ccb959b213eb28e975d78c035aad82abda1f86 100644 --- a/main/features_config.c +++ b/main/features_config.c @@ -1158,6 +1158,21 @@ struct ast_features_xfer_config *ast_get_chan_features_xfer_config(struct ast_ch return cfg->global->xfer; } +char *ast_get_chan_features_xferfailsound(struct ast_channel *chan) +{ + char *res; + struct ast_features_xfer_config *cfg = ast_get_chan_features_xfer_config(chan); + + if (!cfg) { + return NULL; + } + + res = ast_strdup(cfg->xferfailsound); + ao2_ref(cfg, -1); + + return res; +} + struct ast_features_pickup_config *ast_get_chan_features_pickup_config(struct ast_channel *chan) { RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);