Index: main/dsp.c =================================================================== --- main/dsp.c (revision 401703) +++ main/dsp.c (working copy) @@ -49,6 +49,10 @@ detriment. */ +/* + * ZA end of call detection by Michael Walton + */ + /*** MODULEINFO core ***/ @@ -72,13 +76,15 @@ enum gsamp_size { GSAMP_SIZE_NA = 183, /*!< North America - 350, 440, 480, 620, 950, 1400, 1800 Hz */ GSAMP_SIZE_CR = 188, /*!< Costa Rica, Brazil - Only care about 425 Hz */ - GSAMP_SIZE_UK = 160 /*!< UK disconnect goertzel feed - should trigger 400hz */ + GSAMP_SIZE_UK = 160, /*!< UK disconnect goertzel feed - should trigger 400hz */ + GSAMP_SIZE_ZA = 160 /*!< ZA disconnect goertzel feed - should trigger 400hz */ }; enum prog_mode { PROG_MODE_NA = 0, PROG_MODE_CR, - PROG_MODE_UK + PROG_MODE_UK, + PROG_MODE_ZA }; enum freq_index { @@ -94,6 +100,9 @@ /*! For CR/BR modes */ HZ_425 = 0, + /*! For ZA mode */ + HZ_400 = 0, + /*! For UK mode */ HZ_350UK = 0, HZ_400UK, @@ -109,6 +118,7 @@ { "cr", PROG_MODE_CR }, { "br", PROG_MODE_CR }, { "uk", PROG_MODE_UK }, + { "za", PROG_MODE_ZA }, }; static struct progress { @@ -118,6 +128,7 @@ { GSAMP_SIZE_NA, { 350, 440, 480, 620, 950, 1400, 1800 } }, /*!< North America */ { GSAMP_SIZE_CR, { 425 } }, /*!< Costa Rica, Brazil */ { GSAMP_SIZE_UK, { 350, 400, 440 } }, /*!< UK */ + { GSAMP_SIZE_ZA, { 400 } }, /*!< ZA */ }; /*!\brief This value is the minimum threshold, calculated by averaging all @@ -150,9 +161,14 @@ THRESH_BUSY = 4, /*!< Need at least 80ms to accept */ THRESH_CONGESTION = 4, /*!< Need at least 80ms to accept */ THRESH_HANGUP = 60, /*!< Need at least 1300ms to accept hangup */ + ZA_THRESH_HANGUP = 22, /* ZA: 440ms min */ + ZA_THRESH_HANGUP_UPPER = 150, /* ZA: 3000ms max */ + ZA_THRESH_HANGUP_SILENT = 20, /* ZA: 400ms min */ + ZA_THRESH_HANGUP_SILENT_UPPER = 30, /* ZA: 600ms max */ THRESH_RING2ANSWER = 300 /*!< Timeout from start of ring to answer (about 6600 ms) */ }; +#define HANGUP_COUNT 3 #define MAX_DTMF_DIGITS 128 /* Basic DTMF (AT&T) specs: @@ -416,6 +432,8 @@ digit_detect_state_t digit_state; tone_detect_state_t cng_tone_state; tone_detect_state_t ced_tone_state; + int hangupcount; + int hangupmark; }; static void mute_fragment(struct ast_dsp *dsp, fragment_t *fragment) @@ -1063,7 +1081,7 @@ len -= pass; if (dsp->gsamps == dsp->gsamp_size) { float hz[7]; - for (y = 0; y < 7; y++) { + for (y = 0; y < dsp->freqcount; y++) { hz[y] = goertzel_result(&dsp->freqs[y]); } switch (dsp->progmode) { @@ -1108,6 +1126,16 @@ newstate = DSP_TONE_STATE_DIALTONE; } break; + case PROG_MODE_ZA: + if (hz[HZ_400] > TONE_MIN_THRESH * TONE_THRESH * 10.0) { + /* We have a first tone, start looking for the pattern */ + newstate = DSP_TONE_STATE_MAYBE_HUNGUP; + } else if (dsp->features & DSP_PROGRESS_TALK) { + /* Once at beginning of call, indicate answered since we don't detect this condition */ + dsp->features &= ~DSP_PROGRESS_TALK; + res = AST_CONTROL_ANSWER; + } + break; default: ast_log(LOG_WARNING, "Can't process in unknown prog mode '%d'\n", dsp->progmode); } @@ -1145,6 +1173,55 @@ dsp->features &= ~DSP_FEATURE_CALL_PROGRESS; } break; + case DSP_TONE_STATE_MAYBE_HUNGUP: + /* Count mark/space of detected tone to determine end of call + * As the "beep beep beep" progresses, the state will alternate + * between MAYBE_HUNGUP and SILENCE */ + if (dsp->features & DSP_FEATURE_CALL_PROGRESS) { + if (dsp->tcount == ZA_THRESH_HANGUP) { + if (dsp->hangupmark != 1) { + /* We have 440ms of tone (a mark), count the mark */ + dsp->hangupmark = 1; + dsp->hangupcount++; + ast_log(LOG_DEBUG, "HANGUP: mark, count=%d, level=%0.0f\n", dsp->hangupcount, + hz[HZ_400]/1000000000); + if (dsp->hangupcount >= HANGUP_COUNT) { + ast_log(LOG_NOTICE, "HANGUP: hanging up channel\n"); + res = AST_CONTROL_HANGUP; + dsp->features &= ~DSP_FEATURE_CALL_PROGRESS; + dsp->hangupcount = 0; + dsp->hangupmark = 0; + } + } else { + dsp->hangupcount = 0; + dsp->hangupmark = 0; + } + } else if (dsp->tcount == ZA_THRESH_HANGUP_UPPER) { + /* Too long, cancel hangup */ + if (dsp->hangupmark == 1) { + ast_log(LOG_NOTICE, "HANGUP: cancelled (mark too long)\n"); + } + dsp->hangupmark = 0; + dsp->hangupcount = 0; + } + } + break; + case DSP_TONE_STATE_SILENCE: + if ((dsp->features & DSP_FEATURE_CALL_PROGRESS)) { + /* We have seen a mark, now we look for a space */ + if ((dsp->tcount == ZA_THRESH_HANGUP_SILENT) && dsp->hangupmark) { + dsp->hangupmark = 2; + ast_log(LOG_DEBUG, "HANGUP: space, count=%d\n", dsp->hangupcount); + } else if (dsp->tcount == ZA_THRESH_HANGUP_SILENT_UPPER) { + /* Too long, cancel hangup */ + if (dsp->hangupmark == 2) { + ast_log(LOG_NOTICE, "HANGUP: cancelled (space too long)\n"); + } + dsp->hangupcount = 0; + dsp->hangupmark = 0; + } + } + break; case DSP_TONE_STATE_HUNGUP: if ((dsp->features & DSP_FEATURE_CALL_PROGRESS) && (dsp->tcount == THRESH_HANGUP)) { @@ -1670,6 +1747,8 @@ } dsp->freqcount = max; dsp->ringtimeout = 0; + dsp->hangupcount = 0; + dsp->hangupmark = 0; } unsigned int ast_dsp_get_sample_rate(const struct ast_dsp *dsp) Index: include/asterisk/dsp.h =================================================================== --- include/asterisk/dsp.h (revision 401703) +++ include/asterisk/dsp.h (working copy) @@ -57,6 +57,7 @@ #define DSP_TONE_STATE_SPECIAL2 6 #define DSP_TONE_STATE_SPECIAL3 7 #define DSP_TONE_STATE_HUNGUP 8 +#define DSP_TONE_STATE_MAYBE_HUNGUP 9 struct ast_dsp;