diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 764a445206934daf82d3a1ced5ddd43b928390dc..da2d99213eb92334e5fd187b2864f7afb35df191 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -863,6 +863,18 @@ static char vm_mismatch[80] = "vm-mismatch"; static char vm_invalid_password[80] = "vm-invalid-password"; static char vm_pls_try_again[80] = "vm-pls-try-again"; +/* + * XXX If we have the time, motivation, etc. to fix up this prompt, one of the following would be appropriate: + * 1. create a sound along the lines of "Please try again. When done, press the pound key" which could be spliced + * from existing sound clips. This would require some programming changes in the area of vm_forward options and also + * app.c's __ast_play_and_record function + * 2. create a sound prompt saying "Please try again. When done recording, press any key to stop and send the prepended + * message." At the time of this comment, I think this would require new voice work to be commissioned. + * 3. Something way different like providing instructions before a time out or a post-recording menu. This would require + * more effort than either of the other two. + */ +static char vm_prepend_timeout[80] = "then-press-pound"; + static struct ast_flags globalflags = {0}; static int saydurationminfo; @@ -6866,7 +6878,10 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0); cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, 1, silencethreshold, maxsilence); - if (cmd == 'S') { + + if (cmd == 'S') { /* If we timed out, tell the user it didn't work properly and clean up the files */ + ast_stream_and_wait(chan, vm_pls_try_again, ""); /* this might be removed if a proper vm_prepend_timeout is ever recorded */ + ast_stream_and_wait(chan, vm_prepend_timeout, ""); ast_filerename(backup, msgfile, NULL); } @@ -6903,6 +6918,9 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, cmd = '*'; break; default: + /* If time_out and return to menu, reset already_recorded */ + already_recorded = 0; + cmd = ast_play_and_wait(chan, "vm-forwardoptions"); /* "Press 1 to prepend a message or 2 to forward the message without prepending" */ if (!cmd) @@ -6912,8 +6930,9 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, cmd = ast_waitfordigit(chan, 6000); if (!cmd) retries++; - if (retries > 3) - cmd = 't'; + if (retries > 3) { + cmd = '*'; /* Let's cancel this beast */ + } } } @@ -6928,7 +6947,7 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, rename(backup_textfile, textfile); } - if (cmd == 't' || cmd == 'S') + if (cmd == 't' || cmd == 'S') /* XXX entering this block with a value of 'S' is probably no longer possible. */ cmd = 0; return cmd; } @@ -12138,6 +12157,9 @@ static int load_config(int reload) if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) { ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again)); } + if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) { + ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout)); + } /* load configurable audio prompts */ if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val)) ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key)); diff --git a/configs/voicemail.conf.sample b/configs/voicemail.conf.sample index 8a75f2a66289e5e6bd142c2b002c0bddf68336bf..318f682b7b95ea797a78156d71672cec87ba656c 100644 --- a/configs/voicemail.conf.sample +++ b/configs/voicemail.conf.sample @@ -318,6 +318,12 @@ sendvoicemail=yes ; Allow the user to compose and send a voicemail while inside ; vm-pls-try-again=custom_sound ; Customize which sound file is used instead of the ; default prompt that says "Please try again." +; vm-prepend-timeout=custom_sound + ; Customize which sound file is used when the user + ; times out while recording a prepend message instead + ; of the default prompt that says "then press pound" + ; note that this will currently follow vm-pls-try-again. + ; this behavior is subject to change in the near future. ; listen-control-forward-key=# ; Customize the key that fast-forwards message playback ; listen-control-reverse-key=* ; Customize the key that rewinds message playback ; listen-control-pause-key=0 ; Customize the key that pauses/unpauses message playback diff --git a/include/asterisk/app.h b/include/asterisk/app.h index 850afcd836541fae386723495367354f31de2699..fe74e0bddddb766f837d9ff7849cb78338e65bc1 100644 --- a/include/asterisk/app.h +++ b/include/asterisk/app.h @@ -270,18 +270,68 @@ int ast_control_streamfile(struct ast_channel *chan, const char *file, const cha /*! \brief Play a stream and wait for a digit, returning the digit that was pressed */ int ast_play_and_wait(struct ast_channel *chan, const char *fn); +/*! + * \brief Record a file based on input from a channel + * This function will play "auth-thankyou" upon successful recording. + * + * \param chan the channel being recorded + * \param playfile Filename of sound to play before recording begins + * \param recordfile Filename to save the recording + * \param maxtime_sec Longest possible message length in seconds + * \param fmt string containing all formats to be recorded delimited by '|' + * \param duration pointer to integer for storing length of the recording + * \param silencethreshold tolerance of noise levels that can be considered silence for the purpose of silence timeout, -1 for default + * \param maxsilence_ms Length of time in milliseconds which will trigger a timeout from silence, -1 for default + * \param path Optional filesystem path to unlock + * \param acceptdtmf Character of DTMF to end and accept the recording + * \param canceldtmf Character of DTMF to end and cancel the recording + * + * \retval -1 failure or hangup + * \retval 'S' Recording ended from silence timeout + * \retval 't' Recording ended from the message exceeding the maximum duration + * \retval dtmfchar Recording ended via the return value's DTMF character for either cancel or accept. + */ int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int silencethreshold, int maxsilence_ms, const char *path, const char *acceptdtmf, const char *canceldtmf); -/*! \brief Record a file for a max amount of time (in seconds), in a given list of formats separated by '|', outputting the duration of the recording, and with a maximum - \n - permitted silence time in milliseconds of 'maxsilence' under 'silencethreshold' or use '-1' for either or both parameters for defaults. - calls ast_unlock_path() on 'path' if passed */ +/*! + * \brief Record a file based on input from a channel. Use default accept and cancel DTMF. + * This function will play "auth-thankyou" upon successful recording. + * + * \param chan the channel being recorded + * \param playfile Filename of sound to play before recording begins + * \param recordfile Filename to save the recording + * \param maxtime_sec Longest possible message length in seconds + * \param fmt string containing all formats to be recorded delimited by '|' + * \param duration pointer to integer for storing length of the recording + * \param silencethreshold tolerance of noise levels that can be considered silence for the purpose of silence timeout, -1 for default + * \param maxsilence_ms length of time in milliseconds which will trigger a timeout from silence, -1 for default + * \param path Optional filesystem path to unlock + * + * \retval -1 failure or hangup + * \retval 'S' Recording ended from silence timeout + * \retval 't' Recording ended from the message exceeding the maximum duration + * \retval dtmfchar Recording ended via the return value's DTMF character for either cancel or accept. + */ int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int silencethreshold, int maxsilence_ms, const char *path); -/*! \brief Record a message and prepend the message to the given record file after - playing the optional playfile (or a beep), storing the duration in - 'duration' and with a maximum permitted silence time in milliseconds of 'maxsilence' under - 'silencethreshold' or use '-1' for either or both parameters for defaults. */ +/*! + * \brief Record a file based on input frm a channel. Recording is performed in 'prepend' mode which works a little differently from normal recordings + * This function will not play a success message due to post-recording control in the application this was added for. + * + * \param chan the channel being recorded + * \param playfile Filename of sound to play before recording begins + * \param recordfile Filename to save the recording + * \param maxtime_sec Longest possible message length in seconds + * \param fmt string containing all formats to be recorded delimited by '|' + * \param duration pointer to integer for storing length of the recording + * \param beep whether to play a beep to prompt the recording + * \param silencethreshold tolerance of noise levels that can be considered silence for the purpose of silence timeout, -1 for default + * \param maxsilence_ms length of time in milliseconds which will trigger a timeout from silence, -1 for default. + * + * \retval -1 failure or hangup + * \retval 'S' Recording ended from silence timeout + * \retval 't' Recording either exceeded maximum duration or the call was ended via DTMF + */ int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime_sec, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence_ms); enum ast_getdata_result { diff --git a/main/app.c b/main/app.c index 3594b0b86e5758d53613b69beb5319618072f614..eef527c56282b8a0c0ca99e3b380811226525891 100644 --- a/main/app.c +++ b/main/app.c @@ -716,19 +716,24 @@ static int global_maxsilence = 0; * \param chan Channel to playback to/record from. * \param playfile Filename of sound to play before recording begins. * \param recordfile Filename to record to. - * \param maxtime Maximum length of recording (in milliseconds). + * \param maxtime Maximum length of recording (in seconds). * \param fmt Format(s) to record message in. Multiple formats may be specified by separating them with a '|'. * \param duration Where to store actual length of the recorded message (in milliseconds). * \param beep Whether to play a beep before starting to record. * \param silencethreshold * \param maxsilence Length of silence that will end a recording (in milliseconds). * \param path Optional filesystem path to unlock. - * \param prepend If true, prepend the recorded audio to an existing file. + * \param prepend If true, prepend the recorded audio to an existing file and follow prepend mode recording rules * \param acceptdtmf DTMF digits that will end the recording. * \param canceldtmf DTMF digits that will cancel the recording. + * \param skip_confirmation_sound If true, don't play auth-thankyou at end. Nice for custom recording prompts in apps. + * + * \retval -1 failure or hangup + * \retval 'S' Recording ended from silence timeout + * \retval 't' Recording ended from the message exceeding the maximum duration, or via DTMF in prepend mode + * \retval dtmfchar Recording ended via the return value's DTMF character for either cancel or accept. */ - -static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int beep, int silencethreshold, int maxsilence, const char *path, int prepend, const char *acceptdtmf, const char *canceldtmf) +static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int beep, int silencethreshold, int maxsilence, const char *path, int prepend, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound) { int d = 0; char *fmts; @@ -1010,7 +1015,7 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, if (rfmt.id && ast_set_read_format(chan, &rfmt)) { ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(&rfmt), chan->name); } - if (outmsg == 2) { + if ((outmsg == 2) && (!skip_confirmation_sound)) { ast_stream_and_wait(chan, "auth-thankyou", ""); } if (sildet) { @@ -1024,17 +1029,17 @@ static const char default_canceldtmf[] = ""; int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf) { - return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, 0, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, default_acceptdtmf), S_OR(canceldtmf, default_canceldtmf)); + return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, 0, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, default_acceptdtmf), S_OR(canceldtmf, default_canceldtmf), 0); } int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path) { - return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, 0, silencethreshold, maxsilence, path, 0, default_acceptdtmf, default_canceldtmf); + return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, 0, silencethreshold, maxsilence, path, 0, default_acceptdtmf, default_canceldtmf, 0); } int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence) { - return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, beep, silencethreshold, maxsilence, NULL, 1, default_acceptdtmf, default_canceldtmf); + return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, beep, silencethreshold, maxsilence, NULL, 1, default_acceptdtmf, default_canceldtmf, 1); } /* Channel group core functions */