diff --git a/apps/app_sf.c b/apps/app_sf.c
index cd8f79a6bc..0fb902f435 100644
--- a/apps/app_sf.c
+++ b/apps/app_sf.c
@@ -78,6 +78,20 @@
+
@@ -146,18 +160,35 @@
***/
+/* Default post-digit timer */
+#define DEFAULT_POST_DIGIT_TIMER 0.8
+
+/* Bell System Technical Journal 39 (Nov. 1960) */
+#define SF_MIN_OFF 25
+#define SF_ON 67
+#define SF_BETWEEN 600
+#define SF_MIN_DETECT 50
+
enum read_option_flags {
OPT_DELAY = (1 << 0),
OPT_MUTE = (1 << 1),
OPT_QUELCH = (1 << 2),
OPT_RELAXED = (1 << 3),
OPT_EXTRAPULSES = (1 << 4),
+ OPT_DIGIT_TIMEOUT = (1 << 5),
+};
+
+enum {
+ OPT_ARG_DIGIT_TIMEOUT,
+ /* note: this entry _MUST_ be the last one in the enum */
+ OPT_ARG_ARRAY_SIZE,
};
AST_APP_OPTIONS(read_app_options, {
AST_APP_OPTION('d', OPT_DELAY),
AST_APP_OPTION('e', OPT_EXTRAPULSES),
AST_APP_OPTION('m', OPT_MUTE),
+ AST_APP_OPTION_ARG('t', OPT_DIGIT_TIMEOUT, OPT_ARG_DIGIT_TIMEOUT),
AST_APP_OPTION('q', OPT_QUELCH),
AST_APP_OPTION('r', OPT_RELAXED),
});
@@ -172,6 +203,7 @@ static const char sendsf_name[] = "SendSF";
* \param buf Buffer in which to store digits
* \param buflen Size of buffer
* \param timeout ms to wait for all digits before giving up
+ * \param digit_timeout ms to wait for the next digit before giving up
* \param maxdigits Maximum number of digits
* \param freq Frequency to use
* \param features DSP features
@@ -180,13 +212,8 @@ static const char sendsf_name[] = "SendSF";
* \retval 0 if successful
* \retval -1 if unsuccessful (including hangup).
*/
-static int read_sf_digits(struct ast_channel *chan, char *buf, int buflen, int timeout, int maxdigits, int freq, int features, int extrapulses) {
- /* Bell System Technical Journal 39 (Nov. 1960) */
- #define SF_MIN_OFF 25
- #define SF_ON 67
- #define SF_BETWEEN 600
- #define SF_MIN_DETECT 50
-
+static int read_sf_digits(struct ast_channel *chan, char *buf, int buflen, int timeout, int digit_timeout, int maxdigits, int freq, int features, int extrapulses)
+{
struct ast_dsp *dsp = NULL;
struct ast_frame *frame = NULL;
struct timeval start, pulsetimer, digittimer;
@@ -212,6 +239,23 @@ static int read_sf_digits(struct ast_channel *chan, char *buf, int buflen, int t
if (timeout > 0) {
remaining_time = ast_remaining_ms(start, timeout);
if (remaining_time <= 0) {
+ ast_debug(1, "SF all-digit timer expired\n");
+ pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "TIMEOUT");
+ break;
+ }
+ }
+ /* If we haven't received a digit yet, don't apply the post-digit timer just yet,
+ * since the sender may not have started sending any digits.
+ *
+ * Note that we use the digit timer, which is reset for each SF pulse,
+ * as opposed to simply an entire digit being received.
+ * This is done because we only want to expire the timer if there has been no activity
+ * since the last digit. If we're in the middle of receiving a digit (e.g. 0)
+ * we may not have a full digit yet but that should not cause an expiration. */
+ if (digits_read > 0 && digit_timeout > 0) {
+ int remaining_time_for_next_digit = ast_remaining_ms(digittimer, digit_timeout);
+ if (remaining_time_for_next_digit <= 0) {
+ ast_debug(1, "SF post-digit timer expired (>= %d ms since last SF pulse)\n", digit_timeout);
pbx_builtin_setvar_helper(chan, "RECEIVESFSTATUS", "TIMEOUT");
break;
}
@@ -261,7 +305,7 @@ static int read_sf_digits(struct ast_channel *chan, char *buf, int buflen, int t
}
} else if (hits > 0 && ast_remaining_ms(digittimer, SF_BETWEEN) <= 0) {
/* has the digit finished? */
- ast_debug(2, "Received SF digit: %d\n", hits);
+ ast_debug(2, "Received SF digit: %d\n", hits == 10 ? 0 : hits); /* Edge case for 10, since this is the digit '0' */
digits_read++;
if (hits > 10) {
if (extrapulses) {
@@ -321,10 +365,11 @@ static int read_sf_exec(struct ast_channel *chan, const char *data)
{
#define BUFFER_SIZE 256
char tmp[BUFFER_SIZE] = "";
- double tosec;
+ double tosec, digitsec;
struct ast_flags flags = {0};
+ char *opt_args[OPT_ARG_ARRAY_SIZE];
char *argcopy = NULL;
- int res, features = 0, digits = 0, to = 0, freq = 2600;
+ int res, features = 0, digits = 0, to = 0, digit_timeout = 0, freq = 2600;
AST_DECLARE_APP_ARGS(arglist,
AST_APP_ARG(variable);
@@ -344,7 +389,7 @@ static int read_sf_exec(struct ast_channel *chan, const char *data)
AST_STANDARD_APP_ARGS(arglist, argcopy);
if (!ast_strlen_zero(arglist.options)) {
- ast_app_parse_options(read_app_options, &flags, NULL, arglist.options);
+ ast_app_parse_options(read_app_options, &flags, opt_args, arglist.options);
}
if (!ast_strlen_zero(arglist.timeout)) {
@@ -355,6 +400,18 @@ static int read_sf_exec(struct ast_channel *chan, const char *data)
to = tosec * 1000.0;
}
}
+ if (ast_test_flag(&flags, OPT_DIGIT_TIMEOUT)) {
+ digitsec = (!ast_strlen_zero(opt_args[OPT_ARG_DIGIT_TIMEOUT]) ? atof(opt_args[OPT_ARG_DIGIT_TIMEOUT]) : DEFAULT_POST_DIGIT_TIMER);
+ if (digitsec <= 0) {
+ digit_timeout = 0;
+ } else {
+ digit_timeout = digitsec * 1000.0;
+ if (digit_timeout < SF_BETWEEN) {
+ ast_log(LOG_WARNING, "SF post-digit timer (%d) cannot be less than the SF inter-digit timeout (%d ms)\n", digit_timeout, SF_BETWEEN);
+ digit_timeout = SF_BETWEEN; /* If we have a shorter timeout, it won't work at all */
+ }
+ }
+ }
if (!ast_strlen_zero(arglist.digits) && (ast_str_to_int(arglist.digits, &digits) || digits <= 0)) {
ast_log(LOG_WARNING, "Invalid number of digits: %s\n", arglist.digits);
@@ -387,7 +444,7 @@ static int read_sf_exec(struct ast_channel *chan, const char *data)
features |= DSP_DIGITMODE_RELAXDTMF;
}
- res = read_sf_digits(chan, tmp, BUFFER_SIZE, to, digits, freq, features, ast_test_flag(&flags, OPT_EXTRAPULSES));
+ res = read_sf_digits(chan, tmp, BUFFER_SIZE, to, digit_timeout, digits, freq, features, ast_test_flag(&flags, OPT_EXTRAPULSES));
pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
if (!ast_strlen_zero(tmp)) {
ast_verb(3, "SF digits received: '%s'\n", tmp);