Commit cac8a8f3 authored by Tristan Matthews's avatar Tristan Matthews
parents 0d560c6c 7ba369bb
......@@ -123,7 +123,7 @@ AudioRtpRecord::~AudioRtpRecord()
}
AudioRtpRecordHandler::AudioRtpRecordHandler (SIPCall *ca) : _audioRtpRecord (), _ca (ca), echoCanceller(ca->getMemoryPool())
AudioRtpRecordHandler::AudioRtpRecordHandler (SIPCall *ca) : _audioRtpRecord (), _ca (ca), echoCanceller(ca->getMemoryPool()), gainController(8000, 0.0)
{
}
......@@ -328,7 +328,6 @@ int AudioRtpRecordHandler::processDataEncode (void)
// 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);
}
......@@ -372,12 +371,14 @@ void AudioRtpRecordHandler::processDataDecode (unsigned char *spkrData, unsigned
_audioRtpRecord._spkrFadeInComplete = fadeIn (spkrDataDecoded, nbSample, &_audioRtpRecord._micAmplFactor);
}
// Normalize incomming signal
gainController.process(spkrDataDecoded, nbSample);
// test if resampling is required
if (codecSampleRate != mainBufferSampleRate) {
// Do sample rate conversion
int nbSampleDown = nbSample;
nbSample = _audioRtpRecord._converter->upsampleData (spkrDataDecoded, spkrDataConverted, codecSampleRate, mainBufferSampleRate, nbSampleDown);
if(Manager::instance().getEchoCancelState() == "enabled") {
......@@ -390,8 +391,7 @@ void AudioRtpRecordHandler::processDataDecode (unsigned char *spkrData, unsigned
} else {
if(Manager::instance().getEchoCancelState() == "enabled") {
_debug("EchoCancel: ------------------------ Put Data");
echoCanceller.putData(spkrDataDecoded, expandedSize);
echoCanceller.putData(spkrDataDecoded, expandedSize);
}
// put data in audio layer, size in byte
Manager::instance().getMainBuffer()->putData (spkrDataDecoded, expandedSize, 100, _ca->getCallId());
......
......@@ -37,6 +37,7 @@
#include "audio/noisesuppress.h"
#include "audio/speexechocancel.h"
#include "audio/echosuppress.h"
#include "audio/gaincontrol.h"
#include "managerimpl.h"
#include <ccrtp/rtp.h>
......@@ -67,9 +68,9 @@ timeval2microtimeout (const timeval& t)
class AudioRtpSessionException: public std::exception
{
virtual const char* what() const throw() {
return "AudioRtpSessionException occured";
}
virtual const char* what() const throw() {
return "AudioRtpSessionException occured";
}
};
typedef struct DtmfEvent {
......@@ -115,7 +116,7 @@ class AudioRtpRecord
NoiseSuppress *_noiseSuppress;
ost::Mutex audioProcessMutex;
std::string _callId;
unsigned int _dtmfPayloadType;
unsigned int _dtmfPayloadType;
};
......@@ -228,7 +229,9 @@ class AudioRtpRecordHandler
SIPCall *_ca;
EchoSuppress echoCanceller;
EchoSuppress echoCanceller;
GainControl gainController;
};
}
......
......@@ -6,31 +6,55 @@
#include "global.h"
#include "gaincontrol.h"
#define SFL_GAIN_ATTACK_RELEASE_TIME 10
#define SFL_GAIN_ATTACK_TIME 10
#define SFL_GAIN_RELEASE_TIME 300
#define SFL_GAIN_LIMITER_RATIO 0.1
#define SFL_GAIN_LIMITER_THRESHOLD 0.6
GainControl::GainControl(double sr) : averager(sr, SFL_GAIN_ATTACK_RELEASE_TIME)
, limiter(SFL_GAIN_LIMITER_RATIO, SFL_GAIN_LIMITER_THRESHOLD) {}
#define SFL_GAIN_LOGe10 2.30258509299404568402
#define DUMP_GAIN_CONTROL_SIGNAL
GainControl::GainControl(double sr, double target) : averager(sr, SFL_GAIN_ATTACK_TIME, SFL_GAIN_RELEASE_TIME)
, limiter(SFL_GAIN_LIMITER_RATIO, SFL_GAIN_LIMITER_THRESHOLD)
, targetGaindB(target)
, targetGainLinear(0.0)
{
targetGainLinear = exp(targetGaindB * 0.05 * SFL_GAIN_LOGe10);
_debug("GainControl: Target gain %d dB (%d linear)", targetGaindB, targetGainLinear);
}
GainControl::~GainControl() {}
std::fstream tmpRms("testrms.raw", std::fstream::out);
#ifdef DUMP_GAIN_CONTROL_SIGNAL
std::fstream tmpRms("gaintestrms.raw", std::fstream::out);
std::fstream tmpIn("gaintestin.raw", std::fstream::out);
std::fstream tmpOut("gaintestout.raw", std::fstream::out);
#endif
void GainControl::process(SFLDataFormat *inBuf, SFLDataFormat *outBuf, int bufLength)
void GainControl::process(SFLDataFormat *buf, int bufLength)
{
double rms, rmsAvg, in, out;
for(int i = 0; i < bufLength; i++) {
in = (double)inBuf[i] / (double)SHRT_MAX;
in = (double)buf[i] / (double)SHRT_MAX;
rms = detector.getRms(in);
rmsAvg = sqrt(averager.getAverage(rms));
#ifdef DUMP_GAIN_CONTROL_SIGNAL
tmpRms.write(reinterpret_cast<char *>(&rmsAvg), sizeof(double));
tmpIn.write(reinterpret_cast<char *>(&in), sizeof(double));
#endif
out = limiter.limit(in);
outBuf[i] = (short)(out * (double)SHRT_MAX);
#ifdef DUMP_GAIN_CONTROL_SIGNAL
tmpOut.write(reinterpret_cast<char *>(&out), sizeof(double));
#endif
buf[i] = (short)(out * (double)SHRT_MAX);
}
}
......@@ -41,17 +65,24 @@ double GainControl::RmsDetection::getRms(double in)
return in * in;
}
GainControl::DetectionAverage::DetectionAverage(double sr, double t) :
g(0.0), teta(t), samplingRate(sr), previous_y(0.0)
GainControl::DetectionAverage::DetectionAverage(double sr, double ta, double tr) :
g_a(0.0), teta_a(ta), g_r(0.0), teta_r(tr), samplingRate(sr), previous_y(0.0)
{
g = exp(-1.0 / (samplingRate * (teta / 1000.0)));
g_a = exp(-1.0 / (samplingRate * (teta_a / 1000.0)));
g_r = exp(-1.0 / (samplingRate * (teta_r / 1000.0)));
std::cout << "GainControl: g: " << g << ", teta: " << teta << std::endl;
std::cout << "GainControl: g_attack: " << g_a << ", teta_attack: " << teta_a
<< ", g_release: " << g_r << ", teta_release: " << teta_r << std::endl;
}
double GainControl::DetectionAverage::getAverage(double in)
{
previous_y = ((1.0 - g) * in) + (g * previous_y);
if(in > previous_y) {
previous_y = ((1.0 - g_a) * in) + (g_a * previous_y);
}
else {
previous_y = ((1.0 - g_r) * in) + (g_r * previous_y);
}
return previous_y;
}
......
......@@ -8,13 +8,30 @@
class GainControl {
public:
GainControl(double);
/**
* Constructor for the gain controller
* /param Sampling rate
* /param Target gain in dB
*/
GainControl(double, double);
/**
* Destructor for this class
*/
~GainControl(void);
void process(SFLDataFormat *, SFLDataFormat *, int);
/**
* Apply addaptive gain factor on input signal
* /param Input audio buffer
* /param Input buffer length
*/
void process(SFLDataFormat *, int);
private:
/**
* Rms detector
*/
class RmsDetection {
public:
/**
......@@ -24,6 +41,7 @@ private:
/**
* Get rms value
* /param Audio sample
*/
double getRms(double);
......@@ -33,8 +51,11 @@ private:
public:
/**
* Constructor for this class
* /param Sampling rate
* /param Attack ramping time
* /param Release ramping time
*/
DetectionAverage(double, double);
DetectionAverage(double, double, double);
/**
* Process average
......@@ -43,14 +64,24 @@ private:
private:
/**
* Average factor
* Average factor for attack
*/
double g;
double g_a;
/**
* Attack and release ramp time (in ms)
* Attack ramp time (in ms)
*/
double teta;
double teta_a;
/**
* Average factor for release
*/
double g_r;
/**
* Release ramp time (in ms)
*/
double teta_r;
/**
* Samplig rate
......@@ -65,8 +96,16 @@ private:
class Limiter {
public:
/**
* Limiter
* /param Threshold
* /param Ratio
*/
Limiter(double, double);
/**
* Perform compression on input signal
*/
double limit(double);
private:
......@@ -79,6 +118,10 @@ private:
DetectionAverage averager;
Limiter limiter;
double targetGaindB;
double targetGainLinear;
};
#endif // GAINCONTROL_H
......@@ -55,11 +55,13 @@ SpeexEchoCancel::SpeexEchoCancel()
_micData->createReadPointer();
_spkrData->createReadPointer();
#ifdef DUMP_ECHOCANCEL_INTERNAL_DATA
micFile = new ofstream("test_mic_data.raw");
spkrFile = new ofstream("test_spkr_data.raw");
micProcessFile = new ofstream("test_mic_data_process.raw", std::ofstream::out);
spkrProcessFile = new ofstream("test_spkr_data_process.raw", std::ofstream::out);
echoFile = new ofstream("test_echo_data.raw");
#endif
_spkrStopped = true;
}
......@@ -80,11 +82,13 @@ SpeexEchoCancel::~SpeexEchoCancel()
delete _spkrData;
_spkrData = NULL;
#ifdef DUMP_ECHOCANCEL_INTERNAL_DATA
delete micFile;
delete spkrFile;
delete micProcessFile;
delete spkrProcessFile;
delete echoFile;
#endif
}
......@@ -101,7 +105,9 @@ void SpeexEchoCancel::putData (SFLDataFormat *inputData, int nbBytes)
_spkrStopped = false;
}
#ifdef DUMP_ECHOCANCEL_INTERNAL_DATA
spkrFile->write(reinterpret_cast<char *>(inputData), nbBytes);
#endif
// Put data in speaker ring buffer
_spkrData->Put (inputData, nbBytes);
......@@ -131,7 +137,9 @@ int SpeexEchoCancel::process (SFLDataFormat *inputData, SFLDataFormat *outputDat
memset (_tmpMic, 0, 5000 * sizeof(SFLDataFormat));
memset (_tmpOut, 0, 5000 * sizeof(SFLDataFormat));
#ifdef DUMP_ECHOCANCEL_INTERNAL_DATA
micFile->write(reinterpret_cast<char *>(inputData), nbBytes);
#endif
// Put mic data in ringbuffer
_micData->Put (inputData, nbBytes);
......@@ -153,8 +161,10 @@ int SpeexEchoCancel::process (SFLDataFormat *inputData, SFLDataFormat *outputDat
_spkrData->Get (_tmpSpkr, byteSize);
_micData->Get (_tmpMic, byteSize);
#ifdef DUMP_ECHOCANCEL_INTERNAL_DATA
micProcessFile->write(reinterpret_cast<char *>(_tmpMic), byteSize);
spkrProcessFile->write(reinterpret_cast<char *>(_tmpSpkr), byteSize);
#endif
int32_t tmp;
for(int i = 0; i < nbSamples; i++) {
......@@ -172,7 +182,9 @@ int SpeexEchoCancel::process (SFLDataFormat *inputData, SFLDataFormat *outputDat
speex_echo_cancellation (_echoState, _tmpMic, _tmpSpkr, _tmpOut);
speex_preprocess_run(_preState, reinterpret_cast<short *>(_tmpOut));
#ifdef DUMP_ECHOCANCEL_INTERNAL_DATA
echoFile->write(reinterpret_cast<char *>(_tmpOut), byteSize);
#endif
for(int i = 0; i < nbSamples; i++) {
_tmpOut[i] *= 3;
......
......@@ -85,11 +85,13 @@ class SpeexEchoCancel : public Algorithm
SFLDataFormat _tmpMic[5000];
SFLDataFormat _tmpOut[5000];
#ifdef DUMP_ECHOCANCEL_INTERNAL_DATA
ofstream *micFile;
ofstream *spkrFile;
ofstream *micProcessFile;
ofstream *spkrProcessFile;
ofstream *echoFile;
#endif
};
#endif
......@@ -625,77 +625,75 @@ bool ManagerImpl::onHoldCall (const CallID& callId)
}
//THREAD=Main
bool ManagerImpl::offHoldCall (const CallID& call_id)
bool ManagerImpl::offHoldCall (const CallID& callId)
{
AccountID account_id;
AccountID accountId;
bool returnValue, isRec;
std::string codecName;
isRec = false;
_debug ("Manager: Put call %s off hold", call_id.c_str());
_debug ("Manager: Put call %s off hold", callId.c_str());
stopTone();
CallID current_call_id = getCurrentCallId();
CallID currentCallId = getCurrentCallId();
//Place current call on hold if it isn't
if (hasCurrentCall()) {
// if this is not a conference and this and is not a conference participant
if (!isConference (current_call_id) && !participToConference (current_call_id)) {
_debug ("Manager: Has current call (%s), put on hold", current_call_id.c_str());
onHoldCall (current_call_id);
} else if (isConference (current_call_id) && !participToConference (call_id)) {
detachParticipant (default_id, current_call_id);
if (!isConference (currentCallId) && !participToConference (currentCallId)) {
_debug ("Manager: Has current call (%s), put on hold", currentCallId.c_str());
onHoldCall (currentCallId);
} else if (isConference (currentCallId) && !participToConference (callId)) {
detachParticipant (default_id, currentCallId);
}
}
/* Direct IP to IP call */
if (getConfigFromCall (call_id) == Call::IPtoIP) {
if (getConfigFromCall (callId) == Call::IPtoIP) {
// is_rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (call_id);
returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (call_id);
returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (callId);
}
/* Classic call, attached to an account */
else {
account_id = getAccountFromCall (call_id);
accountId = getAccountFromCall (callId);
_debug ("Manager: Setting offhold, Account %s, callid %s", account_id.c_str(), call_id.c_str());
_debug ("Manager: Setting offhold, Account %s, callid %s", accountId.c_str(), callId.c_str());
isRec = getAccountLink (account_id)->getCall (call_id)->isRecording();
returnValue = getAccountLink (account_id)->offhold (call_id);
isRec = getAccountLink (accountId)->getCall (callId)->isRecording();
returnValue = getAccountLink (accountId)->offhold (callId);
}
if (_dbus) {
if (isRec) {
_dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_RECORD");
}
else {
_dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_CURRENT");
}
if (_dbus == NULL) {
_error("Manager: Error: DBUS not initialized");
}
if (participToConference (call_id)) {
if (isRec) {
_dbus->getCallManager()->callStateChanged (callId, "UNHOLD_RECORD");
}
else {
_dbus->getCallManager()->callStateChanged (callId, "UNHOLD_CURRENT");
}
if (participToConference (callId)) {
AccountID currentAccountId;
Call* call = NULL;
currentAccountId = getAccountFromCall (call_id);
call = getAccountLink (currentAccountId)->getCall (call_id);
currentAccountId = getAccountFromCall (callId);
call = getAccountLink (currentAccountId)->getCall (callId);
switchCall (call->getConfId());
} else {
switchCall (call_id);
// audioLayerMutexLock();
// _audiodriver->flushMain();
// audioLayerMutexUnlock();
addStream(call_id);
switchCall (callId);
}
addStream(callId);
getMainBuffer()->stateInfo();
return returnValue;
......@@ -772,30 +770,30 @@ void ManagerImpl::transferSucceded ()
bool ManagerImpl::attendedTransfer(const CallID& transferID, const CallID& targetID)
{
bool returnValue = false;
bool returnValue = false;
_debug("Manager: Attended transfer");
_debug("Manager: Attended transfer");
// Direct IP to IP call
if (getConfigFromCall (transferID) == Call::IPtoIP) {
returnValue = SIPVoIPLink::instance (AccountNULL)-> attendedTransfer(transferID, targetID);
}
else { // Classic call, attached to an account
// Direct IP to IP call
if (getConfigFromCall (transferID) == Call::IPtoIP) {
returnValue = SIPVoIPLink::instance (AccountNULL)-> attendedTransfer(transferID, targetID);
}
else { // Classic call, attached to an account
AccountID accountid = getAccountFromCall (transferID);
AccountID accountid = getAccountFromCall (transferID);
if (accountid == AccountNULL) {
_warn ("Manager: Call doesn't exists");
return false;
}
if (accountid == AccountNULL) {
_warn ("Manager: Call doesn't exists");
return false;
}
returnValue = getAccountLink (accountid)->attendedTransfer (transferID, targetID);
returnValue = getAccountLink (accountid)->attendedTransfer (transferID, targetID);
}
}
getMainBuffer()->stateInfo();
getMainBuffer()->stateInfo();
return returnValue;
return returnValue;
}
//THREAD=Main : Call:Incoming
......
......@@ -38,10 +38,11 @@ using namespace std;
void GainControlTest::testGainProcessing()
{
int fileSize;
SFLDataFormat inbuf[SFL_GAIN_BUFFER_LENGTH];
SFLDataFormat outbuf[SFL_GAIN_BUFFER_LENGTH];
SFLDataFormat buf[SFL_GAIN_BUFFER_LENGTH];
GainControl gcontrol(8000);
// Sampling rate is 8000
// Target level is 0 dB
GainControl gcontrol(8000, 0.0);
/*
fstream inputFile("testgaininput.raw", fstream::in);
......@@ -54,7 +55,7 @@ void GainControlTest::testGainProcessing()
while(fileSize > 0) {
inputFile.read(reinterpret_cast<char *>(inbuf), BUFFER_LENGTH * sizeof(SFLDataFormat));
gcontrol.process(inbuf, outbuf, BUFFER_LENGTH);
gcontrol.process(buf, BUFFER_LENGTH);
outputFile.write(reinterpret_cast<char *>(outbuf), BUFFER_LENGTH * sizeof(SFLDataFormat));
......
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