From 3fa66c92b5e6b8ade849ff1a8adf7894e35d21e9 Mon Sep 17 00:00:00 2001 From: Naveen Albert Date: Sat, 5 Feb 2022 12:13:56 +0000 Subject: [PATCH] features: Add transfer initiation options. Adds additional control options over the transfer feature functionality to give users more control in how the transfer feature sounds and works. First, the "transfer" sound that plays when a transfer is initiated can now be customized by the user in features.conf, just as with the other transfer sounds. Secondly, the user can now specify the transfer extension in advance by using the TRANSFER_EXTEN variable. If a valid extension is contained in this variable, the call will automatically be transferred to this destination. Otherwise, it will fall back to collecting the extension from the user as is always done now. ASTERISK-29899 #close Change-Id: Ibff309caa459a2b958706f2ed0ca393b1ef502e3 --- configs/samples/features.conf.sample | 9 +++- doc/CHANGES-staging/transfer.txt | 14 +++++++ include/asterisk/features_config.h | 2 + main/bridge_basic.c | 61 +++++++++++++++++++++++----- main/features_config.c | 9 ++++ 5 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 doc/CHANGES-staging/transfer.txt 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);