~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to sflphone-common/libs/pjproject/pjmedia/src/pjmedia/echo_common.c

  • Committer: Package Import Robot
  • Author(s): Francois Marier
  • Date: 2011-11-25 13:24:12 UTC
  • mfrom: (4.1.10 sid)
  • Revision ID: package-import@ubuntu.com-20111125132412-dc4qvhyosk74cd42
Tags: 1.0.1-4
Don't assume that arch:all packages will get built (closes: #649726)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: echo_common.c 2757 2009-06-09 13:05:18Z nanang $ */
2
 
/* 
3
 
 * Copyright (C) 2008-2009 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
 
 *  Additional permission under GNU GPL version 3 section 7:
21
 
 *
22
 
 *  If you modify this program, or any covered work, by linking or
23
 
 *  combining it with the OpenSSL project's OpenSSL library (or a
24
 
 *  modified version of that library), containing parts covered by the
25
 
 *  terms of the OpenSSL or SSLeay licenses, Teluu Inc. (http://www.teluu.com)
26
 
 *  grants you additional permission to convey the resulting work.
27
 
 *  Corresponding Source for a non-source form of such a combination
28
 
 *  shall include the source code for the parts of OpenSSL used as well
29
 
 *  as that of the covered work.
30
 
 */
31
 
 
32
 
#include <pjmedia/echo.h>
33
 
#include <pjmedia/delaybuf.h>
34
 
#include <pjmedia/errno.h>
35
 
#include <pj/assert.h>
36
 
#include <pj/list.h>
37
 
#include <pj/log.h>
38
 
#include <pj/pool.h>
39
 
#include "echo_internal.h"
40
 
 
41
 
#define THIS_FILE   "echo_common.c"
42
 
 
43
 
typedef struct ec_operations ec_operations;
44
 
 
45
 
struct frame
46
 
{
47
 
    PJ_DECL_LIST_MEMBER(struct frame);
48
 
    short   buf[1];
49
 
};
50
 
 
51
 
struct pjmedia_echo_state
52
 
{
53
 
    pj_pool_t       *pool;
54
 
    char            *obj_name;
55
 
    unsigned         samples_per_frame;
56
 
    void            *state;
57
 
    ec_operations   *op;
58
 
 
59
 
    pj_bool_t        lat_ready;     /* lat_buf has been filled in.          */
60
 
    unsigned         lat_target_cnt;/* Target number of frames in lat_buf   */
61
 
    unsigned         lat_buf_cnt;   /* Actual number of frames in lat_buf   */
62
 
    struct frame     lat_buf;       /* Frame queue for delayed playback     */
63
 
    struct frame     lat_free;      /* Free frame list.                     */
64
 
 
65
 
    pjmedia_delay_buf   *delay_buf;
66
 
    pj_int16_t      *frm_buf;
67
 
};
68
 
 
69
 
 
70
 
struct ec_operations
71
 
{
72
 
    const char *name;
73
 
 
74
 
    pj_status_t (*ec_create)(pj_pool_t *pool,
75
 
                             unsigned clock_rate,
76
 
                             unsigned channel_count,
77
 
                             unsigned samples_per_frame,
78
 
                             unsigned tail_ms,
79
 
                             unsigned options,
80
 
                             void **p_state );
81
 
    pj_status_t (*ec_destroy)(void *state );
82
 
    void        (*ec_reset)(void *state );
83
 
    pj_status_t (*ec_cancel)(void *state,
84
 
                             pj_int16_t *rec_frm,
85
 
                             const pj_int16_t *play_frm,
86
 
                             unsigned options,
87
 
                             void *reserved );
88
 
};
89
 
 
90
 
 
91
 
static struct ec_operations echo_supp_op = 
92
 
{
93
 
    "Echo suppressor",
94
 
    &echo_supp_create,
95
 
    &echo_supp_destroy,
96
 
    &echo_supp_reset,
97
 
    &echo_supp_cancel_echo
98
 
};
99
 
 
100
 
 
101
 
 
102
 
/*
103
 
 * Speex AEC prototypes
104
 
 */
105
 
#if defined(PJMEDIA_HAS_SPEEX_AEC) && PJMEDIA_HAS_SPEEX_AEC!=0
106
 
static struct ec_operations speex_aec_op = 
107
 
{
108
 
    "AEC",
109
 
    &speex_aec_create,
110
 
    &speex_aec_destroy,
111
 
    &speex_aec_reset,
112
 
    &speex_aec_cancel_echo
113
 
};
114
 
#endif
115
 
 
116
 
 
117
 
/*
118
 
 * IPP AEC prototypes
119
 
 */
120
 
#if defined(PJMEDIA_HAS_INTEL_IPP_AEC) && PJMEDIA_HAS_INTEL_IPP_AEC!=0
121
 
static struct ec_operations ipp_aec_op = 
122
 
{
123
 
    "IPP AEC",
124
 
    &ipp_aec_create,
125
 
    &ipp_aec_destroy,
126
 
    &ipp_aec_reset,
127
 
    &ipp_aec_cancel_echo
128
 
};
129
 
#endif
130
 
 
131
 
/*
132
 
 * Create the echo canceller. 
133
 
 */
134
 
PJ_DEF(pj_status_t) pjmedia_echo_create( pj_pool_t *pool,
135
 
                                         unsigned clock_rate,
136
 
                                         unsigned samples_per_frame,
137
 
                                         unsigned tail_ms,
138
 
                                         unsigned latency_ms,
139
 
                                         unsigned options,
140
 
                                         pjmedia_echo_state **p_echo )
141
 
{
142
 
    return pjmedia_echo_create2(pool, clock_rate, 1, samples_per_frame,
143
 
                                tail_ms, latency_ms, options, p_echo);
144
 
}
145
 
 
146
 
/*
147
 
 * Create the echo canceller. 
148
 
 */
149
 
PJ_DEF(pj_status_t) pjmedia_echo_create2(pj_pool_t *pool,
150
 
                                         unsigned clock_rate,
151
 
                                         unsigned channel_count,
152
 
                                         unsigned samples_per_frame,
153
 
                                         unsigned tail_ms,
154
 
                                         unsigned latency_ms,
155
 
                                         unsigned options,
156
 
                                         pjmedia_echo_state **p_echo )
157
 
{
158
 
    unsigned ptime;
159
 
    pjmedia_echo_state *ec;
160
 
    pj_status_t status;
161
 
 
162
 
    /* Create new pool and instantiate and init the EC */
163
 
    pool = pj_pool_create(pool->factory, "ec%p", 256, 256, NULL);
164
 
    ec = PJ_POOL_ZALLOC_T(pool, struct pjmedia_echo_state);
165
 
    ec->pool = pool;
166
 
    ec->obj_name = pool->obj_name;
167
 
    ec->samples_per_frame = samples_per_frame;
168
 
    ec->frm_buf = (pj_int16_t*)pj_pool_alloc(pool, samples_per_frame<<1);
169
 
    pj_list_init(&ec->lat_buf);
170
 
    pj_list_init(&ec->lat_free);
171
 
 
172
 
    /* Select the backend algorithm */
173
 
    if (0) {
174
 
        /* Dummy */
175
 
        ;
176
 
#if defined(PJMEDIA_HAS_SPEEX_AEC) && PJMEDIA_HAS_SPEEX_AEC!=0
177
 
    } else if ((options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_SPEEX ||
178
 
               (options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_DEFAULT) 
179
 
    {
180
 
        ec->op = &speex_aec_op;
181
 
#endif
182
 
 
183
 
#if defined(PJMEDIA_HAS_INTEL_IPP_AEC) && PJMEDIA_HAS_INTEL_IPP_AEC!=0
184
 
    } else if ((options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_IPP ||
185
 
               (options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_DEFAULT)
186
 
    {
187
 
        ec->op = &ipp_aec_op;
188
 
 
189
 
#endif
190
 
 
191
 
    } else {
192
 
        ec->op = &echo_supp_op;
193
 
    }
194
 
 
195
 
    PJ_LOG(5,(ec->obj_name, "Creating %s", ec->op->name));
196
 
 
197
 
    /* Instantiate EC object */
198
 
    status = (*ec->op->ec_create)(pool, clock_rate, channel_count, 
199
 
                                  samples_per_frame, tail_ms, 
200
 
                                  options, &ec->state);
201
 
    if (status != PJ_SUCCESS) {
202
 
        pj_pool_release(pool);
203
 
        return status;
204
 
    }
205
 
 
206
 
    /* Create latency buffers */
207
 
    ptime = samples_per_frame * 1000 / clock_rate;
208
 
    if (latency_ms == 0) {
209
 
        /* Give at least one frame delay to simplify programming */
210
 
        latency_ms = ptime;
211
 
    }
212
 
    ec->lat_target_cnt = latency_ms / ptime;
213
 
    if (ec->lat_target_cnt != 0) {
214
 
        unsigned i;
215
 
        for (i=0; i < ec->lat_target_cnt; ++i)  {
216
 
            struct frame *frm;
217
 
 
218
 
            frm = (struct frame*) pj_pool_alloc(pool, (samples_per_frame<<1) +
219
 
                                                      sizeof(struct frame));
220
 
            pj_list_push_back(&ec->lat_free, frm);
221
 
        }
222
 
    } else {
223
 
        ec->lat_ready = PJ_TRUE;
224
 
    }
225
 
 
226
 
    /* Create delay buffer to compensate drifts */
227
 
    status = pjmedia_delay_buf_create(ec->pool, ec->obj_name, clock_rate, 
228
 
                                      samples_per_frame, channel_count,
229
 
                                      (PJMEDIA_SOUND_BUFFER_COUNT+1) * ptime,
230
 
                                      0, &ec->delay_buf);
231
 
    if (status != PJ_SUCCESS) {
232
 
        pj_pool_release(pool);
233
 
        return status;
234
 
    }
235
 
 
236
 
    PJ_LOG(4,(ec->obj_name, 
237
 
              "%s created, clock_rate=%d, channel=%d, "
238
 
              "samples per frame=%d, tail length=%d ms, "
239
 
              "latency=%d ms", 
240
 
              ec->op->name, clock_rate, channel_count, samples_per_frame,
241
 
              tail_ms, latency_ms));
242
 
 
243
 
    /* Done */
244
 
    *p_echo = ec;
245
 
 
246
 
    return PJ_SUCCESS;
247
 
}
248
 
 
249
 
 
250
 
/*
251
 
 * Destroy the Echo Canceller. 
252
 
 */
253
 
PJ_DEF(pj_status_t) pjmedia_echo_destroy(pjmedia_echo_state *echo )
254
 
{
255
 
    (*echo->op->ec_destroy)(echo->state);
256
 
 
257
 
    if (echo->delay_buf) {
258
 
        pjmedia_delay_buf_destroy(echo->delay_buf);
259
 
        echo->delay_buf = NULL;
260
 
    }
261
 
 
262
 
    pj_pool_release(echo->pool);
263
 
    return PJ_SUCCESS;
264
 
}
265
 
 
266
 
 
267
 
/*
268
 
 * Reset the echo canceller.
269
 
 */
270
 
PJ_DEF(pj_status_t) pjmedia_echo_reset(pjmedia_echo_state *echo )
271
 
{
272
 
    while (!pj_list_empty(&echo->lat_buf)) {
273
 
        struct frame *frm;
274
 
        frm = echo->lat_buf.next;
275
 
        pj_list_erase(frm);
276
 
        pj_list_push_back(&echo->lat_free, frm);
277
 
    }
278
 
    echo->lat_ready = PJ_FALSE;
279
 
    pjmedia_delay_buf_reset(echo->delay_buf);
280
 
    echo->op->ec_reset(echo->state);
281
 
    return PJ_SUCCESS;
282
 
}
283
 
 
284
 
 
285
 
/*
286
 
 * Let the Echo Canceller know that a frame has been played to the speaker.
287
 
 */
288
 
PJ_DEF(pj_status_t) pjmedia_echo_playback( pjmedia_echo_state *echo,
289
 
                                           pj_int16_t *play_frm )
290
 
{
291
 
    /* Playing frame should be stored, as it will be used by echo_capture() 
292
 
     * as reference frame, delay buffer is used for storing the playing frames
293
 
     * as in case there was clock drift between mic & speaker.
294
 
     *
295
 
     * Ticket #830:
296
 
     * Note that pjmedia_delay_buf_put() may modify the input frame and those
297
 
     * modified frames may not be smooth, i.e: if there were two or more
298
 
     * consecutive pjmedia_delay_buf_get() before next pjmedia_delay_buf_put(),
299
 
     * so we'll just feed the delay buffer with the copy of playing frame,
300
 
     * instead of the original playing frame. However this will cause the EC 
301
 
     * uses slight 'different' frames (for reference) than actually played 
302
 
     * by the speaker.
303
 
     */
304
 
    pjmedia_copy_samples(echo->frm_buf, play_frm, 
305
 
                         echo->samples_per_frame);
306
 
    pjmedia_delay_buf_put(echo->delay_buf, echo->frm_buf);
307
 
 
308
 
    if (!echo->lat_ready) {
309
 
        /* We've not built enough latency in the buffer, so put this frame
310
 
         * in the latency buffer list.
311
 
         */
312
 
        struct frame *frm;
313
 
 
314
 
        if (pj_list_empty(&echo->lat_free)) {
315
 
            echo->lat_ready = PJ_TRUE;
316
 
            PJ_LOG(5,(echo->obj_name, "Latency bufferring complete"));
317
 
            return PJ_SUCCESS;
318
 
        }
319
 
            
320
 
        frm = echo->lat_free.prev;
321
 
        pj_list_erase(frm);
322
 
 
323
 
        /* Move one frame from delay buffer to the latency buffer. */
324
 
        pjmedia_delay_buf_get(echo->delay_buf, echo->frm_buf);
325
 
        pjmedia_copy_samples(frm->buf, echo->frm_buf, echo->samples_per_frame);
326
 
        pj_list_push_back(&echo->lat_buf, frm);
327
 
    }
328
 
 
329
 
    return PJ_SUCCESS;
330
 
}
331
 
 
332
 
 
333
 
/*
334
 
 * Let the Echo Canceller knows that a frame has been captured from 
335
 
 * the microphone.
336
 
 */
337
 
PJ_DEF(pj_status_t) pjmedia_echo_capture( pjmedia_echo_state *echo,
338
 
                                          pj_int16_t *rec_frm,
339
 
                                          unsigned options )
340
 
{
341
 
    struct frame *oldest_frm;
342
 
    pj_status_t status, rc;
343
 
 
344
 
    if (!echo->lat_ready) {
345
 
        /* Prefetching to fill in the desired latency */
346
 
        PJ_LOG(5,(echo->obj_name, "Prefetching.."));
347
 
        return PJ_SUCCESS;
348
 
    }
349
 
 
350
 
    /* Retrieve oldest frame from the latency buffer */
351
 
    oldest_frm = echo->lat_buf.next;
352
 
    pj_list_erase(oldest_frm);
353
 
 
354
 
    /* Cancel echo using this reference frame */
355
 
    status = pjmedia_echo_cancel(echo, rec_frm, oldest_frm->buf, 
356
 
                                 options, NULL);
357
 
 
358
 
    /* Move one frame from delay buffer to the latency buffer. */
359
 
    rc = pjmedia_delay_buf_get(echo->delay_buf, oldest_frm->buf);
360
 
    if (rc != PJ_SUCCESS) {
361
 
        /* Ooops.. no frame! */
362
 
        PJ_LOG(5,(echo->obj_name, 
363
 
                  "No frame from delay buffer. This will upset EC later"));
364
 
        pjmedia_zero_samples(oldest_frm->buf, echo->samples_per_frame);
365
 
    }
366
 
    pj_list_push_back(&echo->lat_buf, oldest_frm);
367
 
    
368
 
    return status;
369
 
}
370
 
 
371
 
 
372
 
/*
373
 
 * Perform echo cancellation.
374
 
 */
375
 
PJ_DEF(pj_status_t) pjmedia_echo_cancel( pjmedia_echo_state *echo,
376
 
                                         pj_int16_t *rec_frm,
377
 
                                         const pj_int16_t *play_frm,
378
 
                                         unsigned options,
379
 
                                         void *reserved )
380
 
{
381
 
    return (*echo->op->ec_cancel)( echo->state, rec_frm, play_frm, options, 
382
 
                                   reserved);
383
 
}
384