mirror of
https://github.com/danog/libtgvoip.git
synced 2024-12-11 08:39:49 +01:00
5caaaafa42
I'm now using the entire audio processing module from WebRTC as opposed to individual DSP algorithms pulled from there before. Seems to work better this way.
230 lines
6.1 KiB
C++
Executable File
230 lines
6.1 KiB
C++
Executable File
//
|
|
// 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 <string.h>
|
|
#include <stdio.h>
|
|
|
|
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<int16_t*>(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<unsigned char*>(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
|
|
}
|
|
|