1
0
mirror of https://github.com/danog/libtgvoip.git synced 2024-12-11 08:39:49 +01:00
libtgvoip/EchoCanceller.cpp

230 lines
6.1 KiB
C++
Raw Normal View History

2017-02-02 17:24:40 +01:00
//
// libtgvoip is free and unencumbered public domain software.
// For more information, see http://unlicense.org or the UNLICENSE file
// you should have received with this source code distribution.
//
#ifndef TGVOIP_NO_DSP
#include "webrtc_dsp/modules/audio_processing/include/audio_processing.h"
#include "webrtc_dsp/api/audio/audio_frame.h"
#endif
2017-02-02 17:24:40 +01:00
#include "EchoCanceller.h"
#include "audio/AudioOutput.h"
#include "audio/AudioInput.h"
2017-02-02 17:24:40 +01:00
#include "logging.h"
#include <string.h>
2017-03-30 16:06:59 +02:00
#include <stdio.h>
2017-02-02 17:24:40 +01:00
using namespace tgvoip;
EchoCanceller::EchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){
#ifndef TGVOIP_NO_DSP
2017-03-30 16:06:59 +02:00
this->enableAEC=enableAEC;
this->enableAGC=enableAGC;
this->enableNS=enableNS;
2018-05-28 01:17:22 +02:00
isOn=true;
2017-02-02 17:24:40 +01:00
webrtc::Config extraConfig;
#ifdef TGVOIP_USE_DESKTOP_DSP
extraConfig.Set(new webrtc::DelayAgnostic(true));
#endif
apm=webrtc::AudioProcessingBuilder().Create(extraConfig);
2017-02-02 17:24:40 +01:00
webrtc::AudioProcessing::Config config;
config.echo_canceller.enabled = enableAEC;
#ifndef TGVOIP_USE_DESKTOP_DSP
config.echo_canceller.mobile_mode = true;
#else
config.echo_canceller.mobile_mode = false;
#endif
config.high_pass_filter.enabled = enableAEC;
config.gain_controller2.enabled = enableAGC;
apm->ApplyConfig(config);
2017-03-30 16:06:59 +02:00
apm->noise_suppression()->set_level(webrtc::NoiseSuppression::Level::kHigh);
apm->noise_suppression()->Enable(enableNS);
if(enableAGC){
apm->gain_control()->set_mode(webrtc::GainControl::Mode::kAdaptiveDigital);
apm->gain_control()->set_target_level_dbfs(9);
2017-03-30 16:06:59 +02:00
}
audioFrame=new webrtc::AudioFrame();
audioFrame->samples_per_channel_=480;
audioFrame->sample_rate_hz_=48000;
audioFrame->num_channels_=1;
farendQueue=new BlockingQueue<int16_t*>(11);
farendBufferPool=new BufferPool(960*2, 10);
running=true;
bufferFarendThread=new Thread(std::bind(&EchoCanceller::RunBufferFarendThread, this));
bufferFarendThread->Start();
2017-02-02 17:24:40 +01:00
#else
this->enableAEC=this->enableAGC=enableAGC=this->enableNS=enableNS=false;
isOn=true;
#endif
2017-02-02 17:24:40 +01:00
}
EchoCanceller::~EchoCanceller(){
#ifndef TGVOIP_NO_DSP
delete apm;
delete audioFrame;
#endif
2017-02-02 17:24:40 +01:00
}
void EchoCanceller::Start(){
2017-02-02 17:24:40 +01:00
}
void EchoCanceller::Stop(){
2017-02-02 17:24:40 +01:00
}
void EchoCanceller::SpeakerOutCallback(unsigned char* data, size_t len){
2018-05-28 01:17:22 +02:00
if(len!=960*2 || !enableAEC || !isOn)
2017-02-02 17:24:40 +01:00
return;
#ifndef TGVOIP_NO_DSP
int16_t* buf=(int16_t*)farendBufferPool->Get();
2017-02-02 17:24:40 +01:00
if(buf){
memcpy(buf, data, 960*2);
farendQueue->Put(buf);
}
#endif
2017-02-02 17:24:40 +01:00
}
#ifndef TGVOIP_NO_DSP
void EchoCanceller::RunBufferFarendThread(){
webrtc::AudioFrame frame;
frame.num_channels_=1;
frame.sample_rate_hz_=48000;
frame.samples_per_channel_=480;
2017-02-02 17:24:40 +01:00
while(running){
int16_t* samplesIn=farendQueue->GetBlocking();
2017-02-02 17:24:40 +01:00
if(samplesIn){
memcpy(frame.mutable_data(), samplesIn, 480*2);
apm->ProcessReverseStream(&frame);
memcpy(frame.mutable_data(), samplesIn+480, 480*2);
apm->ProcessReverseStream(&frame);
2017-02-02 17:24:40 +01:00
didBufferFarend=true;
farendBufferPool->Reuse(reinterpret_cast<unsigned char*>(samplesIn));
2017-02-02 17:24:40 +01:00
}
}
}
#endif
2017-02-02 17:24:40 +01:00
void EchoCanceller::Enable(bool enabled){
2018-05-28 01:17:22 +02:00
isOn=enabled;
2017-02-02 17:24:40 +01:00
}
void EchoCanceller::ProcessInput(int16_t* inOut, size_t numSamples){
2018-05-28 01:17:22 +02:00
if(!isOn || (!enableAEC && !enableAGC && !enableNS)){
2017-02-02 17:24:40 +01:00
return;
}
int delay=audio::AudioInput::GetEstimatedDelay()+audio::AudioOutput::GetEstimatedDelay();
assert(numSamples==960);
memcpy(audioFrame->mutable_data(), inOut, 480*2);
apm->set_stream_delay_ms(delay);
apm->ProcessStream(audioFrame);
memcpy(inOut, audioFrame->data(), 480*2);
memcpy(audioFrame->mutable_data(), inOut+480, 480*2);
apm->set_stream_delay_ms(delay);
apm->ProcessStream(audioFrame);
memcpy(inOut+480, audioFrame->data(), 480*2);
2017-02-02 17:24:40 +01:00
}
2017-12-27 18:25:47 +01:00
void EchoCanceller::SetAECStrength(int strength){
#ifndef TGVOIP_NO_DSP
/*if(aec){
2017-12-27 18:25:47 +01:00
#ifndef TGVOIP_USE_DESKTOP_DSP
AecmConfig cfg;
cfg.cngMode=AecmFalse;
cfg.echoMode=(int16_t) strength;
WebRtcAecm_set_config(aec, cfg);
#endif
}*/
#endif
2017-12-27 18:25:47 +01:00
}
AudioEffect::~AudioEffect(){
}
void AudioEffect::SetPassThrough(bool passThrough){
this->passThrough=passThrough;
}
AutomaticGainControl::AutomaticGainControl(){
#ifndef TGVOIP_NO_DSP
/*splittingFilter=new webrtc::SplittingFilter(1, 3, 960);
splittingFilterIn=new webrtc::IFChannelBuffer(960, 1, 1);
splittingFilterOut=new webrtc::IFChannelBuffer(960, 1, 3);
agc=WebRtcAgc_Create();
WebRtcAgcConfig agcConfig;
agcConfig.compressionGaindB = 9;
agcConfig.limiterEnable = 1;
agcConfig.targetLevelDbfs = 3;
WebRtcAgc_Init(agc, 0, 255, kAgcModeAdaptiveDigital, 48000);
WebRtcAgc_set_config(agc, agcConfig);
agcMicLevel=0;*/
#endif
}
AutomaticGainControl::~AutomaticGainControl(){
#ifndef TGVOIP_NO_DSP
/*delete (webrtc::SplittingFilter*)splittingFilter;
delete (webrtc::IFChannelBuffer*)splittingFilterIn;
delete (webrtc::IFChannelBuffer*)splittingFilterOut;
WebRtcAgc_Free(agc);*/
#endif
}
void AutomaticGainControl::Process(int16_t *inOut, size_t numSamples){
#ifndef TGVOIP_NO_DSP
/*if(passThrough)
return;
if(numSamples!=960){
2017-11-23 16:40:06 +01:00
LOGW("AutomaticGainControl only works on 960-sample buffers (got %u samples)", (unsigned int)numSamples);
return;
}
//LOGV("processing frame through AGC");
webrtc::IFChannelBuffer* bufIn=(webrtc::IFChannelBuffer*) splittingFilterIn;
webrtc::IFChannelBuffer* bufOut=(webrtc::IFChannelBuffer*) splittingFilterOut;
memcpy(bufIn->ibuf()->bands(0)[0], inOut, 960*2);
((webrtc::SplittingFilter*)splittingFilter)->Analysis(bufIn, bufOut);
int i;
int16_t _agcOut[3][320];
int16_t* agcIn[3];
int16_t* agcOut[3];
for(i=0;i<3;i++){
agcIn[i]=(int16_t*)bufOut->ibuf_const()->bands(0)[i];
agcOut[i]=_agcOut[i];
}
uint8_t saturation;
WebRtcAgc_AddMic(agc, agcIn, 3, 160);
WebRtcAgc_Process(agc, (const int16_t *const *) agcIn, 3, 160, agcOut, agcMicLevel, &agcMicLevel, 0, &saturation);
for(i=0;i<3;i++){
agcOut[i]+=160;
agcIn[i]+=160;
}
WebRtcAgc_AddMic(agc, agcIn, 3, 160);
WebRtcAgc_Process(agc, (const int16_t *const *) agcIn, 3, 160, agcOut, agcMicLevel, &agcMicLevel, 0, &saturation);
memcpy(bufOut->ibuf()->bands(0)[0], _agcOut[0], 320*2);
memcpy(bufOut->ibuf()->bands(0)[1], _agcOut[1], 320*2);
memcpy(bufOut->ibuf()->bands(0)[2], _agcOut[2], 320*2);
((webrtc::SplittingFilter*)splittingFilter)->Synthesis(bufOut, bufIn);
memcpy(inOut, bufIn->ibuf_const()->bands(0)[0], 960*2);*/
#endif
}