|
|
|
@ -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);
|
|
|
|
@ -3297,7 +3341,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;
|
|
|
|
@ -3308,7 +3352,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;
|
|
|
|
@ -3319,7 +3363,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;
|
|
|
|
@ -3334,7 +3378,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;
|
|
|
|
@ -3350,7 +3394,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;
|
|
|
|
@ -3360,7 +3404,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;
|
|
|
|
|