diff --git a/sflphone-common/src/audio/echocancel.cpp b/sflphone-common/src/audio/echocancel.cpp index 1eeb7b96c8916b3d17153b5f5aa13b9fc9c5023c..66e8780172a4db082dbdfaad9788cdfd727cfcef 100644 --- a/sflphone-common/src/audio/echocancel.cpp +++ b/sflphone-common/src/audio/echocancel.cpp @@ -52,6 +52,9 @@ EchoCancel::EchoCancel(int smplRate, int frameLength) : _samplingRate(smplRate), spkrFile = new ofstream("spkrData", ofstream::binary); */ + micLearningData = new ofstream("micLearningData", ofstream::binary); + spkrLearningData = new ofstream("spkrLearningData", ofstream::binary); + _micData = new RingBuffer(50000); _spkrData = new RingBuffer(50000); @@ -115,11 +118,17 @@ EchoCancel::~EchoCancel() delete echoFile; */ + micLearningData->close(); + spkrLearningData->close(); + delete micLearningData; + delete spkrLearningData; + } void EchoCancel::reset() { _debug("EchoCancel: Reset internal state, Sampling rate %d, Frame size %d", _samplingRate, _smplPerFrame); + _debug("SIZEOF INT %d", sizeof(int)); memset(_avgSpkrLevelHist, 0, BUFF_SIZE*sizeof(int)); memset(_avgMicLevelHist, 0, BUFF_SIZE*sizeof(int)); @@ -139,11 +148,22 @@ void EchoCancel::reset() memset(_delayLineAmplify, 0, MAX_DELAY_LINE_AMPL*sizeof(float)); _amplDelayIndexIn = 0; - _amplDelayIndexOut = DELAY_AMPLIFY / SEGMENT_LENGTH; + _amplDelayIndexOut = 0; + + _adaptDone = false; + _adaptStarted = false; + _adaptCnt = 0; + _spkrAdaptCnt = 0; + _micAdaptCnt = 0; _micData->flushAll(); _spkrData->flushAll(); + // SFLDataFormat delay[960]; + // memset(delay, 0, sizeof(SFLDataFormat)); + + // _micData->Put(delay, 960*2); + speex_preprocess_state_destroy(_noiseState); _noiseState = speex_preprocess_state_init(_smplPerFrame, _samplingRate); @@ -169,6 +189,7 @@ void EchoCancel::putData(SFLDataFormat *inputData, int nbBytes) // std::cout << "putData nbBytes: " << nbBytes << std::endl; if(_spkrStoped) { + _debug("EchoCancel: Flush data"); _micData->flushAll(); _spkrData->flushAll(); _spkrStoped = false; @@ -202,6 +223,8 @@ int EchoCancel::process(SFLDataFormat *inputData, SFLDataFormat *outputData, int int spkrAvail = _spkrData->AvailForGet(); int micAvail = _micData->AvailForGet(); + _debug("EchoCancel: speaker avail %d, mic avail %d", spkrAvail, micAvail); + // Init number of frame processed int nbFrame = 0; @@ -263,7 +286,8 @@ void EchoCancel::performEchoCancel(SFLDataFormat *micData, SFLDataFormat *spkrDa increaseFactor(0.05); } else { - decreaseFactor(); + // decreaseFactor(); + _amplFactor = 0.0; } } else { @@ -271,13 +295,13 @@ void EchoCancel::performEchoCancel(SFLDataFormat *micData, SFLDataFormat *spkrDa increaseFactor(0.02); } else { - decreaseFactor(); + // decreaseFactor(); + _amplFactor = 0.0; } } // lowpass filtering float amplify = (_lastAmplFactor + _amplFactor) / 2; - _lastAmplFactor = _amplFactor; amplifySignal(micData+(k*_smplPerSeg), outputData+(k*_smplPerSeg), amplify); @@ -323,7 +347,8 @@ void EchoCancel::updateEchoCancel(SFLDataFormat *micData, SFLDataFormat *spkrDat // perform correlation if spkr size is reached if(_adaptCnt > _spkrAdaptSize) { int k = _adaptCnt - _spkrAdaptSize; - _correlationArray[k] = performCorrelation(_spkrAdaptArray, _micAdaptArray+k, _correlationSize); + _correlationArray[k] = performCorrelation(_spkrAdaptArray, _micAdaptArray+k, _correlationSize); + _debug("EchoCancel: Correlation: %d", _correlationArray[k]); } _adaptCnt++; @@ -333,6 +358,9 @@ void EchoCancel::updateEchoCancel(SFLDataFormat *micData, SFLDataFormat *spkrDat _debug("EchoCancel: Echo path adaptation completed"); _adaptDone = true; _amplDelayIndexOut = getMaximumIndex(_correlationArray, _correlationSize); + _debug("EchoCancel: Echo length %d", _amplDelayIndexOut); + spkrLearningData->write((const char *)_spkrAdaptArray, _spkrAdaptSize*sizeof(int)); + micLearningData->write((const char *)_micAdaptArray, _micAdaptSize*sizeof(int)); } } @@ -373,9 +401,23 @@ void EchoCancel::amplifySignal(SFLDataFormat *micData, SFLDataFormat *outputData // Use delayed amplification factor due to sound card latency for(int i = 0; i < _smplPerSeg; i++) { - outputData[i] = (SFLDataFormat)(((float)micData[i])*_delayLineAmplify[_amplDelayIndexOut]); + outputData[i] = (SFLDataFormat)(((float)micData[i])*_delayLineAmplify[_amplDelayIndexOut]); } + // do not increment amplitude array if adaptation is not done + if (_adaptDone) { + for(int i = 0; i < _smplPerSeg; i++) { + outputData[i] = (SFLDataFormat)(((float)micData[i])*_delayLineAmplify[_amplDelayIndexOut]); + } + } + else { + for(int i = 0; i < _smplPerSeg; i++) { + outputData[i] = micData[i]; + } + return; + } + + _amplDelayIndexOut++; _delayLineAmplify[_amplDelayIndexIn++] = amplify; diff --git a/sflphone-common/src/audio/echocancel.h b/sflphone-common/src/audio/echocancel.h index 204aab32622c13dec5922715bfdb22f342527f91..a06863fa19d7d6e68aab2b8504ffce8b71c03795 100644 --- a/sflphone-common/src/audio/echocancel.h +++ b/sflphone-common/src/audio/echocancel.h @@ -32,7 +32,7 @@ #define SEGMENT_LENGTH 10 // Length of the echo tail in ms -#define ECHO_LENGTH 100 +#define ECHO_LENGTH 50 // Voice level threashold #define MIN_SIG_LEVEL 100 @@ -41,7 +41,7 @@ #define DELAY_AMPLIFY 60 // maximum in segment size (segment are SEGMENT_LENGTH long) -#define MAX_DELAY_LINE_AMPL 100 +#define MAX_DELAY_LINE_AMPL 100 // 1 sec // Internal buffer size #define BUFF_SIZE 10000 @@ -50,8 +50,8 @@ #define DEFAULT_FRAME_LENGTH 20 -#define MIC_ADAPT_SIZE 100 -#define SPKR_ADAPT_SIZE 50 +#define MIC_ADAPT_SIZE 100 // 1 sec +#define SPKR_ADAPT_SIZE 20 // 200 ms class EchoCancel : public Algorithm { @@ -280,6 +280,9 @@ class EchoCancel : public Algorithm { ofstream *echoFile; */ + ofstream *micLearningData; + ofstream *spkrLearningData; + /** * Noise reduction processing state */ diff --git a/sflphone-common/src/audio/pulseaudio/audiostream.cpp b/sflphone-common/src/audio/pulseaudio/audiostream.cpp index 1e10ed4ec0aa06b7dece2c8f126a080223aeefb3..8071844ffd820b96bb98ba3138b056456374caa3 100644 --- a/sflphone-common/src/audio/pulseaudio/audiostream.cpp +++ b/sflphone-common/src/audio/pulseaudio/audiostream.cpp @@ -204,6 +204,7 @@ AudioStream::createStream (pa_context* c, std::string *deviceName) else pa_stream_connect_playback (s , NULL, attributes, (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY|PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL); + pa_threaded_mainloop_unlock(_mainloop); } else if (_streamType == CAPTURE_STREAM) { @@ -218,6 +219,7 @@ AudioStream::createStream (pa_context* c, std::string *deviceName) else pa_stream_connect_record (s, NULL, attributes, (pa_stream_flags_t) (PA_STREAM_ADJUST_LATENCY|PA_STREAM_AUTO_TIMING_UPDATE)); + pa_threaded_mainloop_unlock(_mainloop); } else if (_streamType == RINGTONE_STREAM) { diff --git a/sflphone-common/src/audio/pulseaudio/pulselayer.cpp b/sflphone-common/src/audio/pulseaudio/pulselayer.cpp index 5f9b6cb19366de3c500a0b8416b9cc8cf1a2359d..05ea09ec60082493a698536c9a1537bf4c8013fe 100644 --- a/sflphone-common/src/audio/pulseaudio/pulselayer.cpp +++ b/sflphone-common/src/audio/pulseaudio/pulselayer.cpp @@ -64,6 +64,24 @@ static void pa_success_callback(pa_context *c, int success, void *userdata) { _debug("Audio: Success callback"); } +static void latency_update_callback(pa_stream *p, void *userdata) { + + pa_usec_t r_usec; + pa_buffer_attr *buffattr; + + pa_stream_get_latency (p, &r_usec, NULL); + + // buffattr = pa_stream_get_buffer_attr(p); + + _debug("Audio: Stream letency update %0.0f ms for device %s", (float)r_usec/1000, pa_stream_get_device_name(p)); + // _debug("Audio: maxlength %d", buffattr->maxlength); + // _debug("Audio: tlength %d", buffattr->tlength); + // _debug("Audio: prebug %d", buffattr->prebuf); + // _debug("Audio: minreq %d", buffattr->minreq); + // _debug("Audio: fragsize %d", buffattr->fragsize); + +} + static void sink_input_info_callback(pa_context *c, const pa_sink_info *i, int eol, void *userdata) { char s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; @@ -517,6 +535,7 @@ bool PulseLayer::createStreams (pa_context* c) pa_stream_set_underflow_callback (playback->pulseStream(), playback_underflow_callback, this); // pa_stream_set_suspended_callback(playback->pulseStream(), stream_suspended_callback, this); pa_stream_set_moved_callback(playback->pulseStream(), stream_moved_callback, this); + pa_stream_set_latency_update_callback(playback->pulseStream(), latency_update_callback, this); delete playbackParam; PulseLayerType * recordParam = new PulseLayerType(); @@ -536,6 +555,7 @@ bool PulseLayer::createStreams (pa_context* c) pa_stream_set_read_callback (record->pulseStream() , capture_callback, this); // pa_stream_set_suspended_callback(record->pulseStream(), stream_suspended_callback, this); pa_stream_set_moved_callback(record->pulseStream(), stream_moved_callback, this); + pa_stream_set_latency_update_callback(record->pulseStream(), latency_update_callback, this); delete recordParam; PulseLayerType * ringtoneParam = new PulseLayerType(); @@ -896,8 +916,6 @@ void PulseLayer::readFromMic (void) _warn("Audio: Error capture stream peek failed: %s" , pa_strerror (pa_context_errno (context))); } - _debug("*********************** Read from mic: %d **************************", readableSize); - if (data != 0) { int _mainBufferSampleRate = getMainBuffer()->getInternalSamplingRate(); @@ -925,8 +943,6 @@ void PulseLayer::readFromMic (void) // echo cancellation processing int sampleready = _echoCanceller->processAudio(rsmpl_out, echoCancelledMic, nbSample*sizeof(SFLDataFormat)); - _debug("Read from mic: sampleReady %d", sampleready); - // getMainBuffer()->putData ( (void*) rsmpl_out, nbSample*sizeof (SFLDataFormat), 100); if(sampleready) getMainBuffer()->putData ( echoCancelledMic, sampleready*sizeof (SFLDataFormat), 100); @@ -960,8 +976,6 @@ void PulseLayer::ringtoneToSpeaker(void) int writableSize = pa_stream_writable_size(ringtone->pulseStream()); - _debug("writable size: %d", writableSize); - if (file_tone) { if(ringtone->getStreamState() == PA_STREAM_READY) {