1
/* $Id: echo_suppress.c 3664 2011-07-19 03:42:28Z nanang $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
#include <pjmedia/types.h>
21
#include <pjmedia/alaw_ulaw.h>
22
#include <pjmedia/errno.h>
23
#include <pjmedia/frame.h>
24
#include <pjmedia/silencedet.h>
26
#include <pj/assert.h>
32
#include "echo_internal.h"
34
#define THIS_FILE "echo_suppress.c"
36
/* Maximum float constant */
37
#define MAX_FLOAT (float)1.701411e38
39
/* The effective learn duration (in seconds) before we declare that learning
40
* is complete. The actual learning duration itself may be longer depending
41
* on the conversation pattern (e.g. we can't detect echo if speaker is only
44
#define MAX_CALC_DURATION_SEC 3
46
/* The internal audio segment length, in milliseconds. 10ms shold be good
47
* and no need to change it.
49
#define SEGMENT_PTIME 10
51
/* The length of the template signal in milliseconds. The longer the template,
52
* the better correlation will be found, at the expense of more processing
53
* and longer learning time.
55
#define TEMPLATE_PTIME 200
57
/* How long to look back in the past to see if either mic or speaker is
60
#define SIGNAL_LOOKUP_MSEC 200
62
/* The minimum level value to be considered as talking, in uLaw complement
65
#define MIN_SIGNAL_ULAW 35
67
/* The period (in seconds) on which the ES will analize it's effectiveness,
68
* and it may trigger soft-reset to force recalculation.
70
#define CHECK_PERIOD 30
72
/* Maximum signal level of average echo residue (in uLaw complement). When
73
* the residue value exceeds this value, we force the ES to re-learn.
75
#define MAX_RESIDUE 2.5
79
# define TRACE_(expr) PJ_LOG(5,expr)
84
PJ_INLINE(float) FABS(float val)
93
#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0
94
typedef float pj_ufloat_t;
95
# define pj_ufloat_from_float(f) (f)
96
# define pj_ufloat_mul_u(val1, f) ((val1) * (f))
97
# define pj_ufloat_mul_i(val1, f) ((val1) * (f))
99
typedef pj_uint32_t pj_ufloat_t;
101
pj_ufloat_t pj_ufloat_from_float(float f)
103
return (pj_ufloat_t)(f * 65536);
106
unsigned pj_ufloat_mul_u(unsigned val1, pj_ufloat_t val2)
108
return (val1 * val2) >> 16;
111
int pj_ufloat_mul_i(int val1, pj_ufloat_t val2)
113
return (val1 * (pj_int32_t)val2) >> 16;
118
/* Conversation state */
119
typedef enum talk_state
128
const char *state_names[] =
140
The echo suppressor tries to find the position of echoed signal by looking
141
at the correlation between signal played to the speaker (played signal)
142
and the signal captured from the microphone (recorded signal).
144
To do this, it first divides the frames (from mic and speaker) into
145
segments, calculate the audio level of the segment, and save the level
146
information in the playback and record history (play_hist and rec_hist
149
In the history, the newest element (depicted as "t0" in the diagram belo)
150
is put in the last position of the array.
152
The record history size is as large as the template size (tmpl_cnt), since
153
we will use the record history as the template to find the best matching
154
position in the playback history.
156
Here is the record history buffer:
164
As you can see, the newest frame ("t0") is put as the last element in the
167
The playback history size is larger than record history, since we need to
168
find the matching pattern in the past. The playback history size is
169
"templ_cnt + tail_cnt", where "tail_cnt" is the number of segments equal
170
to the maximum tail length. The maximum tail length is set when the ES
173
Here is the playback history buffer:
175
<-----tail_cnt-----> <--templ_cnt-->
176
+-------------------+--------------+
178
+-------------------+--------------+
179
t-play_hist_cnt...t-templ_cnt.......t0
185
During the processing, the ES calculates the following values:
186
- the correlation value, that is how similar the playback signal compared
187
to the mic signal. The lower the correlation value the better (i.e. more
188
similar) the signal is. The correlation value is done over the template
190
- the gain scaling factor, that is the ratio between mic signal and
191
speaker signal. The ES calculates both the minimum and average ratios.
193
The ES calculates both the values above for every tail position in the
194
playback history. The values are saved in arrays below:
197
+-------------------+
199
+-------------------+
201
+-------------------+
203
+-------------------+
205
At the end of processing, the ES iterates through the correlation array and
206
picks the tail index with the lowest corr_sum value. This is the position
207
where echo is most likely to be found.
212
Once learning is done, the ES will change the level of the mic signal
213
depending on the state of the conversation and according to the ratio that
214
has been found in the learning phase above.
219
* The simple echo suppresor state
221
typedef struct echo_supp
223
unsigned clock_rate; /* Clock rate. */
224
pj_uint16_t samples_per_frame; /* Frame length in samples */
225
pj_uint16_t samples_per_segment;/* Segment length in samples */
226
pj_uint16_t tail_ms; /* Tail length in milliseconds */
227
pj_uint16_t tail_samples; /* Tail length in samples. */
229
pj_bool_t learning; /* Are we still learning yet? */
230
talk_state_t talk_state; /* Current talking state */
231
int tail_index; /* Echo location, -1 if not found */
233
unsigned max_calc; /* # of calc before learning complete.
234
(see MAX_CALC_DURATION_SEC) */
235
unsigned calc_cnt; /* Number of calculations so far */
237
unsigned update_cnt; /* # of updates */
238
unsigned templ_cnt; /* Template length, in # of segments */
239
unsigned tail_cnt; /* Tail length, in # of segments */
240
unsigned play_hist_cnt; /* # of segments in play_hist */
241
pj_uint16_t *play_hist; /* Array of playback levels */
242
pj_uint16_t *rec_hist; /* Array of rec levels */
244
float *corr_sum; /* Array of corr for each tail pos. */
245
float *tmp_corr; /* Temporary corr array calculation */
246
float best_corr; /* Best correlation so far. */
248
unsigned sum_rec_level; /* Running sum of level in rec_hist */
249
float rec_corr; /* Running corr in rec_hist. */
251
unsigned sum_play_level0; /* Running sum of level for first pos */
252
float play_corr0; /* Running corr for first pos . */
254
float *min_factor; /* Array of minimum scaling factor */
255
float *avg_factor; /* Array of average scaling factor */
256
float *tmp_factor; /* Array to store provisional result */
258
unsigned running_cnt; /* Running duration in # of frames */
259
float residue; /* Accummulated echo residue. */
260
float last_factor; /* Last factor applied to mic signal */
268
PJ_DEF(pj_status_t) echo_supp_create( pj_pool_t *pool,
270
unsigned channel_count,
271
unsigned samples_per_frame,
278
PJ_UNUSED_ARG(channel_count);
279
PJ_UNUSED_ARG(options);
281
PJ_ASSERT_RETURN(samples_per_frame >= SEGMENT_PTIME * clock_rate / 1000,
284
ec = PJ_POOL_ZALLOC_T(pool, struct echo_supp);
285
ec->clock_rate = clock_rate;
286
ec->samples_per_frame = (pj_uint16_t)samples_per_frame;
287
ec->samples_per_segment = (pj_uint16_t)(SEGMENT_PTIME * clock_rate / 1000);
288
ec->tail_ms = (pj_uint16_t)tail_ms;
289
ec->tail_samples = (pj_uint16_t)(tail_ms * clock_rate / 1000);
291
ec->templ_cnt = TEMPLATE_PTIME / SEGMENT_PTIME;
292
ec->tail_cnt = (pj_uint16_t)(tail_ms / SEGMENT_PTIME);
293
ec->play_hist_cnt = (pj_uint16_t)(ec->tail_cnt+ec->templ_cnt);
295
ec->max_calc = (pj_uint16_t)(MAX_CALC_DURATION_SEC * clock_rate /
296
ec->samples_per_segment);
298
ec->rec_hist = (pj_uint16_t*)
299
pj_pool_alloc(pool, ec->templ_cnt *
300
sizeof(ec->rec_hist[0]));
302
/* Note: play history has twice number of elements */
303
ec->play_hist = (pj_uint16_t*)
304
pj_pool_alloc(pool, ec->play_hist_cnt *
305
sizeof(ec->play_hist[0]));
307
ec->corr_sum = (float*)
308
pj_pool_alloc(pool, ec->tail_cnt *
309
sizeof(ec->corr_sum[0]));
310
ec->tmp_corr = (float*)
311
pj_pool_alloc(pool, ec->tail_cnt *
312
sizeof(ec->tmp_corr[0]));
313
ec->min_factor = (float*)
314
pj_pool_alloc(pool, ec->tail_cnt *
315
sizeof(ec->min_factor[0]));
316
ec->avg_factor = (float*)
317
pj_pool_alloc(pool, ec->tail_cnt *
318
sizeof(ec->avg_factor[0]));
319
ec->tmp_factor = (float*)
320
pj_pool_alloc(pool, ec->tail_cnt *
321
sizeof(ec->tmp_factor[0]));
332
PJ_DEF(pj_status_t) echo_supp_destroy(void *state)
334
PJ_UNUSED_ARG(state);
342
PJ_DEF(void) echo_supp_reset(void *state)
345
echo_supp *ec = (echo_supp*) state;
347
pj_bzero(ec->rec_hist, ec->templ_cnt * sizeof(ec->rec_hist[0]));
348
pj_bzero(ec->play_hist, ec->play_hist_cnt * sizeof(ec->play_hist[0]));
350
for (i=0; i<ec->tail_cnt; ++i) {
351
ec->corr_sum[i] = ec->avg_factor[i] = 0;
352
ec->min_factor[i] = MAX_FLOAT;
357
ec->learning = PJ_TRUE;
359
ec->best_corr = MAX_FLOAT;
360
ec->talk_state = ST_NULL;
361
ec->last_factor = 1.0;
364
ec->sum_rec_level = ec->sum_play_level0 = 0;
365
ec->rec_corr = ec->play_corr0 = 0;
369
* Soft reset to force the EC to re-learn without having to discard all
370
* rec and playback history.
372
PJ_DEF(void) echo_supp_soft_reset(void *state)
376
echo_supp *ec = (echo_supp*) state;
378
for (i=0; i<ec->tail_cnt; ++i) {
384
ec->learning = PJ_TRUE;
385
ec->best_corr = MAX_FLOAT;
388
ec->sum_rec_level = ec->sum_play_level0 = 0;
389
ec->rec_corr = ec->play_corr0 = 0;
391
PJ_LOG(4,(THIS_FILE, "Echo suppressor soft reset. Re-learning.."));
396
static void echo_supp_set_state(echo_supp *ec, talk_state_t state,
399
PJ_UNUSED_ARG(level);
401
if (state != ec->talk_state) {
402
TRACE_((THIS_FILE, "[%03d.%03d] %s --> %s, level=%u",
403
(ec->update_cnt * SEGMENT_PTIME / 1000),
404
((ec->update_cnt * SEGMENT_PTIME) % 1000),
405
state_names[ec->talk_state],
406
state_names[state], level));
407
ec->talk_state = state;
414
static void echo_supp_update(echo_supp *ec, pj_int16_t *rec_frm,
415
const pj_int16_t *play_frm)
418
unsigned i, j, frm_level, sum_play_level, ulaw;
419
pj_uint16_t old_rec_frm_level, old_play_frm_level;
423
if (ec->update_cnt > 0x7FFFFFFF)
424
ec->update_cnt = 0x7FFFFFFF; /* Detect overflow */
426
/* Calculate current play frame level */
427
frm_level = pjmedia_calc_avg_signal(play_frm, ec->samples_per_segment);
428
++frm_level; /* to avoid division by zero */
430
/* Save the oldest frame level for later */
431
old_play_frm_level = ec->play_hist[0];
433
/* Push current frame level to the back of the play history */
434
pj_array_erase(ec->play_hist, sizeof(pj_uint16_t), ec->play_hist_cnt, 0);
435
ec->play_hist[ec->play_hist_cnt-1] = (pj_uint16_t) frm_level;
437
/* Calculate level of current mic frame */
438
frm_level = pjmedia_calc_avg_signal(rec_frm, ec->samples_per_segment);
439
++frm_level; /* to avoid division by zero */
441
/* Save the oldest frame level for later */
442
old_rec_frm_level = ec->rec_hist[0];
444
/* Push to the back of the rec history */
445
pj_array_erase(ec->rec_hist, sizeof(pj_uint16_t), ec->templ_cnt, 0);
446
ec->rec_hist[ec->templ_cnt-1] = (pj_uint16_t) frm_level;
449
/* Can't do the calc until the play history is full. */
450
if (ec->update_cnt < ec->play_hist_cnt)
453
/* Skip if learning is done */
458
/* Calculate rec signal pattern */
459
if (ec->sum_rec_level == 0) {
460
/* Buffer has just been filled up, do full calculation */
462
ec->sum_rec_level = 0;
463
for (i=0; i < ec->templ_cnt-1; ++i) {
465
corr = (float)ec->rec_hist[i+1] / ec->rec_hist[i];
466
ec->rec_corr += corr;
467
ec->sum_rec_level += ec->rec_hist[i];
469
ec->sum_rec_level += ec->rec_hist[i];
471
/* Update from previous calculation */
472
ec->sum_rec_level = ec->sum_rec_level - old_rec_frm_level +
473
ec->rec_hist[ec->templ_cnt-1];
474
ec->rec_corr = ec->rec_corr - ((float)ec->rec_hist[0] /
476
((float)ec->rec_hist[ec->templ_cnt-1] /
477
ec->rec_hist[ec->templ_cnt-2]);
480
/* Iterate through the play history and calculate the signal correlation
481
* for every tail position in the play_hist. Save the result in temporary
482
* array since we may bail out early if the conversation state is not good
486
* First phase: do full calculation for the first position
488
if (ec->sum_play_level0 == 0) {
489
/* Buffer has just been filled up, do full calculation */
492
for (j=0; j<ec->templ_cnt-1; ++j) {
494
corr = (float)ec->play_hist[j+1] / ec->play_hist[j];
496
sum_play_level += ec->play_hist[j];
498
sum_play_level += ec->play_hist[j];
499
ec->sum_play_level0 = sum_play_level;
500
ec->play_corr0 = play_corr;
502
/* Update from previous calculation */
503
ec->sum_play_level0 = ec->sum_play_level0 - old_play_frm_level +
504
ec->play_hist[ec->templ_cnt-1];
505
ec->play_corr0 = ec->play_corr0 - ((float)ec->play_hist[0] /
506
old_play_frm_level) +
507
((float)ec->play_hist[ec->templ_cnt-1] /
508
ec->play_hist[ec->templ_cnt-2]);
509
sum_play_level = ec->sum_play_level0;
510
play_corr = ec->play_corr0;
512
ec->tmp_corr[0] = FABS(play_corr - ec->rec_corr);
513
ec->tmp_factor[0] = (float)ec->sum_rec_level / sum_play_level;
515
/* Bail out if remote isn't talking */
516
ulaw = pjmedia_linear2ulaw(sum_play_level/ec->templ_cnt) ^ 0xFF;
517
if (ulaw < MIN_SIGNAL_ULAW) {
518
echo_supp_set_state(ec, ST_REM_SILENT, ulaw);
521
/* Bail out if local user is talking */
522
if (ec->sum_rec_level >= sum_play_level) {
523
echo_supp_set_state(ec, ST_LOCAL_TALK, ulaw);
528
* Second phase: do incremental calculation for the rest of positions
530
for (i=1; i < ec->tail_cnt; ++i) {
533
end = i + ec->templ_cnt;
535
sum_play_level = sum_play_level - ec->play_hist[i-1] +
536
ec->play_hist[end-1];
537
play_corr = play_corr - ((float)ec->play_hist[i]/ec->play_hist[i-1]) +
538
((float)ec->play_hist[end-1]/ec->play_hist[end-2]);
540
/* Bail out if remote isn't talking */
541
ulaw = pjmedia_linear2ulaw(sum_play_level/ec->templ_cnt) ^ 0xFF;
542
if (ulaw < MIN_SIGNAL_ULAW) {
543
echo_supp_set_state(ec, ST_REM_SILENT, ulaw);
547
/* Bail out if local user is talking */
548
if (ec->sum_rec_level >= sum_play_level) {
549
echo_supp_set_state(ec, ST_LOCAL_TALK, ulaw);
554
// disabled: not a good idea if mic throws out loud echo
555
/* Also bail out if we suspect there's a doubletalk */
556
ulaw = pjmedia_linear2ulaw(ec->sum_rec_level/ec->templ_cnt) ^ 0xFF;
557
if (ulaw > MIN_SIGNAL_ULAW) {
558
echo_supp_set_state(ec, ST_DOUBLETALK, ulaw);
563
/* Calculate correlation and save to temporary array */
564
ec->tmp_corr[i] = FABS(play_corr - ec->rec_corr);
566
/* Also calculate the gain factor between mic and speaker level */
567
ec->tmp_factor[i] = (float)ec->sum_rec_level / sum_play_level;
568
pj_assert(ec->tmp_factor[i] < 1);
571
/* We seem to have good signal, we can update the EC state */
572
echo_supp_set_state(ec, ST_REM_TALK, MIN_SIGNAL_ULAW);
574
/* Accummulate the correlation value to the history and at the same
575
* time find the tail index of the best correlation.
577
prev_index = ec->tail_index;
578
for (i=1; i<ec->tail_cnt-1; ++i) {
579
float *p = &ec->corr_sum[i], sum;
581
/* Accummulate correlation value for this tail position */
582
ec->corr_sum[i] += ec->tmp_corr[i];
584
/* Update the min and avg gain factor for this tail position */
585
if (ec->tmp_factor[i] < ec->min_factor[i])
586
ec->min_factor[i] = ec->tmp_factor[i];
587
ec->avg_factor[i] = ((ec->avg_factor[i] * ec->tail_cnt) +
591
/* To get the best correlation, also include the correlation
592
* value of the neighbouring tail locations.
594
sum = *(p-1) + (*p)*2 + *(p+1);
597
/* See if we have better correlation value */
598
if (sum < ec->best_corr) {
604
if (ec->tail_index != prev_index) {
608
duration = ec->update_cnt * SEGMENT_PTIME;
609
imin = (int)(ec->min_factor[ec->tail_index] * 1000);
610
iavg = (int)(ec->avg_factor[ec->tail_index] * 1000);
613
"Echo suppressor updated at t=%03d.%03ds, echo tail=%d msec"
614
", factor min/avg=%d.%03d/%d.%03d",
615
(duration/1000), (duration%1000),
616
(ec->tail_cnt-ec->tail_index) * SEGMENT_PTIME,
617
imin/1000, imin%1000,
618
iavg/1000, iavg%1000));
624
if (ec->calc_cnt > ec->max_calc) {
629
ec->learning = PJ_FALSE;
632
duration = ec->update_cnt * SEGMENT_PTIME;
633
imin = (int)(ec->min_factor[ec->tail_index] * 1000);
634
iavg = (int)(ec->avg_factor[ec->tail_index] * 1000);
637
"Echo suppressor learning done at t=%03d.%03ds, tail=%d ms"
638
", factor min/avg=%d.%03d/%d.%03d",
639
(duration/1000), (duration%1000),
640
(ec->tail_cnt-ec->tail_index) * SEGMENT_PTIME,
641
imin/1000, imin%1000,
642
iavg/1000, iavg%1000));
649
static void amplify_frame(pj_int16_t *frm, unsigned length,
654
for (i=0; i<length; ++i) {
655
frm[i] = (pj_int16_t)pj_ufloat_mul_i(frm[i], factor);
660
* Perform echo cancellation.
662
PJ_DEF(pj_status_t) echo_supp_cancel_echo( void *state,
664
const pj_int16_t *play_frm,
669
echo_supp *ec = (echo_supp*) state;
671
PJ_UNUSED_ARG(options);
672
PJ_UNUSED_ARG(reserved);
674
/* Calculate number of segments. This should be okay even if
675
* samples_per_frame is not a multiply of samples_per_segment, since
676
* we only calculate level.
678
N = ec->samples_per_frame / ec->samples_per_segment;
680
for (i=0; i<N; ++i) {
681
unsigned pos = i * ec->samples_per_segment;
682
echo_supp_update(ec, rec_frm+pos, play_frm+pos);
685
if (ec->tail_index < 0) {
688
unsigned lookup_cnt, rec_level=0, play_level=0;
692
/* How many previous segments to lookup */
693
lookup_cnt = SIGNAL_LOOKUP_MSEC / SEGMENT_PTIME;
694
if (lookup_cnt > ec->templ_cnt)
695
lookup_cnt = ec->templ_cnt;
697
/* Lookup in recording history to get maximum mic level, to see
698
* if local user is currently talking
700
for (i=ec->templ_cnt - lookup_cnt; i < ec->templ_cnt; ++i) {
701
if (ec->rec_hist[i] > rec_level)
702
rec_level = ec->rec_hist[i];
704
rec_level = pjmedia_linear2ulaw(rec_level) ^ 0xFF;
706
/* Calculate the detected tail length, in # of segments */
707
tail_cnt = (ec->tail_cnt - ec->tail_index);
709
/* Lookup in playback history to get max speaker level, to see
710
* if remote user is currently talking
712
for (i=ec->play_hist_cnt -lookup_cnt -tail_cnt;
713
i<ec->play_hist_cnt-tail_cnt; ++i)
715
if (ec->play_hist[i] > play_level)
716
play_level = ec->play_hist[i];
718
play_level = pjmedia_linear2ulaw(play_level) ^ 0xFF;
720
if (rec_level >= MIN_SIGNAL_ULAW) {
721
if (play_level < MIN_SIGNAL_ULAW) {
722
/* Mic is talking, speaker is idle. Let mic signal pass as is.
725
echo_supp_set_state(ec, ST_LOCAL_TALK, rec_level);
726
} else if (rec_level > play_level) {
727
/* Seems that both are talking. Scale the mic signal
728
* down a little bit to reduce echo, while allowing both
729
* parties to talk at the same time.
731
factor = (float)(ec->avg_factor[ec->tail_index] * 2);
732
echo_supp_set_state(ec, ST_DOUBLETALK, rec_level);
734
/* Speaker is active, but we've picked up large signal in
735
* the microphone. Assume that this is an echo, so bring
736
* the level down to minimum too.
738
factor = ec->min_factor[ec->tail_index] / 2;
739
echo_supp_set_state(ec, ST_REM_TALK, play_level);
742
if (play_level < MIN_SIGNAL_ULAW) {
743
/* Both mic and speaker seems to be idle. Also scale the
744
* mic signal down with average factor to reduce low power
747
factor = ec->avg_factor[ec->tail_index] * 3 / 2;
748
echo_supp_set_state(ec, ST_REM_SILENT, rec_level);
750
/* Mic is idle, but there's something playing in speaker.
751
* Scale the mic down to minimum
753
factor = ec->min_factor[ec->tail_index] / 2;
754
echo_supp_set_state(ec, ST_REM_TALK, play_level);
758
/* Smoothen the transition */
759
if (factor >= ec->last_factor)
760
factor = (factor + ec->last_factor) / 2;
762
factor = (factor + ec->last_factor*19) / 20;
765
amplify_frame(rec_frm, ec->samples_per_frame,
766
pj_ufloat_from_float(factor));
767
ec->last_factor = factor;
769
if (ec->talk_state == ST_REM_TALK) {
770
unsigned level, recalc_cnt;
772
/* Get the adjusted frame signal level */
773
level = pjmedia_calc_avg_signal(rec_frm, ec->samples_per_frame);
774
level = pjmedia_linear2ulaw(level) ^ 0xFF;
776
/* Accumulate average echo residue to see the ES effectiveness */
777
ec->residue = ((ec->residue * ec->running_cnt) + level) /
778
(ec->running_cnt + 1);
782
/* Check if we need to re-learn */
783
recalc_cnt = CHECK_PERIOD * ec->clock_rate / ec->samples_per_frame;
784
if (ec->running_cnt > recalc_cnt) {
787
iresidue = (int)(ec->residue*1000);
789
PJ_LOG(5,(THIS_FILE, "Echo suppressor residue = %d.%03d",
790
iresidue/1000, iresidue%1000));
792
if (ec->residue > MAX_RESIDUE && !ec->learning) {
793
echo_supp_soft_reset(ec);