diff options
author | kpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-12-19 04:04:16 +0000 |
---|---|---|
committer | kpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-12-19 04:04:16 +0000 |
commit | 4a8f1fb6fa4e4ad06f171c30d129dfeef6d07867 (patch) | |
tree | 9489f3307b1958505c482cccf5c5a06fe7da6fdf | |
parent | e68e5ec9adb20f793ad0319b181cfdeea336826d (diff) |
add ability to provide parameters to echo cancelers on a per-channel basis, and remove the three versions of the 'Mark' echo canceler (later replaced by KB1 and then by MG2)
git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@3524 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | kb1ec.h | 51 | ||||
-rw-r--r-- | mec.h | 322 | ||||
-rw-r--r-- | mec2.h | 436 | ||||
-rw-r--r-- | mec2_const.h | 28 | ||||
-rw-r--r-- | mec3-float.h | 229 | ||||
-rw-r--r-- | mec3.h | 257 | ||||
-rw-r--r-- | mg2ec.h | 66 | ||||
-rw-r--r-- | sec-2.h | 57 | ||||
-rw-r--r-- | sec.h | 54 | ||||
-rw-r--r-- | zaptel-base.c | 166 | ||||
-rw-r--r-- | zaptel.h | 28 | ||||
-rw-r--r-- | zconfig.h | 3 |
13 files changed, 254 insertions, 1445 deletions
@@ -372,7 +372,7 @@ wct4xxp/wct4xxp.o: tor2.o: tor2-hw.h tor2fw.h -zaptel-base.o: digits.h arith.h sec.h mec.h sec-2.h mec2.h mec3.h zconfig.h +zaptel-base.o: digits.h arith.h sec.h sec-2.h kb1ec.h mg2ec.h zconfig.h wcusb.o: wcusb.h @@ -529,12 +529,19 @@ static inline short echo_can_update(struct echo_can_state *ec, short iref, short return u; } -static inline struct echo_can_state *echo_can_create(int len, int adaption_mode) +static int echo_can_create(struct zt_echocanparams *ecp, struct zt_echocanparam *p, + struct echo_can_state **ec) { - struct echo_can_state *ec; int maxy; int maxu; - maxy = len + DEFAULT_M; + size_t size; + + if (ecp->param_count > 0) { + printk(KERN_WARNING "KB1 echo canceler does not support parameters; failing request\n"); + return -EINVAL; + } + + maxy = ecp->tap_length + DEFAULT_M; maxu = DEFAULT_M; if (maxy < (1 << DEFAULT_ALPHA_YT_I)) maxy = (1 << DEFAULT_ALPHA_YT_I); @@ -542,26 +549,24 @@ static inline struct echo_can_state *echo_can_create(int len, int adaption_mode) maxy = (1 << DEFAULT_SIGMA_LY_I); if (maxu < (1 << DEFAULT_SIGMA_LU_I)) maxu = (1 << DEFAULT_SIGMA_LU_I); - ec = (struct echo_can_state *)MALLOC(sizeof(struct echo_can_state) + - 4 + /* align */ - sizeof(int) * len + /* a_i */ - sizeof(short) * len + /* a_s */ - 2 * sizeof(short) * (maxy) + /* y_s */ - 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */ - 2 * sizeof(short) * (maxu) + /* u_s */ - 2 * sizeof(short) * len); /* y_tilde_s */ - if (ec) { - memset(ec, 0, sizeof(struct echo_can_state) + - 4 + /* align */ - sizeof(int) * len + /* a_i */ - sizeof(short) * len + /* a_s */ - 2 * sizeof(short) * (maxy) + /* y_s */ - 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */ - 2 * sizeof(short) * (maxu) + /* u_s */ - 2 * sizeof(short) * len); /* y_tilde_s */ - init_cc(ec, len, maxy, maxu); - } - return ec; + + size = sizeof(*ec) + + 4 + /* align */ + sizeof(int) * ecp->tap_length + /* a_i */ + sizeof(short) * ecp->tap_length + /* a_s */ + 2 * sizeof(short) * (maxy) + /* y_s */ + 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */ + 2 * sizeof(short) * (maxu) + /* u_s */ + 2 * sizeof(short) * ecp->tap_length; /* y_tilde_s */ + + if (!(*ec = MALLOC(size))) + return -ENOMEM; + + memset(*ec, 0, size); + + init_cc(*ec, ecp->tap_length, maxy, maxu); + + return 0; } static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val) @@ -1,322 +0,0 @@ -/* - * Mark's Echo Canceller - * - * Mark Spencer <markster@linux-support.net> - * - * Simple, LMS Echo Canceller with double talk detection. - * Partly based on the TI App note: - * "Digital Voice Echo Canceller with a TMS 32020" - * - * Special additional thanks to: - * Jim Dixon (Lambda Telecommunications) - * Iman Ghobrial (Adtran, Inc.) - * - * Copyright (C) 2001, Linux Support Services, Inc. - * - * This program is free software and may be used and - * distributed according to the terms of the GNU - * General Public License, incorporated herein by - * reference. - * - */ - -#ifndef _MEC_H -#define _MEC_H - -/* You have to express the size of the echo canceller in taps as - a power of 2 (6 = 64 taps, 7 = 128 taps, 8 = 256 taps) */ -#define NUM_TAPS_POW2 6 /* Size of echo canceller in power of 2 (taps) */ -#define NUM_TAPS (1 << NUM_TAPS_POW2) /* Actual number of taps */ -#define TAP_MASK (NUM_TAPS-1) - - -#define SIGMA_LU_POW NUM_TAPS_POW2 -#define SIGMA_LY_POW NUM_TAPS_POW2 -#define SIGMA_YT_POW (NUM_TAPS_POW2 - 1) -#define SIGMA_ST_POW (NUM_TAPS_POW2 - 1) - -#define BETA_POW 8 - -#define CUTOFF_S 4 - -/* The higher you make this, the better the quality, but the more CPU time required */ -#define MIN_QUALITY 100 - -/* This optimization saves a lot of processor but may degrade quality */ -#define OPTIMIZEDIV - -#if 0 -/* This converges much more slowly but saves processor */ -#define MIN_UPDATE 256 -#define MIN_SKIP 8 -#endif - -#define HANG_T 600 /* 600 samples, or 75ms */ - -struct echo_can_state { - /* Circular position */ - int cpos; - short y[NUM_TAPS]; /* Last N samples (relative to cpos) transmitted */ - short y_abs[NUM_TAPS]; /* Last N samples (relative to cpos) transmitted (abs value) */ - short s[NUM_TAPS]; /* Last N samples (relative to cpos) received */ - short s_abs[NUM_TAPS]; /* Last N samples (relative to cpos) received (abs value) */ - short u[NUM_TAPS]; /* Last N samples (relative to cpos) with echo removed */ - short u_abs[NUM_TAPS]; /* Last N samples (relative to cpos) with echo removed */ - - int Ly; /* tx power */ - int Lu; /* Power of echo-cancelled output */ - - int Ty[NUM_TAPS]; /* Short term power estimate of transmit */ - int Ts; /* Short term power estimate of received signal */ - - int a[NUM_TAPS]; /* Tap weight coefficients (not relative) */ - - short sdc[NUM_TAPS]; /* Near end signal before High Pass Filter */ - - int samples; /* Sample count */ - int pass; /* Number of passes we've made */ - - int hangt; - - int lastmax; /* Optimize maximum search */ - int maxTy; /* Maximum Ty */ -}; - -#define INLINE inline - -#ifdef __KERNEL__ -#include <linux/kernel.h> -#include <linux/slab.h> -#define MALLOC(a) kmalloc((a), GFP_KERNEL) -#define FREE(a) kfree((a)) -#else -#include <stdlib.h> -#include <unistd.h> -#include <stdint.h> -#include <string.h> -#define MALLOC(a) malloc(a) -#define FREE(a) free(a) -#endif - -static void echo_can_init(void) -{ - printk("Zaptel Echo Canceller: MARK%s\n", ZAPTEL_ECHO_AGGRESSIVE); -} - -static void echo_can_identify(char *buf, size_t len) -{ - strncpy(buf, "MARK2", len); -} - -static void echo_can_shutdown(void) -{ -} - -static INLINE struct echo_can_state *echo_can_create(int len, int adaption_mode) -{ - struct echo_can_state *ec; - /* Uhm, we're only one length, sorry. */ - ec = MALLOC(sizeof(struct echo_can_state)); - if (ec) - memset(ec, 0, sizeof(*ec)); - return ec; -} - -#define PASSPOS 32000 -#undef PASSPOS - -static INLINE void echo_can_free(struct echo_can_state *ec) -{ - FREE(ec); -} - -static INLINE int16_t echo_can_update(struct echo_can_state *ec, int16_t tx, int16_t rx) -{ - /* Process a sample, where tx is the near end and rx is the far end + echo */ - - int suppr; - int nsuppr; - short rxabs, txabs; - register int Lu; - register int x; - register int pos; - register int r_hat; /* Estimated echo */ - int oldrxabs; - int oldtxabs; - int oldsupprabs; - int supprabs; -#ifdef MIN_UPDATE - int totalupd; -#endif - - txabs = abs(tx); - rxabs = abs(rx); - - ec->pass++; - - r_hat = 0; - - /* Load next value */ - ec->y[ec->cpos] = tx; - - /* Load next abs value */ - oldtxabs = ec->y_abs[ec->cpos]; - ec->y_abs[ec->cpos] = txabs; - - /* Bring in receive value (near-end signal) */ - ec->sdc[ec->cpos] = rx; - - /* Bring in receive value absolute value */ - oldrxabs = ec->s_abs[ec->cpos]; - ec->s_abs[ec->cpos] = rxabs; - - Lu = ec->Lu | 1; - -#if 0 - /* Apply first order high pass filter (3 dB @ 160 Hz) */ - tx = ec->s[ec->cpos] = (1.0-DEFGAMMA) * ec->s[(ec->cpos - 1) & TAP_MASK] + - 0.5 * (1.0-DEFGAMMA) * ( ec->sdc[(ec->cpos - 1) & TAP_MASK] - ec->sdc[(ec->cpos - 2) & TAP_MASK]); -#endif - - /* Estimate echo */ - pos = ec->cpos; - for (x=0;x<NUM_TAPS;x++) { - r_hat += ec->a[x] * ec->y[pos]; - /* Go backwards in time and loop around circular buffer */ - pos = (pos - 1) & TAP_MASK; - } - - r_hat >>= 16; - - if (ec->hangt > 0) - ec->hangt--; - - /* printf("rx: %F, rhat: %F\n", rx, r_hat); */ - /* Calculate suppressed amount */ - suppr = rx - r_hat; - - if (ec->pass > NUM_TAPS) { - /* Have to have enough taps to start with */ - if (ec->maxTy > ec->Ts) { - /* There is no near-end speech detected */ - if (!ec->hangt) { - /* We're not in the hang-time from the end of near-end speech */ - if ((ec->Ly > 1024) && ((ec->Ly / Lu) < MIN_QUALITY)) { -#ifdef OPTIMIZEDIV - /* We both have enough signal on the transmit */ - nsuppr = (suppr << 18) / ec->Ly; - - if (nsuppr > 32767) - nsuppr = 32767; - if (nsuppr < -32768) - nsuppr = -32768; - - nsuppr /= ec->Ly; -#else - /* We both have enough signal on the transmit */ - nsuppr = (suppr << 16) / ec->Ly; - - if (nsuppr > 32767) - nsuppr = 32767; - if (nsuppr < -32768) - nsuppr = -32768; - -#endif - - /* Update coefficients */ - pos = ec->cpos; -#ifdef MIN_UPDATE - totalupd =0; -#endif - for (x=0;x<NUM_TAPS;x++) { - register int adj; - adj = ec->y[pos] * nsuppr; -#ifndef OPTIMIZEDIV - adj /= ec->Ly; - adj >>= BETA_POW; -#else - adj >>= BETA_POW + 2; -#endif -#ifdef PASSPOS - if (ec->pass > PASSPOS) - printf("tx: %d, old %d: %d, adj %d, nsuppr: %d, power: %d\n", tx, x, ec->a[x], adj, nsuppr, ec->Ly); -#endif - ec->a[x] += adj; -#ifdef MIN_UPDATE - totalupd += abs(adj); -#endif - /* Go backwards in time and loop around circular buffer */ - pos = (pos - 1) & TAP_MASK; - } -#ifdef MIN_UPDATE - /* If we didn't update at least this much, delay for many more taps */ - if (totalupd < MIN_UPDATE) { - ec->hangt += MIN_SKIP; - } -#endif - } - - } - } else - /* Near end speech detected */ - ec->hangt = HANG_T; - } - - /* Save supression and absolute values */ - supprabs = abs(suppr); - oldsupprabs = ec->u_abs[ec->cpos]; - ec->u[ec->cpos] = suppr; - ec->u_abs[ec->cpos] = supprabs; - - /* Update tx power */ - ec->Ly += (txabs >> SIGMA_LY_POW) - (oldtxabs >> SIGMA_LY_POW); - - /* Update rx power */ - ec->Lu += (supprabs >> SIGMA_LU_POW) - (oldsupprabs >> SIGMA_LU_POW); - - /* Short term power of tx */ - ec->Ty[ec->cpos] = ec->Ty[(ec->cpos - 1) & TAP_MASK] + - ((txabs >> SIGMA_YT_POW ) - (oldtxabs >> SIGMA_YT_POW)); - - /* Keep track of highest */ - if (ec->lastmax == ec->cpos) { - register int maxTy = 0; - /* Have to loop through and find the new highest since our old highest expired */ - /* Estimate echo */ - pos = ec->cpos; - for (x=0;x<NUM_TAPS;x++) { - if (ec->Ty[pos] > maxTy) - maxTy = ec->Ty[pos]; - /* Go backwards in time and loop around circular buffer */ - pos = (pos - 1) & TAP_MASK; - } - ec->maxTy = maxTy; - } else { - /* Just keep the highest */ - if (ec->Ty[ec->cpos] > ec->maxTy) { - ec->maxTy = ec->Ty[ec->cpos]; - ec->lastmax = ec->cpos; - } - } - ec->Ts += (rxabs >> SIGMA_ST_POW) - (oldrxabs >> SIGMA_ST_POW) ; - - /* Increment position memory */ - ec->cpos = (ec->cpos + 1 ) & TAP_MASK; - - return suppr; -} - -static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val) -{ - /* Reset hang counter to avoid adjustments after - initial forced training */ - ec->hangt = NUM_TAPS << 1; - if (pos >= NUM_TAPS) - return 1; - ec->a[pos] = val << 17; - if (++pos >= NUM_TAPS) - return 1; - return 0; -} - -#endif @@ -1,436 +0,0 @@ -/* - * Mark's Second Echo Canceller - * - * Copyright (C) 2002, Digium, Inc. - * - * This program is free software and may be used and - * distributed according to the terms of the GNU - * General Public License, incorporated herein by - * reference. - * - */ -#ifndef _MARK2_ECHO_H -#define _MARK2_ECHO_H - -#ifdef __KERNEL__ -#include <linux/kernel.h> -#include <linux/slab.h> -#define MALLOC(a) kmalloc((a), GFP_KERNEL) -#define FREE(a) kfree(a) -#else -#include <stdlib.h> -#include <unistd.h> -#include <stdint.h> -#include <string.h> -#include <math.h> -#define MALLOC(a) malloc(a) -#define FREE(a) free(a) -#endif - -/* Get optimized routines for math */ -#include "arith.h" - -#ifndef NULL -#define NULL 0 -#endif -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE (!FALSE) -#endif - -#include "mec2_const.h" - -/* Circular buffer definition */ -typedef struct { - int idx_d; - int size_d; - short *buf_d; /* Twice as large as we need */ -} echo_can_cb_s; - -// class definition -// -struct echo_can_state { - /* Echo canceller definition */ - - /* absolute time */ - int i_d; - - /* pre-computed constants */ - - int N_d; - int beta2_i; - - // declare accumulators for power computations - // - int Ly_i; - int Lu_i; - - // declare an accumulator for the near-end signal detector - // - int s_tilde_i; - int HCNTR_d; - - // circular buffers and coefficients - // - int *a_i; - short *a_s; - echo_can_cb_s y_s; - echo_can_cb_s s_s; - echo_can_cb_s u_s; - echo_can_cb_s y_tilde_s; - int y_tilde_i; - - /* Max memory */ - short max_y_tilde; - int max_y_tilde_pos; - -}; - -static void echo_can_init(void) -{ - printk("Zaptel Echo Canceller: MARK2%s\n", ZAPTEL_ECHO_AGGRESSIVE); -} - -static void echo_can_identify(char *buf, size_t len) -{ - strncpy(buf, "MARK2", len); -} - -static void echo_can_shutdown(void) -{ -} - -static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where) -{ - cb->buf_d = (short *)where; - cb->idx_d = 0; - cb->size_d = len; -} - -static inline void add_cc_s(echo_can_cb_s *cb, short newval) -{ - /* Can't use modulus because N+M isn't a power of two (generally) */ - cb->idx_d--; - if (cb->idx_d < (int)0) - {cb->idx_d += cb->size_d;} - /* Load two copies into memory */ - cb->buf_d[cb->idx_d] = newval; - cb->buf_d[cb->idx_d + cb->size_d] = newval; -} - -static inline short get_cc_s(echo_can_cb_s *cb, int pos) -{ - /* Load two copies into memory */ - return cb->buf_d[cb->idx_d + pos]; -} - -static inline void init_cc(struct echo_can_state *ec, int N, int maxy, int maxu) { - - void *ptr = ec; - unsigned long tmp; - /* double-word align past end of state */ - ptr += sizeof(struct echo_can_state); - tmp = (unsigned long)ptr; - tmp += 3; - tmp &= ~3L; - ptr = (void *)tmp; - - // reset parameters - // - ec->N_d = N; - ec->beta2_i = DEFAULT_BETA1_I; - - // allocate coefficient memory - // - ec->a_i = ptr; - ptr += (sizeof(int) * ec->N_d); - ec->a_s = ptr; - ptr += (sizeof(short) * ec->N_d); - - /* Reset Y circular buffer (short version) */ - init_cb_s(&ec->y_s, maxy, ptr); - ptr += (sizeof(short) * (maxy) * 2); - - /* Reset Sig circular buffer (short version for FIR filter) */ - init_cb_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr); - ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2); - - init_cb_s(&ec->u_s, maxu, ptr); - ptr += (sizeof(short) * maxu * 2); - - // allocate a buffer for the reference signal power computation - // - init_cb_s(&ec->y_tilde_s, ec->N_d, ptr); - - - // reset absolute time - // - ec->i_d = (int)0; - - // reset the power computations (for y and u) - // - ec->Ly_i = DEFAULT_CUTOFF_I; - ec->Lu_i = DEFAULT_CUTOFF_I; - - // reset the near-end speech detector - // - ec->s_tilde_i = 0; - ec->y_tilde_i = 0; - ec->HCNTR_d = (int)0; - - // exit gracefully - // -} - -static inline void echo_can_free(struct echo_can_state *ec) -{ - FREE(ec); -} - -static inline short echo_can_update(struct echo_can_state *ec, short iref, short isig) { - - /* declare local variables that are used more than once - */ - int k; - int rs; - short u; - int Py_i; - int two_beta_i; - - /*************************************************************************** - // - // flow A on pg. 428 - // - ***************************************************************************/ - - /* eq. (16): high-pass filter the input to generate the next value; - // push the current value into the circular buffer - // - // sdc_im1_d = sdc_d; - // sdc_d = sig; - // s_i_d = sdc_d; - // s_d = s_i_d; - // s_i_d = (float)(1.0 - gamma_d) * s_i_d - + (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d); */ - - - /* Delete last sample from power estimate */ - ec->y_tilde_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1 )) >> DEFAULT_ALPHA_YT_I; - /* push the reference data onto the circular buffer */ - add_cc_s(&ec->y_s, iref); - - /* eq. (2): compute r in fixed-point */ - rs = CONVOLVE2(ec->a_s, ec->y_s.buf_d + ec->y_s.idx_d, ec->N_d); - rs >>= 15; - - /* eq. (3): compute the output value (see figure 3) and the error - // note: the error is the same as the output signal when near-end - // speech is not present - */ - u = isig - rs; - - add_cc_s(&ec->u_s, u); - - - - /* Delete oldest part of received s_tilde */ - ec->s_tilde_i -= abs(get_cc_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1 )); - - /* push the signal on the circular buffer, too */ - add_cc_s(&ec->s_s, isig); - ec->s_tilde_i += abs(isig); - ec->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_YT_I; - - /* Add to our list of recent y_tilde's */ - add_cc_s(&ec->y_tilde_s, ec->y_tilde_i); - - /**************************************************************************** - // - // flow B on pg. 428 - // - ****************************************************************************/ - - /* compute the new convergence factor - */ - if (!ec->HCNTR_d) { - Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I); - Py_i >>= 15; - } else { - Py_i = (1 << 15); - } - -#if 0 - printf("Py: %e, Py_i: %e\n", Py, Py_i * AMPL_SCALE_1); -#endif - - /* Vary rate of adaptation depending on position in the file - // Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech - // has begun of the file to allow the echo cancellor to estimate the - // channel accurately - */ -#if 0 - if (ec->start_speech_d != 0 ){ - if ( ec->i_d > (DEFAULT_T0 + ec->start_speech_d)*(SAMPLE_FREQ) ){ - ec->beta2_d = max_cc_float(MIN_BETA, - DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((ec->i_d/(float)SAMPLE_FREQ) - - DEFAULT_T0 - - ec->start_speech_d))); - } - } - else {ec->beta2_d = DEFAULT_BETA1;} -#endif - - ec->beta2_i = DEFAULT_BETA1_I; /* Fixed point, inverted */ - - two_beta_i = (ec->beta2_i * Py_i) >> 15; /* Fixed point version, inverted */ - if (!two_beta_i) - two_beta_i++; - - /* Update Lu_i (Suppressed power estimate) */ - ec->Lu_i -= abs(get_cc_s(&ec->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1 )) ; - ec->Lu_i += abs(u); - - /* eq. (10): update power estimate of the reference - */ - ec->Ly_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ; - ec->Ly_i += abs(iref); - - if (ec->Ly_i < DEFAULT_CUTOFF_I) - ec->Ly_i = DEFAULT_CUTOFF_I; - -#if 0 - printf("Float: %e, Int: %e\n", ec->Ly_d, (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * AMPL_SCALE_1); -#endif - - if (ec->y_tilde_i > ec->max_y_tilde) { - /* New highest y_tilde with full life */ - ec->max_y_tilde = ec->y_tilde_i; - ec->max_y_tilde_pos = ec->N_d - 1; - } else if (--ec->max_y_tilde_pos < 0) { - /* Time to find new max y tilde... */ - ec->max_y_tilde = MAX16(ec->y_tilde_s.buf_d + ec->y_tilde_s.idx_d, ec->N_d, &ec->max_y_tilde_pos); - } - - if ((ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > ec->max_y_tilde) - { - ec->HCNTR_d = DEFAULT_HANGT; - } - else if (ec->HCNTR_d > (int)0) - { - ec->HCNTR_d--; - } - - /* update coefficients if no near-end speech and we have enough signal - * to bother trying to update. - */ - if (!ec->HCNTR_d && !(ec->i_d % DEFAULT_M) && - (ec->Lu_i > MIN_UPDATE_THRESH_I)) { - // loop over all filter coefficients - // - for (k=0; k<ec->N_d; k++) { - - // eq. (7): compute an expectation over M_d samples - // - int grad2; - grad2 = CONVOLVE2(ec->u_s.buf_d + ec->u_s.idx_d, - ec->y_s.buf_d + ec->y_s.idx_d + k, DEFAULT_M); - // eq. (7): update the coefficient - // - ec->a_i[k] += grad2 / two_beta_i; - ec->a_s[k] = ec->a_i[k] >> 16; - } - } - - /* paragraph below eq. (15): if no near-end speech, - // check for residual error suppression - */ -#ifndef NO_ECHO_SUPPRESSOR -#ifdef AGGRESSIVE_SUPPRESSOR -#ifdef AGGRESSIVE_TIMELIMIT /* This allows the aggressive suppressor to turn off after set amount of time */ - if (ec->i_d > AGGRESSIVE_TIMELIMIT ) { - if ((ec->HCNTR_d == 0) && ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I)) { - u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1); - } - } - else { -#endif - if ((ec->HCNTR_d < AGGRESSIVE_HCNTR) && (ec->Ly_i > (ec->Lu_i << 1))) { - u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1); - u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1); - } -#ifdef AGGRESSIVE_TIMELIMIT - } -#endif -#else - if ((ec->HCNTR_d == 0) && ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I)) { - u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1); - } -#endif -#endif - -#if 0 - if ((ec->HCNTR_d == 0) && ((ec->Lu_d/ec->Ly_d) < DEFAULT_SUPPR) && - (ec->Lu_d/ec->Ly_d > EC_MIN_DB_VALUE)) { - suppr_factor = (10/(float)(SUPPR_FLOOR-SUPPR_CEIL))*log(ec->Lu_d/ec->Ly_d) - - SUPPR_CEIL/(float)(SUPPR_FLOOR - SUPPR_CEIL); - - u_suppr = pow(10.0,(suppr_factor)*RES_SUPR_FACTOR/10.0)*u_suppr; - - } -#endif - ec->i_d++; - return u; -} - -static inline struct echo_can_state *echo_can_create(int len, int adaption_mode) -{ - struct echo_can_state *ec; - int maxy; - int maxu; - maxy = len + DEFAULT_M; - maxu = DEFAULT_M; - if (maxy < (1 << DEFAULT_ALPHA_YT_I)) - maxy = (1 << DEFAULT_ALPHA_YT_I); - if (maxy < (1 << DEFAULT_SIGMA_LY_I)) - maxy = (1 << DEFAULT_SIGMA_LY_I); - if (maxu < (1 << DEFAULT_SIGMA_LU_I)) - maxu = (1 << DEFAULT_SIGMA_LU_I); - ec = (struct echo_can_state *)MALLOC(sizeof(struct echo_can_state) + - 4 + /* align */ - sizeof(int) * len + /* a_i */ - sizeof(short) * len + /* a_s */ - 2 * sizeof(short) * (maxy) + /* y_s */ - 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */ - 2 * sizeof(short) * (maxu) + /* u_s */ - 2 * sizeof(short) * len); /* y_tilde_s */ - if (ec) { - memset(ec, 0, sizeof(struct echo_can_state) + - 4 + /* align */ - sizeof(int) * len + /* a_i */ - sizeof(short) * len + /* a_s */ - 2 * sizeof(short) * (maxy) + /* y_s */ - 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */ - 2 * sizeof(short) * (maxu) + /* u_s */ - 2 * sizeof(short) * len); /* y_tilde_s */ - init_cc(ec, len, maxy, maxu); - } - return ec; -} - -static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val) -{ - /* Reset hang counter to avoid adjustments after - initial forced training */ - ec->HCNTR_d = ec->N_d << 1; - if (pos >= ec->N_d) - return 1; - ec->a_i[pos] = val << 17; - ec->a_s[pos] = val << 1; - if (++pos >= ec->N_d) - return 1; - return 0; -} - -#endif diff --git a/mec2_const.h b/mec2_const.h deleted file mode 100644 index 4c7e8c9..0000000 --- a/mec2_const.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - Important constants for tuning mec2 echo can - */ -#ifndef _MEC2_CONST_H -#define _MEC2_CONST_H - - -/* Convergence speed -- higher means slower */ -#define DEFAULT_BETA1_I 2048 -#define DEFAULT_SIGMA_LY_I 7 -#define DEFAULT_SIGMA_LU_I 7 -#define DEFAULT_ALPHA_ST_I 5 -#define DEFAULT_ALPHA_YT_I 5 -#define DEFAULT_CUTOFF_I 128 -#define DEFAULT_HANGT 600 -#define DEFAULT_SUPPR_I 16 -#define MIN_UPDATE_THRESH_I 4096 -#define DEFAULT_M 16 -#define SUPPR_FLOOR -64 -#define SUPPR_CEIL -24 -#define RES_SUPR_FACTOR -20 -#define AGGRESSIVE_HCNTR 160 /* 20ms */ - -/* Only use agressive echo cancellation for this amount of time then go back to normal cancelation */ -/* #define AGGRESSIVE_TIMELIMIT 150000 */ /* 8 = 1ms */ - -#endif /* _MEC2_CONST_H */ - diff --git a/mec3-float.h b/mec3-float.h deleted file mode 100644 index 12c3038..0000000 --- a/mec3-float.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Mark's Third Echo Canceller - * - * Copyright (C) 2003, Digium, Inc. - * - * This program is free software and may be used - * and distributed under the terms of the GNU General Public - * License, incorporated herein by reference. - * - * Dedicated to the crew of the Columbia, STS-107 for their - * bravery and courageous sacrifice for science. - * - */ - -#ifndef _MARK3_ECHO_H -#define _MARK3_ECHO_H - -#define ECHO_CAN_FP - -#ifdef __KERNEL__ -#include <linux/kernel.h> -#include <linux/slab.h> -#define MALLOC(a) kmalloc((a), GFP_KERNEL) -#define FREE(a) kfree(a) -#include <math.h> -#else -#include <stdlib.h> -#include <unistd.h> -#include <stdint.h> -#include <string.h> -#include <math.h> -#define MALLOC(a) malloc(a) -#define FREE(a) free(a) -#endif - -/* - * Define COEFF_BACKUP for experimental coefficient backup code - */ - - -#define STEP_SIZE 0.4 /* Convergence rate */ - -#define SIGMA_P 0.01 /* Minimum adjustment */ -#define SIGMA_REF_PWR 0.01 /* Keep denominator from being 0 */ - -#define MIN_TX_ENERGY 256.0/32767.0 /* Must have at least this much reference */ -#define MIN_RX_ENERGY 32.0/32767.0 /* Must have at least this much receive energy */ - -#define MAX_ATTENUATION 64.0 /* Maximum amount of loss we care about */ -#define MAX_BETA 0.1 - -#define SUPPR_ATTENUATION 16.0 /* Amount of loss at which we suppress audio */ - -#define HANG_TIME 600 /* Hangover time */ - -#define NTAPS 256 /* Number of echo can taps */ - -#define BACKUP 256 /* Backup every this number of samples */ - -typedef struct { - float buf[NTAPS * 2]; - float max; - int maxexp; -} cbuf_f; - -struct echo_can_state { - float a[NTAPS]; /* Coefficients */ -#ifdef COEFF_BACKUP - float b[NTAPS]; /* Coefficients */ - float c[NTAPS]; /* Coefficients */ - int backup; /* Backup timer */ -#endif - cbuf_f ref; /* Reference excitation */ - cbuf_f sig; /* Signal (echo + near end + noise) */ - cbuf_f e; /* Error */ - float refpwr; /* Reference power */ - int taps; /* Number of taps */ - int hcntr; /* Hangtime counter */ - int pos; /* Position in curcular buffers */ -}; - -static inline void echo_can_free(struct echo_can_state *ec) -{ - FREE(ec); -} - -static inline void buf_add(cbuf_f *b, float sample, int pos, int taps) -{ - /* Store and keep track of maxima */ - int x; - b->buf[pos] = sample; - b->buf[pos + taps] = sample; - if (sample > b->max) { - b->max = sample; - b->maxexp = taps; - } else { - b->maxexp--; - if (!b->maxexp) { - b->max = 0; - for (x=0;x<taps;x++) - if (b->max < fabs(b->buf[pos + x])) { - b->max = fabs(b->buf[pos + x]); - b->maxexp = x + 1; - } - } - } -} - -static inline short echo_can_update(struct echo_can_state *ec, short iref, short isig) -{ - int x; - float ref; - float sig; - float u; - float refpwr; - float beta; /* Factor */ - float se; /* Simulated echo */ - /* Convert to floats about 1.0 */ - ref = (((float)iref)/32767.0); - sig = (((float)isig)/32767.0); - -#if 0 - printf("start: %d, finish: %d\n", ec->start, ec->finish); -#endif - -#ifdef COEFF_BACKUP - if (!ec->backup) { - /* Backup coefficients periodically */ - ec->backup = BACKUP; - memcpy(ec->c,ec->b,sizeof(ec->c)); - memcpy(ec->b,ec->a,sizeof(ec->b)); - } else - ec->backup--; -#endif - /* Remove old samples from reference power calculation */ - ec->refpwr -= (ec->ref.buf[ec->pos] * ec->ref.buf[ec->pos]); - - /* Store signal and reference */ - buf_add(&ec->ref, ref, ec->pos, ec->taps); - buf_add(&ec->sig, sig, ec->pos, ec->taps); - - /* Add new reference power */ - ec->refpwr += (ec->ref.buf[ec->pos] * ec->ref.buf[ec->pos]); - - - /* Calculate simulated echo */ - se = 0.0; - for (x=0;x<ec->taps;x++) - se += ec->a[x] * ec->ref.buf[ec->pos + x]; - -#if 0 - if (!(ec->pos2++ % 1024)) { - printk("sig: %d, se: %d\n", (int)(32768.0 * sig), (int)(32768.0 * se)); - } -#endif - u = sig - se; - if (ec->hcntr) - ec->hcntr--; - - /* Store error */ - buf_add(&ec->e, u, ec->pos, ec->taps); - if ((ec->ref.max > MIN_TX_ENERGY) && - (ec->sig.max > MIN_RX_ENERGY) && - (ec->e.max * MAX_ATTENUATION > ec->ref.max)) { - /* We have sufficient energy */ - if (ec->sig.max * 2.0 < ec->ref.max) { - /* No double talk */ - if (!ec->hcntr) { - if (ec->refpwr < SIGMA_REF_PWR) - refpwr = SIGMA_REF_PWR; - else - refpwr = ec->refpwr; - beta = STEP_SIZE * u / refpwr; - if (beta > MAX_BETA) - beta = MAX_BETA; - if (beta < -MAX_BETA) - beta = -MAX_BETA; - /* Update coefficients */ - for (x=0;x<ec->taps;x++) { - ec->a[x] += beta * ec->ref.buf[ec->pos + x]; - } - } - } else { -#ifdef COEFF_BACKUP - if (!ec->hcntr) { - /* Our double talk detector is turning on for the first time. Revert - our coefficients, since we're probably well into the double talk by now */ - memcpy(ec->a, ec->c, sizeof(ec->a)); - } - ec->backup = BACKUP; -#endif - /* Reset hang-time counter, and prevent backups */ - ec->hcntr = HANG_TIME; - } - } -#ifndef NO_ECHO_SUPPRESSOR - if (ec->e.max * SUPPR_ATTENUATION < ec->ref.max) { - /* Suppress residual echo */ - u *= u; - } -#endif - ec->pos--; - if (ec->pos < 0) - ec->pos = ec->taps-1; - u *= 32767.0; - if (u < -32768.0) - u = -32768.0; - if (u > 32767.0) - u = 32767.0; - return (short)(u); -} - -static inline struct echo_can_state *echo_can_create(int taps, int adaption_mode) -{ - struct echo_can_state *ec; - taps = NTAPS; - ec = MALLOC(sizeof(struct echo_can_state)); - if (ec) { - printk("Allocating MEC3 canceller (%d)\n", taps); - memset(ec, 0, sizeof(struct echo_can_state)); - ec->taps = taps; - if (ec->taps > NTAPS) - ec->taps = NTAPS; - ec->pos = ec->taps-1; - } - return ec; -} - -#endif @@ -1,257 +0,0 @@ -/* - * Mark's Third Echo Canceller - * - * Copyright (C) 2003, Digium, Inc. - * - * This program is free software and may be used - * and distributed under the terms of the GNU General Public - * License, incorporated herein by reference. - * - * Dedicated to the crew of the Columbia, STS-107 for their - * bravery and courageous sacrifice for science. - * - */ - -#ifndef _MARK3_ECHO_H -#define _MARK3_ECHO_H - - - -#ifdef __KERNEL__ -#include <linux/kernel.h> -#include <linux/slab.h> -#define MALLOC(a) kmalloc((a), GFP_KERNEL) -#define FREE(a) kfree(a) -#else -#include <stdlib.h> -#include <unistd.h> -#include <stdint.h> -#include <string.h> -#include <math.h> -#define MALLOC(a) malloc(a) -#define FREE(a) free(a) -#endif - -/* Features */ - -/* - * DO_BACKUP -- Backup coefficients, and revert in the presense of double talk to try to prevent - * them from diverging during the ramp-up before the DTD kicks in - */ -/* #define DO_BACKUP */ - -#define STEP_SHIFT 2 /* Convergence rate higher = slower / better (as a shift) */ - -#define SIGMA_REF_PWR 655 /* Keep denominator from being 0 */ - -#define MIN_TX_ENERGY 256 /* Must have at least this much reference */ -#define MIN_RX_ENERGY 32 /* Must have at least this much receive energy */ - -#define MAX_ATTENUATION_SHIFT 6 /* Maximum amount of loss we care about */ -#define MAX_BETA 1024 - -#define SUPPR_SHIFT 4 /* Amount of loss at which we suppress audio */ - -#define HANG_TIME 600 /* Hangover time */ - -#define NTAPS 256 /* Number of echo can taps */ - -#define BACKUP 256 /* Backup every this number of samples */ - -#define POWER_OFFSET 5 /* Shift power by this amount to be sure we don't overflow the - reference power. Higher = less likely to overflow, lower = more accurage */ - -#include "arith.h" - -typedef struct { - short buf[NTAPS * 2]; - short max; - int maxexp; -} cbuf_s; - -struct echo_can_state { - short a_s[NTAPS]; /* Coefficients in shorts */ - int a_i[NTAPS]; /* Coefficients in ints*/ -#ifdef DO_BACKUP - int b_i[NTAPS]; /* Coefficients (backup1) */ - int c_i[NTAPS]; /* Coefficients (backup2) */ -#endif - cbuf_s ref; /* Reference excitation */ - cbuf_s sig; /* Signal (echo + near end + noise) */ - cbuf_s e; /* Error */ - int refpwr; /* Reference power */ - int taps; /* Number of taps */ - int tappwr; /* Power of taps */ - int hcntr; /* Hangtime counter */ - int pos; /* Position in curcular buffers */ - int backup; /* Backup timer */ -}; - -static void echo_can_init(void) -{ - printk("Zaptel Echo Canceller: MARK3%s\n", ZAPTEL_ECHO_AGGRESSIVE); -} - -static void echo_can_identify(char *buf, size_t len) -{ - strncpy(buf, "MARK3", len); -} - -static void echo_can_shutdown(void) -{ -} - -static inline void echo_can_free(struct echo_can_state *ec) -{ - FREE(ec); -} - -static inline void buf_add(cbuf_s *b, short sample, int pos, int taps) -{ - /* Store and keep track of maxima */ - int x; - b->buf[pos] = sample; - b->buf[pos + taps] = sample; - if (sample > b->max) { - b->max = sample; - b->maxexp = taps; - } else { - b->maxexp--; - if (!b->maxexp) { - b->max = 0; - for (x=0;x<taps;x++) - if (b->max < abs(b->buf[pos + x])) { - b->max = abs(b->buf[pos + x]); - b->maxexp = x + 1; - } - } - } -} - -static inline short echo_can_update(struct echo_can_state *ec, short ref, short sig) -{ - int x; - short u; - int refpwr; - int beta; /* Factor */ - int se; /* Simulated echo */ -#ifdef DO_BACKUP - if (!ec->backup) { - /* Backup coefficients periodically */ - ec->backup = BACKUP; - memcpy(ec->c_i,ec->b_i,sizeof(ec->c_i)); - memcpy(ec->b_i,ec->a_i,sizeof(ec->b_i)); - } else - ec->backup--; -#endif - /* Remove old samples from reference power calculation */ - ec->refpwr -= ((ec->ref.buf[ec->pos] * ec->ref.buf[ec->pos]) >> POWER_OFFSET); - - /* Store signal and reference */ - buf_add(&ec->ref, ref, ec->pos, ec->taps); - buf_add(&ec->sig, sig, ec->pos, ec->taps); - - /* Add new reference power */ - ec->refpwr += ((ec->ref.buf[ec->pos] * ec->ref.buf[ec->pos]) >> POWER_OFFSET); - - - /* Calculate simulated echo */ - se = CONVOLVE2(ec->a_s, ec->ref.buf + ec->pos, ec->taps); - se >>= 15; - - u = sig - se; - if (ec->hcntr) - ec->hcntr--; - - /* Store error */ - buf_add(&ec->e, u, ec->pos, ec->taps); - if ((ec->ref.max > MIN_TX_ENERGY) && - (ec->sig.max > MIN_RX_ENERGY) && - (ec->e.max > (ec->ref.max >> MAX_ATTENUATION_SHIFT))) { - /* We have sufficient energy */ - if (ec->sig.max < (ec->ref.max >> 1)) { - /* No double talk */ - if (!ec->hcntr) { - refpwr = ec->refpwr >> (16 - POWER_OFFSET); - if (refpwr < SIGMA_REF_PWR) - refpwr = SIGMA_REF_PWR; - beta = (u << 16) / refpwr; - beta >>= STEP_SHIFT; - if (beta > MAX_BETA) - beta = MAX_BETA; - if (beta < -MAX_BETA) - beta = -MAX_BETA; - /* Update coefficients */ - for (x=0;x<ec->taps;x++) { - ec->a_i[x] += beta * ec->ref.buf[ec->pos + x]; - ec->a_s[x] = ec->a_i[x] >> 16; - } - } - } else { -#ifdef DO_BACKUP - if (!ec->hcntr) { - /* Our double talk detector is turning on for the first time. Revert - our coefficients, since we're probably well into the double talk by now */ - memcpy(ec->a_i, ec->c_i, sizeof(ec->a_i)); - for (x=0;x<ec->taps;x++) { - ec->a_s[x] = ec->a_i[x] >> 16; - } - } -#endif - /* Reset hang-time counter, and prevent backups */ - ec->hcntr = HANG_TIME; -#ifdef DO_BACKUP - ec->backup = BACKUP; -#endif - } - } -#ifndef NO_ECHO__SUPPRESSOR - if (ec->e.max < (ec->ref.max >> SUPPR_SHIFT)) { - /* Suppress residual echo */ - u *= u; - u >>= 16; - } -#endif - ec->pos--; - if (ec->pos < 0) - ec->pos = ec->taps-1; - return u; -} - -static inline struct echo_can_state *echo_can_create(int taps, int adaption_mode) -{ - struct echo_can_state *ec; - int x; - - taps = NTAPS; - ec = MALLOC(sizeof(struct echo_can_state)); - if (ec) { - memset(ec, 0, sizeof(struct echo_can_state)); - ec->taps = taps; - ec->pos = ec->taps-1; - for (x=0;x<31;x++) { - if ((1 << x) >= ec->taps) { - ec->tappwr = x; - break; - } - } - } - return ec; -} - -static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val) -{ - /* Reset hang counter to avoid adjustments after - initial forced training */ - ec->hcntr = ec->taps << 1; - if (pos >= ec->taps) - return 1; - ec->a_i[pos] = val << 17; - ec->a_s[pos] = val << 1; - if (++pos >= ec->taps) - return 1; - return 0; -} - - -#endif @@ -508,7 +508,7 @@ static inline short echo_can_update(struct echo_can_state *ec, short iref, short memset(max_coeffs, 0, USED_COEFFS*sizeof(int)); #endif #ifdef MEC2_STATS_DETAILED - printk( KERN_INFO "updating coefficients with: ec->Lu_i %9d\n", ec->Lu_i); + printk(KERN_INFO "updating coefficients with: ec->Lu_i %9d\n", ec->Lu_i); #endif #ifdef MEC2_STATS ec->avg_Lu_i_ok = ec->avg_Lu_i_ok + ec->Lu_i; @@ -550,7 +550,7 @@ static inline short echo_can_update(struct echo_can_state *ec, short iref, short #endif } else { #ifdef MEC2_STATS_DETAILED - printk( KERN_INFO "insufficient signal to update coefficients ec->Lu_i %5d < %5d\n", ec->Lu_i, MIN_UPDATE_THRESH_I); + printk(KERN_INFO "insufficient signal to update coefficients ec->Lu_i %5d < %5d\n", ec->Lu_i, MIN_UPDATE_THRESH_I); #endif #ifdef MEC2_STATS ec->avg_Lu_i_toolow = ec->avg_Lu_i_toolow + ec->Lu_i; @@ -565,7 +565,7 @@ static inline short echo_can_update(struct echo_can_state *ec, short iref, short */ #ifdef MEC2_STATS_DETAILED if (ec->HCNTR_d == 0) - printk( KERN_INFO "possibily correcting frame with ec->Ly_i %9d ec->Lu_i %9d and expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1))); + printk(KERN_INFO "possibily correcting frame with ec->Ly_i %9d ec->Lu_i %9d and expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1))); #endif #ifndef NO_ECHO_SUPPRESSOR @@ -575,7 +575,7 @@ static inline short echo_can_update(struct echo_can_state *ec, short iref, short u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1); } #ifdef MEC2_STATS_DETAILED - printk( KERN_INFO "aggresively correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1))); + printk(KERN_INFO "aggresively correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1))); #endif #ifdef MEC2_STATS ++ec->cntr_residualcorrected_frames; @@ -588,7 +588,7 @@ static inline short echo_can_update(struct echo_can_state *ec, short iref, short u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1); } #ifdef MEC2_STATS_DETAILED - printk( KERN_INFO "correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1))); + printk(KERN_INFO "correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1))); #endif #ifdef MEC2_STATS ++ec->cntr_residualcorrected_frames; @@ -628,7 +628,7 @@ static inline short echo_can_update(struct echo_can_state *ec, short iref, short else ec->avg_Lu_i_ok = -1; - printk( KERN_INFO "%d: Near end speech: %5d Residuals corrected/skipped: %5d/%5d Coefficients updated ok/low sig: %3d/%3d Lu_i avg ok/low sig %6d/%5d\n", + printk(KERN_INFO "%d: Near end speech: %5d Residuals corrected/skipped: %5d/%5d Coefficients updated ok/low sig: %3d/%3d Lu_i avg ok/low sig %6d/%5d\n", ec->id, ec->cntr_nearend_speech_frames, ec->cntr_residualcorrected_frames, ec->cntr_residualcorrected_framesskipped, @@ -650,12 +650,19 @@ static inline short echo_can_update(struct echo_can_state *ec, short iref, short return u; } -static inline struct echo_can_state *echo_can_create(int len, int adaption_mode) +static int echo_can_create(struct zt_echocanparams *ecp, struct zt_echocanparam *p, + struct echo_can_state **ec) { - struct echo_can_state *ec; int maxy; int maxu; - maxy = len + DEFAULT_M; + size_t size; + + if (ecp->param_count > 0) { + printk(KERN_WARNING "MG2 echo canceler does not support parameters; failing request\n"); + return -EINVAL; + } + + maxy = ecp->tap_length + DEFAULT_M; maxu = DEFAULT_M; if (maxy < (1 << DEFAULT_ALPHA_YT_I)) maxy = (1 << DEFAULT_ALPHA_YT_I); @@ -663,30 +670,23 @@ static inline struct echo_can_state *echo_can_create(int len, int adaption_mode) maxy = (1 << DEFAULT_SIGMA_LY_I); if (maxu < (1 << DEFAULT_SIGMA_LU_I)) maxu = (1 << DEFAULT_SIGMA_LU_I); - ec = (struct echo_can_state *)MALLOC(sizeof(struct echo_can_state) + - 4 + /* align */ - sizeof(int) * len + /* a_i */ - sizeof(short) * len + /* a_s */ - sizeof(int) * len + /* b_i */ - sizeof(int) * len + /* c_i */ - 2 * sizeof(short) * (maxy) + /* y_s */ - 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */ - 2 * sizeof(short) * (maxu) + /* u_s */ - 2 * sizeof(short) * len); /* y_tilde_s */ - if (ec) { - memset(ec, 0, sizeof(struct echo_can_state) + - 4 + /* align */ - sizeof(int) * len + /* a_i */ - sizeof(short) * len + /* a_s */ - sizeof(int) * len + /* b_i */ - sizeof(int) * len + /* c_i */ - 2 * sizeof(short) * (maxy) + /* y_s */ - 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */ - 2 * sizeof(short) * (maxu) + /* u_s */ - 2 * sizeof(short) * len); /* y_tilde_s */ - init_cc(ec, len, maxy, maxu); - } - return ec; + size = sizeof(**ec) + + 4 + /* align */ + sizeof(int) * ecp->tap_length + /* a_i */ + sizeof(short) * ecp->tap_length + /* a_s */ + sizeof(int) * ecp->tap_length + /* b_i */ + sizeof(int) * ecp->tap_length + /* c_i */ + 2 * sizeof(short) * (maxy) + /* y_s */ + 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */ + 2 * sizeof(short) * (maxu) + /* u_s */ + 2 * sizeof(short) * ecp->tap_length; /* y_tilde_s */ + + if (!(*ec = MALLOC(size))) + return -ENOMEM; + + memset(*ec, 0, size); + + return 0; } static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val) @@ -97,7 +97,6 @@ struct echo_can_state was skipped, for test purposes */ }; -static struct echo_can_state *echo_can_create(int len, int adaption_mode); static void echo_can_free(struct echo_can_state *ec); static int16_t echo_can_update(struct echo_can_state *ec, int16_t tx, int16_t rx); @@ -127,36 +126,44 @@ static void echo_can_shutdown(void) /* #define MIN_TX_POWER_FOR_ADAPTION 4096 #define MIN_RX_POWER_FOR_ADAPTION 64 */ -static inline struct echo_can_state *echo_can_create(int len, int adaption_mode) +static int echo_can_create(struct zt_echocanparams *ecp, struct zt_echocanparam *p, + struct echo_can_state **ec) { - struct echo_can_state *ec; - void *ptr; - - ptr = ec = (struct echo_can_state *) MALLOC(sizeof(*ec) + len * sizeof(int32_t) + - len * sizeof(int16_t)); - if (ec == NULL) - return NULL; - memset(ec, 0, sizeof(*ec) + len * sizeof(int32_t) + len * sizeof(int16_t)); - ec->taps = len; - ec->curr_pos = len - 1; - ec->tap_mask = len - 1; - ec->fir_taps32 = (int32_t *) (ptr + sizeof(*ec)); - ec->fir_taps16 = (int16_t *) (ptr + sizeof(*ec) + len * sizeof(int32_t)); - /* Create FIR filter */ - fir16_create(&ec->fir_state, ec->fir_taps16, ec->taps); - ec->rx_power_threshold = 10000000; - ec->use_suppressor = FALSE; - /* Non-linear processor - a fancy way to say "zap small signals, to avoid - accumulating noise". */ - ec->use_nlp = FALSE; - return ec; + size_t size; + + if (ecp->param_count > 0) { + printk(KERN_WARNING "SEC-2 echo canceler does not support parameters; failing request\n"); + return -EINVAL; + } + + size = sizeof(**ec) + ecp->tap_length * sizeof(int32_t) + ecp->tap_length * 3 * sizeof(int16_t); + + if (!(*ec = MALLOC(size))) + return -ENOMEM; + + memset(*ec, 0, size); + + (*ec)->taps = ecp->tap_length; + (*ec)->curr_pos = ecp->tap_length - 1; + (*ec)->tap_mask = ecp->tap_length - 1; + (*ec)->fir_taps32 = (int32_t *) (*ec + sizeof(**ec)); + (*ec)->fir_taps16 = (int16_t *) (*ec + sizeof(**ec) + ecp->tap_length * sizeof(int32_t)); + /* Create FIR filter */ + fir16_create(&(*ec)->fir_state, (*ec)->fir_taps16, (*ec)->taps); + (*ec)->rx_power_threshold = 10000000; + (*ec)->use_suppressor = FALSE; + /* Non-linear processor - a fancy way to say "zap small signals, to avoid + accumulating noise". */ + (*ec)->use_nlp = FALSE; + + return 0; } /*- End of function --------------------------------------------------------*/ static inline void echo_can_free(struct echo_can_state *ec) { - fir16_free(&ec->fir_state); - FREE(ec); + fir16_free(&ec->fir_state); + FREE(ec); } /*- End of function --------------------------------------------------------*/ @@ -114,7 +114,6 @@ static void echo_can_shutdown(void) { } -static struct echo_can_state *echo_can_create(int len, int adaption_mode); static void echo_can_free(struct echo_can_state *ec); static int16_t echo_can_update(struct echo_can_state *ec, int16_t tx, int16_t rx); @@ -131,33 +130,44 @@ static int16_t echo_can_update(struct echo_can_state *ec, int16_t tx, int16_t rx #define MIN_RX_POWER_FOR_ADAPTION 64 */ -static inline struct echo_can_state *echo_can_create(int len, int adaption_mode) +static int echo_can_create(struct zt_echocanparams *ecp, struct zt_echocanparam *p, + struct echo_can_state **ec) { - struct echo_can_state *ec; - void *ptr; - - ptr = ec = (struct echo_can_state *) MALLOC(sizeof(*ec) + len * sizeof(int32_t) + - len * 3 * sizeof(int16_t)); - if (ec == NULL) - return NULL; - memset(ec, 0, sizeof(*ec) + len * sizeof(int32_t) + len * 3 * sizeof(int16_t)); - ec->taps = len; - ec->tap_mask = len - 1; - ec->tx_history = (int16_t *) (ptr + sizeof(*ec) ); - ec->fir_taps = (int32_t *) (ptr + sizeof(*ec) + len * 2 * sizeof(int16_t)); - ec->fir_taps_short = (int16_t *) (ptr + sizeof(*ec) + len * sizeof(int32_t) + len * 2 * sizeof(int16_t)); - ec->rx_power_threshold = 10000000; - ec->use_suppressor = FALSE; - /* Non-linear processor - a fancy way to say "zap small signals, to avoid - accumulating noise". */ - ec->use_nlp = TRUE; - return ec; + size_t size; + + if (ecp->param_count > 0) { + printk(KERN_WARNING "SEC echo canceler does not support parameters; failing request\n"); + return -EINVAL; + } + + size = sizeof(**ec) + ecp->tap_length * sizeof(int32_t) + ecp->tap_length * 3 * sizeof(int16_t); + + if (!(*ec = MALLOC(size))) + return -ENOMEM; + + memset(*ec, 0, size); + + (*ec)->taps = ecp->tap_length; + (*ec)->tap_mask = ecp->tap_length - 1; + (*ec)->tx_history = (int16_t *) (*ec + sizeof(**ec)); + (*ec)->fir_taps = (int32_t *) (*ec + sizeof(**ec) + + ecp->tap_length * 2 * sizeof(int16_t)); + (*ec)->fir_taps_short = (int16_t *) (*ec + sizeof(**ec) + + ecp->tap_length * sizeof(int32_t) + + ecp->tap_length * 2 * sizeof(int16_t)); + (*ec)->rx_power_threshold = 10000000; + (*ec)->use_suppressor = FALSE; + /* Non-linear processor - a fancy way to say "zap small signals, to avoid + accumulating noise". */ + (*ec)->use_nlp = TRUE; + + return 0; } /*- End of function --------------------------------------------------------*/ static inline void echo_can_free(struct echo_can_state *ec) { - FREE(ec); + FREE(ec); } /*- End of function --------------------------------------------------------*/ diff --git a/zaptel-base.c b/zaptel-base.c index 309b813..e200d12 100644 --- a/zaptel-base.c +++ b/zaptel-base.c @@ -419,18 +419,12 @@ static struct zt_zone *tone_zones[ZT_TONE_ZONE_MAX]; #include "sec.h" #elif defined(ECHO_CAN_STEVE2) #include "sec-2.h" -#elif defined(ECHO_CAN_MARK) -#include "mec.h" -#elif defined(ECHO_CAN_MARK2) -#include "mec2.h" #elif defined(ECHO_CAN_KB1) #include "kb1ec.h" #elif defined(ECHO_CAN_MG2) #include "mg2ec.h" #elif defined(ECHO_CAN_JP1) #include "jpah.h" -#else -#include "mec3.h" #endif static inline void rotate_sums(void) @@ -4308,6 +4302,95 @@ static void do_ppp_calls(unsigned long data) } #endif +#define MAX_ECHOCANPARAMS 8 + +static int ioctl_echocancel(struct zt_chan *chan, struct zt_echocanparams *ecp, void *data) +{ + struct echo_can_state *ec, *tec; + struct zt_echocanparam params[MAX_ECHOCANPARAMS]; + int ret; + unsigned long flags; + + if (ecp->param_count > MAX_ECHOCANPARAMS) + return -E2BIG; + + if (ecp->tap_length == 0) { + /* disable mode, don't need to inspect params */ + spin_lock_irqsave(&chan->lock, flags); + tec = chan->ec; + chan->echocancel = 0; + chan->ec = NULL; + chan->echostate = ECHO_STATE_IDLE; + chan->echolastupdate = 0; + chan->echotimer = 0; + spin_unlock_irqrestore(&chan->lock, flags); + if (chan->span && chan->span->echocan) + chan->span->echocan(chan, 0); + if (tec) + echo_can_free(tec); + + return 0; + } + + /* if parameters were supplied and this channel's span provides an echocan, + but not one that takes params, then we must punt here and return an error */ + if (ecp->param_count && chan->span && chan->span->echocan && + !chan->span->echocan_with_params) + return -EINVAL; + + /* enable mode, need the params */ + + if (copy_from_user(params, (struct zt_echocanparam *) data, sizeof(params[0]) * ecp->param_count)) + return -EFAULT; + + spin_lock_irqsave(&chan->lock, flags); + tec = chan->ec; + chan->ec = NULL; + spin_unlock_irqrestore(&chan->lock, flags); + + ret = -ENOTTY; + + /* attempt to use the span's echo canceler; fall back to built-in + if it fails (but not if an error occurs) */ + if (chan->span && chan->span->echocan_with_params) + ret = chan->span->echocan_with_params(chan, ecp, params); + + if (ret == -ENOTTY) { + switch (ecp->tap_length) { + case 32: + case 64: + case 128: + case 256: + case 512: + case 1024: + break; + default: + ecp->tap_length = deftaps; + } + + if ((ret = echo_can_create(ecp, params, &ec))) { + if (tec) + echo_can_free(tec); + return ret; + } + + spin_lock_irqsave(&chan->lock, flags); + chan->echocancel = ecp->tap_length; + chan->ec = ec; + chan->echostate = ECHO_STATE_IDLE; + chan->echolastupdate = 0; + chan->echotimer = 0; + echo_can_disable_detector_init(&chan->txecdis); + echo_can_disable_detector_init(&chan->rxecdis); + spin_unlock_irqrestore(&chan->lock, flags); + } + + if (tec) + echo_can_free(tec); + + return 0; +} + static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit) { struct zt_chan *chan = chans[unit]; @@ -4317,6 +4400,7 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm int oldconf; void *rxgain=NULL; struct echo_can_state *ec, *tec; + struct zt_echocanparams ecp; if (!chan) return -ENOSYS; @@ -4481,62 +4565,20 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm case ZT_ECHOCANCEL: if (!(chan->flags & ZT_FLAG_AUDIO)) return -EINVAL; - get_user(j, (int *)data); - if (j) { - spin_lock_irqsave(&chan->lock, flags); - /* If we had an old echo can, zap it now */ - tec = chan->ec; - chan->ec = NULL; - /* Attempt hardware native echo can */ - spin_unlock_irqrestore(&chan->lock, flags); - - if (chan->span && chan->span->echocan) - ret = chan->span->echocan(chan, j); - else - ret = -ENOTTY; - - if (ret) { - /* Use built-in echo can */ - if ((j == 32) || - (j == 64) || - (j == 128) || - (j == 256) || - (j == 512) || - (j == 1024)) { - /* Okay */ - } else { - j = deftaps; - } - ec = echo_can_create(j, 0); - if (!ec) - return -ENOMEM; - spin_lock_irqsave(&chan->lock, flags); - chan->echocancel = j; - chan->ec = ec; - chan->echostate = ECHO_STATE_IDLE; - chan->echolastupdate = 0; - chan->echotimer = 0; - echo_can_disable_detector_init(&chan->txecdis); - echo_can_disable_detector_init(&chan->rxecdis); - spin_unlock_irqrestore(&chan->lock, flags); - } - if (tec) - echo_can_free(tec); - } else { - spin_lock_irqsave(&chan->lock, flags); - tec = chan->ec; - chan->echocancel = 0; - chan->ec = NULL; - chan->echostate = ECHO_STATE_IDLE; - chan->echolastupdate = 0; - chan->echotimer = 0; - spin_unlock_irqrestore(&chan->lock, flags); - /* Attempt hardware native echo can */ - if (chan->span && chan->span->echocan) - chan->span->echocan(chan, 0); - if (tec) - echo_can_free(tec); - } + if (copy_from_user(&ecp, (struct zt_echocanparams *) data, sizeof(ecp))) + return -EFAULT; + data += sizeof(ecp); + if ((ret = ioctl_echocancel(chan, &ecp, (void *) data))) + return ret; + break; + case ZT_ECHOCANCEL_V1: + if (!(chan->flags & ZT_FLAG_AUDIO)) + return -EINVAL; + get_user(j, (int *) data); + ecp.tap_length = j; + ecp.param_count = 0; + if ((ret = ioctl_echocancel(chan, &ecp, (void *) data))) + return ret; break; case ZT_ECHOTRAIN: get_user(j, (int *)data); /* get pre-training time from user */ @@ -560,11 +560,18 @@ struct zt_hwgain{ /* * Enable or disable echo cancellation on a channel + * + * For ECHOCANCEL_V1: * The number is zero to disable echo cancellation and non-zero * to enable echo cancellation. If the number is between 32 - * and 256, it will also set the number of taps in the echo canceller + * and 1024, it will also set the number of taps in the echo canceller + * + * For ECHOCANCEL: + * The structure contains parameters that should be passed to the + * echo canceler instance for the selected channel. */ -#define ZT_ECHOCANCEL _IOW (ZT_CODE, 33, int) +#define ZT_ECHOCANCEL_V1 _IOW (ZT_CODE, 33, int) +#define ZT_ECHOCANCEL _IOW (ZT_CODE, 33, struct zt_echocanparams) /* * Return a channel's channel number (useful for the /dev/zap/pseudo type interfaces @@ -868,6 +875,17 @@ struct zt_ring_cadence { int ringcadence[ZT_MAX_CADENCE]; }; +struct zt_echocanparam { + char name[8]; + unsigned int value; +}; + +struct zt_echocanparams { + unsigned int tap_length; /* 8 taps per millisecond */ + unsigned int param_count; /* number of parameters supplied */ + /* immediately follow this structure with zt_echocanparam structures */ +}; + struct zt_tone_def_header { int count; /* How many samples follow */ int zone; /* Which zone we are loading */ @@ -1165,7 +1183,7 @@ struct echo_can_state; void echo_can_init(void); void echo_chan_shutdown(void); void echo_can_identify(char *buf, size_t len); -struct echo_can_state *echo_can_create(int len, int adaption_mode); +int echo_can_create(struct zt_echocanparams *ecp, struct zt_echocanparam *p, struct echo_can_state **ec); void echo_can_free(struct echo_can_state *ec); short echo_can_update(struct echo_can_state *ec, short iref, short isig); void echo_can_array_update(struct echo_can_state *ec, short *iref, short *isig); @@ -1514,9 +1532,11 @@ struct zt_span { /* Opt: IOCTL */ int (*ioctl)(struct zt_chan *chan, unsigned int cmd, unsigned long data); - /* Opt: Native echo cancellation */ + /* Opt: Native echo cancellation (simple) */ int (*echocan)(struct zt_chan *chan, int ecval); + int (*echocan_with_params)(struct zt_chan *chan, struct zt_echocanparams *ecp, struct zt_echocanparam *p); + /* Okay, now we get to the signalling. You have several options: */ /* Option 1: If you're a T1 like interface, you can just provide a @@ -63,9 +63,6 @@ */ /* #define ECHO_CAN_STEVE */ /* #define ECHO_CAN_STEVE2 */ -/* #define ECHO_CAN_MARK */ -/* #define ECHO_CAN_MARK2 */ -/* #define ECHO_CAN_MARK3 */ /* #define ECHO_CAN_KB1 */ /* This is the new latest and greatest */ #define ECHO_CAN_MG2 |