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
19 * The Original Code is Open Phone Abstraction Library.
21 * The author of this code is Damien Sandras
23 * Contributor(s): Miguel Rodriguez Perez.
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
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
57 * Revision 1.9 2005/12/30 17:13:34 dsandras
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
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.
90 #pragma implementation "echocancel.h"
93 #include <opal/buildopts.h>
97 #if OPAL_HAVE_SPEEX_SPEEX_H
98 #include <speex/speex_echo.h>
99 #include <speex/speex_preprocess.h>
101 #include <speex_echo.h>
102 #include <speex_preprocess.h>
105 #include "../src/codec/speex/libspeex/speex_echo.h"
106 #include "../src/codec/speex/libspeex/speex_preprocess.h"
110 #include <codec/echocancel.h>
112 ///////////////////////////////////////////////////////////////////////////////
114 OpalEchoCanceler::OpalEchoCanceler()
116 #pragma warning(disable:4355)
118 : receiveHandler(PCREATE_NOTIFIER(ReceivedPacket
)),
119 sendHandler(PCREATE_NOTIFIER(SentPacket
))
121 #pragma warning(default:4355)
125 preprocessState
= NULL
;
132 echo_chan
= new PQueueChannel();
133 echo_chan
->Open(10000);
134 echo_chan
->SetReadTimeout(10);
135 echo_chan
->SetWriteTimeout(10);
140 PTRACE(4, "Echo Canceler\tHandler created");
144 OpalEchoCanceler::~OpalEchoCanceler()
146 PWaitAndSignal
m(stateMutex
);
148 speex_echo_state_destroy(echoState
);
152 if (preprocessState
) {
153 speex_preprocess_state_destroy(preprocessState
);
154 preprocessState
= NULL
;
171 void OpalEchoCanceler::SetParameters(const Params
& newParam
)
173 PWaitAndSignal
m(stateMutex
);
177 speex_echo_state_destroy(echoState
);
181 if (preprocessState
) {
182 speex_preprocess_state_destroy(preprocessState
);
183 preprocessState
= NULL
;
188 void OpalEchoCanceler::SetClockRate(const int rate
)
194 void OpalEchoCanceler::SentPacket(RTP_DataFrame
& echo_frame
, INT
)
196 if (echo_frame
.GetPayloadSize() == 0)
199 if (param
.m_mode
== NoCancelation
)
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
)
212 if (input_frame
.GetPayloadSize() == 0)
215 if (param
.m_mode
== NoCancelation
)
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
);
233 #if OPAL_SPEEX_FLOAT_NOISE
234 noise
= malloc((inputSize
/sizeof(short)+1)*sizeof(float));
236 noise
= malloc((inputSize
/sizeof(short)+1)*sizeof(spx_int32_t
));
239 e_buf
= (spx_int16_t
*) malloc(inputSize
);
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
257 speex_preprocess(preprocessState
, (spx_int16_t
*)ref_buf
, NULL
);
258 memcpy(input_frame
.GetPayloadPtr(), (spx_int16_t
*)ref_buf
, input_frame
.GetPayloadSize());
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
);
267 speex_echo_cancel(echoState
, (short *)ref_buf
, (short *)echo_buf
, (short *)e_buf
, (spx_int32_t
*)noise
);
270 /* Suppress the noise */
271 #if OPAL_SPEEX_FLOAT_NOISE
272 speex_preprocess(preprocessState
, (spx_int16_t
*)e_buf
, (float *)noise
);
274 speex_preprocess(preprocessState
, (spx_int16_t
*)e_buf
, (spx_int32_t
*)noise
);
277 /* Use the result of the echo cancelation as capture frame */
278 memcpy(input_frame
.GetPayloadPtr(), e_buf
, input_frame
.GetPayloadSize());