diff --git a/channels/chan_zap.c b/channels/chan_zap.c index 3735dc1424551f44c237d112ebaae48d296d8493..216a135ca9c84d387f365a8c3a18c48c05aa0deb 100644 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -632,7 +632,14 @@ static struct zt_pvt { int stripmsd; int callwaitcas; int callwaitrings; +#if defined(HAVE_ZAPTEL_ECHOCANPARAMS) + struct { + struct zt_echocanparams head; + struct zt_echocanparam params[ZT_MAX_ECHOCANPARAMS]; + } echocancel; +#else int echocancel; +#endif int echotraining; char echorest[20]; int busycount; @@ -776,7 +783,11 @@ static struct zt_chan_conf zt_chan_conf_default(void) { .tonezone = -1, +#if defined(HAVE_ZAPTEL_ECHOCANPARAMS) + .echocancel.head.tap_length = 1, +#else .echocancel = 1, +#endif .busycount = 3, @@ -1627,18 +1638,26 @@ static void zt_enable_ec(struct zt_pvt *p) ast_debug(1, "Echo cancellation isn't required on digital connection\n"); return; } +#if defined(HAVE_ZAPTEL_ECHOCANPARAMS) + if (p->echocancel.head.tap_length) { +#else if (p->echocancel) { +#endif if ((p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP) || (p->sig == SIG_PRI) || (p->sig == SIG_SS7)) { x = 1; res = ioctl(p->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &x); if (res) - ast_log(LOG_WARNING, "Unable to enable echo cancellation on channel %d\n", p->channel); + ast_log(LOG_WARNING, "Unable to enable audio mode on channel %d\n", p->channel); } +#if defined(HAVE_ZAPTEL_ECHOCANPARAMS) + res = ioctl(p->subs[SUB_REAL].zfd, ZT_ECHOCANCEL_PARAMS, &p->echocancel); +#else x = p->echocancel; res = ioctl(p->subs[SUB_REAL].zfd, ZT_ECHOCANCEL, &x); - if (res) +#endif + if (res) { ast_log(LOG_WARNING, "Unable to enable echo cancellation on channel %d\n", p->channel); - else { + } else { p->echocanon = 1; ast_debug(1, "Enabled echo cancellation on channel %d\n", p->channel); } @@ -1650,29 +1669,40 @@ static void zt_train_ec(struct zt_pvt *p) { int x; int res; - if (p && p->echocancel && p->echotraining) { + + if (p && p->echocanon && p->echotraining) { x = p->echotraining; res = ioctl(p->subs[SUB_REAL].zfd, ZT_ECHOTRAIN, &x); if (res) ast_log(LOG_WARNING, "Unable to request echo training on channel %d\n", p->channel); else ast_debug(1, "Engaged echo training on channel %d\n", p->channel); - } else + } else { ast_debug(1, "No echo training requested\n"); + } } static void zt_disable_ec(struct zt_pvt *p) { - int x; int res; - if (p->echocancel) { - x = 0; + + if (p->echocanon) { +#if defined(HAVE_ZAPTEL_ECHOCANPARAMS) + struct zt_echocanparams ecp = { .tap_length = 0 }; + + res = ioctl(p->subs[SUB_REAL].zfd, ZT_ECHOCANCEL_PARAMS, &ecp); +#else + int x = 0; + res = ioctl(p->subs[SUB_REAL].zfd, ZT_ECHOCANCEL, &x); +#endif + if (res) ast_log(LOG_WARNING, "Unable to disable echo cancellation on channel %d\n", p->channel); else - ast_debug(1, "disabled echo cancellation on channel %d\n", p->channel); + ast_debug(1, "Disabled echo cancellation on channel %d\n", p->channel); } + p->echocanon = 0; } @@ -11638,7 +11668,24 @@ static char *zap_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a ast_cli(a->fd, "Default law: %s\n", tmp->law == ZT_LAW_MULAW ? "ulaw" : tmp->law == ZT_LAW_ALAW ? "alaw" : "unknown"); ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no"); ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no"); - ast_cli(a->fd, "Echo Cancellation: %d taps%s, currently %s\n", tmp->echocancel, tmp->echocanbridged ? "" : " unless TDM bridged", tmp->echocanon ? "ON" : "OFF"); + ast_cli(a->fd, "Echo Cancellation:\n"); +#if defined(HAVE_ZAPTEL_ECHOCANPARAMS) + if (tmp->echocancel.head.tap_length) { + ast_cli(a->fd, "\t%d taps\n", tmp->echocancel.head.tap_length); + for (x = 0; x < tmp->echocancel.head.param_count; x++) { + ast_cli(a->fd, "\t\t%s: %ud\n", tmp->echocancel.params[x].name, tmp->echocancel.params[x].value); + } + ast_cli(a->fd, "\t%scurrently %s\n", tmp->echocanbridged ? "" : "(unless TDM bridged) ", tmp->echocanon ? "ON" : "OFF"); + } else { + ast_cli(a->fd, "\tnone\n"); + } +#else + if (tmp->echocancel) + ast_cli(a->fd, "\t%d taps\n", tmp->echocancel); + ast_cli(a->fd, "\t%scurrently %s\n", tmp->echocanbridged ? "" : "(unless TDM bridged) ", tmp->echocanon ? "ON" : "OFF"); + else + ast_cli(a->fd, "\tnone\n"); +#endif if (tmp->master) ast_cli(a->fd, "Master Channel: %d\n", tmp->master->channel); for (x = 0; x < MAX_SLAVES; x++) { @@ -12899,17 +12946,18 @@ static int process_zap(struct zt_chan_conf *confp, struct ast_variable *v, int r } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) confp->chan.callprogress |= CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING; } else if (!strcasecmp(v->name, "echocancel")) { - if (!ast_strlen_zero(v->value)) { - y = atoi(v->value); - } else - y = 0; +#if defined(HAVE_ZAPTEL_ECHOCANPARAMS) + unsigned int *ec = &confp->chan.echocancel.head.tap_length; +#else + int *ec = &confp->chan.echocancel; +#endif + + y = ast_strlen_zero(v->value) ? 0 : atoi(v->value); + if ((y == 32) || (y == 64) || (y == 128) || (y == 256) || (y == 512) || (y == 1024)) - confp->chan.echocancel = y; - else { - confp->chan.echocancel = ast_true(v->value); - if (confp->chan.echocancel) - confp->chan.echocancel=128; - } + *ec = y; + else if ((*ec = ast_true(v->value))) + *ec = 128; } else if (!strcasecmp(v->name, "echotraining")) { if (sscanf(v->value, "%d", &y) == 1) { if ((y < 10) || (y > 4000)) { diff --git a/configs/zapata.conf.sample b/configs/zapata.conf.sample index fac1870ffd6fae96ed1616653209cb3e453fef77..95a49d35391fbc3b5356394425b4ad61123304db 100644 --- a/configs/zapata.conf.sample +++ b/configs/zapata.conf.sample @@ -436,17 +436,28 @@ callreturn=yes ; modules, they take precedence over the software echo canceller compiled ; into Zaptel automatically. ; +; echocancel=yes ; +; As of Zaptel 1.4.8, some Zaptel echo cancellers (software and hardware) +; support adjustable parameters; these parameters can be supplied as +; additional options to the 'echocancel' setting. Note that Asterisk +; does not attempt to validate the parameters or their values, so if you +; supply an invalid parameter you will not know the specific reason it +; failed without checking the kernel message log for the error(s) +; put there by Zaptel. +; +;echocancel=128,param1=32,param2=0,param3=14 +; ; Generally, it is not necessary (and in fact undesirable) to echo cancel when ; the circuit path is entirely TDM. You may, however, change this behavior -; by enabling the echo cancel during pure TDM bridging below. +; by enabling the echo canceller during pure TDM bridging below. ; echocancelwhenbridged=yes ; ; In some cases, the echo canceller doesn't train quickly enough and there ; is echo at the beginning of the call. Enabling echo training will cause -; asterisk to briefly mute the channel, send an impulse, and use the impulse +; Zaptel to briefly mute the channel, send an impulse, and use the impulse ; response to pre-train the echo canceller so it can start out with a much ; closer idea of the actual echo. Value may be "yes", "no", or a number of ; milliseconds to delay before training (default = 400)