static int busydetect = 0;
static int busycount = 3;
+static int busy_tonelength = 0;
+static int busy_quietlength = 0;
static int callprogress = 0;
int echotraining;
char echorest[20];
int busycount;
+ int busy_tonelength;
+ int busy_quietlength;
int callprogress;
struct timeval flashtime; /* Last flash-hook time */
struct ast_dsp *dsp;
ast_dsp_set_call_progress_zone(i->dsp, progzone);
if (i->busydetect && CANBUSYDETECT(i)) {
ast_dsp_set_busy_count(i->dsp, i->busycount);
+ ast_dsp_set_busy_pattern(i->dsp, i->busy_tonelength, i->busy_quietlength);
}
}
}
tmp->echocanbridged = echocanbridged;
tmp->busydetect = busydetect;
tmp->busycount = busycount;
+ tmp->busy_tonelength = busy_tonelength;
+ tmp->busy_quietlength = busy_quietlength;
tmp->callprogress = callprogress;
tmp->cancallforward = cancallforward;
tmp->dtmfrelax = relaxdtmf;
busydetect = ast_true(v->value);
} else if (!strcasecmp(v->name, "busycount")) {
busycount = atoi(v->value);
+ } else if (!strcasecmp(v->name, "busypattern")) {
+ if (sscanf(v->value, "%d,%d", &busy_tonelength, &busy_quietlength) != 2) {
+ ast_log(LOG_ERROR, "busypattern= expects busypattern=tonelength,quietlength\n");
+ }
} else if (!strcasecmp(v->name, "callprogress")) {
if (ast_true(v->value))
callprogress |= 1;
;
; On trunk interfaces (FXS) and E&M interfaces (E&M, Wink, Feature Group D
; etc, it can be useful to perform busy detection either in an effort to
-; detect hangup or for detecting busies
+; detect hangup or for detecting busies. This enables listening for
+; the beep-beep busy pattern.
;
;busydetect=yes
;
; If busydetect is enabled, is also possible to specify how many
-; busy tones to wait before hanging up. The default is 4, but
+; busy tones to wait for before hanging up. The default is 4, but
; better results can be achieved if set to 6 or even 8. Mind that
; higher the number, more time is needed to hangup a channel, but
; lower is probability to get random hangups
;
;busycount=4
;
+; If busydetect is enabled, is also possible to specify the
+; cadence of your busy signal. In many countries it is 500mec
+; on, 500msec off.
+; Without busypattern specified, we'll accept any regular
+; sound-silence pattern than repeats busycount times as a busy
+; signal.
+; If you specify busypattern then we'll further check the length
+; of the sound (tone) and silence, which will further reduce the
+; chance of a false positive.
+;
+;busypattern=500,500
+;
+; NOTE: In the Asterisk Makefile you'll find further options to tweak
+; the busy detector. If your country has a busy tone with the same
+; lengh tone and silence (as many countries do), consider defining
+; the -DBUSYDETECT_COMPARE_TONE_AND_SILENCE option.
+;
; Use a polarity reversal to mark when a outgoing call is answered by the
; remote party.
;
#define DEFAULT_THRESHOLD 512
-#define BUSY_PERCENT 10 /* The percentage diffrence between the two last silence periods */
+#define BUSY_PERCENT 10 /* The percentage difference between the two last silence periods */
+#define BUSY_PAT_PERCENT 7 /* The percentage difference between measured and actual pattern */
#define BUSY_THRESHOLD 100 /* Max number of ms difference between max and min times in busy */
#define BUSY_MIN 75 /* Busy must be at least 80 ms in half-cadence */
#define BUSY_MAX 1100 /* Busy can't be longer than 1100 ms in half-cadence */
int features;
int busymaybe;
int busycount;
+ int busy_tonelength;
+ int busy_quietlength;
int historicnoise[DSP_HISTORY];
int historicsilence[DSP_HISTORY];
goertzel_state_t freqs[7];
accum += abs(s[x]);
accum /= len;
if (accum < dsp->threshold) {
+ /* Silent */
dsp->totalsilence += len/8;
if (dsp->totalnoise) {
/* Move and save history */
dsp->totalnoise = 0;
res = 1;
} else {
+ /* Not silent */
dsp->totalnoise += len/8;
if (dsp->totalsilence) {
int silence1 = dsp->historicsilence[DSP_HISTORY - 1];
dsp->historicsilence[DSP_HISTORY - 1] = dsp->totalsilence;
/* check if the previous sample differs only by BUSY_PERCENT from the one before it */
if (silence1 < silence2) {
- if (silence1 + silence1/BUSY_PERCENT >= silence2)
+ if (silence1 + silence1*BUSY_PERCENT/100 >= silence2)
dsp->busymaybe = 1;
else
dsp->busymaybe = 0;
} else {
- if (silence1 - silence1/BUSY_PERCENT <= silence2)
+ if (silence1 - silence1*BUSY_PERCENT/100 <= silence2)
dsp->busymaybe = 1;
else
dsp->busymaybe = 0;
*totalsilence = dsp->totalsilence;
return res;
}
+
#ifdef BUSYDETECT_MARTIN
int ast_dsp_busydetect(struct ast_dsp *dsp)
{
for (x=DSP_HISTORY - dsp->busycount;x<DSP_HISTORY;x++) {
#ifndef BUSYDETECT_TONEONLY
if (avgsilence > dsp->historicsilence[x]) {
- if (avgsilence - (avgsilence / BUSY_PERCENT) <= dsp->historicsilence[x])
+ if (avgsilence - (avgsilence*BUSY_PERCENT/100) <= dsp->historicsilence[x])
hitsilence++;
} else {
- if (avgsilence + (avgsilence / BUSY_PERCENT) >= dsp->historicsilence[x])
+ if (avgsilence + (avgsilence*BUSY_PERCENT/100) >= dsp->historicsilence[x])
hitsilence++;
}
#endif
if (avgtone > dsp->historicnoise[x]) {
- if (avgtone - (avgtone / BUSY_PERCENT) <= dsp->historicnoise[x])
+ if (avgtone - (avgtone*BUSY_PERCENT/100) <= dsp->historicnoise[x])
hittone++;
} else {
- if (avgtone + (avgtone / BUSY_PERCENT) >= dsp->historicnoise[x])
+ if (avgtone + (avgtone*BUSY_PERCENT/100) >= dsp->historicnoise[x])
hittone++;
}
}
#error You cant use BUSYDETECT_TONEONLY together with BUSYDETECT_COMPARE_TONE_AND_SILENCE
#endif
if (avgtone > avgsilence) {
- if (avgtone - avgtone/(BUSY_PERCENT*2) <= avgsilence)
+ if (avgtone - avgtone*BUSY_PERCENT/100 <= avgsilence)
res = 1;
} else {
- if (avgtone + avgtone/(BUSY_PERCENT*2) >= avgsilence)
+ if (avgtone + avgtone*BUSY_PERCENT/100 >= avgsilence)
res = 1;
}
#else
res = 1;
#endif
}
+ /* If we know the expected busy tone length, check we are in the range */
+ if (res && (dsp->busy_tonelength > 0)) {
+ if (abs(avgtone - dsp->busy_tonelength) > (dsp->busy_tonelength*BUSY_PAT_PERCENT/100)) {
+#if 0
+ ast_log(LOG_NOTICE, "busy detector: avgtone of %d not close enough to desired %d\n",
+ avgtone, dsp->busy_tonelength);
+#endif
+ res = 0;
+ }
+ }
+ /* If we know the expected busy tone silent-period length, check we are in the range */
+ if (res && (dsp->busy_quietlength > 0)) {
+ if (abs(avgsilence - dsp->busy_quietlength) > (dsp->busy_quietlength*BUSY_PAT_PERCENT/100)) {
#if 0
+ ast_log(LOG_NOTICE, "busy detector: avgsilence of %d not close enough to desired %d\n",
+ avgsilence, dsp->busy_quietlength);
+#endif
+ res = 0;
+ }
+ }
+#if 1
if (res)
- ast_log(LOG_NOTICE, "detected busy, avgtone: %d, avgsilence %d\n", avgtone, avgsilence);
+ ast_log(LOG_DEBUG, "ast_dsp_busydetect detected busy, avgtone: %d, avgsilence %d\n", avgtone, avgsilence);
#endif
return res;
}
dsp->busycount = cadences;
}
+void ast_dsp_set_busy_pattern(struct ast_dsp *dsp, int tonelength, int quietlength)
+{
+ dsp->busy_tonelength = tonelength;
+ dsp->busy_quietlength = quietlength;
+ ast_log(LOG_DEBUG, "dsp busy pattern set to %d,%d\n", tonelength, quietlength);
+}
+
void ast_dsp_digitreset(struct ast_dsp *dsp)
{
int i;