On Fri, 28 Apr 2006, Luciano Ramos wrote: > I've checked the source code of chan_ss7.c and it doesn't have any calls to > turn the echo canceller on, is any workaround available in the meantime the > next release of chan_ss7 is released? Well.. chan_ss7-0.8.4 is not official yet, but attached to this mail is a patch. It includes the echo-cancellation + a fix for the T1-timer crash. The patch require a small modification to your ss7.conf file. For each [link-XXX] section, add the following three lines: ; echocancel: allways | 31speech | no echocancel=allways ; echocan_taps: 32 | 64 | 128 | 256 echocan_taps=32 ; echocan_train: between 10ms and 1000ms echocan_train=350 The "echocancel=31speech" should be used if you only want to enable echo-cancellation on 3.1KHz speech calls. Mvh. Jacob -- Jacob Tinning System Developer SIFIRA A/S -------------- next part -------------- diff -u chan_ss7-0.8.3/chan_ss7.c chan_ss7-0.8.3d/chan_ss7.c --- chan_ss7-0.8.3/chan_ss7.c 2006-03-17 10:11:57.000000000 +0100 +++ chan_ss7-0.8.3d/chan_ss7.c 2006-05-01 08:57:56.000000000 +0200 @@ -133,6 +133,8 @@ struct iam iam; /* Last incoming IAM parameters */ char* addr; /* called addr */ int attempts; /* Number of outgoing call attempts on addr */ + int echocan_start; + int echocancel; unsigned char buffer[AST_FRIENDLY_OFFSET + AUDIO_READSIZE]; struct ast_frame frame; @@ -213,6 +215,8 @@ static struct ss7_chan* reattempt_call(struct ss7_chan *pvt); static void *continuity_check_thread_main(void *data); static void handle_complete_address(struct ss7_chan *pvt); +static void zt_disable_ec(struct ss7_chan *pvt); +static int zt_enable_ec(struct ss7_chan *pvt); static const struct ast_channel_tech ss7_tech = { .type = type, @@ -762,7 +766,7 @@ struct ss7_chan *pvt = arg; ast_log(LOG_NOTICE, "T1 timeout (waiting for RLC) CIC=%d.\n", pvt->cic); - isup_send_rel(pvt, pvt->owner->hangupcause); + isup_send_rel(pvt, pvt->hangupcause); return 1; /* Run us again the next period */ } @@ -1594,6 +1598,7 @@ isup_msg_start_optional_part(msg, sizeof(msg), &varptr, ¤t); /* Calling partys number Q.763 (3.10). */ + ast_log(LOG_NOTICE, "cid_pres=0x%X\n", chan->cid.cid_pres); if((chan->cid.cid_pres & AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED) { pres_restr = 1; } else { @@ -1688,6 +1693,8 @@ initiate_release_circuit(pvt, chan->hangupcause); } + zt_disable_ec(pvt); + ast_mutex_unlock(&pvt->lock); ast_mutex_unlock(&glock); @@ -1730,6 +1737,12 @@ } pvt->state = ST_CONNECTED; + /* Start echo-cancelling if required */ + if (pvt->echocan_start) { + zt_enable_ec(pvt); + pvt->echocan_start = 0; + } + ast_mutex_unlock(&pvt->lock); return 0; @@ -2245,6 +2258,51 @@ return newpvt; } +static int zt_enable_ec(struct ss7_chan *pvt) { + int res; + int x, y; + int z = 1; + + res = ioctl(pvt->zaptel_fd, ZT_AUDIOMODE, &z); + if (res) + ast_log(LOG_WARNING, "Unable to set fd %d to audiomode\n", pvt->zaptel_fd); + + x = pvt->link->echocan_taps; + res = ioctl(pvt->zaptel_fd, ZT_ECHOCANCEL, &x); + if (res) { + ast_log(LOG_WARNING, "Unable to enable echo cancellation on cic %d\n", pvt->cic); + return res; + } else { + pvt->echocancel = 1; + ast_log(LOG_DEBUG, "Enabled echo cancellation on cic %d\n", pvt->cic); + y = pvt->link->echocan_train; + res = ioctl(pvt->zaptel_fd, ZT_ECHOTRAIN, &y); + if (res) { + ast_log(LOG_WARNING, "Unable to request echo training on cic %d\n", pvt->cic); + return res; + } else { + ast_log(LOG_DEBUG, "Engaged echo training on cic %d\n", pvt->cic); + } + } + return 0; +} + + +static void zt_disable_ec(struct ss7_chan *pvt) { + int res; + int x = 0; + + if (pvt->echocancel) { + res = ioctl(pvt->zaptel_fd, ZT_ECHOCANCEL, &x); + if (res) + ast_log(LOG_WARNING, "Unable to disable echo cancellation on cic %d\n", pvt->cic); + else + ast_log(LOG_DEBUG, "disabled echo cancellation on cic %d\n", pvt->cic); + } + pvt->echocancel = 0; +} + + static int resolve_dual_seizure(struct ss7_chan *pvt, struct isup_msg *inmsg) { /* Q.764 2.9.1.4: The switch with the higher point code controls even numbered CICs */ int iscontrolling = (inmsg->dpc > inmsg->opc) && ((inmsg->cic & 1) == 0); @@ -2261,14 +2319,14 @@ { struct ast_channel* chan = pvt->owner; - ast_log(LOG_NOTICE, "IAM (cic=%d): ANI=%s DNI=%s RNI=%s redirect=%s/%d complete=%d.\n", + ast_log(LOG_NOTICE, "IAM (cic=%d): ANI=%s DNI=%s RNI=%s redirect=%s/%d complete=%d. echocontr=%d\n", pvt->cic, inmsg->iam.ani.restricted ? "*****" : inmsg->iam.ani.num, inmsg->iam.dni.num, inmsg->iam.rni.restricted ? "*****" : inmsg->iam.rni.num, inmsg->iam.redir_inf.is_redirect ? "yes" : "no", inmsg->iam.redir_inf.reason, - inmsg->iam.dni.complete); + inmsg->iam.dni.complete, inmsg->iam.echocontrol); if(pvt->state != ST_IDLE) { if (resolve_dual_seizure(pvt, inmsg)) { ast_log(LOG_WARNING, "Dual seizure/invalid IAM, discarding on CIC=%d.\n", @@ -2294,6 +2352,16 @@ } } + switch (pvt->link->echocancel) { + case EC_ALLWAYS: + pvt->echocan_start = 1; + break; + + case EC_31SPEECH: + pvt->echocan_start = (inmsg->iam.echocontrol == 0 && inmsg->iam.trans_medium == 0x3); + break; + } + remove_from_idlelist(pvt); pvt->state = ST_GOT_IAM; memcpy(&pvt->iam, &inmsg->iam, sizeof(pvt->iam)); @@ -2326,7 +2394,6 @@ /* Q.764 (2.1.4.6 a): When receiving ACM, stop T7 and start T9. */ t7_clear(pvt); - t9_start(chan); if(pvt->state != ST_SENT_IAM) { ast_log(LOG_NOTICE, "Got ACM message, but sent no IAM, on CIC=%d?!?", @@ -2336,6 +2403,7 @@ reset_circuit(pvt); return; } + t9_start(chan); if(chan == NULL) { ast_log(LOG_NOTICE, "Missing chan pointer for CIC=%d, processing ACM?!?\n", pvt->cic); @@ -2372,6 +2440,9 @@ return; } + /* Start echo-cancelling */ + zt_enable_ec(pvt); + ast_queue_frame(chan, &answer_frame); pvt->state = ST_CONNECTED; check_obci(pvt, inmsg->anm.obc_ind); @@ -3681,6 +3752,14 @@ return RESULT_SUCCESS; } +static int cmd_version(int fd, int argc, char *argv[]) { + + ast_cli(fd, "chan_ss7, v.0.8.3d\n"); + + return RESULT_SUCCESS; +} + + static int cmd_dump_status(int fd, int argc, char *argv[]) { ast_mutex_lock(&dump_mutex); @@ -3705,6 +3784,7 @@ return RESULT_SUCCESS; } + static char *complete_generic(char *word, int state, char **options, int entries) { int which = 0; int i; @@ -4071,6 +4151,12 @@ complete_dump_stop }, + { {"ss7", "version", NULL}, cmd_version, + "Show current version of chan_ss7", + "Usage: ss7 version\n", + NULL + }, + { {"ss7", "dump", "status", NULL}, cmd_dump_status, "Stop what dumps are running", "Usage: ss7 dump status\n", @@ -4211,6 +4297,8 @@ pvt->sending_dtmf = 0; pvt->dsp = NULL; pvt->hangupcause = 0; + pvt->echocan_start = 0; + pvt->echocancel = 0; pvt->has_inband_ind = 0; pvt->grs_count = -1; pvt->cgb_mask = 0; Only in chan_ss7-0.8.3d: chan_ss7.o Only in chan_ss7-0.8.3d: chan_ss7.so Only in chan_ss7-0.8.3d: cluster.o diff -u chan_ss7-0.8.3/config.c chan_ss7-0.8.3d/config.c --- chan_ss7-0.8.3/config.c 2006-03-16 11:59:37.000000000 +0100 +++ chan_ss7-0.8.3d/config.c 2006-05-01 08:57:56.000000000 +0200 @@ -353,6 +353,11 @@ return -1; } + /* Echo cancelation default values */ + link->echocancel = EC_DISABLED; + link->echocan_taps = 128; /* echo cancelation taps, 128 default */ + link->echocan_train = 300; /* echo cancelation training, 300ms default */ + v = ast_variable_browse(cfg, cat); while(v != NULL) { if(0 == strcasecmp(v->name, "linkset")) { @@ -411,6 +416,37 @@ } } has_schannel = 1; + + } else if(0 == strcasecmp(v->name, "echocancel")) { + if (strcasecmp(v->value, "no") == 0) { + link->echocancel = EC_DISABLED; + } else if (strcasecmp(v->value, "31speech") == 0) { + link->echocancel = EC_31SPEECH; + } else if (strcasecmp(v->value, "allways") == 0) { + link->echocancel = EC_ALLWAYS; + } else { + ast_log(LOG_ERROR, "Invalid value '%s' for echocancel entry for link '%s'.\n", v->value, link_name); + return -1; + } + } else if(0 == strcasecmp(v->name, "echocan_train")) { + if(sscanf(v->value, "%d", &link->echocan_train) != 1 || + link->echocan_train < 10 || link->echocan_train > 1000) + { + ast_log(LOG_ERROR, "Invalid value '%s' for echocan_train entry for " + "link '%s'. should be between 10 and 1000\n", + v->value, link_name); + return -1; + } + } else if(0 == strcasecmp(v->name, "echocan_taps")) { + if(!(sscanf(v->value, "%d", &link->echocan_taps) == 1 && + (link->echocan_taps == 32 || link->echocan_taps == 64 || + link->echocan_taps == 128 || link->echocan_taps == 256))) + { + ast_log(LOG_ERROR, "Invalid value '%s' for echocan_taps entry for " + "link '%s'. should be 32, 64, 128 or 256\n", + v->value, link_name); + return -1; + } } else { ast_log(LOG_ERROR, "Unknown config option '%s', aborting.\n", v->name); return -1; diff -u chan_ss7-0.8.3/config.h chan_ss7-0.8.3d/config.h --- chan_ss7-0.8.3/config.h 2006-03-16 11:52:59.000000000 +0100 +++ chan_ss7-0.8.3d/config.h 2006-05-01 08:57:56.000000000 +0200 @@ -39,6 +39,10 @@ #define RECEIVERPORT 4321 + +/* Echo cancelation taps */ +enum {EC_DISABLED, EC_ALLWAYS, EC_31SPEECH}; + typedef enum {STATE_UNKNOWN, STATE_ALIVE, STATE_DEAD} alivestate; struct linkset { char* name; @@ -74,6 +78,9 @@ int enabled; int send_sltm; int linkix; + int echocancel; + int echocan_taps; + int echocan_train; struct linkset* linkset; struct host* on_host; struct receiver* receiver; Only in chan_ss7-0.8.3d: config.o diff -u chan_ss7-0.8.3/isup.c chan_ss7-0.8.3d/isup.c --- chan_ss7-0.8.3/isup.c 2006-03-16 16:48:01.000000000 +0100 +++ chan_ss7-0.8.3d/isup.c 2006-05-01 08:58:26.000000000 +0200 @@ -308,14 +308,27 @@ /* Decode parameter 0x6 "nature of connection indicators" (Q.763 (3.35)). For now, only decodes the "continuity check required" part. */ static int decode_noci_contcheck(unsigned char *p, int len, void *data) { - int *contcheck_ptr = data; + struct iam *iam = data; if(len < 1) { ast_log(LOG_NOTICE, "Short parameter 'nature of connection indicators', " "len %d < 1.\n", len); return 0; } - *contcheck_ptr = ((p[0] >> 2) & 0x3) == 0x1; + iam->contcheck = ((p[0] >> 2) & 0x3) == 0x1; + iam->echocontrol = (p[0] >> 4) & 0x1; + return 1; +} + +static int decode_transmission_medium(unsigned char *p, int len, void *data) { + struct iam *iam = data; + + if(len < 1) { + ast_log(LOG_NOTICE, "Short parameter 'Transmission medium requirement', " + "len %d < 1.\n", len); + return 0; + } + iam->trans_medium = p[0]; return 1; } @@ -481,6 +494,7 @@ num_dig++; n->num[i++] = '0'; break; + default: ast_log(LOG_NOTICE, "unknown nature of address indicator 0x%0x.\n", nature_of_adr_ind); @@ -552,10 +566,10 @@ msg->iam.redir_inf.is_redirect = 0; msg->iam.redir_inf.reason = 0; return param_decode(buf, len, - IP_NATURE_OF_CONNECTION_INDICATORS, 1, decode_noci_contcheck, &msg->iam.contcheck, + IP_NATURE_OF_CONNECTION_INDICATORS, 1, decode_noci_contcheck, &msg->iam, IP_FORWARD_CALL_INDICATORS, 2, NULL, NULL, IP_CALLING_PARTYS_CATEGORY, 1, NULL, NULL, - IP_TRANSMISSION_MEDIUM_REQUIREMENT, 1, NULL, NULL, + IP_TRANSMISSION_MEDIUM_REQUIREMENT, 1, decode_transmission_medium, &msg->iam, 0, IP_CALLED_PARTY_NUMBER, decode_dni, &msg->iam.dni, 0, diff -u chan_ss7-0.8.3/isup.h chan_ss7-0.8.3d/isup.h --- chan_ss7-0.8.3/isup.h 2006-03-16 16:47:50.000000000 +0100 +++ chan_ss7-0.8.3d/isup.h 2006-05-01 08:57:56.000000000 +0200 @@ -71,6 +71,7 @@ IP_EVENT_INFORMATION = 0x24, /* (3.21) */ IP_OPTIONAL_BACKWARD_CALL_INDICATORS = 0x29, /* (3.5) */ IP_SUSPEND_RESUME_INDICATORS = 0x22, /* (3.21) */ + IP_ECHO_CONTROL_INFORMATION = 0x37, /* (3.19) */ }; #define PHONENUM_MAX 20 @@ -122,6 +123,8 @@ struct isup_phonenum rni; struct isup_redir_info redir_inf; int contcheck; + int echocontrol; + unsigned char trans_medium; } iam; struct { struct isup_phonenum sni; Only in chan_ss7-0.8.3d: isup.o Only in chan_ss7-0.8.3d: lffifo.o Only in chan_ss7-0.8.3d: moduletest.o Only in chan_ss7-0.8.3d: mtp.o