~noskcaj/ubuntu/saucy/sflphone/merge-1.2.3-2

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject/pjmedia/src/pjmedia/echo_suppress.c

  • Committer: Jackson Doak
  • Date: 2013-07-10 21:04:46 UTC
  • mfrom: (20.1.3 sid)
  • Revision ID: noskcaj@ubuntu.com-20130710210446-y8f587vza807icr9
Properly merged from upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: echo_suppress.c 3553 2011-05-05 06:14:19Z nanang $ */
2
 
/* 
3
 
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
 
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5
 
 *
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.
10
 
 *
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.
15
 
 *
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 
19
 
 */
20
 
#include <pjmedia/types.h>
21
 
#include <pjmedia/alaw_ulaw.h>
22
 
#include <pjmedia/errno.h>
23
 
#include <pjmedia/silencedet.h>
24
 
#include <pj/array.h>
25
 
#include <pj/assert.h>
26
 
#include <pj/lock.h>
27
 
#include <pj/log.h>
28
 
#include <pj/os.h>
29
 
#include <pj/pool.h>
30
 
 
31
 
#include "echo_internal.h"
32
 
 
33
 
#define THIS_FILE                           "echo_suppress.c"
34
 
 
35
 
/* Maximum float constant */
36
 
#define MAX_FLOAT               (float)1.701411e38
37
 
 
38
 
/* The effective learn duration (in seconds) before we declare that learning
39
 
 * is complete. The actual learning duration itself may be longer depending
40
 
 * on the conversation pattern (e.g. we can't detect echo if speaker is only
41
 
 * playing silence).
42
 
 */
43
 
#define MAX_CALC_DURATION_SEC   3
44
 
 
45
 
/* The internal audio segment length, in milliseconds. 10ms shold be good
46
 
 * and no need to change it.
47
 
 */
48
 
#define SEGMENT_PTIME           10
49
 
 
50
 
/* The length of the template signal in milliseconds. The longer the template,
51
 
 * the better correlation will be found, at the expense of more processing
52
 
 * and longer learning time.
53
 
 */
54
 
#define TEMPLATE_PTIME          200
55
 
 
56
 
/* How long to look back in the past to see if either mic or speaker is
57
 
 * active.
58
 
 */
59
 
#define SIGNAL_LOOKUP_MSEC      200
60
 
 
61
 
/* The minimum level value to be considered as talking, in uLaw complement
62
 
 * (0-255).
63
 
 */
64
 
#define MIN_SIGNAL_ULAW         35
65
 
 
66
 
/* The period (in seconds) on which the ES will analize it's effectiveness,
67
 
 * and it may trigger soft-reset to force recalculation.
68
 
 */
69
 
#define CHECK_PERIOD            30
70
 
 
71
 
/* Maximum signal level of average echo residue (in uLaw complement). When
72
 
 * the residue value exceeds this value, we force the ES to re-learn.
73
 
 */
74
 
#define MAX_RESIDUE             2.5
75
 
 
76
 
 
77
 
#if 0
78
 
#   define TRACE_(expr) PJ_LOG(5,expr)
79
 
#else
80
 
#   define TRACE_(expr)
81
 
#endif
82
 
 
83
 
PJ_INLINE(float) FABS(float val)
84
 
{
85
 
    if (val < 0)
86
 
        return -val;
87
 
    else
88
 
        return val;
89
 
}
90
 
 
91
 
 
92
 
#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0
93
 
    typedef float pj_ufloat_t;
94
 
#   define pj_ufloat_from_float(f)      (f)
95
 
#   define pj_ufloat_mul_u(val1, f)     ((val1) * (f))
96
 
#   define pj_ufloat_mul_i(val1, f)     ((val1) * (f))
97
 
#else
98
 
    typedef pj_uint32_t pj_ufloat_t;
99
 
 
100
 
    pj_ufloat_t pj_ufloat_from_float(float f)
101
 
    {
102
 
        return (pj_ufloat_t)(f * 65536);
103
 
    }
104
 
 
105
 
    unsigned pj_ufloat_mul_u(unsigned val1, pj_ufloat_t val2)
106
 
    {
107
 
        return (val1 * val2) >> 16;
108
 
    }
109
 
 
110
 
    int pj_ufloat_mul_i(int val1, pj_ufloat_t val2)
111
 
    {
112
 
        return (val1 * (pj_int32_t)val2) >> 16;
113
 
    }
114
 
#endif
115
 
 
116
 
 
117
 
/* Conversation state */
118
 
typedef enum talk_state
119
 
{
120
 
    ST_NULL,
121
 
    ST_LOCAL_TALK,
122
 
    ST_REM_SILENT,
123
 
    ST_DOUBLETALK,
124
 
    ST_REM_TALK
125
 
} talk_state_t;
126
 
 
127
 
const char *state_names[] = 
128
 
{
129
 
    "Null",
130
 
    "local talking",
131
 
    "remote silent",
132
 
    "doubletalk",
133
 
    "remote talking"
134
 
};
135
 
 
136
 
 
137
 
/* Description:
138
 
 
139
 
   The echo suppressor tries to find the position of echoed signal by looking
140
 
   at the correlation between signal played to the speaker (played signal) 
141
 
   and the signal captured from the microphone (recorded signal).
142
 
 
143
 
   To do this, it first divides the frames (from mic and speaker) into 
144
 
   segments, calculate the audio level of the segment, and save the level
145
 
   information in the playback and record history (play_hist and rec_hist
146
 
   respectively).
147
 
 
148
 
   In the history, the newest element (depicted as "t0" in the diagram belo)
149
 
   is put in the last position of the array.
150
 
 
151
 
   The record history size is as large as the template size (tmpl_cnt), since
152
 
   we will use the record history as the template to find the best matching 
153
 
   position in the playback history.
154
 
 
155
 
   Here is the record history buffer:
156
 
 
157
 
       <--templ_cnt-->
158
 
       +-------------+
159
 
       |   rec_hist  |
160
 
       +-------------+
161
 
    t-templ_cnt......t0
162
 
 
163
 
   As you can see, the newest frame ("t0") is put as the last element in the
164
 
   array.
165
 
 
166
 
   The playback history size is larger than record history, since we need to
167
 
   find the matching pattern in the past. The playback history size is
168
 
   "templ_cnt + tail_cnt", where "tail_cnt" is the number of segments equal
169
 
   to the maximum tail length. The maximum tail length is set when the ES
170
 
   is created.
171
 
 
172
 
   Here is the playback history buffer:
173
 
 
174
 
       <-----tail_cnt-----> <--templ_cnt-->
175
 
       +-------------------+--------------+
176
 
       |             play_hist            |
177
 
       +-------------------+--------------+
178
 
   t-play_hist_cnt...t-templ_cnt.......t0
179
 
 
180
 
 
181
 
 
182
 
   Learning:
183
 
 
184
 
   During the processing, the ES calculates the following values:
185
 
    - the correlation value, that is how similar the playback signal compared
186
 
      to the mic signal. The lower the correlation value the better (i.e. more
187
 
      similar) the signal is. The correlation value is done over the template
188
 
      duration.
189
 
    - the gain scaling factor, that is the ratio between mic signal and 
190
 
      speaker signal. The ES calculates both the minimum and average ratios.
191
 
 
192
 
   The ES calculates both the values above for every tail position in the
193
 
   playback history. The values are saved in arrays below:
194
 
 
195
 
     <-----tail_cnt----->
196
 
     +-------------------+
197
 
     |      corr_sum     |
198
 
     +-------------------+
199
 
     |     min_factor    |
200
 
     +-------------------+
201
 
     |     avg_factor    |
202
 
     +-------------------+
203
 
 
204
 
   At the end of processing, the ES iterates through the correlation array and
205
 
   picks the tail index with the lowest corr_sum value. This is the position
206
 
   where echo is most likely to be found.
207
 
 
208
 
 
209
 
   Processing:
210
 
 
211
 
   Once learning is done, the ES will change the level of the mic signal 
212
 
   depending on the state of the conversation and according to the ratio that
213
 
   has been found in the learning phase above.
214
 
 
215
 
 */
216
 
 
217
 
/*
218
 
 * The simple echo suppresor state
219
 
 */
220
 
typedef struct echo_supp
221
 
{
222
 
    unsigned     clock_rate;        /* Clock rate.                          */
223
 
    pj_uint16_t  samples_per_frame; /* Frame length in samples              */
224
 
    pj_uint16_t  samples_per_segment;/* Segment length in samples           */
225
 
    pj_uint16_t  tail_ms;           /* Tail length in milliseconds          */
226
 
    pj_uint16_t  tail_samples;      /* Tail length in samples.              */
227
 
 
228
 
    pj_bool_t    learning;          /* Are we still learning yet?           */
229
 
    talk_state_t talk_state;        /* Current talking state                */
230
 
    int          tail_index;        /* Echo location, -1 if not found       */
231
 
 
232
 
    unsigned     max_calc;          /* # of calc before learning complete.
233
 
                                       (see MAX_CALC_DURATION_SEC)          */
234
 
    unsigned     calc_cnt;          /* Number of calculations so far        */
235
 
 
236
 
    unsigned     update_cnt;        /* # of updates                         */
237
 
    unsigned     templ_cnt;         /* Template length, in # of segments    */
238
 
    unsigned     tail_cnt;          /* Tail length, in # of segments        */
239
 
    unsigned     play_hist_cnt;     /* # of segments in play_hist           */
240
 
    pj_uint16_t *play_hist;         /* Array of playback levels             */
241
 
    pj_uint16_t *rec_hist;          /* Array of rec levels                  */
242
 
 
243
 
    float       *corr_sum;          /* Array of corr for each tail pos.     */
244
 
    float       *tmp_corr;          /* Temporary corr array calculation     */
245
 
    float        best_corr;         /* Best correlation so far.             */
246
 
 
247
 
    unsigned     sum_rec_level;     /* Running sum of level in rec_hist     */
248
 
    float        rec_corr;          /* Running corr in rec_hist.            */
249
 
 
250
 
    unsigned     sum_play_level0;   /* Running sum of level for first pos   */
251
 
    float        play_corr0;        /* Running corr for first pos .         */
252
 
 
253
 
    float       *min_factor;        /* Array of minimum scaling factor      */
254
 
    float       *avg_factor;        /* Array of average scaling factor      */
255
 
    float       *tmp_factor;        /* Array to store provisional result    */
256
 
 
257
 
    unsigned     running_cnt;       /* Running duration in # of frames      */
258
 
    float        residue;           /* Accummulated echo residue.           */
259
 
    float        last_factor;       /* Last factor applied to mic signal    */
260
 
} echo_supp;
261
 
 
262
 
 
263
 
 
264
 
/*
265
 
 * Create. 
266
 
 */
267
 
PJ_DEF(pj_status_t) echo_supp_create( pj_pool_t *pool,
268
 
                                      unsigned clock_rate,
269
 
                                      unsigned channel_count,
270
 
                                      unsigned samples_per_frame,
271
 
                                      unsigned tail_ms,
272
 
                                      unsigned options,
273
 
                                      void **p_state )
274
 
{
275
 
    echo_supp *ec;
276
 
 
277
 
    PJ_UNUSED_ARG(channel_count);
278
 
    PJ_UNUSED_ARG(options);
279
 
 
280
 
    PJ_ASSERT_RETURN(samples_per_frame >= SEGMENT_PTIME * clock_rate / 1000,
281
 
                     PJ_ENOTSUP);
282
 
 
283
 
    ec = PJ_POOL_ZALLOC_T(pool, struct echo_supp);
284
 
    ec->clock_rate = clock_rate;
285
 
    ec->samples_per_frame = (pj_uint16_t)samples_per_frame;
286
 
    ec->samples_per_segment = (pj_uint16_t)(SEGMENT_PTIME * clock_rate / 1000);
287
 
    ec->tail_ms = (pj_uint16_t)tail_ms;
288
 
    ec->tail_samples = (pj_uint16_t)(tail_ms * clock_rate / 1000);
289
 
 
290
 
    ec->templ_cnt = TEMPLATE_PTIME / SEGMENT_PTIME;
291
 
    ec->tail_cnt = (pj_uint16_t)(tail_ms / SEGMENT_PTIME);
292
 
    ec->play_hist_cnt = (pj_uint16_t)(ec->tail_cnt+ec->templ_cnt);
293
 
 
294
 
    ec->max_calc = (pj_uint16_t)(MAX_CALC_DURATION_SEC * clock_rate / 
295
 
                                 ec->samples_per_segment);
296
 
 
297
 
    ec->rec_hist = (pj_uint16_t*) 
298
 
                    pj_pool_alloc(pool, ec->templ_cnt *
299
 
                                        sizeof(ec->rec_hist[0]));
300
 
 
301
 
    /* Note: play history has twice number of elements */
302
 
    ec->play_hist = (pj_uint16_t*) 
303
 
                     pj_pool_alloc(pool, ec->play_hist_cnt *
304
 
                                         sizeof(ec->play_hist[0]));
305
 
 
306
 
    ec->corr_sum = (float*)
307
 
                   pj_pool_alloc(pool, ec->tail_cnt * 
308
 
                                       sizeof(ec->corr_sum[0]));
309
 
    ec->tmp_corr = (float*)
310
 
                   pj_pool_alloc(pool, ec->tail_cnt * 
311
 
                                       sizeof(ec->tmp_corr[0]));
312
 
    ec->min_factor = (float*)
313
 
                     pj_pool_alloc(pool, ec->tail_cnt * 
314
 
                                         sizeof(ec->min_factor[0]));
315
 
    ec->avg_factor = (float*)
316
 
                     pj_pool_alloc(pool, ec->tail_cnt * 
317
 
                                         sizeof(ec->avg_factor[0]));
318
 
    ec->tmp_factor = (float*)
319
 
                     pj_pool_alloc(pool, ec->tail_cnt * 
320
 
                                         sizeof(ec->tmp_factor[0]));
321
 
    echo_supp_reset(ec);
322
 
 
323
 
    *p_state = ec;
324
 
    return PJ_SUCCESS;
325
 
}
326
 
 
327
 
 
328
 
/*
329
 
 * Destroy. 
330
 
 */
331
 
PJ_DEF(pj_status_t) echo_supp_destroy(void *state)
332
 
{
333
 
    PJ_UNUSED_ARG(state);
334
 
    return PJ_SUCCESS;
335
 
}
336
 
 
337
 
 
338
 
/*
339
 
 * Hard reset
340
 
 */
341
 
PJ_DEF(void) echo_supp_reset(void *state)
342
 
{
343
 
    unsigned i;
344
 
    echo_supp *ec = (echo_supp*) state;
345
 
 
346
 
    pj_bzero(ec->rec_hist, ec->templ_cnt * sizeof(ec->rec_hist[0]));
347
 
    pj_bzero(ec->play_hist, ec->play_hist_cnt * sizeof(ec->play_hist[0]));
348
 
 
349
 
    for (i=0; i<ec->tail_cnt; ++i) {
350
 
        ec->corr_sum[i] = ec->avg_factor[i] = 0;
351
 
        ec->min_factor[i] = MAX_FLOAT;
352
 
    }
353
 
 
354
 
    ec->update_cnt = 0;
355
 
    ec->calc_cnt = 0;
356
 
    ec->learning = PJ_TRUE;
357
 
    ec->tail_index = -1;
358
 
    ec->best_corr = MAX_FLOAT;
359
 
    ec->talk_state = ST_NULL;
360
 
    ec->last_factor = 1.0;
361
 
    ec->residue = 0;
362
 
    ec->running_cnt = 0;
363
 
    ec->sum_rec_level = ec->sum_play_level0 = 0;
364
 
    ec->rec_corr = ec->play_corr0 = 0;
365
 
}
366
 
 
367
 
/*
368
 
 * Soft reset to force the EC to re-learn without having to discard all
369
 
 * rec and playback history.
370
 
 */
371
 
PJ_DEF(void) echo_supp_soft_reset(void *state)
372
 
{
373
 
    unsigned i;
374
 
 
375
 
    echo_supp *ec = (echo_supp*) state;
376
 
 
377
 
    for (i=0; i<ec->tail_cnt; ++i) {
378
 
        ec->corr_sum[i] = 0;
379
 
    }
380
 
 
381
 
    ec->update_cnt = 0;
382
 
    ec->calc_cnt = 0;
383
 
    ec->learning = PJ_TRUE;
384
 
    ec->best_corr = MAX_FLOAT;
385
 
    ec->residue = 0;
386
 
    ec->running_cnt = 0;
387
 
    ec->sum_rec_level = ec->sum_play_level0 = 0;
388
 
    ec->rec_corr = ec->play_corr0 = 0;
389
 
 
390
 
    PJ_LOG(4,(THIS_FILE, "Echo suppressor soft reset. Re-learning.."));
391
 
}
392
 
 
393
 
 
394
 
/* Set state */
395
 
static void echo_supp_set_state(echo_supp *ec, talk_state_t state, 
396
 
                                unsigned level)
397
 
{
398
 
    PJ_UNUSED_ARG(level);
399
 
 
400
 
    if (state != ec->talk_state) {
401
 
        TRACE_((THIS_FILE, "[%03d.%03d] %s --> %s, level=%u", 
402
 
                           (ec->update_cnt * SEGMENT_PTIME / 1000), 
403
 
                           ((ec->update_cnt * SEGMENT_PTIME) % 1000),
404
 
                           state_names[ec->talk_state],
405
 
                           state_names[state], level));
406
 
        ec->talk_state = state;
407
 
    }
408
 
}
409
 
 
410
 
/*
411
 
 * Update EC state
412
 
 */
413
 
static void echo_supp_update(echo_supp *ec, pj_int16_t *rec_frm,
414
 
                             const pj_int16_t *play_frm)
415
 
{
416
 
    int prev_index;
417
 
    unsigned i, j, frm_level, sum_play_level, ulaw;
418
 
    pj_uint16_t old_rec_frm_level, old_play_frm_level;
419
 
    float play_corr;
420
 
 
421
 
    ++ec->update_cnt;
422
 
    if (ec->update_cnt > 0x7FFFFFFF)
423
 
        ec->update_cnt = 0x7FFFFFFF; /* Detect overflow */
424
 
 
425
 
    /* Calculate current play frame level */
426
 
    frm_level = pjmedia_calc_avg_signal(play_frm, ec->samples_per_segment);
427
 
    ++frm_level; /* to avoid division by zero */
428
 
 
429
 
    /* Save the oldest frame level for later */
430
 
    old_play_frm_level = ec->play_hist[0];
431
 
 
432
 
    /* Push current frame level to the back of the play history */
433
 
    pj_array_erase(ec->play_hist, sizeof(pj_uint16_t), ec->play_hist_cnt, 0);
434
 
    ec->play_hist[ec->play_hist_cnt-1] = (pj_uint16_t) frm_level;
435
 
 
436
 
    /* Calculate level of current mic frame */
437
 
    frm_level = pjmedia_calc_avg_signal(rec_frm, ec->samples_per_segment);
438
 
    ++frm_level; /* to avoid division by zero */
439
 
 
440
 
    /* Save the oldest frame level for later */
441
 
    old_rec_frm_level = ec->rec_hist[0];
442
 
 
443
 
    /* Push to the back of the rec history */
444
 
    pj_array_erase(ec->rec_hist, sizeof(pj_uint16_t), ec->templ_cnt, 0);
445
 
    ec->rec_hist[ec->templ_cnt-1] = (pj_uint16_t) frm_level;
446
 
 
447
 
 
448
 
    /* Can't do the calc until the play history is full. */
449
 
    if (ec->update_cnt < ec->play_hist_cnt)
450
 
        return;
451
 
 
452
 
    /* Skip if learning is done */
453
 
    if (!ec->learning)
454
 
        return;
455
 
 
456
 
 
457
 
    /* Calculate rec signal pattern */
458
 
    if (ec->sum_rec_level == 0) {
459
 
        /* Buffer has just been filled up, do full calculation */
460
 
        ec->rec_corr = 0;
461
 
        ec->sum_rec_level = 0;
462
 
        for (i=0; i < ec->templ_cnt-1; ++i) {
463
 
            float corr;
464
 
            corr = (float)ec->rec_hist[i+1] / ec->rec_hist[i];
465
 
            ec->rec_corr += corr;
466
 
            ec->sum_rec_level += ec->rec_hist[i];
467
 
        }
468
 
        ec->sum_rec_level += ec->rec_hist[i];
469
 
    } else {
470
 
        /* Update from previous calculation */
471
 
        ec->sum_rec_level = ec->sum_rec_level - old_rec_frm_level + 
472
 
                            ec->rec_hist[ec->templ_cnt-1];
473
 
        ec->rec_corr = ec->rec_corr - ((float)ec->rec_hist[0] / 
474
 
                                              old_rec_frm_level) +
475
 
                       ((float)ec->rec_hist[ec->templ_cnt-1] /
476
 
                               ec->rec_hist[ec->templ_cnt-2]);
477
 
    }
478
 
 
479
 
    /* Iterate through the play history and calculate the signal correlation
480
 
     * for every tail position in the play_hist. Save the result in temporary
481
 
     * array since we may bail out early if the conversation state is not good
482
 
     * to detect echo.
483
 
     */
484
 
    /* 
485
 
     * First phase: do full calculation for the first position 
486
 
     */
487
 
    if (ec->sum_play_level0 == 0) {
488
 
        /* Buffer has just been filled up, do full calculation */
489
 
        sum_play_level = 0;
490
 
        play_corr = 0;
491
 
        for (j=0; j<ec->templ_cnt-1; ++j) {
492
 
            float corr;
493
 
            corr = (float)ec->play_hist[j+1] / ec->play_hist[j];
494
 
            play_corr += corr;
495
 
            sum_play_level += ec->play_hist[j];
496
 
        }
497
 
        sum_play_level += ec->play_hist[j];
498
 
        ec->sum_play_level0 = sum_play_level;
499
 
        ec->play_corr0 = play_corr;
500
 
    } else {
501
 
        /* Update from previous calculation */
502
 
        ec->sum_play_level0 = ec->sum_play_level0 - old_play_frm_level + 
503
 
                              ec->play_hist[ec->templ_cnt-1];
504
 
        ec->play_corr0 = ec->play_corr0 - ((float)ec->play_hist[0] / 
505
 
                                                  old_play_frm_level) +
506
 
                         ((float)ec->play_hist[ec->templ_cnt-1] /
507
 
                                 ec->play_hist[ec->templ_cnt-2]);
508
 
        sum_play_level = ec->sum_play_level0;
509
 
        play_corr = ec->play_corr0;
510
 
    }
511
 
    ec->tmp_corr[0] = FABS(play_corr - ec->rec_corr);
512
 
    ec->tmp_factor[0] = (float)ec->sum_rec_level / sum_play_level;
513
 
 
514
 
    /* Bail out if remote isn't talking */
515
 
    ulaw = pjmedia_linear2ulaw(sum_play_level/ec->templ_cnt) ^ 0xFF;
516
 
    if (ulaw < MIN_SIGNAL_ULAW) {
517
 
        echo_supp_set_state(ec, ST_REM_SILENT, ulaw);
518
 
        return;
519
 
    }
520
 
    /* Bail out if local user is talking */
521
 
    if (ec->sum_rec_level >= sum_play_level) {
522
 
        echo_supp_set_state(ec, ST_LOCAL_TALK, ulaw);
523
 
        return;
524
 
    }
525
 
 
526
 
    /*
527
 
     * Second phase: do incremental calculation for the rest of positions
528
 
     */
529
 
    for (i=1; i < ec->tail_cnt; ++i) {
530
 
        unsigned end;
531
 
 
532
 
        end = i + ec->templ_cnt;
533
 
 
534
 
        sum_play_level = sum_play_level - ec->play_hist[i-1] +
535
 
                         ec->play_hist[end-1];
536
 
        play_corr = play_corr - ((float)ec->play_hist[i]/ec->play_hist[i-1]) +
537
 
                    ((float)ec->play_hist[end-1]/ec->play_hist[end-2]);
538
 
 
539
 
        /* Bail out if remote isn't talking */
540
 
        ulaw = pjmedia_linear2ulaw(sum_play_level/ec->templ_cnt) ^ 0xFF;
541
 
        if (ulaw < MIN_SIGNAL_ULAW) {
542
 
            echo_supp_set_state(ec, ST_REM_SILENT, ulaw);
543
 
            return;
544
 
        }
545
 
 
546
 
        /* Bail out if local user is talking */
547
 
        if (ec->sum_rec_level >= sum_play_level) {
548
 
            echo_supp_set_state(ec, ST_LOCAL_TALK, ulaw);
549
 
            return;
550
 
        }
551
 
 
552
 
#if 0
553
 
        // disabled: not a good idea if mic throws out loud echo
554
 
        /* Also bail out if we suspect there's a doubletalk */
555
 
        ulaw = pjmedia_linear2ulaw(ec->sum_rec_level/ec->templ_cnt) ^ 0xFF;
556
 
        if (ulaw > MIN_SIGNAL_ULAW) {
557
 
            echo_supp_set_state(ec, ST_DOUBLETALK, ulaw);
558
 
            return;
559
 
        }
560
 
#endif
561
 
 
562
 
        /* Calculate correlation and save to temporary array */
563
 
        ec->tmp_corr[i] = FABS(play_corr - ec->rec_corr);
564
 
 
565
 
        /* Also calculate the gain factor between mic and speaker level */
566
 
        ec->tmp_factor[i] = (float)ec->sum_rec_level / sum_play_level;
567
 
        pj_assert(ec->tmp_factor[i] < 1);
568
 
    }
569
 
 
570
 
    /* We seem to have good signal, we can update the EC state */
571
 
    echo_supp_set_state(ec, ST_REM_TALK, MIN_SIGNAL_ULAW);
572
 
 
573
 
    /* Accummulate the correlation value to the history and at the same
574
 
     * time find the tail index of the best correlation.
575
 
     */
576
 
    prev_index = ec->tail_index;
577
 
    for (i=1; i<ec->tail_cnt-1; ++i) {
578
 
        float *p = &ec->corr_sum[i], sum;
579
 
 
580
 
        /* Accummulate correlation value  for this tail position */
581
 
        ec->corr_sum[i] += ec->tmp_corr[i];
582
 
 
583
 
        /* Update the min and avg gain factor for this tail position */
584
 
        if (ec->tmp_factor[i] < ec->min_factor[i])
585
 
            ec->min_factor[i] = ec->tmp_factor[i];
586
 
        ec->avg_factor[i] = ((ec->avg_factor[i] * ec->tail_cnt) + 
587
 
                                    ec->tmp_factor[i]) /
588
 
                            (ec->tail_cnt + 1);
589
 
 
590
 
        /* To get the best correlation, also include the correlation
591
 
         * value of the neighbouring tail locations.
592
 
         */
593
 
        sum = *(p-1) + (*p)*2 + *(p+1);
594
 
        //sum = *p;
595
 
 
596
 
        /* See if we have better correlation value */
597
 
        if (sum < ec->best_corr) {
598
 
            ec->tail_index = i;
599
 
            ec->best_corr = sum;
600
 
        }
601
 
    }
602
 
 
603
 
    if (ec->tail_index != prev_index) {
604
 
        unsigned duration;
605
 
        int imin, iavg;
606
 
 
607
 
        duration = ec->update_cnt * SEGMENT_PTIME;
608
 
        imin = (int)(ec->min_factor[ec->tail_index] * 1000);
609
 
        iavg = (int)(ec->avg_factor[ec->tail_index] * 1000);
610
 
 
611
 
        PJ_LOG(4,(THIS_FILE, 
612
 
                  "Echo suppressor updated at t=%03d.%03ds, echo tail=%d msec"
613
 
                  ", factor min/avg=%d.%03d/%d.%03d",
614
 
                  (duration/1000), (duration%1000),
615
 
                  (ec->tail_cnt-ec->tail_index) * SEGMENT_PTIME,
616
 
                  imin/1000, imin%1000,
617
 
                  iavg/1000, iavg%1000));
618
 
 
619
 
    }
620
 
 
621
 
    ++ec->calc_cnt;
622
 
 
623
 
    if (ec->calc_cnt > ec->max_calc) {
624
 
        unsigned duration;
625
 
        int imin, iavg;
626
 
 
627
 
 
628
 
        ec->learning = PJ_FALSE;
629
 
        ec->running_cnt = 0;
630
 
 
631
 
        duration = ec->update_cnt * SEGMENT_PTIME;
632
 
        imin = (int)(ec->min_factor[ec->tail_index] * 1000);
633
 
        iavg = (int)(ec->avg_factor[ec->tail_index] * 1000);
634
 
 
635
 
        PJ_LOG(4,(THIS_FILE, 
636
 
                  "Echo suppressor learning done at t=%03d.%03ds, tail=%d ms"
637
 
                  ", factor min/avg=%d.%03d/%d.%03d",
638
 
                  (duration/1000), (duration%1000),
639
 
                  (ec->tail_cnt-ec->tail_index) * SEGMENT_PTIME,
640
 
                  imin/1000, imin%1000,
641
 
                  iavg/1000, iavg%1000));
642
 
    }
643
 
 
644
 
}
645
 
 
646
 
 
647
 
/* Amplify frame */
648
 
static void amplify_frame(pj_int16_t *frm, unsigned length, 
649
 
                          pj_ufloat_t factor)
650
 
{
651
 
    unsigned i;
652
 
 
653
 
    for (i=0; i<length; ++i) {
654
 
        frm[i] = (pj_int16_t)pj_ufloat_mul_i(frm[i], factor);
655
 
    }
656
 
}
657
 
 
658
 
/* 
659
 
 * Perform echo cancellation.
660
 
 */
661
 
PJ_DEF(pj_status_t) echo_supp_cancel_echo( void *state,
662
 
                                           pj_int16_t *rec_frm,
663
 
                                           const pj_int16_t *play_frm,
664
 
                                           unsigned options,
665
 
                                           void *reserved )
666
 
{
667
 
    unsigned i, N;
668
 
    echo_supp *ec = (echo_supp*) state;
669
 
 
670
 
    PJ_UNUSED_ARG(options);
671
 
    PJ_UNUSED_ARG(reserved);
672
 
 
673
 
    /* Calculate number of segments. This should be okay even if
674
 
     * samples_per_frame is not a multiply of samples_per_segment, since
675
 
     * we only calculate level.
676
 
     */
677
 
    N = ec->samples_per_frame / ec->samples_per_segment;
678
 
    pj_assert(N>0);
679
 
    for (i=0; i<N; ++i) {
680
 
        unsigned pos = i * ec->samples_per_segment;
681
 
        echo_supp_update(ec, rec_frm+pos, play_frm+pos);
682
 
    }
683
 
 
684
 
    if (ec->tail_index < 0) {
685
 
        /* Not ready */
686
 
    } else {
687
 
        unsigned lookup_cnt, rec_level=0, play_level=0;
688
 
        unsigned tail_cnt;
689
 
        float factor;
690
 
 
691
 
        /* How many previous segments to lookup */
692
 
        lookup_cnt = SIGNAL_LOOKUP_MSEC / SEGMENT_PTIME;
693
 
        if (lookup_cnt > ec->templ_cnt)
694
 
            lookup_cnt = ec->templ_cnt;
695
 
 
696
 
        /* Lookup in recording history to get maximum mic level, to see
697
 
         * if local user is currently talking
698
 
         */
699
 
        for (i=ec->templ_cnt - lookup_cnt; i < ec->templ_cnt; ++i) {
700
 
            if (ec->rec_hist[i] > rec_level)
701
 
                rec_level = ec->rec_hist[i];
702
 
        }
703
 
        rec_level = pjmedia_linear2ulaw(rec_level) ^ 0xFF;
704
 
 
705
 
        /* Calculate the detected tail length, in # of segments */
706
 
        tail_cnt = (ec->tail_cnt - ec->tail_index);
707
 
 
708
 
        /* Lookup in playback history to get max speaker level, to see
709
 
         * if remote user is currently talking
710
 
         */
711
 
        for (i=ec->play_hist_cnt -lookup_cnt -tail_cnt; 
712
 
             i<ec->play_hist_cnt-tail_cnt; ++i) 
713
 
        {
714
 
            if (ec->play_hist[i] > play_level)
715
 
                play_level = ec->play_hist[i];
716
 
        }
717
 
        play_level = pjmedia_linear2ulaw(play_level) ^ 0xFF;
718
 
 
719
 
        if (rec_level >= MIN_SIGNAL_ULAW) {
720
 
            if (play_level < MIN_SIGNAL_ULAW) {
721
 
                /* Mic is talking, speaker is idle. Let mic signal pass as is.
722
 
                 */
723
 
                factor = 1.0;
724
 
                echo_supp_set_state(ec, ST_LOCAL_TALK, rec_level);
725
 
            } else if (rec_level > play_level) {
726
 
                /* Seems that both are talking. Scale the mic signal
727
 
                 * down a little bit to reduce echo, while allowing both
728
 
                 * parties to talk at the same time.
729
 
                 */
730
 
                factor = (float)(ec->avg_factor[ec->tail_index] * 2);
731
 
                echo_supp_set_state(ec, ST_DOUBLETALK, rec_level);
732
 
            } else {
733
 
                /* Speaker is active, but we've picked up large signal in
734
 
                 * the microphone. Assume that this is an echo, so bring 
735
 
                 * the level down to minimum too.
736
 
                 */
737
 
                factor = ec->min_factor[ec->tail_index] / 2;
738
 
                echo_supp_set_state(ec, ST_REM_TALK, play_level);
739
 
            }
740
 
        } else {
741
 
            if (play_level < MIN_SIGNAL_ULAW) {
742
 
                /* Both mic and speaker seems to be idle. Also scale the
743
 
                 * mic signal down with average factor to reduce low power
744
 
                 * echo.
745
 
                 */
746
 
                factor = ec->avg_factor[ec->tail_index] * 3 / 2;
747
 
                echo_supp_set_state(ec, ST_REM_SILENT, rec_level);
748
 
            } else {
749
 
                /* Mic is idle, but there's something playing in speaker.
750
 
                 * Scale the mic down to minimum
751
 
                 */
752
 
                factor = ec->min_factor[ec->tail_index] / 2;
753
 
                echo_supp_set_state(ec, ST_REM_TALK, play_level);
754
 
            }
755
 
        }
756
 
 
757
 
        /* Smoothen the transition */
758
 
        if (factor >= ec->last_factor)
759
 
            factor = (factor + ec->last_factor) / 2;
760
 
        else
761
 
            factor = (factor + ec->last_factor*19) / 20;
762
 
 
763
 
        /* Amplify frame */
764
 
        amplify_frame(rec_frm, ec->samples_per_frame, 
765
 
                      pj_ufloat_from_float(factor));
766
 
        ec->last_factor = factor;
767
 
 
768
 
        if (ec->talk_state == ST_REM_TALK) {
769
 
            unsigned level, recalc_cnt;
770
 
 
771
 
            /* Get the adjusted frame signal level */
772
 
            level = pjmedia_calc_avg_signal(rec_frm, ec->samples_per_frame);
773
 
            level = pjmedia_linear2ulaw(level) ^ 0xFF;
774
 
 
775
 
            /* Accumulate average echo residue to see the ES effectiveness */
776
 
            ec->residue = ((ec->residue * ec->running_cnt) + level) / 
777
 
                          (ec->running_cnt + 1);
778
 
 
779
 
            ++ec->running_cnt;
780
 
 
781
 
            /* Check if we need to re-learn */
782
 
            recalc_cnt = CHECK_PERIOD * ec->clock_rate / ec->samples_per_frame;
783
 
            if (ec->running_cnt > recalc_cnt) {
784
 
                int iresidue;
785
 
 
786
 
                iresidue = (int)(ec->residue*1000);
787
 
 
788
 
                PJ_LOG(5,(THIS_FILE, "Echo suppressor residue = %d.%03d",
789
 
                          iresidue/1000, iresidue%1000));
790
 
 
791
 
                if (ec->residue > MAX_RESIDUE && !ec->learning) {
792
 
                    echo_supp_soft_reset(ec);
793
 
                    ec->residue = 0;
794
 
                } else {
795
 
                    ec->running_cnt = 0;
796
 
                    ec->residue = 0;
797
 
                }
798
 
            }
799
 
        }
800
 
    }
801
 
 
802
 
    return PJ_SUCCESS;
803
 
}
804