1
/* $Id: echo_common.c 3841 2011-10-24 09:28:13Z ming $ */
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
21
#include <pjmedia/echo.h>
22
#include <pjmedia/delaybuf.h>
23
#include <pjmedia/frame.h>
24
#include <pjmedia/errno.h>
25
#include <pj/assert.h>
30
#include "echo_internal.h"
32
#define THIS_FILE "echo_common.c"
34
typedef struct ec_operations ec_operations;
38
PJ_DECL_LIST_MEMBER(struct frame);
42
struct pjmedia_echo_state
46
unsigned samples_per_frame;
50
pj_bool_t lat_ready; /* lat_buf has been filled in. */
51
struct frame lat_buf; /* Frame queue for delayed playback */
52
struct frame lat_free; /* Free frame list. */
54
pjmedia_delay_buf *delay_buf;
63
pj_status_t (*ec_create)(pj_pool_t *pool,
65
unsigned channel_count,
66
unsigned samples_per_frame,
70
pj_status_t (*ec_destroy)(void *state );
71
void (*ec_reset)(void *state );
72
pj_status_t (*ec_cancel)(void *state,
74
const pj_int16_t *play_frm,
80
static struct ec_operations echo_supp_op =
86
&echo_supp_cancel_echo
92
* Speex AEC prototypes
94
#if defined(PJMEDIA_HAS_SPEEX_AEC) && PJMEDIA_HAS_SPEEX_AEC!=0
95
static struct ec_operations speex_aec_op =
101
&speex_aec_cancel_echo
109
#if defined(PJMEDIA_HAS_INTEL_IPP_AEC) && PJMEDIA_HAS_INTEL_IPP_AEC!=0
110
static struct ec_operations ipp_aec_op =
121
* Create the echo canceller.
123
PJ_DEF(pj_status_t) pjmedia_echo_create( pj_pool_t *pool,
125
unsigned samples_per_frame,
129
pjmedia_echo_state **p_echo )
131
return pjmedia_echo_create2(pool, clock_rate, 1, samples_per_frame,
132
tail_ms, latency_ms, options, p_echo);
136
* Create the echo canceller.
138
PJ_DEF(pj_status_t) pjmedia_echo_create2(pj_pool_t *pool,
140
unsigned channel_count,
141
unsigned samples_per_frame,
145
pjmedia_echo_state **p_echo )
147
unsigned ptime, lat_cnt;
148
unsigned delay_buf_opt = 0;
149
pjmedia_echo_state *ec;
152
/* Create new pool and instantiate and init the EC */
153
pool = pj_pool_create(pool->factory, "ec%p", 256, 256, NULL);
154
ec = PJ_POOL_ZALLOC_T(pool, struct pjmedia_echo_state);
156
ec->obj_name = pool->obj_name;
157
ec->samples_per_frame = samples_per_frame;
158
ec->frm_buf = (pj_int16_t*)pj_pool_alloc(pool, samples_per_frame<<1);
159
pj_list_init(&ec->lat_buf);
160
pj_list_init(&ec->lat_free);
162
/* Select the backend algorithm */
166
#if defined(PJMEDIA_HAS_SPEEX_AEC) && PJMEDIA_HAS_SPEEX_AEC!=0
167
} else if ((options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_SPEEX ||
168
(options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_DEFAULT)
170
ec->op = &speex_aec_op;
173
#if defined(PJMEDIA_HAS_INTEL_IPP_AEC) && PJMEDIA_HAS_INTEL_IPP_AEC!=0
174
} else if ((options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_IPP ||
175
(options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_DEFAULT)
177
ec->op = &ipp_aec_op;
182
ec->op = &echo_supp_op;
185
PJ_LOG(5,(ec->obj_name, "Creating %s", ec->op->name));
187
/* Instantiate EC object */
188
status = (*ec->op->ec_create)(pool, clock_rate, channel_count,
189
samples_per_frame, tail_ms,
190
options, &ec->state);
191
if (status != PJ_SUCCESS) {
192
pj_pool_release(pool);
196
/* Create latency buffers */
197
ptime = samples_per_frame * 1000 / clock_rate;
198
if (latency_ms > ptime) {
199
/* Normalize latency with delaybuf/WSOLA latency */
200
latency_ms -= PJ_MIN(ptime, PJMEDIA_WSOLA_DELAY_MSEC);
202
if (latency_ms < ptime) {
203
/* Give at least one frame delay to simplify programming */
206
lat_cnt = latency_ms / ptime;
210
frm = (struct frame*) pj_pool_alloc(pool, (samples_per_frame<<1) +
211
sizeof(struct frame));
212
pj_list_push_back(&ec->lat_free, frm);
215
/* Create delay buffer to compensate drifts */
216
if (options & PJMEDIA_ECHO_USE_SIMPLE_FIFO)
217
delay_buf_opt |= PJMEDIA_DELAY_BUF_SIMPLE_FIFO;
218
status = pjmedia_delay_buf_create(ec->pool, ec->obj_name, clock_rate,
219
samples_per_frame, channel_count,
220
(PJMEDIA_SOUND_BUFFER_COUNT+1) * ptime,
221
delay_buf_opt, &ec->delay_buf);
222
if (status != PJ_SUCCESS) {
223
pj_pool_release(pool);
227
PJ_LOG(4,(ec->obj_name,
228
"%s created, clock_rate=%d, channel=%d, "
229
"samples per frame=%d, tail length=%d ms, "
231
ec->op->name, clock_rate, channel_count, samples_per_frame,
232
tail_ms, latency_ms));
242
* Destroy the Echo Canceller.
244
PJ_DEF(pj_status_t) pjmedia_echo_destroy(pjmedia_echo_state *echo )
246
(*echo->op->ec_destroy)(echo->state);
248
if (echo->delay_buf) {
249
pjmedia_delay_buf_destroy(echo->delay_buf);
250
echo->delay_buf = NULL;
253
pj_pool_release(echo->pool);
259
* Reset the echo canceller.
261
PJ_DEF(pj_status_t) pjmedia_echo_reset(pjmedia_echo_state *echo )
263
while (!pj_list_empty(&echo->lat_buf)) {
265
frm = echo->lat_buf.next;
267
pj_list_push_back(&echo->lat_free, frm);
269
echo->lat_ready = PJ_FALSE;
270
pjmedia_delay_buf_reset(echo->delay_buf);
271
echo->op->ec_reset(echo->state);
277
* Let the Echo Canceller know that a frame has been played to the speaker.
279
PJ_DEF(pj_status_t) pjmedia_echo_playback( pjmedia_echo_state *echo,
280
pj_int16_t *play_frm )
282
/* Playing frame should be stored, as it will be used by echo_capture()
283
* as reference frame, delay buffer is used for storing the playing frames
284
* as in case there was clock drift between mic & speaker.
287
* Note that pjmedia_delay_buf_put() may modify the input frame and those
288
* modified frames may not be smooth, i.e: if there were two or more
289
* consecutive pjmedia_delay_buf_get() before next pjmedia_delay_buf_put(),
290
* so we'll just feed the delay buffer with the copy of playing frame,
291
* instead of the original playing frame. However this will cause the EC
292
* uses slight 'different' frames (for reference) than actually played
295
pjmedia_copy_samples(echo->frm_buf, play_frm,
296
echo->samples_per_frame);
297
pjmedia_delay_buf_put(echo->delay_buf, echo->frm_buf);
299
if (!echo->lat_ready) {
300
/* We've not built enough latency in the buffer, so put this frame
301
* in the latency buffer list.
305
if (pj_list_empty(&echo->lat_free)) {
306
echo->lat_ready = PJ_TRUE;
307
PJ_LOG(5,(echo->obj_name, "Latency bufferring complete"));
311
frm = echo->lat_free.prev;
314
/* Move one frame from delay buffer to the latency buffer. */
315
pjmedia_delay_buf_get(echo->delay_buf, echo->frm_buf);
316
pjmedia_copy_samples(frm->buf, echo->frm_buf, echo->samples_per_frame);
317
pj_list_push_back(&echo->lat_buf, frm);
325
* Let the Echo Canceller knows that a frame has been captured from
328
PJ_DEF(pj_status_t) pjmedia_echo_capture( pjmedia_echo_state *echo,
332
struct frame *oldest_frm;
333
pj_status_t status, rc;
335
if (!echo->lat_ready) {
336
/* Prefetching to fill in the desired latency */
337
PJ_LOG(5,(echo->obj_name, "Prefetching.."));
341
/* Retrieve oldest frame from the latency buffer */
342
oldest_frm = echo->lat_buf.next;
343
pj_list_erase(oldest_frm);
345
/* Cancel echo using this reference frame */
346
status = pjmedia_echo_cancel(echo, rec_frm, oldest_frm->buf,
349
/* Move one frame from delay buffer to the latency buffer. */
350
rc = pjmedia_delay_buf_get(echo->delay_buf, oldest_frm->buf);
351
if (rc != PJ_SUCCESS) {
352
/* Ooops.. no frame! */
353
PJ_LOG(5,(echo->obj_name,
354
"No frame from delay buffer. This will upset EC later"));
355
pjmedia_zero_samples(oldest_frm->buf, echo->samples_per_frame);
357
pj_list_push_back(&echo->lat_buf, oldest_frm);
364
* Perform echo cancellation.
366
PJ_DEF(pj_status_t) pjmedia_echo_cancel( pjmedia_echo_state *echo,
368
const pj_int16_t *play_frm,
372
return (*echo->op->ec_cancel)( echo->state, rec_frm, play_frm, options,