Index: dsp.c =================================================================== RCS file: /usr/cvsroot/asterisk/dsp.c,v retrieving revision 1.42 diff -u -r1.42 dsp.c --- dsp.c 15 May 2005 17:22:41 -0000 1.42 +++ dsp.c 19 May 2005 01:16:49 -0000 @@ -80,7 +80,7 @@ { GSAMP_SIZE_CR, { 425 } }, }; -#define DEFAULT_THRESHOLD 512 +#define DEFAULT_THRESHOLD 512 /* If energy is below this, consider it silence */ #define BUSY_PERCENT 10 /* The percentage diffrence between the two last silence periods */ #define BUSY_THRESHOLD 100 /* Max number of ms difference between max and min times in busy */ @@ -1114,18 +1114,20 @@ return __ast_dsp_call_progress(dsp, inf->data, inf->datalen / 2); } -static int __ast_dsp_silence(struct ast_dsp *dsp, short *s, int len, int *totalsilence) +static int __ast_dsp_energy(struct ast_dsp *dsp, short *s, int len, int *totalsilence) { int accum; int x; - int res = 0; if (!len) return 0; + accum = 0; for (x=0;xthreshold) { dsp->totalsilence += len/8; if (dsp->totalnoise) { @@ -1138,7 +1140,6 @@ #endif } dsp->totalnoise = 0; - res = 1; } else { dsp->totalnoise += len/8; if (dsp->totalsilence) { @@ -1162,10 +1163,23 @@ } dsp->totalsilence = 0; } + if (totalsilence) *totalsilence = dsp->totalsilence; - return res; + + return accum; +} + +static int __ast_dsp_silence(struct ast_dsp *dsp, short *s, int len, int *totalsilence) +{ + int accum; + accum = __ast_dsp_energy(dsp, s, len, totalsilence); + if (accum < dsp->threshold) + return 1; + else + return 0; } + #ifdef BUSYDETECT_MARTIN int ast_dsp_busydetect(struct ast_dsp *dsp) { @@ -1297,9 +1311,27 @@ return __ast_dsp_silence(dsp, s, len, totalsilence); } +int ast_dsp_energy(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence) +{ + short *s; + int len; + + if (f->frametype != AST_FRAME_VOICE) { + ast_log(LOG_WARNING, "Can't calculate voice energy on a non-voice frame\n"); + return 0; + } + if (f->subclass != AST_FORMAT_SLINEAR) { + ast_log(LOG_WARNING, "Can only calculate voice energy on signed-linear frames :(\n"); + return 0; + } + s = f->data; + len = f->datalen/2; + return __ast_dsp_energy(dsp, s, len, totalsilence); +} + struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, struct ast_frame *af) { - int silence; + int energy; int res; int digit; int x; @@ -1359,11 +1391,17 @@ ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(af->subclass)); return af; } - silence = __ast_dsp_silence(dsp, shortdata, len, NULL); - if ((dsp->features & DSP_FEATURE_SILENCE_SUPPRESS) && silence) { - memset(&dsp->f, 0, sizeof(dsp->f)); - dsp->f.frametype = AST_FRAME_NULL; - return &dsp->f; + if (dsp->features & (DSP_FEATURE_SILENCE_DETECT | DSP_FEATURE_SILENCE_SUPPRESS)) { + energy = __ast_dsp_energy(dsp, shortdata, len, NULL); + af->energy = energy; + if (energy < dsp->threshold) { + if (dsp->features & DSP_FEATURE_SILENCE_SUPPRESS) { + af->frametype = AST_FRAME_CNG; + } + /* a silence frame should not be processed any further */ + FIX_INF(af); + return af; + } } if ((dsp->features & DSP_FEATURE_BUSY_DETECT) && ast_dsp_busydetect(dsp)) { chan->_softhangup |= AST_SOFTHANGUP_DEV; @@ -1514,7 +1552,8 @@ if (dsp) { memset(dsp, 0, sizeof(struct ast_dsp)); dsp->threshold = DEFAULT_THRESHOLD; - dsp->features = DSP_FEATURE_SILENCE_SUPPRESS; + /* No features are enabled at creation time */ + dsp->features = 0; dsp->busycount = DSP_HISTORY; /* Initialize DTMF detector */ ast_dtmf_detect_init(&dsp->td.dtmf); Index: frame.c =================================================================== RCS file: /usr/cvsroot/asterisk/frame.c,v retrieving revision 1.55 diff -u -r1.55 frame.c --- frame.c 15 May 2005 05:46:34 -0000 1.55 +++ frame.c 19 May 2005 01:16:50 -0000 @@ -279,6 +279,7 @@ out->datalen = fr->datalen; out->samples = fr->samples; out->offset = fr->offset; + out->energy = fr->energy; out->src = NULL; out->data = fr->data; } else { @@ -334,6 +335,7 @@ out->delivery = f->delivery; out->mallocd = AST_MALLOCD_HDR; out->offset = AST_FRIENDLY_OFFSET; + out->energy = f->energy; out->data = buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET; if (srclen > 0) { out->src = out->data + f->datalen; Index: channels/chan_zap.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_zap.c,v retrieving revision 1.447 diff -u -r1.447 chan_zap.c --- channels/chan_zap.c 16 May 2005 19:15:56 -0000 1.447 +++ channels/chan_zap.c 19 May 2005 01:16:59 -0000 @@ -303,6 +303,15 @@ /* When to send the CallerID signals (rings) */ static int sendcalleridafter = DEFAULT_CIDRINGS; +/* Whether to mark a voice frame as being silence (but still keeping the audio) */ +static int silencedetection = 0; + +/* Whether to convert silence frames to comfort noise generator (CNG) frames */ +static int silencesuppression = 0; + +/* What magic number to use for the silence detection accumulator in dsp.c */ +static int silencethreshold = 512; + /* Protect the monitoring thread, so only one process can kill or start it, and not when it's doing something critical. */ AST_MUTEX_DEFINE_STATIC(monlock); @@ -631,6 +640,9 @@ int sigchecked; #endif int polarity; + int silencedetection; + int silencesuppression; + int silencethreshold; } *iflist = NULL, *ifend = NULL; static struct ast_channel *zt_request(const char *type, int format, void *data, int *cause); @@ -4740,6 +4752,11 @@ if (ioctl(i->subs[index].zfd, ZT_TONEDETECT, &x)) #endif features |= DSP_FEATURE_DTMF_DETECT; + if (i->silencedetection) + features |= DSP_FEATURE_SILENCE_DETECT; + if (i->silencesuppression) { + features |= DSP_FEATURE_SILENCE_SUPPRESS; + } if (features) { if (i->dsp) { ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", tmp->name); @@ -4755,6 +4772,7 @@ features = 0; } #endif + ast_dsp_set_threshold(i->dsp, i->silencethreshold); ast_dsp_set_features(i->dsp, features); ast_dsp_digitmode(i->dsp, DSP_DIGITMODE_DTMF | i->dtmfrelax); if (!ast_strlen_zero(progzone)) @@ -6862,6 +6880,9 @@ tmp->answeronpolarityswitch = answeronpolarityswitch; tmp->hanguponpolarityswitch = hanguponpolarityswitch; tmp->sendcalleridafter = sendcalleridafter; + tmp->silencedetection = silencedetection; + tmp->silencesuppression = silencesuppression; + tmp->silencethreshold = silencethreshold; } if (tmp && !here) { @@ -10359,7 +10380,13 @@ ast_copy_string(defaultcic, v->value, sizeof(defaultcic)); } else if (!strcasecmp(v->name, "defaultozz")) { ast_copy_string(defaultozz, v->value, sizeof(defaultozz)); - } + } else if (!strcasecmp(v->name, "silencedetection")) { + silencedetection = ast_true(v->value); + } else if (!strcasecmp(v->name, "silencesuppression")) { + silencesuppression = ast_true(v->value); + } else if (!strcasecmp(v->name, "silencethreshold")) { + silencethreshold = atoi(v->value); + } } else ast_log(LOG_WARNING, "Ignoring %s\n", v->name); v = v->next; Index: configs/zapata.conf.sample =================================================================== RCS file: /usr/cvsroot/asterisk/configs/zapata.conf.sample,v retrieving revision 1.47 diff -u -r1.47 zapata.conf.sample --- configs/zapata.conf.sample 12 May 2005 15:04:55 -0000 1.47 +++ configs/zapata.conf.sample 19 May 2005 01:17:00 -0000 @@ -396,6 +396,24 @@ ;callprogress=yes ;progzone=us ; +; Frames of minimal noise energy can be turned into special Comfort Noise +; Generation frames. These frames can be useful to save bandwidth amongst other +; things. Setting "silencesuppression=yes" will turn this on. Default is "no". +; +; silencesuppression=no +; +; Instead of converting the silence into CNG, it might be useful to simply +; detect the energy in each frame for some other purpose. Setting +; "silencedetection=yes" will turn this on. Default is "no". +; +; silencedetection=no +; +; Define the threshold for which frames below this amount of voice energy will +; be considered silence. Default is 512. This option does nothing unless +; "silencesuppression=yes" +; +; silencethreshold=512 +; ; For FXO (FXS signalled) devices, whether to use pulse dial instead of DTMF ; ;pulsedial=yes Index: include/asterisk/dsp.h =================================================================== RCS file: /usr/cvsroot/asterisk/include/asterisk/dsp.h,v retrieving revision 1.6 diff -u -r1.6 dsp.h --- include/asterisk/dsp.h 17 Nov 2004 05:55:26 -0000 1.6 +++ include/asterisk/dsp.h 19 May 2005 01:17:00 -0000 @@ -15,7 +15,8 @@ #define _ASTERISK_DSP_H #define DSP_FEATURE_SILENCE_SUPPRESS (1 << 0) -#define DSP_FEATURE_BUSY_DETECT (1 << 1) +#define DSP_FEATURE_SILENCE_DETECT (1 << 1) +#define DSP_FEATURE_BUSY_DETECT (1 << 2) #define DSP_FEATURE_DTMF_DETECT (1 << 3) #define DSP_FEATURE_FAX_DETECT (1 << 4) @@ -65,6 +66,10 @@ /* Return non-zero if this is silence. Updates "totalsilence" with the total number of seconds of silence */ int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence); + +/* Return the amount of voice energy in a frame. Updates "totalsilence" with the total + number of seconds of silence */ +int ast_dsp_energy(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence); /* Return non-zero if historically this should be a busy, request that ast_dsp_silence has already been called */ Index: include/asterisk/frame.h =================================================================== RCS file: /usr/cvsroot/asterisk/include/asterisk/frame.h,v retrieving revision 1.52 diff -u -r1.52 frame.h --- include/asterisk/frame.h 15 May 2005 04:48:30 -0000 1.52 +++ include/asterisk/frame.h 19 May 2005 01:17:00 -0000 @@ -45,6 +45,8 @@ int mallocd; /*! How far into "data" the data really starts */ int offset; + /*! Set by the DSP to how ever much "noise power" is in the frame, only non-zero for frames run thru ast_dsp_process */ + int energy; /*! Optional source of frame for debugging */ const char *src; /*! Pointer to actual data */