Commit dac50fad authored by Alexandre Savard's avatar Alexandre Savard

#5855: Implement pjsip echo canceller

parent 764a6576
......@@ -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"));
......
......@@ -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 \
......
......@@ -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());
}
......
......@@ -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;
};
}
......
/*
* 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) {}
/*
* 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_ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment