blob: b6bacbec58f3de3e7e758a41cf45160e9f0abfce [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $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 pj_status_t (*ec_playback)(void *state,
78 pj_int16_t *play_frm );
79 pj_status_t (*ec_capture)(void *state,
80 pj_int16_t *rec_frm,
81 unsigned options );
82};
83
84
85static struct ec_operations echo_supp_op =
86{
87 "Echo suppressor",
88 &echo_supp_create,
89 &echo_supp_destroy,
90 &echo_supp_reset,
91 &echo_supp_cancel_echo
92};
93
94
95
96/*
97 * Speex AEC prototypes
98 */
99#if defined(PJMEDIA_HAS_SPEEX_AEC) && PJMEDIA_HAS_SPEEX_AEC!=0
100static struct ec_operations speex_aec_op =
101{
102 "AEC",
103 &speex_aec_create,
104 &speex_aec_destroy,
105 &speex_aec_reset,
106 &speex_aec_cancel_echo,
107 &speex_aec_playback,
108 &speex_aec_capture
109};
110#endif
111
112
113/*
114 * IPP AEC prototypes
115 */
116#if defined(PJMEDIA_HAS_INTEL_IPP_AEC) && PJMEDIA_HAS_INTEL_IPP_AEC!=0
117static struct ec_operations ipp_aec_op =
118{
119 "IPP AEC",
120 &ipp_aec_create,
121 &ipp_aec_destroy,
122 &ipp_aec_reset,
123 &ipp_aec_cancel_echo
124};
125#endif
126
127/*
128 * Create the echo canceller.
129 */
130PJ_DEF(pj_status_t) pjmedia_echo_create( pj_pool_t *pool,
131 unsigned clock_rate,
132 unsigned samples_per_frame,
133 unsigned tail_ms,
134 unsigned latency_ms,
135 unsigned options,
136 pjmedia_echo_state **p_echo )
137{
138 return pjmedia_echo_create2(pool, clock_rate, 1, samples_per_frame,
139 tail_ms, latency_ms, options, p_echo);
140}
141
142/*
143 * Create the echo canceller.
144 */
145PJ_DEF(pj_status_t) pjmedia_echo_create2(pj_pool_t *pool,
146 unsigned clock_rate,
147 unsigned channel_count,
148 unsigned samples_per_frame,
149 unsigned tail_ms,
150 unsigned latency_ms,
151 unsigned options,
152 pjmedia_echo_state **p_echo )
153{
154 unsigned ptime, lat_cnt;
155 unsigned delay_buf_opt = 0;
156 pjmedia_echo_state *ec;
157 pj_status_t status;
158
159 /* Create new pool and instantiate and init the EC */
160 pool = pj_pool_create(pool->factory, "ec%p", 256, 256, NULL);
161 ec = PJ_POOL_ZALLOC_T(pool, struct pjmedia_echo_state);
162 ec->pool = pool;
163 ec->obj_name = pool->obj_name;
164 ec->samples_per_frame = samples_per_frame;
165 ec->frm_buf = (pj_int16_t*)pj_pool_alloc(pool, samples_per_frame<<1);
166 pj_list_init(&ec->lat_buf);
167 pj_list_init(&ec->lat_free);
168
169 /* Select the backend algorithm */
170 if (0) {
171 /* Dummy */
172 ;
173#if defined(PJMEDIA_HAS_SPEEX_AEC) && PJMEDIA_HAS_SPEEX_AEC!=0
174 } else if ((options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_SPEEX ||
175 (options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_DEFAULT)
176 {
177 ec->op = &speex_aec_op;
178#endif
179
180#if defined(PJMEDIA_HAS_INTEL_IPP_AEC) && PJMEDIA_HAS_INTEL_IPP_AEC!=0
181 } else if ((options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_IPP ||
182 (options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_DEFAULT)
183 {
184 ec->op = &ipp_aec_op;
185
186#endif
187
188 } else {
189 ec->op = &echo_supp_op;
190 }
191
192 /* Completeness check for EC operation playback and capture, they must
193 * be implemented both or none.
194 */
195 pj_assert(!ec->op->ec_capture == !ec->op->ec_playback);
196
197 PJ_LOG(5,(ec->obj_name, "Creating %s", ec->op->name));
198
199 /* Instantiate EC object */
200 status = (*ec->op->ec_create)(pool, clock_rate, channel_count,
201 samples_per_frame, tail_ms,
202 options, &ec->state);
203 if (status != PJ_SUCCESS) {
204 pj_pool_release(pool);
205 return status;
206 }
207
208 /* If EC algo does not have playback and capture callbakcs,
209 * create latency buffer and delay buffer to handle drift.
210 */
211 if (ec->op->ec_playback && ec->op->ec_capture) {
212 latency_ms = 0;
213 } else {
214 /* Create latency buffers */
215 ptime = samples_per_frame * 1000 / clock_rate;
216 if (latency_ms > ptime) {
217 /* Normalize latency with delaybuf/WSOLA latency */
218 latency_ms -= PJ_MIN(ptime, PJMEDIA_WSOLA_DELAY_MSEC);
219 }
220 if (latency_ms < ptime) {
221 /* Give at least one frame delay to simplify programming */
222 latency_ms = ptime;
223 }
224 lat_cnt = latency_ms / ptime;
225 while (lat_cnt--) {
226 struct frame *frm;
227
228 frm = (struct frame*) pj_pool_alloc(pool, (samples_per_frame<<1) +
229 sizeof(struct frame));
230 pj_list_push_back(&ec->lat_free, frm);
231 }
232
233 /* Create delay buffer to compensate drifts */
234 if (options & PJMEDIA_ECHO_USE_SIMPLE_FIFO)
235 delay_buf_opt |= PJMEDIA_DELAY_BUF_SIMPLE_FIFO;
236 status = pjmedia_delay_buf_create(ec->pool, ec->obj_name, clock_rate,
237 samples_per_frame, channel_count,
238 (PJMEDIA_SOUND_BUFFER_COUNT+1) * ptime,
239 delay_buf_opt, &ec->delay_buf);
240 if (status != PJ_SUCCESS) {
241 pj_pool_release(pool);
242 return status;
243 }
244 }
245
246 PJ_LOG(4,(ec->obj_name,
247 "%s created, clock_rate=%d, channel=%d, "
248 "samples per frame=%d, tail length=%d ms, "
249 "latency=%d ms",
250 ec->op->name, clock_rate, channel_count, samples_per_frame,
251 tail_ms, latency_ms));
252
253 /* Done */
254 *p_echo = ec;
255
256 return PJ_SUCCESS;
257}
258
259
260/*
261 * Destroy the Echo Canceller.
262 */
263PJ_DEF(pj_status_t) pjmedia_echo_destroy(pjmedia_echo_state *echo )
264{
265 (*echo->op->ec_destroy)(echo->state);
266
267 if (echo->delay_buf) {
268 pjmedia_delay_buf_destroy(echo->delay_buf);
269 echo->delay_buf = NULL;
270 }
271
272 pj_pool_release(echo->pool);
273 return PJ_SUCCESS;
274}
275
276
277/*
278 * Reset the echo canceller.
279 */
280PJ_DEF(pj_status_t) pjmedia_echo_reset(pjmedia_echo_state *echo )
281{
282 while (!pj_list_empty(&echo->lat_buf)) {
283 struct frame *frm;
284 frm = echo->lat_buf.next;
285 pj_list_erase(frm);
286 pj_list_push_back(&echo->lat_free, frm);
287 }
288 echo->lat_ready = PJ_FALSE;
289 if (echo->delay_buf)
290 pjmedia_delay_buf_reset(echo->delay_buf);
291 echo->op->ec_reset(echo->state);
292 return PJ_SUCCESS;
293}
294
295
296/*
297 * Let the Echo Canceller know that a frame has been played to the speaker.
298 */
299PJ_DEF(pj_status_t) pjmedia_echo_playback( pjmedia_echo_state *echo,
300 pj_int16_t *play_frm )
301{
302 /* If EC algo has playback handler, just pass the frame. */
303 if (echo->op->ec_playback) {
304 return (*echo->op->ec_playback)(echo->state, play_frm);
305 }
306
307 /* Playing frame should be stored, as it will be used by echo_capture()
308 * as reference frame, delay buffer is used for storing the playing frames
309 * as in case there was clock drift between mic & speaker.
310 *
311 * Ticket #830:
312 * Note that pjmedia_delay_buf_put() may modify the input frame and those
313 * modified frames may not be smooth, i.e: if there were two or more
314 * consecutive pjmedia_delay_buf_get() before next pjmedia_delay_buf_put(),
315 * so we'll just feed the delay buffer with the copy of playing frame,
316 * instead of the original playing frame. However this will cause the EC
317 * uses slight 'different' frames (for reference) than actually played
318 * by the speaker.
319 */
320 pjmedia_copy_samples(echo->frm_buf, play_frm,
321 echo->samples_per_frame);
322 pjmedia_delay_buf_put(echo->delay_buf, echo->frm_buf);
323
324 if (!echo->lat_ready) {
325 /* We've not built enough latency in the buffer, so put this frame
326 * in the latency buffer list.
327 */
328 struct frame *frm;
329
330 if (pj_list_empty(&echo->lat_free)) {
331 echo->lat_ready = PJ_TRUE;
332 PJ_LOG(5,(echo->obj_name, "Latency bufferring complete"));
333 return PJ_SUCCESS;
334 }
335
336 frm = echo->lat_free.prev;
337 pj_list_erase(frm);
338
339 /* Move one frame from delay buffer to the latency buffer. */
340 pjmedia_delay_buf_get(echo->delay_buf, echo->frm_buf);
341 pjmedia_copy_samples(frm->buf, echo->frm_buf, echo->samples_per_frame);
342 pj_list_push_back(&echo->lat_buf, frm);
343 }
344
345 return PJ_SUCCESS;
346}
347
348
349/*
350 * Let the Echo Canceller knows that a frame has been captured from
351 * the microphone.
352 */
353PJ_DEF(pj_status_t) pjmedia_echo_capture( pjmedia_echo_state *echo,
354 pj_int16_t *rec_frm,
355 unsigned options )
356{
357 struct frame *oldest_frm;
358 pj_status_t status, rc;
359
360 /* If EC algo has capture handler, just pass the frame. */
361 if (echo->op->ec_capture) {
362 return (*echo->op->ec_capture)(echo->state, rec_frm, options);
363 }
364
365 if (!echo->lat_ready) {
366 /* Prefetching to fill in the desired latency */
367 PJ_LOG(5,(echo->obj_name, "Prefetching.."));
368 return PJ_SUCCESS;
369 }
370
371 /* Retrieve oldest frame from the latency buffer */
372 oldest_frm = echo->lat_buf.next;
373 pj_list_erase(oldest_frm);
374
375 /* Cancel echo using this reference frame */
376 status = pjmedia_echo_cancel(echo, rec_frm, oldest_frm->buf,
377 options, NULL);
378
379 /* Move one frame from delay buffer to the latency buffer. */
380 rc = pjmedia_delay_buf_get(echo->delay_buf, oldest_frm->buf);
381 if (rc != PJ_SUCCESS) {
382 /* Ooops.. no frame! */
383 PJ_LOG(5,(echo->obj_name,
384 "No frame from delay buffer. This will upset EC later"));
385 pjmedia_zero_samples(oldest_frm->buf, echo->samples_per_frame);
386 }
387 pj_list_push_back(&echo->lat_buf, oldest_frm);
388
389 return status;
390}
391
392
393/*
394 * Perform echo cancellation.
395 */
396PJ_DEF(pj_status_t) pjmedia_echo_cancel( pjmedia_echo_state *echo,
397 pj_int16_t *rec_frm,
398 const pj_int16_t *play_frm,
399 unsigned options,
400 void *reserved )
401{
402 return (*echo->op->ec_cancel)( echo->state, rec_frm, play_frm, options,
403 reserved);
404}
405