staging: echo: move to drivers/misc/
The code is clean, there are users of it, so it doesn't belong in staging anymore, move it to drivers/misc/. Cc: Steve Underwood <steveu@coppice.org> Cc: David Rowe <david@rowetel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
187
drivers/misc/echo/echo.h
Normal file
187
drivers/misc/echo/echo.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* echo.c - A line echo canceller. This code is being developed
|
||||
* against and partially complies with G168.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
* and David Rowe <david_at_rowetel_dot_com>
|
||||
*
|
||||
* Copyright (C) 2001 Steve Underwood and 2007 David Rowe
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ECHO_H
|
||||
#define __ECHO_H
|
||||
|
||||
/*
|
||||
Line echo cancellation for voice
|
||||
|
||||
What does it do?
|
||||
|
||||
This module aims to provide G.168-2002 compliant echo cancellation, to remove
|
||||
electrical echoes (e.g. from 2-4 wire hybrids) from voice calls.
|
||||
|
||||
How does it work?
|
||||
|
||||
The heart of the echo cancellor is FIR filter. This is adapted to match the
|
||||
echo impulse response of the telephone line. It must be long enough to
|
||||
adequately cover the duration of that impulse response. The signal transmitted
|
||||
to the telephone line is passed through the FIR filter. Once the FIR is
|
||||
properly adapted, the resulting output is an estimate of the echo signal
|
||||
received from the line. This is subtracted from the received signal. The result
|
||||
is an estimate of the signal which originated at the far end of the line, free
|
||||
from echos of our own transmitted signal.
|
||||
|
||||
The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and
|
||||
was introduced in 1960. It is the commonest form of filter adaption used in
|
||||
things like modem line equalisers and line echo cancellers. There it works very
|
||||
well. However, it only works well for signals of constant amplitude. It works
|
||||
very poorly for things like speech echo cancellation, where the signal level
|
||||
varies widely. This is quite easy to fix. If the signal level is normalised -
|
||||
similar to applying AGC - LMS can work as well for a signal of varying
|
||||
amplitude as it does for a modem signal. This normalised least mean squares
|
||||
(NLMS) algorithm is the commonest one used for speech echo cancellation. Many
|
||||
other algorithms exist - e.g. RLS (essentially the same as Kalman filtering),
|
||||
FAP, etc. Some perform significantly better than NLMS. However, factors such
|
||||
as computational complexity and patents favour the use of NLMS.
|
||||
|
||||
A simple refinement to NLMS can improve its performance with speech. NLMS tends
|
||||
to adapt best to the strongest parts of a signal. If the signal is white noise,
|
||||
the NLMS algorithm works very well. However, speech has more low frequency than
|
||||
high frequency content. Pre-whitening (i.e. filtering the signal to flatten its
|
||||
spectrum) the echo signal improves the adapt rate for speech, and ensures the
|
||||
final residual signal is not heavily biased towards high frequencies. A very
|
||||
low complexity filter is adequate for this, so pre-whitening adds little to the
|
||||
compute requirements of the echo canceller.
|
||||
|
||||
An FIR filter adapted using pre-whitened NLMS performs well, provided certain
|
||||
conditions are met:
|
||||
|
||||
- The transmitted signal has poor self-correlation.
|
||||
- There is no signal being generated within the environment being
|
||||
cancelled.
|
||||
|
||||
The difficulty is that neither of these can be guaranteed.
|
||||
|
||||
If the adaption is performed while transmitting noise (or something fairly
|
||||
noise like, such as voice) the adaption works very well. If the adaption is
|
||||
performed while transmitting something highly correlative (typically narrow
|
||||
band energy such as signalling tones or DTMF), the adaption can go seriously
|
||||
wrong. The reason is there is only one solution for the adaption on a near
|
||||
random signal - the impulse response of the line. For a repetitive signal,
|
||||
there are any number of solutions which converge the adaption, and nothing
|
||||
guides the adaption to choose the generalised one. Allowing an untrained
|
||||
canceller to converge on this kind of narrowband energy probably a good thing,
|
||||
since at least it cancels the tones. Allowing a well converged canceller to
|
||||
continue converging on such energy is just a way to ruin its generalised
|
||||
adaption. A narrowband detector is needed, so adapation can be suspended at
|
||||
appropriate times.
|
||||
|
||||
The adaption process is based on trying to eliminate the received signal. When
|
||||
there is any signal from within the environment being cancelled it may upset
|
||||
the adaption process. Similarly, if the signal we are transmitting is small,
|
||||
noise may dominate and disturb the adaption process. If we can ensure that the
|
||||
adaption is only performed when we are transmitting a significant signal level,
|
||||
and the environment is not, things will be OK. Clearly, it is easy to tell when
|
||||
we are sending a significant signal. Telling, if the environment is generating
|
||||
a significant signal, and doing it with sufficient speed that the adaption will
|
||||
not have diverged too much more we stop it, is a little harder.
|
||||
|
||||
The key problem in detecting when the environment is sourcing significant
|
||||
energy is that we must do this very quickly. Given a reasonably long sample of
|
||||
the received signal, there are a number of strategies which may be used to
|
||||
assess whether that signal contains a strong far end component. However, by the
|
||||
time that assessment is complete the far end signal will have already caused
|
||||
major mis-convergence in the adaption process. An assessment algorithm is
|
||||
needed which produces a fairly accurate result from a very short burst of far
|
||||
end energy.
|
||||
|
||||
How do I use it?
|
||||
|
||||
The echo cancellor processes both the transmit and receive streams sample by
|
||||
sample. The processing function is not declared inline. Unfortunately,
|
||||
cancellation requires many operations per sample, so the call overhead is only
|
||||
a minor burden.
|
||||
*/
|
||||
|
||||
#include "fir.h"
|
||||
#include "oslec.h"
|
||||
|
||||
/*
|
||||
G.168 echo canceller descriptor. This defines the working state for a line
|
||||
echo canceller.
|
||||
*/
|
||||
struct oslec_state {
|
||||
int16_t tx;
|
||||
int16_t rx;
|
||||
int16_t clean;
|
||||
int16_t clean_nlp;
|
||||
|
||||
int nonupdate_dwell;
|
||||
int curr_pos;
|
||||
int taps;
|
||||
int log2taps;
|
||||
int adaption_mode;
|
||||
|
||||
int cond_met;
|
||||
int32_t pstates;
|
||||
int16_t adapt;
|
||||
int32_t factor;
|
||||
int16_t shift;
|
||||
|
||||
/* Average levels and averaging filter states */
|
||||
int ltxacc;
|
||||
int lrxacc;
|
||||
int lcleanacc;
|
||||
int lclean_bgacc;
|
||||
int ltx;
|
||||
int lrx;
|
||||
int lclean;
|
||||
int lclean_bg;
|
||||
int lbgn;
|
||||
int lbgn_acc;
|
||||
int lbgn_upper;
|
||||
int lbgn_upper_acc;
|
||||
|
||||
/* foreground and background filter states */
|
||||
struct fir16_state_t fir_state;
|
||||
struct fir16_state_t fir_state_bg;
|
||||
int16_t *fir_taps16[2];
|
||||
|
||||
/* DC blocking filter states */
|
||||
int tx_1;
|
||||
int tx_2;
|
||||
int rx_1;
|
||||
int rx_2;
|
||||
|
||||
/* optional High Pass Filter states */
|
||||
int32_t xvtx[5];
|
||||
int32_t yvtx[5];
|
||||
int32_t xvrx[5];
|
||||
int32_t yvrx[5];
|
||||
|
||||
/* Parameters for the optional Hoth noise generator */
|
||||
int cng_level;
|
||||
int cng_rndnum;
|
||||
int cng_filter;
|
||||
|
||||
/* snapshot sample of coeffs used for development */
|
||||
int16_t *snapshot;
|
||||
};
|
||||
|
||||
#endif /* __ECHO_H */
|
Reference in New Issue
Block a user