1
0
mirror of https://github.com/danog/libtgvoip.git synced 2024-12-11 16:49:52 +01:00
libtgvoip/OpusEncoder.cpp

266 lines
7.6 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.
//
#include "OpusEncoder.h"
#include <assert.h>
2018-12-31 02:05:58 +01:00
#include <algorithm>
2017-02-02 17:24:40 +01:00
#include "logging.h"
2017-03-30 16:06:59 +02:00
#include "VoIPServerConfig.h"
2019-11-18 09:44:18 +01:00
#if defined HAVE_CONFIG_H || defined TGVOIP_USE_INSTALLED_OPUS
#include <opus/opus.h>
#else
2020-01-18 15:36:59 +01:00
#include "opus.h"
#endif
2017-02-02 17:24:40 +01:00
namespace{
int serverConfigValueToBandwidth(int config){
switch(config){
case 0:
return OPUS_BANDWIDTH_NARROWBAND;
case 1:
return OPUS_BANDWIDTH_MEDIUMBAND;
case 2:
return OPUS_BANDWIDTH_WIDEBAND;
case 3:
return OPUS_BANDWIDTH_SUPERWIDEBAND;
case 4:
default:
return OPUS_BANDWIDTH_FULLBAND;
}
}
}
tgvoip::OpusEncoder::OpusEncoder(MediaStreamItf *source, bool needSecondary):queue(10){
2017-02-02 17:24:40 +01:00
this->source=source;
source->SetCallback(tgvoip::OpusEncoder::Callback, this);
2017-02-02 17:24:40 +01:00
enc=opus_encoder_create(48000, 1, OPUS_APPLICATION_VOIP, NULL);
opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10));
opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(1));
2017-02-02 17:24:40 +01:00
opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1));
opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
2019-04-24 18:36:32 +02:00
opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO));
2018-11-30 13:39:31 +01:00
requestedBitrate=20000;
2017-02-02 17:24:40 +01:00
currentBitrate=0;
running=false;
echoCanceller=NULL;
complexity=10;
frameDuration=20;
2018-05-15 20:23:46 +02:00
levelMeter=NULL;
2018-11-30 13:39:31 +01:00
vadNoVoiceBitrate=static_cast<uint32_t>(ServerConfig::GetSharedInstance()->GetInt("audio_vad_no_voice_bitrate", 6000));
vadModeVoiceBandwidth=serverConfigValueToBandwidth(ServerConfig::GetSharedInstance()->GetInt("audio_vad_bandwidth", 3));
vadModeNoVoiceBandwidth=serverConfigValueToBandwidth(ServerConfig::GetSharedInstance()->GetInt("audio_vad_no_voice_bandwidth", 0));
secondaryEnabledBandwidth=serverConfigValueToBandwidth(ServerConfig::GetSharedInstance()->GetInt("audio_extra_ec_bandwidth", 2));
2018-06-04 21:37:43 +02:00
secondaryEncoderEnabled=false;
if(needSecondary){
secondaryEncoder=opus_encoder_create(48000, 1, OPUS_APPLICATION_VOIP, NULL);
opus_encoder_ctl(secondaryEncoder, OPUS_SET_COMPLEXITY(10));
opus_encoder_ctl(secondaryEncoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
opus_encoder_ctl(secondaryEncoder, OPUS_SET_BITRATE(8000));
}else{
secondaryEncoder=NULL;
}
2017-02-02 17:24:40 +01:00
}
tgvoip::OpusEncoder::~OpusEncoder(){
2017-02-02 17:24:40 +01:00
opus_encoder_destroy(enc);
2018-06-04 21:37:43 +02:00
if(secondaryEncoder)
opus_encoder_destroy(secondaryEncoder);
2017-02-02 17:24:40 +01:00
}
void tgvoip::OpusEncoder::Start(){
2017-02-02 17:24:40 +01:00
if(running)
return;
running=true;
thread=new Thread(std::bind(&tgvoip::OpusEncoder::RunThread, this));
2018-05-15 20:23:46 +02:00
thread->SetName("OpusEncoder");
thread->SetMaxPriority();
thread->Start();
2017-02-02 17:24:40 +01:00
}
void tgvoip::OpusEncoder::Stop(){
2017-02-02 17:24:40 +01:00
if(!running)
return;
running=false;
queue.Put(Buffer());
2018-05-15 20:23:46 +02:00
thread->Join();
delete thread;
2017-02-02 17:24:40 +01:00
}
void tgvoip::OpusEncoder::SetBitrate(uint32_t bitrate){
2017-02-02 17:24:40 +01:00
requestedBitrate=bitrate;
}
void tgvoip::OpusEncoder::Encode(int16_t* data, size_t len){
2017-02-02 17:24:40 +01:00
if(requestedBitrate!=currentBitrate){
opus_encoder_ctl(enc, OPUS_SET_BITRATE(requestedBitrate));
currentBitrate=requestedBitrate;
LOGV("opus_encoder: setting bitrate to %u", currentBitrate);
}
2018-05-15 20:23:46 +02:00
if(levelMeter)
levelMeter->Update(data, len);
if(secondaryEncoderEnabled!=wasSecondaryEncoderEnabled){
wasSecondaryEncoderEnabled=secondaryEncoderEnabled;
}
int32_t r=opus_encode(enc, data, static_cast<int>(len), buffer, 4096);
2019-04-24 18:36:32 +02:00
// int bw;
// opus_encoder_ctl(enc, OPUS_GET_BANDWIDTH(&bw));
// LOGV("Opus bandwidth: %d", bw);
2017-02-02 17:24:40 +01:00
if(r<=0){
LOGE("Error encoding: %d", r);
}else if(r==1){
LOGW("DTX");
}else if(running){
//LOGV("Packet size = %d", r);
2018-06-04 21:37:43 +02:00
int32_t secondaryLen=0;
unsigned char secondaryBuffer[128];
if(secondaryEncoderEnabled && secondaryEncoder){
secondaryLen=opus_encode(secondaryEncoder, data, static_cast<int>(len), secondaryBuffer, sizeof(secondaryBuffer));
2018-06-04 21:37:43 +02:00
//LOGV("secondaryLen %d", secondaryLen);
}
InvokeCallback(buffer, (size_t)r, secondaryBuffer, (size_t)secondaryLen);
2017-02-02 17:24:40 +01:00
}
}
size_t tgvoip::OpusEncoder::Callback(unsigned char *data, size_t len, void* param){
assert(len==960*2);
OpusEncoder* e=(OpusEncoder*)param;
try{
Buffer buf=e->bufferPool.Get();
buf.CopyFrom(data, 0, 960*2);
e->queue.Put(std::move(buf));
}catch(std::bad_alloc& x){
2017-02-02 17:24:40 +01:00
LOGW("opus_encoder: no buffer slots left");
if(e->complexity>1){
e->complexity--;
opus_encoder_ctl(e->enc, OPUS_SET_COMPLEXITY(e->complexity));
}
}
return 0;
}
uint32_t tgvoip::OpusEncoder::GetBitrate(){
2017-02-02 17:24:40 +01:00
return requestedBitrate;
}
void tgvoip::OpusEncoder::SetEchoCanceller(EchoCanceller* aec){
2017-02-02 17:24:40 +01:00
echoCanceller=aec;
}
void tgvoip::OpusEncoder::RunThread(){
2017-02-02 17:24:40 +01:00
uint32_t bufferedCount=0;
uint32_t packetsPerFrame=frameDuration/20;
LOGV("starting encoder, packets per frame=%d", packetsPerFrame);
int16_t* frame;
2017-02-02 17:24:40 +01:00
if(packetsPerFrame>1)
frame=(int16_t*) malloc(960*2*packetsPerFrame);
2017-02-02 17:24:40 +01:00
else
frame=NULL;
2018-11-30 13:39:31 +01:00
bool frameHasVoice=false;
bool wasVadMode=false;
2017-02-02 17:24:40 +01:00
while(running){
Buffer _packet=queue.GetBlocking();
if(!_packet.IsEmpty()){
int16_t* packet=(int16_t*)*_packet;
2018-11-30 13:39:31 +01:00
bool hasVoice=true;
2017-02-02 17:24:40 +01:00
if(echoCanceller)
2018-11-30 13:39:31 +01:00
echoCanceller->ProcessInput(packet, 960, hasVoice);
if(!postProcEffects.empty()){
for(effects::AudioEffect* effect:postProcEffects){
effect->Process(packet, 960);
}
}
2017-02-02 17:24:40 +01:00
if(packetsPerFrame==1){
Encode(packet, 960);
2017-02-02 17:24:40 +01:00
}else{
memcpy(frame+(960*bufferedCount), packet, 960*2);
2018-11-30 13:39:31 +01:00
frameHasVoice=frameHasVoice || hasVoice;
2017-02-02 17:24:40 +01:00
bufferedCount++;
if(bufferedCount==packetsPerFrame){
2018-11-30 13:39:31 +01:00
if(vadMode){
if(frameHasVoice){
opus_encoder_ctl(enc, OPUS_SET_BITRATE(currentBitrate));
if(secondaryEncoder){
opus_encoder_ctl(secondaryEncoder, OPUS_SET_BITRATE(currentBitrate));
}
}else{
opus_encoder_ctl(enc, OPUS_SET_BITRATE(vadNoVoiceBitrate));
if(secondaryEncoder){
opus_encoder_ctl(secondaryEncoder, OPUS_SET_BITRATE(vadNoVoiceBitrate));
}
}
wasVadMode=true;
}else if(wasVadMode){
wasVadMode=false;
opus_encoder_ctl(enc, OPUS_SET_BITRATE(currentBitrate));
if(secondaryEncoder){
opus_encoder_ctl(secondaryEncoder, OPUS_SET_BITRATE(currentBitrate));
}
}
Encode(frame, 960*packetsPerFrame);
2017-02-02 17:24:40 +01:00
bufferedCount=0;
2018-11-30 13:39:31 +01:00
frameHasVoice=false;
2017-02-02 17:24:40 +01:00
}
}
}else{
break;
2017-02-02 17:24:40 +01:00
}
}
if(frame)
free(frame);
}
void tgvoip::OpusEncoder::SetOutputFrameDuration(uint32_t duration){
2017-02-02 17:24:40 +01:00
frameDuration=duration;
}
void tgvoip::OpusEncoder::SetPacketLoss(int percent){
2018-11-30 13:39:31 +01:00
packetLossPercent=std::min(20, percent);
opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packetLossPercent));
opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(percent>0 && !secondaryEncoderEnabled ? 1 : 0));
2017-03-30 16:06:59 +02:00
}
int tgvoip::OpusEncoder::GetPacketLoss(){
2017-03-30 16:06:59 +02:00
return packetLossPercent;
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
void tgvoip::OpusEncoder::SetDTX(bool enable){
opus_encoder_ctl(enc, OPUS_SET_DTX(enable ? 1 : 0));
}
void tgvoip::OpusEncoder::SetLevelMeter(tgvoip::AudioLevelMeter *levelMeter){
this->levelMeter=levelMeter;
}
2018-06-04 21:37:43 +02:00
void tgvoip::OpusEncoder::SetCallback(std::function <void(unsigned char*, size_t, unsigned char*, size_t)> f){
2018-06-04 21:37:43 +02:00
callback=f;
}
void tgvoip::OpusEncoder::InvokeCallback(unsigned char *data, size_t length, unsigned char *secondaryData, size_t secondaryLength){
callback(data, length, secondaryData, secondaryLength);
2018-06-04 21:37:43 +02:00
}
void tgvoip::OpusEncoder::SetSecondaryEncoderEnabled(bool enabled){
secondaryEncoderEnabled=enabled;
}
2018-11-30 13:39:31 +01:00
void tgvoip::OpusEncoder::SetVadMode(bool vad){
vadMode=vad;
}
void tgvoip::OpusEncoder::AddAudioEffect(effects::AudioEffect *effect){
postProcEffects.push_back(effect);
}
void tgvoip::OpusEncoder::RemoveAudioEffect(effects::AudioEffect *effect){
std::vector<effects::AudioEffect*>::iterator i=std::find(postProcEffects.begin(), postProcEffects.end(), effect);
if(i!=postProcEffects.end())
postProcEffects.erase(i);
}