diff --git a/configs/samples/features.conf.sample b/configs/samples/features.conf.sample index afdcf5ae4f..05b514e7b9 100644 --- a/configs/samples/features.conf.sample +++ b/configs/samples/features.conf.sample @@ -6,7 +6,11 @@ [general] ;transferdigittimeout => 3 ; Number of seconds to wait between digits when transferring a call - ; (default is 3 seconds) + ; (default is 3 seconds). If the TRANSFER_EXTEN dialplan variable has been set + ; on the channel of the user that is invoking the transfer feature, then + ; this option is not used as the user is transferred directly to the extension + ; specified by TRANSFER_EXTEN (the transfer context remains the context specified + ; by TRANSFER_CONTEXT, if set, and otherwise the default context). ;xfersound = beep ; to indicate an attended transfer is complete ;xferfailsound = beeperr ; to indicate a failed transfer ;pickupexten = *8 ; Configure the pickup extension. (default is *8) @@ -26,12 +30,13 @@ ; By default, this is 2. ;transferdialattempts = 3 ; Number of times that a transferer may attempt to dial an extension before ; being kicked back to the original call. +;transferannouncesound = beep ; Sound to play to a transferer to indicate transfer process has begun. If empty, no sound will be played. ;transferretrysound = beep ; Sound to play when a transferer fails to dial a valid extension. ;transferinvalidsound = beeperr ; Sound to play when a transferer fails to dial a valid extension and is out of retries. ;atxferabort = *1 ; cancel the attended transfer ;atxfercomplete = *2 ; complete the attended transfer, dropping out of the call ;atxferthreeway = *3 ; complete the attended transfer, but stay in the call. This will turn the call into a multi-party bridge -;atxferswap = *4 ; swap to the other party. Once an attended transfer has begun, this options may be used multiple times +;atxferswap = *4 ; swap to the other party. Once an attended transfer has begun, this option may be used multiple times ; Note that the DTMF features listed below only work when two channels have answered and are bridged together. ; They can not be used while the remote party is ringing or in progress. If you require this feature you can use diff --git a/doc/CHANGES-staging/transfer.txt b/doc/CHANGES-staging/transfer.txt new file mode 100644 index 0000000000..962272fcf7 --- /dev/null +++ b/doc/CHANGES-staging/transfer.txt @@ -0,0 +1,14 @@ +Subject: Transfer feature + +The following capabilities have been added to the +transfer feature: + +- The transfer initiation announcement prompt can +now be customized in features.conf. + +- The TRANSFER_EXTEN variable now can be set on the +transferer's channel in order to allow the transfer +function to automatically attempt to go to the extension +contained in this variable, if it exists. The transfer +context behavior is not changed (TRANSFER_CONTEXT is used +if it exists; otherwise the default context is used). diff --git a/include/asterisk/features_config.h b/include/asterisk/features_config.h index 52533693b5..9d626ee0b7 100644 --- a/include/asterisk/features_config.h +++ b/include/asterisk/features_config.h @@ -72,6 +72,8 @@ struct ast_features_xfer_config { AST_STRING_FIELD(transferretrysound); /*! Sound played when an invalid extension is dialed, and the transferer is being returned to the call. */ AST_STRING_FIELD(transferinvalidsound); + /*! Sound to play to announce the transfer process has started. */ + AST_STRING_FIELD_EXTENDED(transferannouncesound); ); /*! Seconds allowed between digit presses when dialing transfer destination */ unsigned int transferdigittimeout; diff --git a/main/bridge_basic.c b/main/bridge_basic.c index df211957f6..c291fb202d 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -1397,6 +1397,27 @@ static const char *get_transfer_context(struct ast_channel *transferer, const ch return "default"; } +/*! + * \internal + * \brief Determine the transfer extension to use. + * + * \param transferer Channel initiating the transfer. + * \param extension User supplied extension if available. May be NULL. + * + * \return The extension to use for the transfer. + */ +static const char *get_transfer_exten(struct ast_channel *transferer, const char *exten) +{ + if (!ast_strlen_zero(exten)) { + return exten; + } + exten = pbx_builtin_getvar_helper(transferer, "TRANSFER_EXTEN"); + if (!ast_strlen_zero(exten)) { + return exten; + } + return ""; /* empty default, to get transfer extension from user now */ +} + /*! * \brief Allocate and initialize attended transfer properties * @@ -3162,10 +3183,25 @@ static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len int attempts = 0; int max_attempts; struct ast_features_xfer_config *xfer_cfg; - char *retry_sound; - char *invalid_sound; + char *announce_sound, *retry_sound, *invalid_sound; + const char *extenoverride; ast_channel_lock(chan); + extenoverride = get_transfer_exten(chan, NULL); + + if (!ast_strlen_zero(extenoverride)) { + int extenres = ast_exists_extension(chan, context, extenoverride, 1, + S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)) ? 1 : 0; + if (extenres) { + ast_copy_string(exten, extenoverride, exten_len); + ast_channel_unlock(chan); + ast_verb(3, "Transfering call to '%s@%s'", exten, context); + return 0; + } + ast_log(LOG_WARNING, "Override extension '%s' does not exist in context '%s'\n", extenoverride, context); + /* since we didn't get a valid extension from the channel, fall back and grab it from the user as usual now */ + } + xfer_cfg = ast_get_chan_features_xfer_config(chan); if (!xfer_cfg) { ast_log(LOG_ERROR, "Channel %s: Unable to get transfer configuration\n", @@ -3175,21 +3211,24 @@ static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len } digit_timeout = xfer_cfg->transferdigittimeout * 1000; max_attempts = xfer_cfg->transferdialattempts; + announce_sound = ast_strdupa(xfer_cfg->transferannouncesound); 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 */ - 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; + if (!ast_strlen_zero(announce_sound)) { + res = ast_stream_and_wait(chan, announce_sound, 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 */ diff --git a/main/features_config.c b/main/features_config.c index ac0135abe3..ba2f905003 100644 --- a/main/features_config.c +++ b/main/features_config.c @@ -143,6 +143,9 @@ Sound that is played when an incorrect extension is dialed and the transferer has no attempts remaining. + + Sound that is played to the transferer when a transfer is initiated. If empty, no sound will be played. + DTMF options that can be triggered during bridged calls @@ -324,6 +327,7 @@ + @@ -387,6 +391,7 @@ #define DEFAULT_TRANSFER_DIAL_ATTEMPTS 3 #define DEFAULT_TRANSFER_RETRY_SOUND "pbx-invalid" #define DEFAULT_TRANSFER_INVALID_SOUND "privacy-incorrect" +#define DEFAULT_TRANSFER_ANNOUNCE_SOUND "pbx-transfer" /*! Default pickup options */ #define DEFAULT_PICKUPEXTEN "*8" @@ -910,6 +915,8 @@ static int xfer_set(struct ast_features_xfer_config *xfer, const char *name, ast_string_field_set(xfer, transferretrysound, value); } else if (!strcasecmp(name, "transferinvalidsound")) { ast_string_field_set(xfer, transferinvalidsound, value); + } else if (!strcasecmp(name, "transferannouncesound")) { + ast_string_field_set(xfer, transferannouncesound, value); } else { /* Unrecognized option */ res = -1; @@ -1801,6 +1808,8 @@ static int load_config(void) DEFAULT_TRANSFER_RETRY_SOUND, xfer_handler, 0); aco_option_register_custom(&cfg_info, "transferinvalidsound", ACO_EXACT, global_options, DEFAULT_TRANSFER_INVALID_SOUND, xfer_handler, 0); + aco_option_register_custom(&cfg_info, "transferannouncesound", ACO_EXACT, global_options, + DEFAULT_TRANSFER_ANNOUNCE_SOUND, xfer_handler, 0); aco_option_register_custom(&cfg_info, "pickupexten", ACO_EXACT, global_options, DEFAULT_PICKUPEXTEN, pickup_handler, 0);