Reviewed and adjusted PTRACE log levels
[opal.git] / src / codec / echocancel.cxx
blob7bd7d7bf5f6da45a347da97f12e94f8bf3d40245
1 /*
2 * echocancel.cxx
4 * Open Phone Abstraction Library (OPAL)
5 * Formally known as the Open H323 project.
7 * Copyright (c) 2001 Post Increment
9 * The contents of this file are subject to the Mozilla Public License
10 * Version 1.0 (the "License"); you may not use this file except in
11 * compliance with the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
14 * Software distributed under the License is distributed on an "AS IS"
15 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
16 * the License for the specific language governing rights and limitations
17 * under the License.
19 * The Original Code is Open Phone Abstraction Library.
21 * The author of this code is Damien Sandras
23 * Contributor(s): Miguel Rodriguez Perez.
25 * $Log$
26 * Revision 1.19 2007/04/04 02:12:00 rjongbloed
27 * Reviewed and adjusted PTRACE log levels
28 * Now follows 1=error,2=warn,3=info,4+=debug
30 * Revision 1.18 2006/02/04 14:27:18 dsandras
31 * Fixed leak.
33 * Revision 1.17 2006/02/01 09:00:46 csoutheren
34 * Changes to remove dependencies in Speex code accidentally introduced
36 * Revision 1.16 2006/01/31 10:28:04 csoutheren
37 * Added detection for variants to speex 1.11.11.1
39 * Revision 1.15 2006/01/31 03:28:03 csoutheren
40 * Changed to compile on MSVC 6
42 * Revision 1.14 2006/01/23 23:01:19 dsandras
43 * Protect internal speex state changes with a mutex.
45 * Revision 1.13 2006/01/21 23:33:36 csoutheren
46 * Fixed error again :)
48 * Revision 1.12 2006/01/21 23:27:06 csoutheren
49 * Fixed error under MSVC 6
51 * Revision 1.11 2006/01/07 17:37:50 dsandras
52 * Updated to speex 1.1.11.2 to fix divergeance issues.
54 * Revision 1.10 2005/12/31 09:18:44 dsandras
55 * Some fine-tuning.
57 * Revision 1.9 2005/12/30 17:13:34 dsandras
58 * Fixed typo.
60 * Revision 1.8 2005/12/30 14:33:47 dsandras
61 * Denoise the signal even when there is no echo to remove in it.
63 * Revision 1.7 2005/12/29 16:20:53 dsandras
64 * Added wideband support to the echo canceller.
66 * Revision 1.6 2005/12/28 20:03:36 dsandras
67 * Do not cancel echo when the frame is silent.
69 * Revision 1.5 2005/12/25 11:49:01 dsandras
70 * Return if Read is unsuccessful.
72 * Revision 1.4 2005/11/27 20:48:05 dsandras
73 * Changed ReadTimeout, WriteTimeout in case the remote is not sending data. Fixed compilation warning.
75 * Revision 1.3 2005/11/25 21:00:37 dsandras
76 * Remove the DC or the algorithm is puzzled. Added several post-processing filters. Added missing declaration.
78 * Revision 1.2 2005/11/24 20:34:44 dsandras
79 * Modified copyright.
81 * Revision 1.1 2005/11/24 20:31:54 dsandras
82 * Added support for echo cancelation using Speex.
83 * Added possibility to add a filter to an OpalMediaPatch for all patches of a connection.
87 #include <ptlib.h>
89 #ifdef __GNUC__
90 #pragma implementation "echocancel.h"
91 #endif
93 #include <opal/buildopts.h>
95 extern "C" {
96 #if OPAL_SYSTEM_SPEEX
97 #if OPAL_HAVE_SPEEX_SPEEX_H
98 #include <speex/speex_echo.h>
99 #include <speex/speex_preprocess.h>
100 #else
101 #include <speex_echo.h>
102 #include <speex_preprocess.h>
103 #endif
104 #else
105 #include "../src/codec/speex/libspeex/speex_echo.h"
106 #include "../src/codec/speex/libspeex/speex_preprocess.h"
107 #endif
110 #include <codec/echocancel.h>
112 ///////////////////////////////////////////////////////////////////////////////
114 OpalEchoCanceler::OpalEchoCanceler()
115 #ifdef _MSC_VER
116 #pragma warning(disable:4355)
117 #endif
118 : receiveHandler(PCREATE_NOTIFIER(ReceivedPacket)),
119 sendHandler(PCREATE_NOTIFIER(SentPacket))
120 #ifdef _MSC_VER
121 #pragma warning(default:4355)
122 #endif
124 echoState = NULL;
125 preprocessState = NULL;
127 e_buf = NULL;
128 echo_buf = NULL;
129 ref_buf = NULL;
130 noise = NULL;
132 echo_chan = new PQueueChannel();
133 echo_chan->Open(10000);
134 echo_chan->SetReadTimeout(10);
135 echo_chan->SetWriteTimeout(10);
137 mean = 0;
138 clockRate = 8000;
140 PTRACE(4, "Echo Canceler\tHandler created");
144 OpalEchoCanceler::~OpalEchoCanceler()
146 PWaitAndSignal m(stateMutex);
147 if (echoState) {
148 speex_echo_state_destroy(echoState);
149 echoState = NULL;
152 if (preprocessState) {
153 speex_preprocess_state_destroy(preprocessState);
154 preprocessState = NULL;
157 if (ref_buf)
158 free(ref_buf);
159 if (e_buf)
160 free(e_buf);
161 if (echo_buf)
162 free(echo_buf);
163 if (noise)
164 free(noise);
166 echo_chan->Close();
167 delete(echo_chan);
171 void OpalEchoCanceler::SetParameters(const Params& newParam)
173 PWaitAndSignal m(stateMutex);
174 param = newParam;
176 if (echoState) {
177 speex_echo_state_destroy(echoState);
178 echoState = NULL;
181 if (preprocessState) {
182 speex_preprocess_state_destroy(preprocessState);
183 preprocessState = NULL;
188 void OpalEchoCanceler::SetClockRate(const int rate)
190 clockRate = rate;
194 void OpalEchoCanceler::SentPacket(RTP_DataFrame& echo_frame, INT)
196 if (echo_frame.GetPayloadSize() == 0)
197 return;
199 if (param.m_mode == NoCancelation)
200 return;
202 /* Write to the soundcard, and write the frame to the PQueueChannel */
203 echo_chan->Write(echo_frame.GetPayloadPtr(), echo_frame.GetPayloadSize());
207 void OpalEchoCanceler::ReceivedPacket(RTP_DataFrame& input_frame, INT)
209 int inputSize = 0;
210 int i = 1;
212 if (input_frame.GetPayloadSize() == 0)
213 return;
215 if (param.m_mode == NoCancelation)
216 return;
218 inputSize = input_frame.GetPayloadSize(); // Size is in bytes
220 PWaitAndSignal m(stateMutex);
222 if (echoState == NULL)
223 echoState = speex_echo_state_init(inputSize/sizeof(short), 32*inputSize);
225 if (preprocessState == NULL) {
226 preprocessState = speex_preprocess_state_init(inputSize/sizeof(short), clockRate);
227 speex_preprocess_ctl(preprocessState, SPEEX_PREPROCESS_SET_DENOISE, &i);
230 if (echo_buf == NULL)
231 echo_buf = (spx_int16_t *) malloc(inputSize);
232 if (noise == NULL)
233 #if OPAL_SPEEX_FLOAT_NOISE
234 noise = malloc((inputSize/sizeof(short)+1)*sizeof(float));
235 #else
236 noise = malloc((inputSize/sizeof(short)+1)*sizeof(spx_int32_t));
237 #endif
238 if (e_buf == NULL)
239 e_buf = (spx_int16_t *) malloc(inputSize);
240 if (ref_buf == NULL)
241 ref_buf = (spx_int16_t *) malloc(inputSize);
243 /* Remove the DC offset */
244 short *j = (short *) input_frame.GetPayloadPtr();
245 for (i = 0 ; i < (int) (inputSize/sizeof(short)) ; i++) {
246 mean = 0.999*mean + 0.001*j[i];
247 ((spx_int16_t *)ref_buf)[i] = j[i] - (short) mean;
250 /* Read from the PQueueChannel a reference echo frame of the size
251 * of the captured frame. */
252 if (!echo_chan->Read((short *) echo_buf, input_frame.GetPayloadSize())) {
254 /* Nothing to read from the speaker signal, only suppress the noise
255 * and return.
257 speex_preprocess(preprocessState, (spx_int16_t *)ref_buf, NULL);
258 memcpy(input_frame.GetPayloadPtr(), (spx_int16_t *)ref_buf, input_frame.GetPayloadSize());
260 return;
263 /* Cancel the echo in this frame */
264 #if OPAL_SPEEX_FLOAT_NOISE
265 speex_echo_cancel(echoState, (short *)ref_buf, (short *)echo_buf, (short *)e_buf, (float *)noise);
266 #else
267 speex_echo_cancel(echoState, (short *)ref_buf, (short *)echo_buf, (short *)e_buf, (spx_int32_t *)noise);
268 #endif
270 /* Suppress the noise */
271 #if OPAL_SPEEX_FLOAT_NOISE
272 speex_preprocess(preprocessState, (spx_int16_t *)e_buf, (float *)noise);
273 #else
274 speex_preprocess(preprocessState, (spx_int16_t *)e_buf, (spx_int32_t *)noise);
275 #endif
277 /* Use the result of the echo cancelation as capture frame */
278 memcpy(input_frame.GetPayloadPtr(), e_buf, input_frame.GetPayloadSize());