1
/* $Id: echo_speex.c 3553 2011-05-05 06:14:19Z nanang $ */
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/errno.h>
23
#include <pj/assert.h>
27
#if defined(PJMEDIA_HAS_SPEEX_AEC) && PJMEDIA_HAS_SPEEX_AEC != 0
29
#include <speex/speex_echo.h>
30
#include <speex/speex_preprocess.h>
32
#include "echo_internal.h"
34
typedef struct speex_ec
36
SpeexEchoState *state;
37
SpeexPreprocessState *preprocess;
39
unsigned samples_per_frame;
42
pj_int16_t *tmp_frame;
50
PJ_DEF(pj_status_t) speex_aec_create(pj_pool_t *pool,
52
unsigned channel_count,
53
unsigned samples_per_frame,
63
echo = PJ_POOL_ZALLOC_T(pool, speex_ec);
64
PJ_ASSERT_RETURN(echo != NULL, PJ_ENOMEM);
66
echo->samples_per_frame = samples_per_frame;
67
echo->options = options;
70
echo->state = speex_echo_state_init_mc(echo->samples_per_frame,
71
clock_rate * tail_ms / 1000,
72
channel_count, channel_count);
74
if (channel_count != 1) {
75
PJ_LOG(2,("echo_speex.c", "Multichannel EC is not supported by this "
76
"echo canceller. It may not work."));
78
echo->state = speex_echo_state_init(echo->samples_per_frame,
79
clock_rate * tail_ms / 1000);
81
if (echo->state == NULL) {
85
/* Set sampling rate */
86
sampling_rate = clock_rate;
87
speex_echo_ctl(echo->state, SPEEX_ECHO_SET_SAMPLING_RATE,
90
echo->preprocess = speex_preprocess_state_init(echo->samples_per_frame,
92
if (echo->preprocess == NULL) {
93
speex_echo_state_destroy(echo->state);
97
/* Disable all preprocessing, we only want echo cancellation */
101
speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_DENOISE,
103
speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_AGC,
105
speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_VAD,
107
speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_DEREVERB,
111
/* Control echo cancellation in the preprocessor */
112
speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE,
116
/* Create temporary frame for echo cancellation */
117
echo->tmp_frame = (pj_int16_t*) pj_pool_zalloc(pool, 2*samples_per_frame);
118
PJ_ASSERT_RETURN(echo->tmp_frame != NULL, PJ_ENOMEM);
130
PJ_DEF(pj_status_t) speex_aec_destroy(void *state )
132
speex_ec *echo = (speex_ec*) state;
134
PJ_ASSERT_RETURN(echo && echo->state, PJ_EINVAL);
137
speex_echo_state_destroy(echo->state);
141
if (echo->preprocess) {
142
speex_preprocess_state_destroy(echo->preprocess);
143
echo->preprocess = NULL;
153
PJ_DEF(void) speex_aec_reset(void *state )
155
speex_ec *echo = (speex_ec*) state;
156
speex_echo_state_reset(echo->state);
161
* Perform echo cancellation.
163
PJ_DEF(pj_status_t) speex_aec_cancel_echo( void *state,
165
const pj_int16_t *play_frm,
169
speex_ec *echo = (speex_ec*) state;
172
PJ_ASSERT_RETURN(echo && rec_frm && play_frm && options==0 &&
173
reserved==NULL, PJ_EINVAL);
175
/* Cancel echo, put output in temporary buffer */
176
speex_echo_cancellation(echo->state, (const spx_int16_t*)rec_frm,
177
(const spx_int16_t*)play_frm,
178
(spx_int16_t*)echo->tmp_frame);
181
/* Preprocess output */
182
speex_preprocess_run(echo->preprocess, (spx_int16_t*)echo->tmp_frame);
184
/* Copy temporary buffer back to original rec_frm */
185
pjmedia_copy_samples(rec_frm, echo->tmp_frame, echo->samples_per_frame);