// // 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 #include "EchoCanceller.h" #include "audio/AudioOutput.h" #include "audio/AudioInput.h" #include "logging.h" #include #include using namespace tgvoip; EchoCanceller::EchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){ #ifndef TGVOIP_NO_DSP this->enableAEC=enableAEC; this->enableAGC=enableAGC; this->enableNS=enableNS; isOn=true; webrtc::Config extraConfig; #ifdef TGVOIP_USE_DESKTOP_DSP extraConfig.Set(new webrtc::DelayAgnostic(true)); #endif apm=webrtc::AudioProcessingBuilder().Create(extraConfig); 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); 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); } audioFrame=new webrtc::AudioFrame(); audioFrame->samples_per_channel_=480; audioFrame->sample_rate_hz_=48000; audioFrame->num_channels_=1; farendQueue=new BlockingQueue(11); farendBufferPool=new BufferPool(960*2, 10); running=true; bufferFarendThread=new Thread(std::bind(&EchoCanceller::RunBufferFarendThread, this)); bufferFarendThread->Start(); #else this->enableAEC=this->enableAGC=enableAGC=this->enableNS=enableNS=false; isOn=true; #endif } EchoCanceller::~EchoCanceller(){ #ifndef TGVOIP_NO_DSP delete apm; delete audioFrame; #endif } void EchoCanceller::Start(){ } void EchoCanceller::Stop(){ } void EchoCanceller::SpeakerOutCallback(unsigned char* data, size_t len){ if(len!=960*2 || !enableAEC || !isOn) return; #ifndef TGVOIP_NO_DSP int16_t* buf=(int16_t*)farendBufferPool->Get(); if(buf){ memcpy(buf, data, 960*2); farendQueue->Put(buf); } #endif } #ifndef TGVOIP_NO_DSP void EchoCanceller::RunBufferFarendThread(){ webrtc::AudioFrame frame; frame.num_channels_=1; frame.sample_rate_hz_=48000; frame.samples_per_channel_=480; while(running){ int16_t* samplesIn=farendQueue->GetBlocking(); if(samplesIn){ memcpy(frame.mutable_data(), samplesIn, 480*2); apm->ProcessReverseStream(&frame); memcpy(frame.mutable_data(), samplesIn+480, 480*2); apm->ProcessReverseStream(&frame); didBufferFarend=true; farendBufferPool->Reuse(reinterpret_cast(samplesIn)); } } } #endif void EchoCanceller::Enable(bool enabled){ isOn=enabled; } void EchoCanceller::ProcessInput(int16_t* inOut, size_t numSamples){ if(!isOn || (!enableAEC && !enableAGC && !enableNS)){ 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); } void EchoCanceller::SetAECStrength(int strength){ #ifndef TGVOIP_NO_DSP /*if(aec){ #ifndef TGVOIP_USE_DESKTOP_DSP AecmConfig cfg; cfg.cngMode=AecmFalse; cfg.echoMode=(int16_t) strength; WebRtcAecm_set_config(aec, cfg); #endif }*/ #endif } 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){ 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 }