blob: 191a80f1fa609a56bcc6cdde8df80e30ca1242f8 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
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
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>
26#include <pj/list.h>
27#include <pj/log.h>
28#include <pj/math.h>
29#include <pj/pool.h>
30#include "echo_internal.h"
31
32#define THIS_FILE "echo_common.c"
33
34typedef struct ec_operations ec_operations;
35
36struct frame
37{
38 PJ_DECL_LIST_MEMBER(struct frame);
39 short buf[1];
40};
41
42struct pjmedia_echo_state
43{
44 pj_pool_t *pool;
45 char *obj_name;
46 unsigned samples_per_frame;
47 void *state;
48 ec_operations *op;
49
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. */
53
54 pjmedia_delay_buf *delay_buf;
55 pj_int16_t *frm_buf;
56};
57
58
59struct ec_operations
60{
61 const char *name;
62
63 pj_status_t (*ec_create)(pj_pool_t *pool,
64 unsigned clock_rate,
65 unsigned channel_count,
66 unsigned samples_per_frame,
67 unsigned tail_ms,
68 unsigned options,
69 void **p_state );
70 pj_status_t (*ec_destroy)(void *state );
71 void (*ec_reset)(void *state );
72 pj_status_t (*ec_cancel)(void *state,
73 pj_int16_t *rec_frm,
74 const pj_int16_t *play_frm,
75 unsigned options,
76 void *reserved );
77};
78
79
80static struct ec_operations echo_supp_op =
81{
82 "Echo suppressor",
83 &echo_supp_create,
84 &echo_supp_destroy,
85 &echo_supp_reset,
86 &echo_supp_cancel_echo
87};
88
89
90
91/*
92 * Speex AEC prototypes
93 */
94#if defined(PJMEDIA_HAS_SPEEX_AEC) && PJMEDIA_HAS_SPEEX_AEC!=0
95static struct ec_operations speex_aec_op =
96{
97 "AEC",
98 &speex_aec_create,
99 &speex_aec_destroy,
100 &speex_aec_reset,
101 &speex_aec_cancel_echo
102};
103#endif
104
105
106/*
107 * IPP AEC prototypes
108 */
109#if defined(PJMEDIA_HAS_INTEL_IPP_AEC) && PJMEDIA_HAS_INTEL_IPP_AEC!=0
110static struct ec_operations ipp_aec_op =
111{
112 "IPP AEC",
113 &ipp_aec_create,
114 &ipp_aec_destroy,
115 &ipp_aec_reset,
116 &ipp_aec_cancel_echo
117};
118#endif
119
120/*
121 * Create the echo canceller.
122 */
123PJ_DEF(pj_status_t) pjmedia_echo_create( pj_pool_t *pool,
124 unsigned clock_rate,
125 unsigned samples_per_frame,
126 unsigned tail_ms,
127 unsigned latency_ms,
128 unsigned options,
129 pjmedia_echo_state **p_echo )
130{
131 return pjmedia_echo_create2(pool, clock_rate, 1, samples_per_frame,
132 tail_ms, latency_ms, options, p_echo);
133}
134
135/*
136 * Create the echo canceller.
137 */
138PJ_DEF(pj_status_t) pjmedia_echo_create2(pj_pool_t *pool,
139 unsigned clock_rate,
140 unsigned channel_count,
141 unsigned samples_per_frame,
142 unsigned tail_ms,
143 unsigned latency_ms,
144 unsigned options,
145 pjmedia_echo_state **p_echo )
146{
147 unsigned ptime, lat_cnt;
148 unsigned delay_buf_opt = 0;
149 pjmedia_echo_state *ec;
150 pj_status_t status;
151
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);
155 ec->pool = pool;
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);
161
162 /* Select the backend algorithm */
163 if (0) {
164 /* Dummy */
165 ;
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)
169 {
170 ec->op = &speex_aec_op;
171#endif
172
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)
176 {
177 ec->op = &ipp_aec_op;
178
179#endif
180
181 } else {
182 ec->op = &echo_supp_op;
183 }
184
185 PJ_LOG(5,(ec->obj_name, "Creating %s", ec->op->name));
186
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);
193 return status;
194 }
195
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);
201 }
202 if (latency_ms < ptime) {
203 /* Give at least one frame delay to simplify programming */
204 latency_ms = ptime;
205 }
206 lat_cnt = latency_ms / ptime;
207 while (lat_cnt--) {
208 struct frame *frm;
209
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);
213 }
214
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);
224 return status;
225 }
226
227 PJ_LOG(4,(ec->obj_name,
228 "%s created, clock_rate=%d, channel=%d, "
229 "samples per frame=%d, tail length=%d ms, "
230 "latency=%d ms",
231 ec->op->name, clock_rate, channel_count, samples_per_frame,
232 tail_ms, latency_ms));
233
234 /* Done */
235 *p_echo = ec;
236
237 return PJ_SUCCESS;
238}
239
240
241/*
242 * Destroy the Echo Canceller.
243 */
244PJ_DEF(pj_status_t) pjmedia_echo_destroy(pjmedia_echo_state *echo )
245{
246 (*echo->op->ec_destroy)(echo->state);
247
248 if (echo->delay_buf) {
249 pjmedia_delay_buf_destroy(echo->delay_buf);
250 echo->delay_buf = NULL;
251 }
252
253 pj_pool_release(echo->pool);
254 return PJ_SUCCESS;
255}
256
257
258/*
259 * Reset the echo canceller.
260 */
261PJ_DEF(pj_status_t) pjmedia_echo_reset(pjmedia_echo_state *echo )
262{
263 while (!pj_list_empty(&echo->lat_buf)) {
264 struct frame *frm;
265 frm = echo->lat_buf.next;
266 pj_list_erase(frm);
267 pj_list_push_back(&echo->lat_free, frm);
268 }
269 echo->lat_ready = PJ_FALSE;
270 pjmedia_delay_buf_reset(echo->delay_buf);
271 echo->op->ec_reset(echo->state);
272 return PJ_SUCCESS;
273}
274
275
276/*
277 * Let the Echo Canceller know that a frame has been played to the speaker.
278 */
279PJ_DEF(pj_status_t) pjmedia_echo_playback( pjmedia_echo_state *echo,
280 pj_int16_t *play_frm )
281{
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.
285 *
286 * Ticket #830:
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
293 * by the speaker.
294 */
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);
298
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.
302 */
303 struct frame *frm;
304
305 if (pj_list_empty(&echo->lat_free)) {
306 echo->lat_ready = PJ_TRUE;
307 PJ_LOG(5,(echo->obj_name, "Latency bufferring complete"));
308 return PJ_SUCCESS;
309 }
310
311 frm = echo->lat_free.prev;
312 pj_list_erase(frm);
313
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);
318 }
319
320 return PJ_SUCCESS;
321}
322
323
324/*
325 * Let the Echo Canceller knows that a frame has been captured from
326 * the microphone.
327 */
328PJ_DEF(pj_status_t) pjmedia_echo_capture( pjmedia_echo_state *echo,
329 pj_int16_t *rec_frm,
330 unsigned options )
331{
332 struct frame *oldest_frm;
333 pj_status_t status, rc;
334
335 if (!echo->lat_ready) {
336 /* Prefetching to fill in the desired latency */
337 PJ_LOG(5,(echo->obj_name, "Prefetching.."));
338 return PJ_SUCCESS;
339 }
340
341 /* Retrieve oldest frame from the latency buffer */
342 oldest_frm = echo->lat_buf.next;
343 pj_list_erase(oldest_frm);
344
345 /* Cancel echo using this reference frame */
346 status = pjmedia_echo_cancel(echo, rec_frm, oldest_frm->buf,
347 options, NULL);
348
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);
356 }
357 pj_list_push_back(&echo->lat_buf, oldest_frm);
358
359 return status;
360}
361
362
363/*
364 * Perform echo cancellation.
365 */
366PJ_DEF(pj_status_t) pjmedia_echo_cancel( pjmedia_echo_state *echo,
367 pj_int16_t *rec_frm,
368 const pj_int16_t *play_frm,
369 unsigned options,
370 void *reserved )
371{
372 return (*echo->op->ec_cancel)( echo->state, rec_frm, play_frm, options,
373 reserved);
374}
375