[asterisk-ss7] asterisk oh323 - chan-ss7 echo problem

Jacob Tinning tinning at sifira.dk
Mon May 1 00:08:27 MST 2006


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, &current);
 
   /* 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


More information about the asterisk-ss7 mailing list