diff --git a/sflphone-common/libs/pjproject/pjmedia/src/pjmedia/delaybuf.c b/sflphone-common/libs/pjproject/pjmedia/src/pjmedia/delaybuf.c
index 667bcdbe9ab90d1c58e124604711772a994a79af..3f26b76b7dbb5e613f204aaf6301bc0058a25b47 100644
--- a/sflphone-common/libs/pjproject/pjmedia/src/pjmedia/delaybuf.c
+++ b/sflphone-common/libs/pjproject/pjmedia/src/pjmedia/delaybuf.c
@@ -144,8 +144,8 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool,
 	return status;
 
     /* Finally, create mutex */
-    status = pj_lock_create_recursive_mutex(pool, b->obj_name, 
-					    &b->lock);
+//    status = pj_lock_create_recursive_mutex(pool, b->obj_name,
+//					    &b->lock);
     if (status != PJ_SUCCESS)
 	return status;
 
@@ -162,15 +162,15 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b)
 
     PJ_ASSERT_RETURN(b, PJ_EINVAL);
 
-    pj_lock_acquire(b->lock);
+//    pj_lock_acquire(b->lock);
 
     status = pjmedia_wsola_destroy(b->wsola);
     if (status == PJ_SUCCESS)
 	b->wsola = NULL;
 
-    pj_lock_release(b->lock);
+//    pj_lock_release(b->lock);
 
-    pj_lock_destroy(b->lock);
+//    pj_lock_destroy(b->lock);
     b->lock = NULL;
 
     return status;
@@ -273,13 +273,13 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b,
 
     PJ_ASSERT_RETURN(b && frame, PJ_EINVAL);
 
-    pj_lock_acquire(b->lock);
+    // pj_lock_acquire(b->lock);
 
     update(b, OP_PUT);
     
     status = pjmedia_wsola_save(b->wsola, frame, PJ_FALSE);
     if (status != PJ_SUCCESS) {
-	pj_lock_release(b->lock);
+//	pj_lock_release(b->lock);
 	return status;
     }
 
@@ -316,7 +316,7 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b,
 
     pjmedia_circ_buf_write(b->circ_buf, frame, b->samples_per_frame);
 
-    pj_lock_release(b->lock);
+    // pj_lock_release(b->lock);
     return PJ_SUCCESS;
 }
 
@@ -327,7 +327,7 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b,
 
     PJ_ASSERT_RETURN(b && frame, PJ_EINVAL);
 
-    pj_lock_acquire(b->lock);
+    // pj_lock_acquire(b->lock);
 
     update(b, OP_GET);
 
@@ -342,7 +342,7 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b,
 	if (status == PJ_SUCCESS) {
 	    TRACE__((b->obj_name,"Successfully generate 1 frame"));
 	    if (pjmedia_circ_buf_get_len(b->circ_buf) == 0) {
-		pj_lock_release(b->lock);
+//		pj_lock_release(b->lock);
 		return PJ_SUCCESS;
 	    }
 
@@ -363,7 +363,7 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b,
 	    /* The buffer is empty now, reset it */
 	    pjmedia_circ_buf_reset(b->circ_buf);
 
-	    pj_lock_release(b->lock);
+	    // pj_lock_release(b->lock);
 
 	    return PJ_SUCCESS;
 	}
@@ -371,7 +371,7 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b,
 
     pjmedia_circ_buf_read(b->circ_buf, frame, b->samples_per_frame);
 
-    pj_lock_release(b->lock);
+    //pj_lock_release(b->lock);
 
     return PJ_SUCCESS;
 }
@@ -381,7 +381,7 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b)
 {
     PJ_ASSERT_RETURN(b, PJ_EINVAL);
 
-    pj_lock_acquire(b->lock);
+    // pj_lock_acquire(b->lock);
 
     b->recalc_timer = RECALC_TIME;
 
@@ -391,7 +391,7 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b)
     /* Reset WSOLA */
     pjmedia_wsola_reset(b->wsola, 0);
 
-    pj_lock_release(b->lock);
+    // pj_lock_release(b->lock);
 
     PJ_LOG(5,(b->obj_name,"Delay buffer is reset"));
 
diff --git a/sflphone-common/src/audio/Makefile.am b/sflphone-common/src/audio/Makefile.am
index 4fd2854e713a9a83f609b2c15b1ecef259210822..40b669fd1ff746004878992a3d7d208b2b4201de 100644
--- a/sflphone-common/src/audio/Makefile.am
+++ b/sflphone-common/src/audio/Makefile.am
@@ -20,6 +20,7 @@ libaudio_la_SOURCES = \
 		samplerateconverter.cpp \
 		delaydetection.cpp \
 		echocancel.cpp \
+		echosuppress.cpp \
 		speexechocancel.cpp \
 		noisesuppress.cpp \
 		audioprocessing.cpp \
@@ -39,6 +40,7 @@ noinst_HEADERS = \
 		algorithm.h \
 		delaydetection.h \
 		echocancel.h \
+		echosuppress.h \
 		speexechocancel.h \
 		noisesuppress.h \
 		audioprocessing.h \
diff --git a/sflphone-common/src/audio/audiortp/AudioRtpRecordHandler.cpp b/sflphone-common/src/audio/audiortp/AudioRtpRecordHandler.cpp
index 201c2b22e0359cc653287e0e587050f04777c01d..2e69bdc1f1479e6cdca5061980d09ea01b9ec050 100644
--- a/sflphone-common/src/audio/audiortp/AudioRtpRecordHandler.cpp
+++ b/sflphone-common/src/audio/audiortp/AudioRtpRecordHandler.cpp
@@ -123,7 +123,7 @@ AudioRtpRecord::~AudioRtpRecord()
 }
 
 
-AudioRtpRecordHandler::AudioRtpRecordHandler (SIPCall *ca) : _audioRtpRecord (), _ca (ca) {}
+AudioRtpRecordHandler::AudioRtpRecordHandler (SIPCall *ca) : _audioRtpRecord (), _ca (ca), echoCanceller(ca->getMemoryPool()) {}
 
 
 AudioRtpRecordHandler::~AudioRtpRecordHandler() {}
@@ -299,14 +299,16 @@ int AudioRtpRecordHandler::processDataEncode (void)
             _audioRtpRecord._audioProcess->processAudio (micDataConverted, nbSample * sizeof (SFLDataFormat));
         }
 
-        echoCanceller.process(micDataConverted, micDataEchoCancelled, nbSample * sizeof(SFLDataFormat));
-
+        // echoCanceller.process(micDataConverted, micDataEchoCancelled, nbSample * sizeof(SFLDataFormat));
+        if(Manager::instance().getEchoCancelState() != "enabled") {
+            echoCanceller.getData(micData);
+        }
 
         _audioRtpRecord.audioProcessMutex.leave();
 
         _audioRtpRecord.audioCodecMutex.enter();
 
-        compSize = _audioRtpRecord._audioCodec->encode (micDataEncoded, micDataEchoCancelled, nbSample * sizeof (SFLDataFormat));
+        compSize = _audioRtpRecord._audioCodec->encode (micDataEncoded, micData, nbSample * sizeof (SFLDataFormat));
         // compSize = _audioRtpRecord._audioCodec->encode (micDataEncoded, micDataConverted, nbSample * sizeof (SFLDataFormat));
 
         _audioRtpRecord.audioCodecMutex.leave();
@@ -320,9 +322,14 @@ int AudioRtpRecordHandler::processDataEncode (void)
             // _audioRtpRecord._audioProcess->processAudio (micDataEchoCancelled, nbSample * sizeof (SFLDataFormat));
         }
 
-        echoCanceller.process(micData, micDataEchoCancelled, nbSample * sizeof(SFLDataFormat));
+        // echoCanceller.process(micData, micDataEchoCancelled, nbSample * sizeof(SFLDataFormat));
+        // echoCanceller.process(micData, micDataEchoCancelled, nbSample * sizeof(SFLDataFormat));
+        if(Manager::instance().getEchoCancelState() != "enabled") {
+        	_debug("EchoCancel: -------------------------- getData");
+            echoCanceller.getData(micData);
+        }
 
-        teststream.write(reinterpret_cast<char *>(micDataEchoCancelled), nbSample * sizeof(SFLDataFormat));
+        teststream.write(reinterpret_cast<char *>(micData), nbSample * sizeof(SFLDataFormat));
 
         
         _audioRtpRecord.audioProcessMutex.leave();
@@ -331,7 +338,7 @@ int AudioRtpRecordHandler::processDataEncode (void)
 
         // no resampling required
         // compSize = _audioRtpRecord._audioCodec->encode (micDataEncoded, micData, nbSample * sizeof (SFLDataFormat));
-        compSize = _audioRtpRecord._audioCodec->encode (micDataEncoded, micDataEchoCancelled, nbSample * sizeof (SFLDataFormat));
+        compSize = _audioRtpRecord._audioCodec->encode (micDataEncoded, micData, nbSample * sizeof (SFLDataFormat));
 
         _audioRtpRecord.audioCodecMutex.leave();
     }
@@ -370,15 +377,19 @@ void AudioRtpRecordHandler::processDataDecode (unsigned char *spkrData, unsigned
 
         nbSample = _audioRtpRecord._converter->upsampleData (spkrDataDecoded, spkrDataConverted, codecSampleRate, mainBufferSampleRate, nbSampleDown);
 
-        echoCanceller.putData(spkrDataConverted, nbSample * sizeof(SFLDataFormat));
+        if(Manager::instance().getEchoCancelState() != "enabled") {
+            echoCanceller.putData(spkrDataConverted, nbSample * sizeof(SFLDataFormat));
+        }
 
         // put data in audio layer, size in byte
         Manager::instance().getMainBuffer()->putData (spkrDataConverted, nbSample * sizeof (SFLDataFormat), 100, _ca->getCallId());
 
 
     } else {
-    	echoCanceller.putData(spkrDataDecoded, expandedSize);
-
+    	if(Manager::instance().getEchoCancelState() != "enabled") {
+    		_debug("EchoCancel: ------------------------ Put Data");
+    		echoCanceller.putData(spkrDataDecoded, expandedSize);
+    	}
         // put data in audio layer, size in byte
         Manager::instance().getMainBuffer()->putData (spkrDataDecoded, expandedSize, 100, _ca->getCallId());
     }
diff --git a/sflphone-common/src/audio/audiortp/AudioRtpRecordHandler.h b/sflphone-common/src/audio/audiortp/AudioRtpRecordHandler.h
index f08e512e0dd198e8e8788aae610698e810184314..96f733da2716016f1f3f7a0c45dee5ee04f96c34 100644
--- a/sflphone-common/src/audio/audiortp/AudioRtpRecordHandler.h
+++ b/sflphone-common/src/audio/audiortp/AudioRtpRecordHandler.h
@@ -36,6 +36,7 @@
 #include "audio/audioprocessing.h"
 #include "audio/noisesuppress.h"
 #include "audio/speexechocancel.h"
+#include "audio/echosuppress.h"
 #include "managerimpl.h"
 #include <ccrtp/rtp.h>
 
@@ -227,7 +228,7 @@ class AudioRtpRecordHandler
 
         SIPCall *_ca;
 
- 	    SpeexEchoCancel echoCanceller;
+ 	    EchoSuppress echoCanceller;
 };
 
 }
diff --git a/sflphone-common/src/audio/echosuppress.cpp b/sflphone-common/src/audio/echosuppress.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..46c9fd67377a411daef5948c35fa44a49d642c63
--- /dev/null
+++ b/sflphone-common/src/audio/echosuppress.cpp
@@ -0,0 +1,94 @@
+/*
+ * EchoSuppress.cpp
+ *
+ *  Created on: 2011-05-18
+ *      Author: asavard
+ */
+
+#include "echosuppress.h"
+#include "pj/os.h"
+
+#define ECHO_CANCEL_MEM_SIZE 1000
+
+EchoSuppress::EchoSuppress(pj_pool_t *pool)
+{
+    pj_status_t status;
+
+    _debug("********************************************************************** Init echo suppress");
+
+    // pj_thread_register
+
+    pj_thread_desc aPJThreadDesc;
+    pj_thread_t *pjThread;
+    _debug("EchoCancel: Thread not yet registered to pjsip, registering");
+    status = pj_thread_register("EchoCanceller", aPJThreadDesc, &pjThread);
+    if (status != PJ_SUCCESS) {
+    	_error("EchoCancel: Error: Could not register new thread");
+    }
+//    if (!pj_thread_is_registered()) {
+//    }
+
+    if (!pj_thread_is_registered()) {
+    	_warn("EchoCancel: Thread not registered...");
+    }
+
+    // pj_thread_register();
+
+//    status = pj_init();
+//    if(status != PJ_SUCCESS) {
+//        _error("EchoCancel: Error: could not init pj");
+//    }
+//
+//    pj_caching_pool_init(&echoCachingPool, &pj_pool_factory_default_policy, ECHO_CANCEL_MEM_SIZE);
+
+    // echoCancelPool = pj_pool_create_int(&echoCachingPool.factory, "EchoCancelPool", 1000, 1000, NULL);
+    echoCancelPool = pool;
+
+    status = pjmedia_echo_create(echoCancelPool, 8000, 160, 250, 0, PJMEDIA_ECHO_SIMPLE, &echoState);
+    if(status != PJ_SUCCESS) {
+    	_error("EchoCancel: Error: Could not create echo canceller");
+    }
+}
+
+EchoSuppress::~EchoSuppress()
+{
+//	pjmedia_echo_destroy(echoState);
+
+	// pj_pool_destroy(echoCancelPool);
+
+	//pj_caching_pool_destroy(&echoCachingPool);
+}
+
+void EchoSuppress::reset()
+{
+
+}
+
+void EchoSuppress::putData (SFLDataFormat *inputData, int nbBytes)
+{
+	pj_status_t status;
+
+	status = pjmedia_echo_playback(echoState, reinterpret_cast<pj_int16_t *>(inputData));
+
+	if(status != PJ_SUCCESS) {
+		_warn("EchoCancel: Warning: Problem while putting input data");
+	}
+}
+
+int EchoSuppress::getData(SFLDataFormat *outputData)
+{
+	pj_status_t status;
+
+	status = pjmedia_echo_capture(echoState, reinterpret_cast<pj_int16_t *>(outputData), 0);
+	if(status != PJ_SUCCESS) {
+		_warn("EchoCancel: Warning: Problem while getting output data");
+	}
+
+	return 0;
+}
+
+void EchoSuppress::process (SFLDataFormat *data UNUSED, int nbBytes UNUSED) {}
+
+int EchoSuppress::process (SFLDataFormat *inputData, SFLDataFormat *outputData, int nbBytes) { return 0; }
+
+void EchoSuppress::process (SFLDataFormat *micData UNUSED, SFLDataFormat *spkrData UNUSED, SFLDataFormat *outputData UNUSED, int nbBytes UNUSED) {}
diff --git a/sflphone-common/src/audio/echosuppress.h b/sflphone-common/src/audio/echosuppress.h
new file mode 100644
index 0000000000000000000000000000000000000000..f4bba4c688a957053583f053f7ecc65d6d4c7aa0
--- /dev/null
+++ b/sflphone-common/src/audio/echosuppress.h
@@ -0,0 +1,66 @@
+/*
+ * EchoSuppress.h
+ *
+ *  Created on: 2011-05-18
+ *      Author: asavard
+ */
+
+#ifndef ECHOSUPPRESS_H_
+#define ECHOSUPPRESS_H_
+
+#include "pjmedia/echo.h"
+#include "pj/pool.h"
+
+#include "audioprocessing.h"
+
+class EchoSuppress: public Algorithm {
+public:
+	EchoSuppress(pj_pool_t *pool);
+
+	virtual ~EchoSuppress();
+
+    virtual void reset (void);
+
+    /**
+     * Add speaker data into internal buffer
+     * \param inputData containing far-end voice data to be sent to speakers
+     */
+    virtual void putData (SFLDataFormat *, int);
+
+    virtual int getData(SFLDataFormat *);
+
+    /**
+     * Unused
+     */
+    virtual void process (SFLDataFormat *, int);
+
+    /**
+     * Perform echo cancellation using internal buffers
+     * \param inputData containing mixed echo and voice data
+     * \param outputData containing
+     */
+    virtual int process (SFLDataFormat *, SFLDataFormat *, int);
+
+    /**
+     * Perform echo cancellation, application must provide its own buffer
+     * \param micData containing mixed echo and voice data
+     * \param spkrData containing far-end voice data to be sent to speakers
+     * \param outputData containing the processed data
+	 * \param size in bytes
+	 */
+    virtual void process (SFLDataFormat *, SFLDataFormat *, SFLDataFormat *, int);
+
+private:
+
+    /**
+     * Memory pool for echo cancellation
+     */
+    pj_pool_t *echoCancelPool;
+
+    /**
+     * The internal state of the echo canceller
+     */
+    pjmedia_echo_state *echoState;
+};
+
+#endif /* ECHOSUPPRESS_H_ */