1
0
mirror of https://github.com/danog/libtgvoip.git synced 2024-11-26 20:24:38 +01:00
libtgvoip/MediaStreamItf.cpp
Grishka 5caaaafa42 Updated WebRTC APM
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.
2018-11-23 04:02:53 +03:00

210 lines
5.1 KiB
C++

//
// 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.
//
#include "logging.h"
#include "MediaStreamItf.h"
#include "EchoCanceller.h"
#include <stdint.h>
#include <algorithm>
#include <math.h>
#include <assert.h>
using namespace tgvoip;
void MediaStreamItf::SetCallback(size_t (*f)(unsigned char *, size_t, void*), void* param){
callback=f;
callbackParam=param;
}
size_t MediaStreamItf::InvokeCallback(unsigned char *data, size_t length){
if(callback)
return (*callback)(data, length, callbackParam);
return 0;
}
AudioMixer::AudioMixer() : bufferPool(960*2, 16), processedQueue(16), semaphore(16, 0){
running=false;
}
AudioMixer::~AudioMixer(){
}
void AudioMixer::SetOutput(MediaStreamItf* output){
output->SetCallback(OutputCallback, this);
}
void AudioMixer::Start(){
assert(!running);
running=true;
thread=new Thread(std::bind(&AudioMixer::RunThread, this));
thread->SetName("AudioMixer");
thread->Start();
}
void AudioMixer::Stop(){
if(!running){
LOGE("Tried to stop AudioMixer that wasn't started");
return;
}
running=false;
semaphore.Release();
thread->Join();
delete thread;
thread=NULL;
}
void AudioMixer::DoCallback(unsigned char *data, size_t length){
//memset(data, 0, 960*2);
//LOGD("audio mixer callback, %d inputs", inputs.size());
if(processedQueue.Size()==0)
semaphore.Release(2);
else
semaphore.Release();
unsigned char* buf=processedQueue.GetBlocking();
memcpy(data, buf, 960*2);
bufferPool.Reuse(buf);
}
size_t AudioMixer::OutputCallback(unsigned char *data, size_t length, void *arg){
((AudioMixer*)arg)->DoCallback(data, length);
return 960*2;
}
void AudioMixer::AddInput(std::shared_ptr<MediaStreamItf> input){
MutexGuard m(inputsMutex);
MixerInput in;
in.multiplier=1;
in.source=input;
inputs.push_back(in);
}
void AudioMixer::RemoveInput(std::shared_ptr<MediaStreamItf> input){
MutexGuard m(inputsMutex);
for(std::vector<MixerInput>::iterator i=inputs.begin();i!=inputs.end();++i){
if(i->source==input){
inputs.erase(i);
return;
}
}
}
void AudioMixer::SetInputVolume(std::shared_ptr<MediaStreamItf> input, float volumeDB){
MutexGuard m(inputsMutex);
for(std::vector<MixerInput>::iterator i=inputs.begin();i!=inputs.end();++i){
if(i->source==input){
if(volumeDB==-INFINITY)
i->multiplier=0;
else
i->multiplier=expf(volumeDB/20.0f * logf(10.0f));
return;
}
}
}
void AudioMixer::RunThread(){
LOGV("AudioMixer thread started");
while(running){
semaphore.Acquire();
if(!running)
break;
unsigned char* data=bufferPool.Get();
//LOGV("Audio mixer processing a frame");
if(!data){
LOGE("AudioMixer: no buffers left");
continue;
}
MutexGuard m(inputsMutex);
int16_t* buf=reinterpret_cast<int16_t*>(data);
int16_t input[960];
float out[960];
memset(out, 0, 960*4);
int usedInputs=0;
for(std::vector<MixerInput>::iterator in=inputs.begin();in!=inputs.end();++in){
size_t res=in->source->InvokeCallback(reinterpret_cast<unsigned char*>(input), 960*2);
if(!res || in->multiplier==0){
//LOGV("AudioMixer: skipping silent packet");
continue;
}
usedInputs++;
float k=in->multiplier;
if(k!=1){
for(size_t i=0; i<960; i++){
out[i]+=(float)input[i]*k;
}
}else{
for(size_t i=0;i<960;i++){
out[i]+=(float)input[i];
}
}
}
if(usedInputs>0){
for(size_t i=0; i<960; i++){
if(out[i]>32767.0f)
buf[i]=INT16_MAX;
else if(out[i]<-32768.0f)
buf[i]=INT16_MIN;
else
buf[i]=(int16_t)out[i];
}
}else{
memset(data, 0, 960*2);
}
if(echoCanceller)
echoCanceller->SpeakerOutCallback(data, 960*2);
processedQueue.Put(data);
}
LOGI("======== audio mixer thread exiting =========");
}
void AudioMixer::SetEchoCanceller(EchoCanceller *aec){
echoCanceller=aec;
}
AudioLevelMeter::AudioLevelMeter(){
absMax=0;
count=0;
currentLevel=0;
currentLevelFullRange=0;
}
float AudioLevelMeter::GetLevel(){
return currentLevel/9.0f;
}
void AudioLevelMeter::Update(int16_t *samples, size_t count){
// Number of bars on the indicator.
// Note that the number of elements is specified because we are indexing it
// in the range of 0-32
const int8_t permutation[33]={0,1,2,3,4,4,5,5,5,5,6,6,6,6,6,7,7,7,7,8,8,8,9,9,9,9,9,9,9,9,9,9,9};
int16_t absValue=0;
for(unsigned int k=0;k<count;k++){
int16_t absolute=(int16_t)abs(samples[k]);
if (absolute>absValue)
absValue=absolute;
}
if(absValue>absMax)
absMax = absValue;
// Update level approximately 10 times per second
if (this->count++==10){
currentLevelFullRange=absMax;
this->count=0;
// Highest value for a int16_t is 0x7fff = 32767
// Divide with 1000 to get in the range of 0-32 which is the range of
// the permutation vector
int32_t position=absMax/1000;
// Make it less likely that the bar stays at position 0. I.e. only if
// its in the range 0-250 (instead of 0-1000)
/*if ((position==0) && (absMax>250)){
position=1;
}*/
currentLevel=permutation[position];
// Decay the absolute maximum (divide by 4)
absMax >>= 2;
}
}