mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-30 01:11:46 +00:00
2.0-alpha4
This commit is contained in:
parent
a3feec022c
commit
b52eb581fa
@ -21,12 +21,10 @@ public:
|
||||
BlockingQueue(size_t capacity) : semaphore(capacity, 0){
|
||||
this->capacity=capacity;
|
||||
overflowCallback=NULL;
|
||||
init_mutex(mutex);
|
||||
};
|
||||
|
||||
~BlockingQueue(){
|
||||
semaphore.Release();
|
||||
free_mutex(mutex);
|
||||
}
|
||||
|
||||
void Put(T thing){
|
||||
@ -86,7 +84,7 @@ private:
|
||||
size_t capacity;
|
||||
//tgvoip_lock_t lock;
|
||||
Semaphore semaphore;
|
||||
tgvoip_mutex_t mutex;
|
||||
Mutex mutex;
|
||||
void (*overflowCallback)(T);
|
||||
};
|
||||
}
|
||||
|
@ -98,6 +98,13 @@ void BufferInputStream::ReadBytes(unsigned char *to, size_t count){
|
||||
offset+=count;
|
||||
}
|
||||
|
||||
BufferInputStream BufferInputStream::GetPartBuffer(size_t length, bool advance){
|
||||
EnsureEnoughRemaining(length);
|
||||
BufferInputStream s=BufferInputStream(buffer+offset, length);
|
||||
if(advance)
|
||||
offset+=length;
|
||||
return s;
|
||||
}
|
||||
|
||||
void BufferInputStream::EnsureEnoughRemaining(size_t need){
|
||||
if(length-offset<need){
|
||||
|
@ -26,6 +26,7 @@ public:
|
||||
int16_t ReadInt16();
|
||||
int32_t ReadTlLength();
|
||||
void ReadBytes(unsigned char* to, size_t count);
|
||||
BufferInputStream GetPartBuffer(size_t length, bool advance);
|
||||
|
||||
private:
|
||||
void EnsureEnoughRemaining(size_t need);
|
||||
|
@ -97,3 +97,8 @@ void BufferOutputStream::Reset(){
|
||||
offset=0;
|
||||
}
|
||||
|
||||
void BufferOutputStream::Rewind(size_t numBytes){
|
||||
if(numBytes>offset)
|
||||
throw std::out_of_range("buffer underflow");
|
||||
offset-=numBytes;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ public:
|
||||
unsigned char* GetBuffer();
|
||||
size_t GetLength();
|
||||
void Reset();
|
||||
void Rewind(size_t numBytes);
|
||||
|
||||
private:
|
||||
void ExpandBufferIfNeeded(size_t need);
|
||||
|
@ -13,10 +13,9 @@ using namespace tgvoip;
|
||||
|
||||
BufferPool::BufferPool(unsigned int size, unsigned int count){
|
||||
assert(count<=64);
|
||||
init_mutex(mutex);
|
||||
buffers[0]=(unsigned char*) malloc(size*count);
|
||||
bufferCount=count;
|
||||
int i;
|
||||
unsigned int i;
|
||||
for(i=1;i<count;i++){
|
||||
buffers[i]=buffers[0]+i*size;
|
||||
}
|
||||
@ -25,31 +24,27 @@ BufferPool::BufferPool(unsigned int size, unsigned int count){
|
||||
}
|
||||
|
||||
BufferPool::~BufferPool(){
|
||||
free_mutex(mutex);
|
||||
free(buffers[0]);
|
||||
}
|
||||
|
||||
unsigned char* BufferPool::Get(){
|
||||
lock_mutex(mutex);
|
||||
MutexGuard m(mutex);
|
||||
int i;
|
||||
for(i=0;i<bufferCount;i++){
|
||||
if(!((usedBuffers >> i) & 1)){
|
||||
usedBuffers|=(1LL << i);
|
||||
unlock_mutex(mutex);
|
||||
return buffers[i];
|
||||
}
|
||||
}
|
||||
unlock_mutex(mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void BufferPool::Reuse(unsigned char* buffer){
|
||||
lock_mutex(mutex);
|
||||
MutexGuard m(mutex);
|
||||
int i;
|
||||
for(i=0;i<bufferCount;i++){
|
||||
if(buffers[i]==buffer){
|
||||
usedBuffers&= ~(1LL << i);
|
||||
unlock_mutex(mutex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ private:
|
||||
int bufferCount;
|
||||
size_t size;
|
||||
unsigned char* buffers[64];
|
||||
tgvoip_mutex_t mutex;
|
||||
Mutex mutex;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -30,11 +30,9 @@ CongestionControl::CongestionControl(){
|
||||
inflightDataSize=0;
|
||||
lossCount=0;
|
||||
cwnd=(size_t) ServerConfig::GetSharedInstance()->GetInt("audio_congestion_window", 1024);
|
||||
init_mutex(mutex);
|
||||
}
|
||||
|
||||
CongestionControl::~CongestionControl(){
|
||||
free_mutex(mutex);
|
||||
}
|
||||
|
||||
size_t CongestionControl::GetAcknowledgedDataSize(){
|
||||
|
@ -64,7 +64,7 @@ private:
|
||||
uint32_t tickCount;
|
||||
size_t inflightDataSize;
|
||||
size_t cwnd;
|
||||
tgvoip_mutex_t mutex;
|
||||
Mutex mutex;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,6 @@ EchoCanceller::EchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){
|
||||
splittingFilterFarendOut=new webrtc::IFChannelBuffer(960, 1, 3);
|
||||
|
||||
if(enableAEC){
|
||||
init_mutex(aecMutex);
|
||||
#ifndef TGVOIP_USE_DESKTOP_DSP
|
||||
aec=WebRtcAecm_Create();
|
||||
WebRtcAecm_Init(aec, 16000);
|
||||
@ -79,7 +78,8 @@ EchoCanceller::EchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){
|
||||
farendBufferPool=new BufferPool(960*2, 10);
|
||||
running=true;
|
||||
|
||||
start_thread(bufferFarendThread, EchoCanceller::StartBufferFarendThread, this);
|
||||
bufferFarendThread=new Thread(new MethodPointer<EchoCanceller>(&EchoCanceller::RunBufferFarendThread, this), NULL);
|
||||
bufferFarendThread->Start();
|
||||
}else{
|
||||
aec=NULL;
|
||||
}
|
||||
@ -117,7 +117,8 @@ EchoCanceller::~EchoCanceller(){
|
||||
if(enableAEC){
|
||||
running=false;
|
||||
farendQueue->Put(NULL);
|
||||
join_thread(bufferFarendThread);
|
||||
bufferFarendThread->Join();
|
||||
delete bufferFarendThread;
|
||||
delete farendQueue;
|
||||
delete farendBufferPool;
|
||||
#ifndef TGVOIP_USE_DESKTOP_DSP
|
||||
@ -145,10 +146,6 @@ EchoCanceller::~EchoCanceller(){
|
||||
delete (webrtc::IFChannelBuffer*)splittingFilterOut;
|
||||
delete (webrtc::IFChannelBuffer*)splittingFilterFarendIn;
|
||||
delete (webrtc::IFChannelBuffer*)splittingFilterFarendOut;
|
||||
|
||||
if (this->enableAEC) {
|
||||
free_mutex(aecMutex);
|
||||
}
|
||||
}
|
||||
|
||||
void EchoCanceller::Start(){
|
||||
@ -175,12 +172,7 @@ void EchoCanceller::SpeakerOutCallback(unsigned char* data, size_t len){
|
||||
}
|
||||
}
|
||||
|
||||
void *EchoCanceller::StartBufferFarendThread(void *arg){
|
||||
((EchoCanceller*)arg)->RunBufferFarendThread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void EchoCanceller::RunBufferFarendThread(){
|
||||
void EchoCanceller::RunBufferFarendThread(void* arg){
|
||||
while(running){
|
||||
int16_t* samplesIn=farendQueue->GetBlocking();
|
||||
if(samplesIn){
|
||||
@ -189,7 +181,7 @@ void EchoCanceller::RunBufferFarendThread(){
|
||||
memcpy(bufIn->ibuf()->bands(0)[0], samplesIn, 960*2);
|
||||
farendBufferPool->Reuse((unsigned char *) samplesIn);
|
||||
((webrtc::SplittingFilter*)splittingFilterFarend)->Analysis(bufIn, bufOut);
|
||||
lock_mutex(aecMutex);
|
||||
aecMutex.Lock();
|
||||
#ifndef TGVOIP_USE_DESKTOP_DSP
|
||||
WebRtcAecm_BufferFarend(aec, bufOut->ibuf_const()->bands(0)[0], 160);
|
||||
WebRtcAecm_BufferFarend(aec, bufOut->ibuf_const()->bands(0)[0]+160, 160);
|
||||
@ -197,7 +189,7 @@ void EchoCanceller::RunBufferFarendThread(){
|
||||
webrtc::WebRtcAec_BufferFarend(aec, bufOut->fbuf_const()->bands(0)[0], 160);
|
||||
webrtc::WebRtcAec_BufferFarend(aec, bufOut->fbuf_const()->bands(0)[0]+160, 160);
|
||||
#endif
|
||||
unlock_mutex(aecMutex);
|
||||
aecMutex.Unlock();
|
||||
didBufferFarend=true;
|
||||
}
|
||||
}
|
||||
@ -241,16 +233,16 @@ void EchoCanceller::ProcessInput(unsigned char* data, unsigned char* out, size_t
|
||||
|
||||
memcpy(bufOut->ibuf()->bands(0)[1], _nsOut[1], 320*2*2);
|
||||
|
||||
lock_mutex(aecMutex);
|
||||
aecMutex.Lock();
|
||||
WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0], _nsOut[0], samplesOut, AEC_FRAME_SIZE, (int16_t) tgvoip::audio::AudioOutput::GetEstimatedDelay());
|
||||
WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0]+160, _nsOut[0]+160, samplesOut+160, AEC_FRAME_SIZE, (int16_t) (tgvoip::audio::AudioOutput::GetEstimatedDelay()+audio::AudioInput::GetEstimatedDelay()));
|
||||
unlock_mutex(aecMutex);
|
||||
aecMutex.Unlock();
|
||||
memcpy(bufOut->ibuf()->bands(0)[0], samplesOut, 320*2);
|
||||
}else if(enableAEC){
|
||||
lock_mutex(aecMutex);
|
||||
aecMutex.Lock();
|
||||
WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0], NULL, samplesOut, AEC_FRAME_SIZE, (int16_t) tgvoip::audio::AudioOutput::GetEstimatedDelay());
|
||||
WebRtcAecm_Process(aec, bufOut->ibuf()->bands(0)[0]+160, NULL, samplesOut+160, AEC_FRAME_SIZE, (int16_t) (tgvoip::audio::AudioOutput::GetEstimatedDelay()+audio::AudioInput::GetEstimatedDelay()));
|
||||
unlock_mutex(aecMutex);
|
||||
aecMutex.Unlock();
|
||||
memcpy(bufOut->ibuf()->bands(0)[0], samplesOut, 320*2);
|
||||
}else if(enableNS){
|
||||
int16_t _nsOut[3][320];
|
||||
|
@ -30,10 +30,9 @@ private:
|
||||
bool enableAGC;
|
||||
bool enableNS;
|
||||
#ifndef TGVOIP_NO_DSP
|
||||
static void* StartBufferFarendThread(void* arg);
|
||||
void RunBufferFarendThread();
|
||||
void RunBufferFarendThread(void* arg);
|
||||
bool didBufferFarend;
|
||||
tgvoip_mutex_t aecMutex;
|
||||
Mutex aecMutex;
|
||||
void* aec;
|
||||
void* splittingFilter; // webrtc::SplittingFilter
|
||||
void* splittingFilterIn; // webrtc::IFChannelBuffer
|
||||
@ -41,7 +40,7 @@ private:
|
||||
void* splittingFilterFarend; // webrtc::SplittingFilter
|
||||
void* splittingFilterFarendIn; // webrtc::IFChannelBuffer
|
||||
void* splittingFilterFarendOut; // webrtc::IFChannelBuffer
|
||||
tgvoip_thread_t bufferFarendThread;
|
||||
Thread* bufferFarendThread;
|
||||
BlockingQueue<int16_t*>* farendQueue;
|
||||
BufferPool* farendBufferPool;
|
||||
bool running;
|
||||
|
@ -40,15 +40,22 @@ JitterBuffer::JitterBuffer(MediaStreamItf *out, uint32_t step):bufferPool(JITTER
|
||||
}
|
||||
lossesToReset=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_losses_to_reset", 20);
|
||||
resyncThreshold=ServerConfig::GetSharedInstance()->GetDouble("jitter_resync_threshold", 1.0);
|
||||
//dump=fopen("/sdcard/tgvoip_jitter_dump.txt", "a");
|
||||
//fprintf(dump, "==================================\n");
|
||||
#ifdef TGVOIP_DUMP_JITTER_STATS
|
||||
#ifdef TGVOIP_JITTER_DUMP_FILE
|
||||
dump=fopen(TGVOIP_JITTER_DUMP_FILE, "w");
|
||||
#elif defined(__ANDROID__)
|
||||
dump=fopen("/sdcard/tgvoip_jitter_dump.txt", "w");
|
||||
#else
|
||||
dump=fopen("tgvoip_jitter_dump.txt", "w");
|
||||
#endif
|
||||
tgvoip_log_file_write_header(dump);
|
||||
fprintf(dump, "PTS\tRTS\tNumInBuf\tAJitter\tADelay\tTDelay\n");
|
||||
#endif
|
||||
Reset();
|
||||
init_mutex(mutex);
|
||||
}
|
||||
|
||||
JitterBuffer::~JitterBuffer(){
|
||||
Reset();
|
||||
free_mutex(mutex);
|
||||
}
|
||||
|
||||
void JitterBuffer::SetMinPacketCount(uint32_t count){
|
||||
@ -76,9 +83,9 @@ void JitterBuffer::HandleInput(unsigned char *data, size_t len, uint32_t timesta
|
||||
pkt.size=len;
|
||||
pkt.buffer=data;
|
||||
pkt.timestamp=timestamp;
|
||||
lock_mutex(mutex);
|
||||
mutex.Lock();
|
||||
PutInternal(&pkt);
|
||||
unlock_mutex(mutex);
|
||||
mutex.Unlock();
|
||||
//LOGV("in, ts=%d", timestamp);
|
||||
}
|
||||
|
||||
@ -106,12 +113,12 @@ void JitterBuffer::Reset(){
|
||||
}
|
||||
|
||||
|
||||
size_t JitterBuffer::HandleOutput(unsigned char *buffer, size_t len, int offsetInSteps, int* playbackScaledDuration){
|
||||
size_t JitterBuffer::HandleOutput(unsigned char *buffer, size_t len, int offsetInSteps, bool advance, int* playbackScaledDuration){
|
||||
jitter_packet_t pkt;
|
||||
pkt.buffer=buffer;
|
||||
pkt.size=len;
|
||||
lock_mutex(mutex);
|
||||
int result=GetInternal(&pkt, offsetInSteps);
|
||||
MutexGuard m(mutex);
|
||||
int result=GetInternal(&pkt, offsetInSteps, advance);
|
||||
if(playbackScaledDuration){
|
||||
if(outstandingDelayChange!=0){
|
||||
if(outstandingDelayChange<0){
|
||||
@ -121,12 +128,14 @@ size_t JitterBuffer::HandleOutput(unsigned char *buffer, size_t len, int offsetI
|
||||
*playbackScaledDuration=80;
|
||||
outstandingDelayChange-=20;
|
||||
}
|
||||
LOGV("outstanding delay change: %d", outstandingDelayChange);
|
||||
//LOGV("outstanding delay change: %d", outstandingDelayChange);
|
||||
}else if(advance && GetCurrentDelay()==0){
|
||||
//LOGV("stretching packet because the next one is late");
|
||||
*playbackScaledDuration=80;
|
||||
}else{
|
||||
*playbackScaledDuration=60;
|
||||
}
|
||||
}
|
||||
unlock_mutex(mutex);
|
||||
if(result==JR_OK){
|
||||
return pkt.size;
|
||||
}else{
|
||||
@ -135,7 +144,7 @@ size_t JitterBuffer::HandleOutput(unsigned char *buffer, size_t len, int offsetI
|
||||
}
|
||||
|
||||
|
||||
int JitterBuffer::GetInternal(jitter_packet_t* pkt, int offset){
|
||||
int JitterBuffer::GetInternal(jitter_packet_t* pkt, int offset, bool advance){
|
||||
/*if(needBuffering && lastPutTimestamp<nextTimestamp){
|
||||
LOGV("jitter: don't have timestamp %lld, buffering", (long long int)nextTimestamp);
|
||||
Advance();
|
||||
@ -172,9 +181,9 @@ int JitterBuffer::GetInternal(jitter_packet_t* pkt, int offset){
|
||||
return JR_OK;
|
||||
}
|
||||
|
||||
LOGW("jitter: found no packet for timestamp %lld (last put = %d, lost = %d)", (long long int)timestampToGet, lastPutTimestamp, lostCount);
|
||||
//LOGV("jitter: found no packet for timestamp %lld (last put = %d, lost = %d)", (long long int)timestampToGet, lastPutTimestamp, lostCount);
|
||||
|
||||
if(offset==0)
|
||||
if(advance)
|
||||
Advance();
|
||||
|
||||
if(!needBuffering){
|
||||
@ -242,11 +251,11 @@ void JitterBuffer::PutInternal(jitter_packet_t* pkt){
|
||||
}
|
||||
|
||||
if(pkt->timestamp<nextTimestamp){
|
||||
LOGW("jitter: would drop packet with timestamp %d because it is late but not hopelessly", pkt->timestamp);
|
||||
//LOGW("jitter: would drop packet with timestamp %d because it is late but not hopelessly", pkt->timestamp);
|
||||
latePacketCount++;
|
||||
lostPackets--;
|
||||
}else if(pkt->timestamp<nextTimestamp-1){
|
||||
LOGW("jitter: dropping packet with timestamp %d because it is too late", pkt->timestamp);
|
||||
//LOGW("jitter: dropping packet with timestamp %d because it is too late", pkt->timestamp);
|
||||
latePacketCount++;
|
||||
return;
|
||||
}
|
||||
@ -280,7 +289,9 @@ void JitterBuffer::PutInternal(jitter_packet_t* pkt){
|
||||
memcpy(slots[i].buffer, pkt->buffer, pkt->size);
|
||||
else
|
||||
LOGE("WTF!!");
|
||||
//fprintf(dump, "%f %d\n", time-prevRecvTime, GetCurrentDelay());
|
||||
#ifdef TGVOIP_DUMP_JITTER_STATS
|
||||
fprintf(dump, "%u\t%.03f\t%d\t%.03f\t%.03f\t%.03f\n", pkt->timestamp, time, GetCurrentDelay(), lastMeasuredJitter, lastMeasuredDelay, minDelay);
|
||||
#endif
|
||||
prevRecvTime=time;
|
||||
}
|
||||
|
||||
@ -290,8 +301,8 @@ void JitterBuffer::Advance(){
|
||||
}
|
||||
|
||||
|
||||
int JitterBuffer::GetCurrentDelay(){
|
||||
int delay=0;
|
||||
unsigned int JitterBuffer::GetCurrentDelay(){
|
||||
unsigned int delay=0;
|
||||
int i;
|
||||
for(i=0;i<JITTER_SLOT_COUNT;i++){
|
||||
if(slots[i].buffer!=NULL)
|
||||
@ -301,11 +312,9 @@ int JitterBuffer::GetCurrentDelay(){
|
||||
}
|
||||
|
||||
void JitterBuffer::Tick(){
|
||||
lock_mutex(mutex);
|
||||
MutexGuard m(mutex);
|
||||
int i;
|
||||
|
||||
int count=0;
|
||||
|
||||
memmove(&lateHistory[1], lateHistory, 63*sizeof(int));
|
||||
lateHistory[0]=latePacketCount;
|
||||
latePacketCount=0;
|
||||
@ -329,26 +338,6 @@ void JitterBuffer::Tick(){
|
||||
if(avgLate16>=resyncThreshold){
|
||||
wasReset=true;
|
||||
}
|
||||
/*if(avgLate16>=0.3){
|
||||
if(dontIncMinDelay==0 && minDelay<15){
|
||||
minDelay++;
|
||||
if(GetCurrentDelay()<minDelay)
|
||||
nextTimestamp-=(minDelay-GetCurrentDelay());
|
||||
dontIncMinDelay=16;
|
||||
dontDecMinDelay+=128;
|
||||
}
|
||||
}else if(absolutelyNoLatePackets){
|
||||
if(dontDecMinDelay>0)
|
||||
dontDecMinDelay--;
|
||||
if(dontDecMinDelay==0 && minDelay>minMinDelay){
|
||||
minDelay--;
|
||||
dontDecMinDelay=64;
|
||||
dontIncMinDelay+=16;
|
||||
}
|
||||
}
|
||||
|
||||
if(dontIncMinDelay>0)
|
||||
dontIncMinDelay--;*/
|
||||
|
||||
if(absolutelyNoLatePackets){
|
||||
if(dontDecMinDelay>0)
|
||||
@ -444,7 +433,6 @@ void JitterBuffer::Tick(){
|
||||
|
||||
tickCount++;
|
||||
|
||||
unlock_mutex(mutex);
|
||||
}
|
||||
|
||||
|
||||
@ -468,10 +456,9 @@ void JitterBuffer::GetAverageLateCount(double *out){
|
||||
|
||||
|
||||
int JitterBuffer::GetAndResetLostPacketCount(){
|
||||
lock_mutex(mutex);
|
||||
MutexGuard m(mutex);
|
||||
int r=lostPackets;
|
||||
lostPackets=0;
|
||||
unlock_mutex(mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -36,11 +36,11 @@ public:
|
||||
~JitterBuffer();
|
||||
void SetMinPacketCount(uint32_t count);
|
||||
int GetMinPacketCount();
|
||||
int GetCurrentDelay();
|
||||
unsigned int GetCurrentDelay();
|
||||
double GetAverageDelay();
|
||||
void Reset();
|
||||
void HandleInput(unsigned char* data, size_t len, uint32_t timestamp);
|
||||
size_t HandleOutput(unsigned char* buffer, size_t len, int offsetInSteps, int* playbackScaledDuration);
|
||||
size_t HandleOutput(unsigned char* buffer, size_t len, int offsetInSteps, bool advance, int* playbackScaledDuration);
|
||||
void Tick();
|
||||
void GetAverageLateCount(double* out);
|
||||
int GetAndResetLostPacketCount();
|
||||
@ -51,24 +51,24 @@ private:
|
||||
static size_t CallbackIn(unsigned char* data, size_t len, void* param);
|
||||
static size_t CallbackOut(unsigned char* data, size_t len, void* param);
|
||||
void PutInternal(jitter_packet_t* pkt);
|
||||
int GetInternal(jitter_packet_t* pkt, int offset);
|
||||
int GetInternal(jitter_packet_t* pkt, int offset, bool advance);
|
||||
void Advance();
|
||||
|
||||
BufferPool bufferPool;
|
||||
tgvoip_mutex_t mutex;
|
||||
Mutex mutex;
|
||||
jitter_packet_t slots[JITTER_SLOT_COUNT];
|
||||
int64_t nextTimestamp;
|
||||
uint32_t step;
|
||||
uint32_t minDelay;
|
||||
double minDelay;
|
||||
uint32_t minMinDelay;
|
||||
uint32_t maxMinDelay;
|
||||
uint32_t maxUsedSlots;
|
||||
uint32_t lastPutTimestamp;
|
||||
uint32_t lossesToReset;
|
||||
double resyncThreshold;
|
||||
int lostCount;
|
||||
int lostSinceReset;
|
||||
int gotSinceReset;
|
||||
unsigned int lostCount;
|
||||
unsigned int lostSinceReset;
|
||||
unsigned int gotSinceReset;
|
||||
bool wasReset;
|
||||
bool needBuffering;
|
||||
int delayHistory[64];
|
||||
@ -88,7 +88,9 @@ private:
|
||||
int outstandingDelayChange;
|
||||
unsigned int dontChangeDelay;
|
||||
double avgDelay;
|
||||
//FILE* dump;
|
||||
#ifdef TGVOIP_DUMP_JITTER_STATS
|
||||
FILE* dump;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,13 @@
|
||||
// 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;
|
||||
|
||||
@ -16,3 +22,190 @@ void MediaStreamItf::SetCallback(size_t (*f)(unsigned char *, size_t, void*), vo
|
||||
size_t MediaStreamItf::InvokeCallback(unsigned char *data, size_t length){
|
||||
return (*callback)(data, length, callbackParam);
|
||||
}
|
||||
|
||||
AudioMixer::AudioMixer() : bufferPool(960*2, 16), processedQueue(16), semaphore(16, 0){
|
||||
output=NULL;
|
||||
running=false;
|
||||
}
|
||||
|
||||
AudioMixer::~AudioMixer(){
|
||||
}
|
||||
|
||||
void AudioMixer::SetOutput(MediaStreamItf *output){
|
||||
if(this->output)
|
||||
this->output->SetCallback(NULL, NULL);
|
||||
this->output=output;
|
||||
output->SetCallback(OutputCallback, this);
|
||||
}
|
||||
|
||||
void AudioMixer::Start(){
|
||||
assert(!running);
|
||||
running=true;
|
||||
thread=new Thread(new MethodPointer<AudioMixer>(&AudioMixer::RunThread, this), NULL);
|
||||
thread->Start();
|
||||
thread->SetName("AudioMixer");
|
||||
}
|
||||
|
||||
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(MediaStreamItf *input){
|
||||
MutexGuard m(inputsMutex);
|
||||
MixerInput in;
|
||||
in.multiplier=1;
|
||||
in.source=input;
|
||||
inputs.push_back(in);
|
||||
}
|
||||
|
||||
void AudioMixer::RemoveInput(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(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(void* arg){
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,16 @@
|
||||
#define LIBTGVOIP_MEDIASTREAMINPUT_H
|
||||
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include "threading.h"
|
||||
#include "BlockingQueue.h"
|
||||
#include "BufferPool.h"
|
||||
|
||||
namespace tgvoip{
|
||||
|
||||
class EchoCanceller;
|
||||
|
||||
class MediaStreamItf{
|
||||
public:
|
||||
virtual void Start()=0;
|
||||
@ -23,7 +31,58 @@ private:
|
||||
size_t (*callback)(unsigned char*, size_t, void*);
|
||||
void* callbackParam;
|
||||
};
|
||||
}
|
||||
|
||||
class AudioMixer : public MediaStreamItf{
|
||||
public:
|
||||
AudioMixer();
|
||||
virtual ~AudioMixer();
|
||||
void SetOutput(MediaStreamItf* output);
|
||||
virtual void Start();
|
||||
virtual void Stop();
|
||||
void AddInput(MediaStreamItf* input);
|
||||
void RemoveInput(MediaStreamItf* input);
|
||||
void SetInputVolume(MediaStreamItf* input, float volumeDB);
|
||||
void SetEchoCanceller(EchoCanceller* aec);
|
||||
private:
|
||||
void RunThread(void* arg);
|
||||
struct MixerInput{
|
||||
MediaStreamItf* source;
|
||||
float multiplier;
|
||||
};
|
||||
Mutex inputsMutex;
|
||||
void DoCallback(unsigned char* data, size_t length);
|
||||
static size_t OutputCallback(unsigned char* data, size_t length, void* arg);
|
||||
MediaStreamItf* output;
|
||||
std::vector<MixerInput> inputs;
|
||||
Thread* thread;
|
||||
BufferPool bufferPool;
|
||||
BlockingQueue<unsigned char*> processedQueue;
|
||||
Semaphore semaphore;
|
||||
EchoCanceller* echoCanceller;
|
||||
bool running;
|
||||
};
|
||||
|
||||
class CallbackWrapper : public MediaStreamItf{
|
||||
public:
|
||||
CallbackWrapper(){};
|
||||
virtual ~CallbackWrapper(){};
|
||||
virtual void Start(){};
|
||||
virtual void Stop(){};
|
||||
|
||||
};
|
||||
|
||||
class AudioLevelMeter{
|
||||
public:
|
||||
AudioLevelMeter();
|
||||
float GetLevel();
|
||||
void Update(int16_t* samples, size_t count);
|
||||
private:
|
||||
int16_t absMax;
|
||||
int16_t count;
|
||||
int8_t currentLevel;
|
||||
int16_t currentLevelFullRange;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif //LIBTGVOIP_MEDIASTREAMINPUT_H
|
||||
|
@ -110,7 +110,7 @@ void NetworkSocket::EncryptForTCPO2(unsigned char *buffer, size_t len, TCPO2Stat
|
||||
}
|
||||
|
||||
size_t NetworkSocket::Receive(unsigned char *buffer, size_t len){
|
||||
NetworkPacket pkt;
|
||||
NetworkPacket pkt={0};
|
||||
pkt.data=buffer;
|
||||
pkt.length=len;
|
||||
Receive(&pkt);
|
||||
@ -118,7 +118,7 @@ size_t NetworkSocket::Receive(unsigned char *buffer, size_t len){
|
||||
}
|
||||
|
||||
size_t NetworkSocket::Send(unsigned char *buffer, size_t len){
|
||||
NetworkPacket pkt;
|
||||
NetworkPacket pkt={0};
|
||||
pkt.data=buffer;
|
||||
pkt.length=len;
|
||||
Send(&pkt);
|
||||
@ -361,7 +361,7 @@ void NetworkSocketSOCKS5Proxy::Send(NetworkPacket *packet){
|
||||
}
|
||||
out.WriteInt16(htons(packet->port));
|
||||
out.WriteBytes(packet->data, packet->length);
|
||||
NetworkPacket p;
|
||||
NetworkPacket p={0};
|
||||
p.data=buf;
|
||||
p.length=out.GetLength();
|
||||
p.address=connectedAddress;
|
||||
@ -376,7 +376,7 @@ void NetworkSocketSOCKS5Proxy::Receive(NetworkPacket *packet){
|
||||
tcp->Receive(packet);
|
||||
}else if(protocol==PROTO_UDP){
|
||||
unsigned char buf[1500];
|
||||
NetworkPacket p;
|
||||
NetworkPacket p={0};
|
||||
p.data=buf;
|
||||
p.length=sizeof(buf);
|
||||
udp->Receive(&p);
|
||||
@ -587,6 +587,7 @@ void NetworkSocketSOCKS5Proxy::InitConnection(){
|
||||
failed=true;
|
||||
return;
|
||||
}
|
||||
LOGV("socks5: authentication succeeded");
|
||||
}else{
|
||||
LOGW("socks5: unsupported auth method");
|
||||
failed=true;
|
||||
|
331
OpusDecoder.cpp
331
OpusDecoder.cpp
@ -10,32 +10,49 @@
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "VoIPController.h"
|
||||
|
||||
#define PACKET_SIZE (960*2)
|
||||
|
||||
using namespace tgvoip;
|
||||
|
||||
tgvoip::OpusDecoder::OpusDecoder(MediaStreamItf *dst) : semaphore(32, 0){
|
||||
//this->source=source;
|
||||
tgvoip::OpusDecoder::OpusDecoder(MediaStreamItf *dst, bool isAsync){
|
||||
async=isAsync;
|
||||
dst->SetCallback(OpusDecoder::Callback, this);
|
||||
if(async){
|
||||
decodedQueue=new BlockingQueue<unsigned char*>(33);
|
||||
bufferPool=new BufferPool(PACKET_SIZE, 32);
|
||||
semaphore=new Semaphore(32, 0);
|
||||
}else{
|
||||
decodedQueue=NULL;
|
||||
bufferPool=NULL;
|
||||
semaphore=NULL;
|
||||
}
|
||||
dec=opus_decoder_create(48000, 1, NULL);
|
||||
//test=fopen("/sdcard/test.raw", "wb");
|
||||
buffer=(unsigned char *) malloc(8192);
|
||||
//lastDecoded=(unsigned char*) malloc(960*2);
|
||||
lastDecoded=NULL;
|
||||
lastDecodedLen=0;
|
||||
outputBufferSize=0;
|
||||
lastDecodedOffset=0;
|
||||
decodedQueue=new BlockingQueue<unsigned char*>(33);
|
||||
bufferPool=new BufferPool(PACKET_SIZE, 32);
|
||||
echoCanceller=NULL;
|
||||
frameDuration=20;
|
||||
consecutiveLostPackets=0;
|
||||
enableDTX=false;
|
||||
silentPacketCount=0;
|
||||
levelMeter=NULL;
|
||||
nextLen=0;
|
||||
running=false;
|
||||
remainingDataLen=0;
|
||||
processedBuffer=NULL;
|
||||
}
|
||||
|
||||
tgvoip::OpusDecoder::~OpusDecoder(){
|
||||
opus_decoder_destroy(dec);
|
||||
free(buffer);
|
||||
delete bufferPool;
|
||||
delete decodedQueue;
|
||||
if(bufferPool)
|
||||
delete bufferPool;
|
||||
if(decodedQueue)
|
||||
delete decodedQueue;
|
||||
if(semaphore)
|
||||
delete semaphore;
|
||||
}
|
||||
|
||||
|
||||
@ -44,215 +61,177 @@ void tgvoip::OpusDecoder::SetEchoCanceller(EchoCanceller* canceller){
|
||||
}
|
||||
|
||||
size_t tgvoip::OpusDecoder::Callback(unsigned char *data, size_t len, void *param){
|
||||
((OpusDecoder*)param)->HandleCallback(data, len);
|
||||
return 0;
|
||||
return ((OpusDecoder*)param)->HandleCallback(data, len);
|
||||
}
|
||||
|
||||
void tgvoip::OpusDecoder::HandleCallback(unsigned char *data, size_t len){
|
||||
if(!running){
|
||||
memset(data, 0, len);
|
||||
return;
|
||||
}
|
||||
if(outputBufferSize==0){
|
||||
outputBufferSize=len;
|
||||
int packetsNeeded;
|
||||
if(len>PACKET_SIZE)
|
||||
packetsNeeded=len/PACKET_SIZE;
|
||||
else
|
||||
packetsNeeded=1;
|
||||
packetsNeeded*=2;
|
||||
semaphore.Release(packetsNeeded);
|
||||
}
|
||||
assert(outputBufferSize==len && "output buffer size is supposed to be the same throughout callbacks");
|
||||
if(len>PACKET_SIZE){
|
||||
int count=len/PACKET_SIZE;
|
||||
int i;
|
||||
for(i=0;i<count;i++){
|
||||
lastDecoded=(unsigned char*) decodedQueue->GetBlocking();
|
||||
if(!lastDecoded)
|
||||
return;
|
||||
memcpy(data+(i*PACKET_SIZE), lastDecoded, PACKET_SIZE);
|
||||
if(echoCanceller)
|
||||
echoCanceller->SpeakerOutCallback(data, PACKET_SIZE);
|
||||
bufferPool->Reuse(lastDecoded);
|
||||
size_t tgvoip::OpusDecoder::HandleCallback(unsigned char *data, size_t len){
|
||||
if(async){
|
||||
if(!running){
|
||||
memset(data, 0, len);
|
||||
return 0;
|
||||
}
|
||||
semaphore.Release(count);
|
||||
}else if(len==PACKET_SIZE){
|
||||
lastDecoded=(unsigned char*) decodedQueue->GetBlocking();
|
||||
if(!lastDecoded)
|
||||
return;
|
||||
memcpy(data, lastDecoded, PACKET_SIZE);
|
||||
bufferPool->Reuse(lastDecoded);
|
||||
semaphore.Release();
|
||||
lock_mutex(mutex);
|
||||
if(echoCanceller)
|
||||
echoCanceller->SpeakerOutCallback(data, PACKET_SIZE);
|
||||
unlock_mutex(mutex);
|
||||
}else if(len<PACKET_SIZE){
|
||||
if(lastDecodedOffset==0){
|
||||
lastDecoded=(unsigned char*) decodedQueue->GetBlocking();
|
||||
}
|
||||
if(!lastDecoded)
|
||||
return;
|
||||
|
||||
memcpy(data, lastDecoded+lastDecodedOffset, len);
|
||||
lastDecodedOffset+=len;
|
||||
|
||||
if(lastDecodedOffset>=PACKET_SIZE){
|
||||
if(echoCanceller)
|
||||
echoCanceller->SpeakerOutCallback(lastDecoded, PACKET_SIZE);
|
||||
lastDecodedOffset=0;
|
||||
bufferPool->Reuse(lastDecoded);
|
||||
//LOGV("before req packet, qsize=%d", decodedQueue->Size());
|
||||
if(decodedQueue->Size()==0)
|
||||
semaphore.Release(2);
|
||||
if(outputBufferSize==0){
|
||||
outputBufferSize=len;
|
||||
int packetsNeeded;
|
||||
if(len>PACKET_SIZE)
|
||||
packetsNeeded=len/PACKET_SIZE;
|
||||
else
|
||||
semaphore.Release();
|
||||
}
|
||||
}
|
||||
/*if(lastDecodedLen){
|
||||
LOGV("ldl=%d, l=%d", lastDecodedLen, len);
|
||||
if(len==PACKET_SIZE){
|
||||
memcpy(data, lastDecoded, len);
|
||||
packetsNeeded=1;
|
||||
}else if(len>PACKET_SIZE){
|
||||
memcpy(data, lastDecoded, len);
|
||||
//LOGV("ldl=%d, l=%d", lastDecodedLen, len);
|
||||
packetsNeeded=len/PACKET_SIZE;
|
||||
}else if(len<PACKET_SIZE){
|
||||
memcpy(data, lastDecoded+lastDecodedOffset, len);
|
||||
lastDecodedOffset+=len;
|
||||
if(lastDecodedOffset>=PACKET_SIZE){
|
||||
packetsNeeded=1;
|
||||
lastDecodedOffset=0;
|
||||
packetsNeeded*=2;
|
||||
semaphore->Release(packetsNeeded);
|
||||
}
|
||||
assert(outputBufferSize==len && "output buffer size is supposed to be the same throughout callbacks");
|
||||
if(len==PACKET_SIZE){
|
||||
lastDecoded=(unsigned char *) decodedQueue->GetBlocking();
|
||||
if(!lastDecoded)
|
||||
return 0;
|
||||
memcpy(data, lastDecoded, PACKET_SIZE);
|
||||
bufferPool->Reuse(lastDecoded);
|
||||
semaphore->Release();
|
||||
if(silentPacketCount>0){
|
||||
silentPacketCount--;
|
||||
if(levelMeter)
|
||||
levelMeter->Update(reinterpret_cast<int16_t *>(data), 0);
|
||||
return 0;
|
||||
}
|
||||
if(echoCanceller){
|
||||
echoCanceller->SpeakerOutCallback(data, PACKET_SIZE);
|
||||
}
|
||||
}else{
|
||||
LOGE("Opus decoder buffer length != 960 samples");
|
||||
abort();
|
||||
}
|
||||
}else{
|
||||
LOGW("skipping callback");
|
||||
if(len>PACKET_SIZE)
|
||||
packetsNeeded=len/PACKET_SIZE;
|
||||
else
|
||||
packetsNeeded=1;
|
||||
}*/
|
||||
/*if(packetsNeeded>0){
|
||||
lock_mutex(mutex);
|
||||
notify_lock(lock);
|
||||
unlock_mutex(mutex);
|
||||
}*/
|
||||
if(remainingDataLen==0 && silentPacketCount==0){
|
||||
int duration=DecodeNextFrame();
|
||||
remainingDataLen=(size_t) (duration/20*960*2);
|
||||
}
|
||||
if(silentPacketCount>0 || remainingDataLen==0 || !processedBuffer){
|
||||
if(silentPacketCount>0)
|
||||
silentPacketCount--;
|
||||
memset(data, 0, 960*2);
|
||||
if(levelMeter)
|
||||
levelMeter->Update(reinterpret_cast<int16_t *>(data), 0);
|
||||
return 0;
|
||||
}
|
||||
memcpy(data, processedBuffer, 960*2);
|
||||
remainingDataLen-=960*2;
|
||||
if(remainingDataLen>0){
|
||||
memmove(processedBuffer, processedBuffer+960*2, remainingDataLen);
|
||||
}
|
||||
}
|
||||
if(levelMeter)
|
||||
levelMeter->Update(reinterpret_cast<int16_t *>(data), len/2);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
void tgvoip::OpusDecoder::Start(){
|
||||
init_mutex(mutex);
|
||||
if(!async)
|
||||
return;
|
||||
running=true;
|
||||
start_thread(thread, OpusDecoder::StartThread, this);
|
||||
set_thread_priority(thread, get_thread_max_priority());
|
||||
set_thread_name(thread, "opus_decoder");
|
||||
thread=new Thread(new MethodPointer<tgvoip::OpusDecoder>(&tgvoip::OpusDecoder::RunThread, this), NULL);
|
||||
thread->SetName("opus_decoder");
|
||||
thread->SetMaxPriority();
|
||||
thread->Start();
|
||||
}
|
||||
|
||||
void tgvoip::OpusDecoder::Stop(){
|
||||
if(!running)
|
||||
if(!running || !async)
|
||||
return;
|
||||
running=false;
|
||||
semaphore.Release();
|
||||
join_thread(thread);
|
||||
free_mutex(mutex);
|
||||
semaphore->Release();
|
||||
thread->Join();
|
||||
delete thread;
|
||||
}
|
||||
|
||||
|
||||
void* tgvoip::OpusDecoder::StartThread(void *param){
|
||||
((tgvoip::OpusDecoder*)param)->RunThread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void tgvoip::OpusDecoder::RunThread(){
|
||||
unsigned char nextBuffer[8192];
|
||||
unsigned char decodeBuffer[8192];
|
||||
void tgvoip::OpusDecoder::RunThread(void* param){
|
||||
int i;
|
||||
int packetsPerFrame=frameDuration/20;
|
||||
bool first=true;
|
||||
LOGI("decoder: packets per frame %d", packetsPerFrame);
|
||||
size_t nextLen=0;
|
||||
while(running){
|
||||
//LOGV("after wait, running=%d", running);
|
||||
//LOGD("Will get %d packets", packetsNeeded);
|
||||
//lastDecodedLen=0;
|
||||
memcpy(buffer, nextBuffer, nextLen);
|
||||
size_t inLen=nextLen;
|
||||
//nextLen=InvokeCallback(nextBuffer, 8192);
|
||||
int playbackDuration=0;
|
||||
nextLen=jitterBuffer->HandleOutput(nextBuffer, 8192, 0, &playbackDuration);
|
||||
if(first){
|
||||
first=false;
|
||||
continue;
|
||||
}
|
||||
//LOGV("Before decode, len=%d", inLen);
|
||||
if(!inLen){
|
||||
LOGV("Trying to recover late packet");
|
||||
inLen=jitterBuffer->HandleOutput(buffer, 8192, -2, &playbackDuration);
|
||||
if(inLen)
|
||||
LOGV("Decoding late packet");
|
||||
}
|
||||
int size;
|
||||
if(inLen || nextLen)
|
||||
size=opus_decode(dec, inLen ? buffer : nextBuffer, inLen ? inLen : nextLen, (opus_int16*) decodeBuffer, packetsPerFrame*960, inLen ? 0 : 1);
|
||||
else{ // do packet loss concealment
|
||||
size=opus_decode(dec, NULL, 0, (opus_int16 *) decodeBuffer, packetsPerFrame*960, 0);
|
||||
LOGV("PLC");
|
||||
}
|
||||
if(size<0)
|
||||
LOGW("decoder: opus_decode error %d", size);
|
||||
//LOGV("After decode, size=%d", size);
|
||||
//LOGD("playbackDuration=%d", playbackDuration);
|
||||
unsigned char* processedBuffer;
|
||||
if(playbackDuration==80){
|
||||
processedBuffer=buffer;
|
||||
audio::Resampler::Rescale60To80((int16_t*) decodeBuffer, (int16_t*) processedBuffer);
|
||||
}else if(playbackDuration==40){
|
||||
processedBuffer=buffer;
|
||||
audio::Resampler::Rescale60To40((int16_t*) decodeBuffer, (int16_t*) processedBuffer);
|
||||
}else{
|
||||
processedBuffer=decodeBuffer;
|
||||
}
|
||||
for(i=0;i</*packetsPerFrame*/ playbackDuration/20;i++){
|
||||
semaphore.Acquire();
|
||||
int playbackDuration=DecodeNextFrame();
|
||||
for(i=0;i<playbackDuration/20;i++){
|
||||
semaphore->Acquire();
|
||||
if(!running){
|
||||
LOGI("==== decoder exiting ====");
|
||||
return;
|
||||
}
|
||||
unsigned char *buf=bufferPool->Get();
|
||||
if(buf){
|
||||
if(size>0){
|
||||
if(remainingDataLen>0){
|
||||
for(std::vector<AudioEffect*>::iterator effect=postProcEffects.begin();effect!=postProcEffects.end();++effect){
|
||||
(*effect)->Process(reinterpret_cast<int16_t*>(processedBuffer+(PACKET_SIZE*i)), 960);
|
||||
}
|
||||
memcpy(buf, processedBuffer+(PACKET_SIZE*i), PACKET_SIZE);
|
||||
}else{
|
||||
LOGE("Error decoding, result=%d", size);
|
||||
//LOGE("Error decoding, result=%d", size);
|
||||
memset(buf, 0, PACKET_SIZE);
|
||||
}
|
||||
decodedQueue->Put(buf);
|
||||
}else{
|
||||
LOGW("decoder: no buffers left!");
|
||||
}
|
||||
//LOGD("packets needed: %d", packetsNeeded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int tgvoip::OpusDecoder::DecodeNextFrame(){
|
||||
/*memcpy(buffer, nextBuffer, nextLen);
|
||||
size_t inLen=nextLen;
|
||||
int playbackDuration=0;
|
||||
nextLen=jitterBuffer->HandleOutput(nextBuffer, 8192, 0, &playbackDuration);
|
||||
if(first){
|
||||
first=false;
|
||||
return 0;
|
||||
}
|
||||
if(!inLen){
|
||||
LOGV("Trying to recover late packet");
|
||||
inLen=jitterBuffer->HandleOutput(buffer, 8192, -2, &playbackDuration);
|
||||
if(inLen)
|
||||
LOGV("Decoding late packet");
|
||||
}*/
|
||||
int playbackDuration=0;
|
||||
size_t len=jitterBuffer->HandleOutput(buffer, 8192, 0, true, &playbackDuration);
|
||||
bool fec=false;
|
||||
if(!len){
|
||||
fec=true;
|
||||
len=jitterBuffer->HandleOutput(buffer, 8192, 0, false, &playbackDuration);
|
||||
if(len)
|
||||
LOGV("Trying FEC...");
|
||||
}
|
||||
int size;
|
||||
if(len){
|
||||
size=opus_decode(dec, buffer, len, (opus_int16 *) decodeBuffer, packetsPerFrame*960, fec ? 1 : 0);
|
||||
consecutiveLostPackets=0;
|
||||
}else{ // do packet loss concealment
|
||||
consecutiveLostPackets++;
|
||||
if(consecutiveLostPackets>2 && enableDTX){
|
||||
silentPacketCount+=packetsPerFrame;
|
||||
size=packetsPerFrame*960;
|
||||
}else{
|
||||
size=opus_decode(dec, NULL, 0, (opus_int16 *) decodeBuffer, packetsPerFrame*960, 0);
|
||||
//LOGV("PLC");
|
||||
}
|
||||
}
|
||||
if(size<0)
|
||||
LOGW("decoder: opus_decode error %d", size);
|
||||
remainingDataLen=size;
|
||||
if(playbackDuration==80){
|
||||
processedBuffer=buffer;
|
||||
audio::Resampler::Rescale60To80((int16_t*) decodeBuffer, (int16_t*) processedBuffer);
|
||||
}else if(playbackDuration==40){
|
||||
processedBuffer=buffer;
|
||||
audio::Resampler::Rescale60To40((int16_t*) decodeBuffer, (int16_t*) processedBuffer);
|
||||
}else{
|
||||
processedBuffer=decodeBuffer;
|
||||
}
|
||||
return playbackDuration;
|
||||
}
|
||||
|
||||
|
||||
void tgvoip::OpusDecoder::SetFrameDuration(uint32_t duration){
|
||||
frameDuration=duration;
|
||||
}
|
||||
|
||||
|
||||
void tgvoip::OpusDecoder::ResetQueue(){
|
||||
/*lock_mutex(mutex);
|
||||
packetsNeeded=0;
|
||||
unlock_mutex(mutex);
|
||||
while(decodedQueue->Size()>0){
|
||||
bufferPool->Reuse((unsigned char *) decodedQueue->Get());
|
||||
}*/
|
||||
packetsPerFrame=frameDuration/20;
|
||||
}
|
||||
|
||||
|
||||
@ -260,6 +239,14 @@ void tgvoip::OpusDecoder::SetJitterBuffer(JitterBuffer* jitterBuffer){
|
||||
this->jitterBuffer=jitterBuffer;
|
||||
}
|
||||
|
||||
void tgvoip::OpusDecoder::SetDTX(bool enable){
|
||||
enableDTX=enable;
|
||||
}
|
||||
|
||||
void tgvoip::OpusDecoder::SetLevelMeter(AudioLevelMeter *levelMeter){
|
||||
this->levelMeter=levelMeter;
|
||||
}
|
||||
|
||||
void tgvoip::OpusDecoder::AddAudioEffect(AudioEffect *effect){
|
||||
postProcEffects.push_back(effect);
|
||||
}
|
||||
|
@ -25,35 +25,46 @@ public:
|
||||
|
||||
virtual void Stop();
|
||||
|
||||
OpusDecoder(MediaStreamItf* dst);
|
||||
OpusDecoder(MediaStreamItf* dst, bool isAsync);
|
||||
virtual ~OpusDecoder();
|
||||
void HandleCallback(unsigned char* data, size_t len);
|
||||
size_t HandleCallback(unsigned char* data, size_t len);
|
||||
void SetEchoCanceller(EchoCanceller* canceller);
|
||||
void SetFrameDuration(uint32_t duration);
|
||||
void ResetQueue();
|
||||
void SetJitterBuffer(JitterBuffer* jitterBuffer);
|
||||
void SetDTX(bool enable);
|
||||
void SetLevelMeter(AudioLevelMeter* levelMeter);
|
||||
void AddAudioEffect(AudioEffect* effect);
|
||||
void RemoveAudioEffect(AudioEffect* effect);
|
||||
|
||||
private:
|
||||
static size_t Callback(unsigned char* data, size_t len, void* param);
|
||||
static void* StartThread(void* param);
|
||||
void RunThread();
|
||||
void RunThread(void* param);
|
||||
int DecodeNextFrame();
|
||||
::OpusDecoder* dec;
|
||||
BlockingQueue<unsigned char*>* decodedQueue;
|
||||
BufferPool* bufferPool;
|
||||
unsigned char* buffer;
|
||||
unsigned char* lastDecoded;
|
||||
size_t lastDecodedLen, lastDecodedOffset;
|
||||
unsigned char* processedBuffer;
|
||||
size_t outputBufferSize;
|
||||
bool running;
|
||||
tgvoip_thread_t thread;
|
||||
Semaphore semaphore;
|
||||
tgvoip_mutex_t mutex;
|
||||
Thread* thread;
|
||||
Semaphore* semaphore;
|
||||
uint32_t frameDuration;
|
||||
EchoCanceller* echoCanceller;
|
||||
JitterBuffer* jitterBuffer;
|
||||
AudioLevelMeter* levelMeter;
|
||||
int consecutiveLostPackets;
|
||||
bool enableDTX;
|
||||
size_t silentPacketCount;
|
||||
std::vector<AudioEffect*> postProcEffects;
|
||||
bool async;
|
||||
unsigned char nextBuffer[8192];
|
||||
unsigned char decodeBuffer[8192];
|
||||
bool first;
|
||||
size_t nextLen;
|
||||
unsigned int packetsPerFrame;
|
||||
ssize_t remainingDataLen;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ tgvoip::OpusEncoder::OpusEncoder(MediaStreamItf *source):queue(11), bufferPool(9
|
||||
echoCanceller=NULL;
|
||||
complexity=10;
|
||||
frameDuration=20;
|
||||
levelMeter=NULL;
|
||||
mediumCorrectionBitrate=ServerConfig::GetSharedInstance()->GetInt("audio_medium_fec_bitrate", 10000);
|
||||
strongCorrectionBitrate=ServerConfig::GetSharedInstance()->GetInt("audio_strong_fec_bitrate", 8000);
|
||||
mediumCorrectionMultiplier=ServerConfig::GetSharedInstance()->GetDouble("audio_medium_fec_multiplier", 1.5);
|
||||
@ -38,9 +39,10 @@ void tgvoip::OpusEncoder::Start(){
|
||||
if(running)
|
||||
return;
|
||||
running=true;
|
||||
start_thread(thread, StartThread, this);
|
||||
set_thread_priority(thread, get_thread_max_priority());
|
||||
set_thread_name(thread, "opus_encoder");
|
||||
thread=new Thread(new MethodPointer<tgvoip::OpusEncoder>(&tgvoip::OpusEncoder::RunThread, this), NULL);
|
||||
thread->SetName("OpusEncoder");
|
||||
thread->Start();
|
||||
thread->SetMaxPriority();
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::Stop(){
|
||||
@ -48,7 +50,8 @@ void tgvoip::OpusEncoder::Stop(){
|
||||
return;
|
||||
running=false;
|
||||
queue.Put(NULL);
|
||||
join_thread(thread);
|
||||
thread->Join();
|
||||
delete thread;
|
||||
}
|
||||
|
||||
|
||||
@ -62,6 +65,8 @@ void tgvoip::OpusEncoder::Encode(unsigned char *data, size_t len){
|
||||
currentBitrate=requestedBitrate;
|
||||
LOGV("opus_encoder: setting bitrate to %u", currentBitrate);
|
||||
}
|
||||
if(levelMeter)
|
||||
levelMeter->Update(reinterpret_cast<int16_t *>(data), len/2);
|
||||
int32_t r=opus_encode(enc, (int16_t*)data, len/2, buffer, 4096);
|
||||
if(r<=0){
|
||||
LOGE("Error encoding: %d", r);
|
||||
@ -99,12 +104,7 @@ void tgvoip::OpusEncoder::SetEchoCanceller(EchoCanceller* aec){
|
||||
echoCanceller=aec;
|
||||
}
|
||||
|
||||
void* tgvoip::OpusEncoder::StartThread(void* arg){
|
||||
((OpusEncoder*)arg)->RunThread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::RunThread(){
|
||||
void tgvoip::OpusEncoder::RunThread(void* arg){
|
||||
unsigned char buf[960*2];
|
||||
uint32_t bufferedCount=0;
|
||||
uint32_t packetsPerFrame=frameDuration/20;
|
||||
@ -158,3 +158,11 @@ void tgvoip::OpusEncoder::SetPacketLoss(int percent){
|
||||
int tgvoip::OpusEncoder::GetPacketLoss(){
|
||||
return packetLossPercent;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -30,18 +30,19 @@ public:
|
||||
void SetPacketLoss(int percent);
|
||||
int GetPacketLoss();
|
||||
uint32_t GetBitrate();
|
||||
void SetDTX(bool enable);
|
||||
void SetLevelMeter(AudioLevelMeter* levelMeter);
|
||||
|
||||
private:
|
||||
static size_t Callback(unsigned char* data, size_t len, void* param);
|
||||
static void* StartThread(void* arg);
|
||||
void RunThread();
|
||||
void RunThread(void* arg);
|
||||
void Encode(unsigned char* data, size_t len);
|
||||
MediaStreamItf* source;
|
||||
::OpusEncoder* enc;
|
||||
unsigned char buffer[4096];
|
||||
uint32_t requestedBitrate;
|
||||
uint32_t currentBitrate;
|
||||
tgvoip_thread_t thread;
|
||||
Thread* thread;
|
||||
BlockingQueue<unsigned char*> queue;
|
||||
BufferPool bufferPool;
|
||||
EchoCanceller* echoCanceller;
|
||||
@ -53,6 +54,7 @@ private:
|
||||
uint32_t strongCorrectionBitrate;
|
||||
double mediumCorrectionMultiplier;
|
||||
double strongCorrectionMultiplier;
|
||||
AudioLevelMeter* levelMeter;
|
||||
};
|
||||
}
|
||||
|
||||
|
3141
VoIPController.cpp
3141
VoIPController.cpp
File diff suppressed because it is too large
Load Diff
811
VoIPController.h
811
VoIPController.h
@ -13,6 +13,7 @@
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#include <TargetConditionals.h>
|
||||
#include "os/darwin/AudioUnitIO.h"
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
@ -28,55 +29,15 @@
|
||||
#include "EchoCanceller.h"
|
||||
#include "CongestionControl.h"
|
||||
#include "NetworkSocket.h"
|
||||
#include "BufferInputStream.h"
|
||||
|
||||
#define LIBTGVOIP_VERSION "1.0.3"
|
||||
|
||||
#define STATE_WAIT_INIT 1
|
||||
#define STATE_WAIT_INIT_ACK 2
|
||||
#define STATE_ESTABLISHED 3
|
||||
#define STATE_FAILED 4
|
||||
#define STATE_RECONNECTING 5
|
||||
|
||||
#define TGVOIP_ERROR_UNKNOWN 0
|
||||
#define TGVOIP_ERROR_INCOMPATIBLE 1
|
||||
#define TGVOIP_ERROR_TIMEOUT 2
|
||||
#define TGVOIP_ERROR_AUDIO_IO 3
|
||||
|
||||
#define NET_TYPE_UNKNOWN 0
|
||||
#define NET_TYPE_GPRS 1
|
||||
#define NET_TYPE_EDGE 2
|
||||
#define NET_TYPE_3G 3
|
||||
#define NET_TYPE_HSPA 4
|
||||
#define NET_TYPE_LTE 5
|
||||
#define NET_TYPE_WIFI 6
|
||||
#define NET_TYPE_ETHERNET 7
|
||||
#define NET_TYPE_OTHER_HIGH_SPEED 8
|
||||
#define NET_TYPE_OTHER_LOW_SPEED 9
|
||||
#define NET_TYPE_DIALUP 10
|
||||
#define NET_TYPE_OTHER_MOBILE 11
|
||||
|
||||
#define EP_TYPE_UDP_P2P_INET 1
|
||||
#define EP_TYPE_UDP_P2P_LAN 2
|
||||
#define EP_TYPE_UDP_RELAY 3
|
||||
#define EP_TYPE_TCP_RELAY 4
|
||||
|
||||
#define DATA_SAVING_NEVER 0
|
||||
#define DATA_SAVING_MOBILE 1
|
||||
#define DATA_SAVING_ALWAYS 2
|
||||
#define LIBTGVOIP_VERSION "2.0-alpha4"
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
|
||||
struct voip_stream_t{
|
||||
int32_t userID;
|
||||
unsigned char id;
|
||||
unsigned char type;
|
||||
unsigned char codec;
|
||||
bool enabled;
|
||||
uint16_t frameDuration;
|
||||
};
|
||||
typedef struct voip_stream_t voip_stream_t;
|
||||
#define TGVOIP_PEER_CAP_GROUP_CALLS 1
|
||||
|
||||
struct voip_queued_packet_t{
|
||||
unsigned char type;
|
||||
@ -100,21 +61,11 @@ struct voip_config_t{
|
||||
bool enableAEC;
|
||||
bool enableNS;
|
||||
bool enableAGC;
|
||||
|
||||
bool enableCallUpgrade;
|
||||
};
|
||||
typedef struct voip_config_t voip_config_t;
|
||||
|
||||
#if defined(__APPLE__) && TARGET_OS_IPHONE
|
||||
// temporary fix for nasty linking errors
|
||||
struct voip_legacy_endpoint_t{
|
||||
const char* address;
|
||||
const char* address6;
|
||||
uint16_t port;
|
||||
int64_t id;
|
||||
unsigned char peerTag[16];
|
||||
};
|
||||
typedef struct voip_legacy_endpoint_t voip_legacy_endpoint_t;
|
||||
#endif
|
||||
|
||||
struct voip_stats_t{
|
||||
uint64_t bytesSentWifi;
|
||||
uint64_t bytesRecvdWifi;
|
||||
@ -130,6 +81,8 @@ struct voip_crypto_functions_t{
|
||||
void (*aes_ige_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_ige_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_ctr_encrypt)(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num);
|
||||
void (*aes_cbc_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_cbc_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
};
|
||||
typedef struct voip_crypto_functions_t voip_crypto_functions_t;
|
||||
|
||||
@ -147,193 +100,229 @@ namespace tgvoip{
|
||||
//PROXY_HTTP
|
||||
};
|
||||
|
||||
class Endpoint{
|
||||
friend class VoIPController;
|
||||
public:
|
||||
Endpoint(int64_t id, uint16_t port, IPv4Address& address, IPv6Address& v6address, char type, unsigned char* peerTag);
|
||||
Endpoint();
|
||||
int64_t id;
|
||||
uint16_t port;
|
||||
IPv4Address address;
|
||||
IPv6Address v6address;
|
||||
char type;
|
||||
unsigned char peerTag[16];
|
||||
enum{
|
||||
STATE_WAIT_INIT=1,
|
||||
STATE_WAIT_INIT_ACK,
|
||||
STATE_ESTABLISHED,
|
||||
STATE_FAILED,
|
||||
STATE_RECONNECTING
|
||||
};
|
||||
|
||||
private:
|
||||
double lastPingTime;
|
||||
uint32_t lastPingSeq;
|
||||
double rtts[6];
|
||||
double averageRTT;
|
||||
NetworkSocket* socket;
|
||||
};
|
||||
enum{
|
||||
ERROR_UNKNOWN=0,
|
||||
ERROR_INCOMPATIBLE,
|
||||
ERROR_TIMEOUT,
|
||||
ERROR_AUDIO_IO
|
||||
};
|
||||
|
||||
class AudioDevice{
|
||||
public:
|
||||
std::string id;
|
||||
std::string displayName;
|
||||
};
|
||||
enum{
|
||||
NET_TYPE_UNKNOWN=0,
|
||||
NET_TYPE_GPRS,
|
||||
NET_TYPE_EDGE,
|
||||
NET_TYPE_3G,
|
||||
NET_TYPE_HSPA,
|
||||
NET_TYPE_LTE,
|
||||
NET_TYPE_WIFI,
|
||||
NET_TYPE_ETHERNET,
|
||||
NET_TYPE_OTHER_HIGH_SPEED,
|
||||
NET_TYPE_OTHER_LOW_SPEED,
|
||||
NET_TYPE_DIALUP,
|
||||
NET_TYPE_OTHER_MOBILE
|
||||
};
|
||||
|
||||
class AudioOutputDevice : public AudioDevice{
|
||||
enum{
|
||||
DATA_SAVING_NEVER=0,
|
||||
DATA_SAVING_MOBILE,
|
||||
DATA_SAVING_ALWAYS
|
||||
};
|
||||
|
||||
};
|
||||
class Endpoint{
|
||||
friend class VoIPController;
|
||||
friend class VoIPGroupController;
|
||||
public:
|
||||
|
||||
class AudioInputDevice : public AudioDevice{
|
||||
enum{
|
||||
TYPE_UDP_P2P_INET=1,
|
||||
TYPE_UDP_P2P_LAN,
|
||||
TYPE_UDP_RELAY,
|
||||
TYPE_TCP_RELAY
|
||||
};
|
||||
|
||||
};
|
||||
Endpoint(int64_t id, uint16_t port, IPv4Address& address, IPv6Address& v6address, char type, unsigned char* peerTag);
|
||||
Endpoint();
|
||||
int64_t id;
|
||||
uint16_t port;
|
||||
IPv4Address address;
|
||||
IPv6Address v6address;
|
||||
char type;
|
||||
unsigned char peerTag[16];
|
||||
|
||||
class VoIPController
|
||||
{
|
||||
public:
|
||||
VoIPController();
|
||||
~VoIPController();
|
||||
private:
|
||||
double lastPingTime;
|
||||
uint32_t lastPingSeq;
|
||||
double rtts[6];
|
||||
double averageRTT;
|
||||
NetworkSocket* socket;
|
||||
int udpPongCount;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the initial endpoints (relays)
|
||||
* @param endpoints Endpoints converted from phone.PhoneConnection TL objects
|
||||
* @param allowP2p Whether p2p connectivity is allowed
|
||||
*/
|
||||
void SetRemoteEndpoints(std::vector<Endpoint> endpoints, bool allowP2p);
|
||||
/**
|
||||
* Initialize and start all the internal threads
|
||||
*/
|
||||
void Start();
|
||||
/**
|
||||
* Initiate connection
|
||||
*/
|
||||
void Connect();
|
||||
Endpoint& GetRemoteEndpoint();
|
||||
/**
|
||||
* Get the debug info string to be displayed in client UI
|
||||
* @param buffer The buffer to put the string into
|
||||
* @param len The length of the buffer
|
||||
*/
|
||||
void GetDebugString(char* buffer, size_t len);
|
||||
/**
|
||||
* Notify the library of network type change
|
||||
* @param type The new network type
|
||||
*/
|
||||
void SetNetworkType(int type);
|
||||
/**
|
||||
* Get the average round-trip time for network packets
|
||||
* @return
|
||||
*/
|
||||
double GetAverageRTT();
|
||||
/**
|
||||
* Set the function to be called whenever the connection state changes
|
||||
* @param f
|
||||
*/
|
||||
void SetStateCallback(void (*f)(VoIPController*, int));
|
||||
static double GetCurrentTime();
|
||||
/**
|
||||
* Use this field to store any of your context data associated with this call
|
||||
*/
|
||||
void* implData;
|
||||
/**
|
||||
*
|
||||
* @param mute
|
||||
*/
|
||||
void SetMicMute(bool mute);
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param isOutgoing
|
||||
*/
|
||||
void SetEncryptionKey(char* key, bool isOutgoing);
|
||||
/**
|
||||
*
|
||||
* @param cfg
|
||||
*/
|
||||
void SetConfig(voip_config_t* cfg);
|
||||
float GetOutputLevel();
|
||||
void DebugCtl(int request, int param);
|
||||
/**
|
||||
*
|
||||
* @param stats
|
||||
*/
|
||||
void GetStats(voip_stats_t* stats);
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int64_t GetPreferredRelayID();
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int GetLastError();
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static voip_crypto_functions_t crypto;
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static const char* GetVersion();
|
||||
#ifdef TGVOIP_USE_AUDIO_SESSION
|
||||
void SetAcquireAudioSession(void (^)(void (^)()));
|
||||
void ReleaseAudioSession(void (^completion)());
|
||||
#endif
|
||||
class AudioDevice{
|
||||
public:
|
||||
std::string id;
|
||||
std::string displayName;
|
||||
};
|
||||
|
||||
class AudioOutputDevice : public AudioDevice{
|
||||
|
||||
};
|
||||
|
||||
class AudioInputDevice : public AudioDevice{
|
||||
|
||||
};
|
||||
|
||||
class VoIPController{
|
||||
friend class VoIPGroupController;
|
||||
public:
|
||||
VoIPController();
|
||||
virtual ~VoIPController();
|
||||
|
||||
/**
|
||||
* Set the initial endpoints (relays)
|
||||
* @param endpoints Endpoints converted from phone.PhoneConnection TL objects
|
||||
* @param allowP2p Whether p2p connectivity is allowed
|
||||
*/
|
||||
void SetRemoteEndpoints(std::vector<Endpoint> endpoints, bool allowP2p, int32_t connectionMaxLayer);
|
||||
/**
|
||||
* Initialize and start all the internal threads
|
||||
*/
|
||||
void Start();
|
||||
/**
|
||||
* Stop any internal threads. Don't call any other methods after this.
|
||||
*/
|
||||
void Stop();
|
||||
/**
|
||||
* Initiate connection
|
||||
*/
|
||||
void Connect();
|
||||
Endpoint& GetRemoteEndpoint();
|
||||
/**
|
||||
* Get the debug info string to be displayed in client UI
|
||||
* @param buffer The buffer to put the string into
|
||||
* @param len The length of the buffer
|
||||
*/
|
||||
virtual void GetDebugString(char* buffer, size_t len);
|
||||
/**
|
||||
* Notify the library of network type change
|
||||
* @param type The new network type
|
||||
*/
|
||||
virtual void SetNetworkType(int type);
|
||||
/**
|
||||
* Get the average round-trip time for network packets
|
||||
* @return
|
||||
*/
|
||||
double GetAverageRTT();
|
||||
static double GetCurrentTime();
|
||||
/**
|
||||
* Use this field to store any of your context data associated with this call
|
||||
*/
|
||||
void* implData;
|
||||
/**
|
||||
*
|
||||
* @param mute
|
||||
*/
|
||||
virtual void SetMicMute(bool mute);
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param isOutgoing
|
||||
*/
|
||||
void SetEncryptionKey(char* key, bool isOutgoing);
|
||||
/**
|
||||
*
|
||||
* @param cfg
|
||||
*/
|
||||
void SetConfig(voip_config_t* cfg);
|
||||
float GetOutputLevel();
|
||||
void DebugCtl(int request, int param);
|
||||
/**
|
||||
*
|
||||
* @param stats
|
||||
*/
|
||||
void GetStats(voip_stats_t* stats);
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetDebugLog();
|
||||
int64_t GetPreferredRelayID();
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int GetLastError();
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static voip_crypto_functions_t crypto;
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static const char* GetVersion();
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetDebugLog();
|
||||
/**
|
||||
*
|
||||
* @param buffer
|
||||
*/
|
||||
void GetDebugLog(char* buffer);
|
||||
size_t GetDebugLogLength();
|
||||
void GetDebugLog(char* buffer);
|
||||
size_t GetDebugLogLength();
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static std::vector<AudioInputDevice> EnumerateAudioInputs();
|
||||
static std::vector<AudioInputDevice> EnumerateAudioInputs();
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static std::vector<AudioOutputDevice> EnumerateAudioOutputs();
|
||||
static std::vector<AudioOutputDevice> EnumerateAudioOutputs();
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
void SetCurrentAudioInput(std::string id);
|
||||
void SetCurrentAudioInput(std::string id);
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
void SetCurrentAudioOutput(std::string id);
|
||||
void SetCurrentAudioOutput(std::string id);
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetCurrentAudioInputID();
|
||||
std::string GetCurrentAudioInputID();
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetCurrentAudioOutputID();
|
||||
/**
|
||||
* Set the proxy server to route the data through. Call this before connecting.
|
||||
* @param protocol PROXY_NONE or PROXY_SOCKS5
|
||||
* @param address IP address or domain name of the server
|
||||
* @param port Port of the server
|
||||
* @param username Username; empty string for anonymous
|
||||
* @param password Password; empty string if none
|
||||
*/
|
||||
void SetProxy(int protocol, std::string address, uint16_t port, std::string username, std::string password);
|
||||
std::string GetCurrentAudioOutputID();
|
||||
/**
|
||||
* Set the proxy server to route the data through. Call this before connecting.
|
||||
* @param protocol PROXY_NONE or PROXY_SOCKS5
|
||||
* @param address IP address or domain name of the server
|
||||
* @param port Port of the server
|
||||
* @param username Username; empty string for anonymous
|
||||
* @param password Password; empty string if none
|
||||
*/
|
||||
void SetProxy(int protocol, std::string address, uint16_t port, std::string username, std::string password);
|
||||
/**
|
||||
* Get the number of signal bars to display in the client UI.
|
||||
* @return the number of signal bars, from 1 to 4
|
||||
*/
|
||||
int GetSignalBarsCount();
|
||||
/**
|
||||
* Set the callback to be called when the signal bar count changes.
|
||||
* @param f
|
||||
*/
|
||||
void SetSignalBarsCountCallback(void (*f)(VoIPController*, int));
|
||||
/**
|
||||
* Enable or disable AGC (automatic gain control) on audio output. Should only be enabled on phones when the earpiece speaker is being used.
|
||||
* The audio output will be louder with this on.
|
||||
@ -341,182 +330,292 @@ public:
|
||||
* @param enabled I usually pick argument names to be self-explanatory
|
||||
*/
|
||||
void SetAudioOutputGainControlEnabled(bool enabled);
|
||||
/**
|
||||
* Get the additional capabilities of the peer client app
|
||||
* @return corresponding TGVOIP_PEER_CAP_* flags OR'ed together
|
||||
*/
|
||||
uint32_t GetPeerCapabilities();
|
||||
/**
|
||||
* Send the peer the key for the group call to prepare this private call to an upgrade to a E2E group call.
|
||||
* The peer must have the TGVOIP_PEER_CAP_GROUP_CALLS capability. After the peer acknowledges the key, Callbacks::groupCallKeySent will be called.
|
||||
* @param key newly-generated group call key, must be exactly 265 bytes long
|
||||
*/
|
||||
void SendGroupCallKey(unsigned char* key);
|
||||
/**
|
||||
* In an incoming call, request the peer to generate a new encryption key, send it to you and upgrade this call to a E2E group call.
|
||||
*/
|
||||
void RequestCallUpgrade();
|
||||
void SetEchoCancellationStrength(int strength);
|
||||
|
||||
private:
|
||||
struct PendingOutgoingPacket{
|
||||
struct Callbacks{
|
||||
void (*connectionStateChanged)(VoIPController*, int);
|
||||
void (*signalBarCountChanged)(VoIPController*, int);
|
||||
void (*groupCallKeySent)(VoIPController*);
|
||||
void (*groupCallKeyReceived)(VoIPController*, unsigned char*);
|
||||
void (*upgradeToGroupCallRequested)(VoIPController*);
|
||||
};
|
||||
void SetCallbacks(Callbacks callbacks);
|
||||
|
||||
protected:
|
||||
struct RecentOutgoingPacket{
|
||||
uint32_t seq;
|
||||
uint16_t id; // for group calls only
|
||||
double sendTime;
|
||||
double ackTime;
|
||||
};
|
||||
struct PendingOutgoingPacket{
|
||||
uint32_t seq;
|
||||
unsigned char type;
|
||||
size_t len;
|
||||
unsigned char* data;
|
||||
Endpoint* endpoint;
|
||||
};
|
||||
virtual void ProcessIncomingPacket(NetworkPacket& packet, Endpoint* srcEndpoint);
|
||||
virtual void WritePacketHeader(uint32_t seq, BufferOutputStream* s, unsigned char type, uint32_t length);
|
||||
virtual void SendPacket(unsigned char* data, size_t len, Endpoint* ep, PendingOutgoingPacket& srcPacket);
|
||||
virtual void SendInit();
|
||||
virtual void SendUdpPing(Endpoint* endpoint);
|
||||
virtual void SendRelayPings();
|
||||
virtual void OnAudioOutputReady();
|
||||
|
||||
private:
|
||||
struct Stream{
|
||||
int32_t userID;
|
||||
unsigned char id;
|
||||
unsigned char type;
|
||||
uint32_t codec;
|
||||
bool enabled;
|
||||
uint16_t frameDuration;
|
||||
JitterBuffer* jitterBuffer;
|
||||
OpusDecoder* decoder;
|
||||
CallbackWrapper* callbackWrapper;
|
||||
};
|
||||
enum{
|
||||
UDP_UNKNOWN=0,
|
||||
UDP_PING_SENT,
|
||||
UDP_AVAILABLE,
|
||||
UDP_NOT_AVAILABLE,
|
||||
UDP_BAD
|
||||
};
|
||||
|
||||
void RunRecvThread(void* arg);
|
||||
void RunSendThread(void* arg);
|
||||
void RunTickThread(void* arg);
|
||||
void HandleAudioInput(unsigned char* data, size_t len);
|
||||
void UpdateAudioBitrate();
|
||||
void SetState(int state);
|
||||
void UpdateAudioOutputState();
|
||||
void InitUDPProxy();
|
||||
void UpdateDataSavingState();
|
||||
void KDF(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv);
|
||||
void KDF2(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv);
|
||||
static size_t AudioInputCallback(unsigned char* data, size_t length, void* param);
|
||||
void SendPublicEndpointsRequest();
|
||||
void SendPublicEndpointsRequest(Endpoint& relay);
|
||||
Endpoint* GetEndpointByType(int type);
|
||||
void SendPacketReliably(unsigned char type, unsigned char* data, size_t len, double retryInterval, double timeout);
|
||||
uint32_t GenerateOutSeq();
|
||||
void LogDebugInfo();
|
||||
void ActuallySendPacket(NetworkPacket& pkt, Endpoint* ep);
|
||||
void StartAudio();
|
||||
int state;
|
||||
std::vector<Endpoint*> endpoints;
|
||||
Endpoint* currentEndpoint;
|
||||
Endpoint* preferredRelay;
|
||||
Endpoint* peerPreferredRelay;
|
||||
bool runReceiver;
|
||||
uint32_t seq;
|
||||
unsigned char type;
|
||||
size_t len;
|
||||
unsigned char* data;
|
||||
Endpoint* endpoint;
|
||||
};
|
||||
enum{
|
||||
UDP_UNKNOWN=0,
|
||||
UDP_PING_SENT,
|
||||
UDP_AVAILABIE,
|
||||
UDP_NOT_AVAILABLE
|
||||
};
|
||||
uint32_t lastRemoteSeq;
|
||||
uint32_t lastRemoteAckSeq;
|
||||
uint32_t lastSentSeq;
|
||||
std::vector<RecentOutgoingPacket> recentOutgoingPackets;
|
||||
double recvPacketTimes[32];
|
||||
uint32_t sendLossCountHistory[32];
|
||||
uint32_t audioTimestampIn;
|
||||
uint32_t audioTimestampOut;
|
||||
tgvoip::audio::AudioInput* audioInput;
|
||||
tgvoip::audio::AudioOutput* audioOutput;
|
||||
OpusEncoder* encoder;
|
||||
BlockingQueue<PendingOutgoingPacket>* sendQueue;
|
||||
EchoCanceller* echoCanceller;
|
||||
Mutex sendBufferMutex;
|
||||
Mutex endpointsMutex;
|
||||
bool stopping;
|
||||
bool audioOutStarted;
|
||||
Thread* recvThread;
|
||||
Thread* sendThread;
|
||||
Thread* tickThread;
|
||||
uint32_t packetsRecieved;
|
||||
uint32_t recvLossCount;
|
||||
uint32_t prevSendLossCount;
|
||||
uint32_t firstSentPing;
|
||||
double rttHistory[32];
|
||||
bool waitingForAcks;
|
||||
int networkType;
|
||||
int dontSendPackets;
|
||||
int lastError;
|
||||
bool micMuted;
|
||||
uint32_t maxBitrate;
|
||||
std::vector<Stream> outgoingStreams;
|
||||
std::vector<Stream> incomingStreams;
|
||||
unsigned char encryptionKey[256];
|
||||
unsigned char keyFingerprint[8];
|
||||
unsigned char callID[16];
|
||||
double stateChangeTime;
|
||||
bool waitingForRelayPeerInfo;
|
||||
bool allowP2p;
|
||||
bool dataSavingMode;
|
||||
bool dataSavingRequestedByPeer;
|
||||
std::string activeNetItfName;
|
||||
double publicEndpointsReqTime;
|
||||
std::vector<voip_queued_packet_t*> queuedPackets;
|
||||
Mutex queuedPacketsMutex;
|
||||
double connectionInitTime;
|
||||
double lastRecvPacketTime;
|
||||
voip_config_t config;
|
||||
int32_t peerVersion;
|
||||
CongestionControl* conctl;
|
||||
voip_stats_t stats;
|
||||
bool receivedInit;
|
||||
bool receivedInitAck;
|
||||
std::vector<std::string> debugLogs;
|
||||
bool isOutgoing;
|
||||
NetworkSocket* udpSocket;
|
||||
NetworkSocket* realUdpSocket;
|
||||
FILE* statsDump;
|
||||
std::string currentAudioInput;
|
||||
std::string currentAudioOutput;
|
||||
bool useTCP;
|
||||
bool useUDP;
|
||||
bool didAddTcpRelays;
|
||||
double setEstablishedAt;
|
||||
SocketSelectCanceller* selectCanceller;
|
||||
NetworkSocket* openingTcpSocket;
|
||||
unsigned char signalBarsHistory[4];
|
||||
|
||||
static void* StartRecvThread(void* arg);
|
||||
static void* StartSendThread(void* arg);
|
||||
static void* StartTickThread(void* arg);
|
||||
void RunRecvThread();
|
||||
void RunSendThread();
|
||||
void RunTickThread();
|
||||
void SendPacket(unsigned char* data, size_t len, Endpoint* ep);
|
||||
void HandleAudioInput(unsigned char* data, size_t len);
|
||||
void UpdateAudioBitrate();
|
||||
void SetState(int state);
|
||||
void UpdateAudioOutputState();
|
||||
void SendInit();
|
||||
void InitUDPProxy();
|
||||
void UpdateDataSavingState();
|
||||
void KDF(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv);
|
||||
void WritePacketHeader(uint32_t seq, BufferOutputStream* s, unsigned char type, uint32_t length);
|
||||
static size_t AudioInputCallback(unsigned char* data, size_t length, void* param);
|
||||
void SendPublicEndpointsRequest();
|
||||
void SendPublicEndpointsRequest(Endpoint& relay);
|
||||
Endpoint* GetEndpointByType(int type);
|
||||
void SendPacketReliably(unsigned char type, unsigned char* data, size_t len, double retryInterval, double timeout);
|
||||
uint32_t GenerateOutSeq();
|
||||
void LogDebugInfo();
|
||||
void SendUdpPing(Endpoint* endpoint);
|
||||
int state;
|
||||
std::vector<Endpoint*> endpoints;
|
||||
Endpoint* currentEndpoint;
|
||||
Endpoint* preferredRelay;
|
||||
Endpoint* peerPreferredRelay;
|
||||
bool runReceiver;
|
||||
uint32_t seq;
|
||||
uint32_t lastRemoteSeq;
|
||||
uint32_t lastRemoteAckSeq;
|
||||
uint32_t lastSentSeq;
|
||||
double remoteAcks[32];
|
||||
double sentPacketTimes[32];
|
||||
double recvPacketTimes[32];
|
||||
uint32_t sendLossCountHistory[32];
|
||||
uint32_t audioTimestampIn;
|
||||
uint32_t audioTimestampOut;
|
||||
tgvoip::audio::AudioInput* audioInput;
|
||||
tgvoip::audio::AudioOutput* audioOutput;
|
||||
JitterBuffer* jitterBuffer;
|
||||
OpusDecoder* decoder;
|
||||
OpusEncoder* encoder;
|
||||
BlockingQueue<PendingOutgoingPacket>* sendQueue;
|
||||
EchoCanceller* echoCanceller;
|
||||
tgvoip_mutex_t sendBufferMutex;
|
||||
tgvoip_mutex_t endpointsMutex;
|
||||
bool stopping;
|
||||
bool audioOutStarted;
|
||||
tgvoip_thread_t recvThread;
|
||||
tgvoip_thread_t sendThread;
|
||||
tgvoip_thread_t tickThread;
|
||||
uint32_t packetsRecieved;
|
||||
uint32_t recvLossCount;
|
||||
uint32_t prevSendLossCount;
|
||||
uint32_t firstSentPing;
|
||||
double rttHistory[32];
|
||||
bool waitingForAcks;
|
||||
int networkType;
|
||||
int dontSendPackets;
|
||||
int lastError;
|
||||
bool micMuted;
|
||||
uint32_t maxBitrate;
|
||||
void (*stateCallback)(VoIPController*, int);
|
||||
std::vector<voip_stream_t*> outgoingStreams;
|
||||
std::vector<voip_stream_t*> incomingStreams;
|
||||
unsigned char encryptionKey[256];
|
||||
unsigned char keyFingerprint[8];
|
||||
unsigned char callID[16];
|
||||
double stateChangeTime;
|
||||
bool waitingForRelayPeerInfo;
|
||||
bool allowP2p;
|
||||
bool dataSavingMode;
|
||||
bool dataSavingRequestedByPeer;
|
||||
std::string activeNetItfName;
|
||||
double publicEndpointsReqTime;
|
||||
std::vector<voip_queued_packet_t*> queuedPackets;
|
||||
tgvoip_mutex_t queuedPacketsMutex;
|
||||
double connectionInitTime;
|
||||
double lastRecvPacketTime;
|
||||
voip_config_t config;
|
||||
int32_t peerVersion;
|
||||
CongestionControl* conctl;
|
||||
voip_stats_t stats;
|
||||
bool receivedInit;
|
||||
bool receivedInitAck;
|
||||
std::vector<std::string> debugLogs;
|
||||
bool isOutgoing;
|
||||
NetworkSocket* udpSocket;
|
||||
NetworkSocket* realUdpSocket;
|
||||
FILE* statsDump;
|
||||
std::string currentAudioInput;
|
||||
std::string currentAudioOutput;
|
||||
bool useTCP;
|
||||
bool useUDP;
|
||||
bool didAddTcpRelays;
|
||||
double setEstablishedAt;
|
||||
SocketSelectCanceller* selectCanceller;
|
||||
NetworkSocket* openingTcpSocket;
|
||||
unsigned char signalBarsHistory[4];
|
||||
BufferPool outgoingPacketsBufferPool;
|
||||
int udpConnectivityState;
|
||||
double lastUdpPingTime;
|
||||
int udpPingCount;
|
||||
int echoCancellationStrength;
|
||||
|
||||
BufferPool outgoingPacketsBufferPool;
|
||||
int udpConnectivityState;
|
||||
double lastUdpPingTime;
|
||||
int udpPingCount;
|
||||
int echoCancellationStrength;
|
||||
|
||||
int proxyProtocol;
|
||||
std::string proxyAddress;
|
||||
uint16_t proxyPort;
|
||||
std::string proxyUsername;
|
||||
std::string proxyPassword;
|
||||
IPv4Address* resolvedProxyAddress;
|
||||
int proxyProtocol;
|
||||
std::string proxyAddress;
|
||||
uint16_t proxyPort;
|
||||
std::string proxyUsername;
|
||||
std::string proxyPassword;
|
||||
IPv4Address* resolvedProxyAddress;
|
||||
|
||||
int signalBarCount;
|
||||
void (*signalBarCountCallback)(VoIPController*, int);
|
||||
|
||||
AutomaticGainControl* outputAGC;
|
||||
bool outputAGCEnabled;
|
||||
|
||||
/*** server config values ***/
|
||||
uint32_t maxAudioBitrate;
|
||||
uint32_t maxAudioBitrateEDGE;
|
||||
uint32_t maxAudioBitrateGPRS;
|
||||
uint32_t maxAudioBitrateSaving;
|
||||
uint32_t initAudioBitrate;
|
||||
uint32_t initAudioBitrateEDGE;
|
||||
uint32_t initAudioBitrateGPRS;
|
||||
uint32_t initAudioBitrateSaving;
|
||||
uint32_t minAudioBitrate;
|
||||
uint32_t audioBitrateStepIncr;
|
||||
uint32_t audioBitrateStepDecr;
|
||||
double relaySwitchThreshold;
|
||||
double p2pToRelaySwitchThreshold;
|
||||
double relayToP2pSwitchThreshold;
|
||||
double reconnectingTimeout;
|
||||
uint32_t peerCapabilities;
|
||||
Callbacks callbacks;
|
||||
bool didReceiveGroupCallKey;
|
||||
bool didReceiveGroupCallKeyAck;
|
||||
bool didSendGroupCallKey;
|
||||
bool didSendUpgradeRequest;
|
||||
bool didInvokeUpdateCallback;
|
||||
|
||||
#ifdef TGVOIP_USE_AUDIO_SESSION
|
||||
void (^acquireAudioSession)(void (^)());
|
||||
bool needNotifyAcquiredAudioSession;
|
||||
#endif
|
||||
int32_t connectionMaxLayer;
|
||||
bool useMTProto2;
|
||||
bool setCurrentEndpointToTCP;
|
||||
|
||||
public:
|
||||
/*** server config values ***/
|
||||
uint32_t maxAudioBitrate;
|
||||
uint32_t maxAudioBitrateEDGE;
|
||||
uint32_t maxAudioBitrateGPRS;
|
||||
uint32_t maxAudioBitrateSaving;
|
||||
uint32_t initAudioBitrate;
|
||||
uint32_t initAudioBitrateEDGE;
|
||||
uint32_t initAudioBitrateGPRS;
|
||||
uint32_t initAudioBitrateSaving;
|
||||
uint32_t minAudioBitrate;
|
||||
uint32_t audioBitrateStepIncr;
|
||||
uint32_t audioBitrateStepDecr;
|
||||
double relaySwitchThreshold;
|
||||
double p2pToRelaySwitchThreshold;
|
||||
double relayToP2pSwitchThreshold;
|
||||
double reconnectingTimeout;
|
||||
|
||||
/*** platform-specific things **/
|
||||
#ifdef __APPLE__
|
||||
static double machTimebase;
|
||||
static uint64_t machTimestart;
|
||||
#if TARGET_OS_IPHONE
|
||||
// temporary fix for nasty linking errors
|
||||
void SetRemoteEndpoints(voip_legacy_endpoint_t* buffer, size_t count, bool allowP2P);
|
||||
audio::AudioUnitIO* appleAudioIO;
|
||||
#endif
|
||||
|
||||
public:
|
||||
#ifdef __APPLE__
|
||||
static double machTimebase;
|
||||
static uint64_t machTimestart;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
static int64_t win32TimeScale;
|
||||
static bool didInitWin32TimeScale;
|
||||
static int64_t win32TimeScale;
|
||||
static bool didInitWin32TimeScale;
|
||||
#endif
|
||||
};
|
||||
|
||||
class VoIPGroupController : public VoIPController{
|
||||
public:
|
||||
VoIPGroupController(int32_t timeDifference);
|
||||
virtual ~VoIPGroupController();
|
||||
void SetGroupCallInfo(unsigned char* encryptionKey, unsigned char* reflectorGroupTag, unsigned char* reflectorSelfTag, unsigned char* reflectorSelfSecret, unsigned char* reflectorSelfTagHash, int32_t selfUserID, IPv4Address reflectorAddress, IPv6Address reflectorAddressV6, uint16_t reflectorPort);
|
||||
void AddGroupCallParticipant(int32_t userID, unsigned char* memberTagHash, unsigned char* serializedStreams, size_t streamsLength);
|
||||
void RemoveGroupCallParticipant(int32_t userID);
|
||||
float GetParticipantAudioLevel(int32_t userID);
|
||||
virtual void SetMicMute(bool mute);
|
||||
void SetParticipantVolume(int32_t userID, float volume);
|
||||
void SetParticipantStreams(int32_t userID, unsigned char* serializedStreams, size_t length);
|
||||
static size_t GetInitialStreams(unsigned char* buf, size_t size);
|
||||
|
||||
struct Callbacks : public VoIPController::Callbacks{
|
||||
void (*updateStreams)(VoIPGroupController*, unsigned char*, size_t);
|
||||
void (*participantAudioStateChanged)(VoIPGroupController*, int32_t, bool);
|
||||
|
||||
};
|
||||
void SetCallbacks(Callbacks callbacks);
|
||||
virtual void GetDebugString(char* buffer, size_t length);
|
||||
virtual void SetNetworkType(int type);
|
||||
protected:
|
||||
virtual void ProcessIncomingPacket(NetworkPacket& packet, Endpoint* srcEndpoint);
|
||||
virtual void SendInit();
|
||||
virtual void SendUdpPing(Endpoint* endpoint);
|
||||
virtual void SendRelayPings();
|
||||
virtual void SendPacket(unsigned char* data, size_t len, Endpoint* ep, PendingOutgoingPacket& srcPacket);
|
||||
virtual void WritePacketHeader(uint32_t seq, BufferOutputStream* s, unsigned char type, uint32_t length);
|
||||
virtual void OnAudioOutputReady();
|
||||
private:
|
||||
int32_t GetCurrentUnixtime();
|
||||
std::vector<Stream> DeserializeStreams(BufferInputStream& in);
|
||||
void SendRecentPacketsRequest();
|
||||
void SendSpecialReflectorRequest(unsigned char* data, size_t len);
|
||||
void SerializeAndUpdateOutgoingStreams();
|
||||
struct GroupCallParticipant{
|
||||
int32_t userID;
|
||||
unsigned char memberTagHash[32];
|
||||
std::vector<Stream> streams;
|
||||
AudioLevelMeter* levelMeter;
|
||||
};
|
||||
std::vector<GroupCallParticipant> participants;
|
||||
unsigned char reflectorSelfTag[16];
|
||||
unsigned char reflectorSelfSecret[16];
|
||||
unsigned char reflectorSelfTagHash[32];
|
||||
int32_t userSelfID;
|
||||
Endpoint* groupReflector;
|
||||
AudioMixer* audioMixer;
|
||||
AudioLevelMeter selfLevelMeter;
|
||||
Callbacks groupCallbacks;
|
||||
struct PacketIdMapping{
|
||||
uint32_t seq;
|
||||
uint16_t id;
|
||||
double ackTime;
|
||||
};
|
||||
std::vector<PacketIdMapping> recentSentPackets;
|
||||
Mutex sentPacketsMutex;
|
||||
Mutex participantsMutex;
|
||||
int32_t timeDifference;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -13,11 +13,9 @@ using namespace tgvoip;
|
||||
ServerConfig* ServerConfig::sharedInstance=NULL;
|
||||
|
||||
ServerConfig::ServerConfig(){
|
||||
init_mutex(mutex);
|
||||
}
|
||||
|
||||
ServerConfig::~ServerConfig(){
|
||||
free_mutex(mutex);
|
||||
}
|
||||
|
||||
ServerConfig *ServerConfig::GetSharedInstance(){
|
||||
|
@ -30,7 +30,7 @@ private:
|
||||
static ServerConfig* sharedInstance;
|
||||
bool ContainsKey(std::string key);
|
||||
std::map<std::string, std::string> config;
|
||||
tgvoip_mutex_t mutex;
|
||||
Mutex mutex;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ AudioInput::AudioInput(std::string deviceID) : currentDevice(deviceID){
|
||||
failed=false;
|
||||
}
|
||||
|
||||
AudioInput *AudioInput::Create(std::string deviceID){
|
||||
AudioInput *AudioInput::Create(std::string deviceID, void* platformSpecific){
|
||||
#if defined(__ANDROID__)
|
||||
return new AudioInputAndroid();
|
||||
#elif defined(__APPLE__)
|
||||
@ -47,7 +47,7 @@ AudioInput *AudioInput::Create(std::string deviceID){
|
||||
if(kCFCoreFoundationVersionNumber<kCFCoreFoundationVersionNumber10_7)
|
||||
return new AudioInputAudioUnitLegacy(deviceID);
|
||||
#endif
|
||||
return new AudioInputAudioUnit(deviceID);
|
||||
return new AudioInputAudioUnit(deviceID, reinterpret_cast<AudioUnitIO*>(platformSpecific));
|
||||
#elif defined(_WIN32)
|
||||
#ifdef TGVOIP_WINXP_COMPAT
|
||||
if(LOBYTE(LOWORD(GetVersion()))<6)
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
bool IsInitialized();
|
||||
virtual std::string GetCurrentDevice();
|
||||
virtual void SetCurrentDevice(std::string deviceID);
|
||||
static AudioInput* Create(std::string deviceID);
|
||||
static AudioInput* Create(std::string deviceID, void* platformSpecific);
|
||||
static void EnumerateDevices(std::vector<AudioInputDevice>& devs);
|
||||
static int32_t GetEstimatedDelay();
|
||||
|
||||
|
@ -6,9 +6,11 @@
|
||||
|
||||
#include "AudioOutput.h"
|
||||
#include "../logging.h"
|
||||
#include <stdlib.h>
|
||||
#if defined(__ANDROID__)
|
||||
#include "../os/android/AudioOutputOpenSLES.h"
|
||||
#include "../os/android/AudioOutputAndroid.h"
|
||||
#include <sys/system_properties.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#include "../os/darwin/AudioOutputAudioUnit.h"
|
||||
@ -30,13 +32,13 @@
|
||||
using namespace tgvoip;
|
||||
using namespace tgvoip::audio;
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
int AudioOutput::systemVersion;
|
||||
#endif
|
||||
int32_t AudioOutput::estimatedDelay=60;
|
||||
|
||||
AudioOutput *AudioOutput::Create(std::string deviceID){
|
||||
AudioOutput *AudioOutput::Create(std::string deviceID, void* platformSpecific){
|
||||
#if defined(__ANDROID__)
|
||||
char sdkNum[PROP_VALUE_MAX];
|
||||
__system_property_get("ro.build.version.sdk", sdkNum);
|
||||
int systemVersion=atoi(sdkNum);
|
||||
//if(systemVersion<21)
|
||||
return new AudioOutputAndroid();
|
||||
//return new AudioOutputOpenSLES();
|
||||
@ -45,7 +47,7 @@ AudioOutput *AudioOutput::Create(std::string deviceID){
|
||||
if(kCFCoreFoundationVersionNumber<kCFCoreFoundationVersionNumber10_7)
|
||||
return new AudioOutputAudioUnitLegacy(deviceID);
|
||||
#endif
|
||||
return new AudioOutputAudioUnit(deviceID);
|
||||
return new AudioOutputAudioUnit(deviceID, reinterpret_cast<AudioUnitIO*>(platformSpecific));
|
||||
#elif defined(_WIN32)
|
||||
#ifdef TGVOIP_WINXP_COMPAT
|
||||
if(LOBYTE(LOWORD(GetVersion()))<6)
|
||||
@ -80,6 +82,9 @@ AudioOutput::~AudioOutput(){
|
||||
|
||||
int32_t AudioOutput::GetEstimatedDelay(){
|
||||
#if defined(__ANDROID__)
|
||||
char sdkNum[PROP_VALUE_MAX];
|
||||
__system_property_get("ro.build.version.sdk", sdkNum);
|
||||
int systemVersion=atoi(sdkNum);
|
||||
return systemVersion<21 ? 150 : 50;
|
||||
#endif
|
||||
return estimatedDelay;
|
||||
|
@ -29,14 +29,10 @@ public:
|
||||
static int32_t GetEstimatedDelay();
|
||||
virtual std::string GetCurrentDevice();
|
||||
virtual void SetCurrentDevice(std::string deviceID);
|
||||
static AudioOutput* Create(std::string deviceID);
|
||||
static AudioOutput* Create(std::string deviceID, void* platformSpecific);
|
||||
static void EnumerateDevices(std::vector<AudioOutputDevice>& devs);
|
||||
bool IsInitialized();
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
static int systemVersion;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
std::string currentDevice;
|
||||
bool failed;
|
||||
|
@ -22,6 +22,12 @@ jfieldID audioRecordInstanceFld=NULL;
|
||||
jfieldID audioTrackInstanceFld=NULL;
|
||||
jmethodID setStateMethod=NULL;
|
||||
jmethodID setSignalBarsMethod=NULL;
|
||||
jmethodID setSelfStreamsMethod=NULL;
|
||||
jmethodID setParticipantAudioEnabledMethod=NULL;
|
||||
jmethodID groupCallKeyReceivedMethod=NULL;
|
||||
jmethodID groupCallKeySentMethod=NULL;
|
||||
jmethodID callUpgradeRequestReceivedMethod=NULL;
|
||||
jclass jniUtilitiesClass=NULL;
|
||||
|
||||
struct impl_data_android_t{
|
||||
jobject javaObject;
|
||||
@ -30,48 +36,164 @@ struct impl_data_android_t{
|
||||
using namespace tgvoip;
|
||||
using namespace tgvoip::audio;
|
||||
|
||||
void updateConnectionState(VoIPController* cntrlr, int state){
|
||||
impl_data_android_t* impl=(impl_data_android_t*) cntrlr->implData;
|
||||
if(!impl->javaObject)
|
||||
return;
|
||||
JNIEnv* env=NULL;
|
||||
bool didAttach=false;
|
||||
sharedJVM->GetEnv((void**) &env, JNI_VERSION_1_6);
|
||||
if(!env){
|
||||
sharedJVM->AttachCurrentThread(&env, NULL);
|
||||
didAttach=true;
|
||||
namespace tgvoip {
|
||||
void updateConnectionState(VoIPController *cntrlr, int state){
|
||||
impl_data_android_t *impl=(impl_data_android_t *) cntrlr->implData;
|
||||
if(!impl->javaObject)
|
||||
return;
|
||||
JNIEnv *env=NULL;
|
||||
bool didAttach=false;
|
||||
sharedJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
|
||||
if(!env){
|
||||
sharedJVM->AttachCurrentThread(&env, NULL);
|
||||
didAttach=true;
|
||||
}
|
||||
|
||||
if(setStateMethod)
|
||||
env->CallVoidMethod(impl->javaObject, setStateMethod, state);
|
||||
|
||||
if(didAttach){
|
||||
sharedJVM->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
if(setStateMethod)
|
||||
env->CallVoidMethod(impl->javaObject, setStateMethod, state);
|
||||
void updateSignalBarCount(VoIPController *cntrlr, int count){
|
||||
impl_data_android_t *impl=(impl_data_android_t *) cntrlr->implData;
|
||||
if(!impl->javaObject)
|
||||
return;
|
||||
JNIEnv *env=NULL;
|
||||
bool didAttach=false;
|
||||
sharedJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
|
||||
if(!env){
|
||||
sharedJVM->AttachCurrentThread(&env, NULL);
|
||||
didAttach=true;
|
||||
}
|
||||
|
||||
if(didAttach){
|
||||
sharedJVM->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
if(setSignalBarsMethod)
|
||||
env->CallVoidMethod(impl->javaObject, setSignalBarsMethod, count);
|
||||
|
||||
void updateSignalBarCount(VoIPController* cntrlr, int count){
|
||||
impl_data_android_t* impl=(impl_data_android_t*) cntrlr->implData;
|
||||
if(!impl->javaObject)
|
||||
return;
|
||||
JNIEnv* env=NULL;
|
||||
bool didAttach=false;
|
||||
sharedJVM->GetEnv((void**) &env, JNI_VERSION_1_6);
|
||||
if(!env){
|
||||
sharedJVM->AttachCurrentThread(&env, NULL);
|
||||
didAttach=true;
|
||||
if(didAttach){
|
||||
sharedJVM->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
if(setSignalBarsMethod)
|
||||
env->CallVoidMethod(impl->javaObject, setSignalBarsMethod, count);
|
||||
void updateGroupCallStreams(VoIPGroupController *cntrlr, unsigned char *streams, size_t len){
|
||||
impl_data_android_t *impl=(impl_data_android_t *) cntrlr->implData;
|
||||
if(!impl->javaObject)
|
||||
return;
|
||||
JNIEnv *env=NULL;
|
||||
bool didAttach=false;
|
||||
sharedJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
|
||||
if(!env){
|
||||
sharedJVM->AttachCurrentThread(&env, NULL);
|
||||
didAttach=true;
|
||||
}
|
||||
|
||||
if(didAttach){
|
||||
sharedJVM->DetachCurrentThread();
|
||||
if(setSelfStreamsMethod){
|
||||
jbyteArray jstreams=env->NewByteArray(len);
|
||||
jbyte *el=env->GetByteArrayElements(jstreams, NULL);
|
||||
memcpy(el, streams, len);
|
||||
env->ReleaseByteArrayElements(jstreams, el, 0);
|
||||
env->CallVoidMethod(impl->javaObject, setSelfStreamsMethod, jstreams);
|
||||
}
|
||||
|
||||
|
||||
if(didAttach){
|
||||
sharedJVM->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
void groupCallKeyReceived(VoIPController *cntrlr, unsigned char *key){
|
||||
impl_data_android_t *impl=(impl_data_android_t *) cntrlr->implData;
|
||||
if(!impl->javaObject)
|
||||
return;
|
||||
JNIEnv *env=NULL;
|
||||
bool didAttach=false;
|
||||
sharedJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
|
||||
if(!env){
|
||||
sharedJVM->AttachCurrentThread(&env, NULL);
|
||||
didAttach=true;
|
||||
}
|
||||
|
||||
if(groupCallKeyReceivedMethod){
|
||||
jbyteArray jkey=env->NewByteArray(256);
|
||||
jbyte *el=env->GetByteArrayElements(jkey, NULL);
|
||||
memcpy(el, key, 256);
|
||||
env->ReleaseByteArrayElements(jkey, el, 0);
|
||||
env->CallVoidMethod(impl->javaObject, groupCallKeyReceivedMethod, jkey);
|
||||
}
|
||||
|
||||
if(didAttach){
|
||||
sharedJVM->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
void groupCallKeySent(VoIPController *cntrlr){
|
||||
impl_data_android_t *impl=(impl_data_android_t *) cntrlr->implData;
|
||||
if(!impl->javaObject)
|
||||
return;
|
||||
JNIEnv *env=NULL;
|
||||
bool didAttach=false;
|
||||
sharedJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
|
||||
if(!env){
|
||||
sharedJVM->AttachCurrentThread(&env, NULL);
|
||||
didAttach=true;
|
||||
}
|
||||
|
||||
if(groupCallKeySentMethod){
|
||||
env->CallVoidMethod(impl->javaObject, groupCallKeySentMethod);
|
||||
}
|
||||
|
||||
if(didAttach){
|
||||
sharedJVM->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
void callUpgradeRequestReceived(VoIPController* cntrlr){
|
||||
impl_data_android_t *impl=(impl_data_android_t *) cntrlr->implData;
|
||||
if(!impl->javaObject)
|
||||
return;
|
||||
JNIEnv *env=NULL;
|
||||
bool didAttach=false;
|
||||
sharedJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
|
||||
if(!env){
|
||||
sharedJVM->AttachCurrentThread(&env, NULL);
|
||||
didAttach=true;
|
||||
}
|
||||
|
||||
if(groupCallKeySentMethod){
|
||||
env->CallVoidMethod(impl->javaObject, callUpgradeRequestReceivedMethod);
|
||||
}
|
||||
|
||||
if(didAttach){
|
||||
sharedJVM->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
void updateParticipantAudioState(VoIPGroupController *cntrlr, int32_t userID, bool enabled){
|
||||
impl_data_android_t *impl=(impl_data_android_t *) cntrlr->implData;
|
||||
if(!impl->javaObject)
|
||||
return;
|
||||
JNIEnv *env=NULL;
|
||||
bool didAttach=false;
|
||||
sharedJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
|
||||
if(!env){
|
||||
sharedJVM->AttachCurrentThread(&env, NULL);
|
||||
didAttach=true;
|
||||
}
|
||||
|
||||
if(setParticipantAudioEnabledMethod){
|
||||
env->CallVoidMethod(impl->javaObject, setParticipantAudioEnabledMethod, userID, enabled);
|
||||
}
|
||||
|
||||
|
||||
if(didAttach){
|
||||
sharedJVM->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong Java_org_telegram_messenger_voip_VoIPController_nativeInit(JNIEnv* env, jobject thiz, jint systemVersion){
|
||||
AudioOutputAndroid::systemVersion=systemVersion;
|
||||
|
||||
env->GetJavaVM(&sharedJVM);
|
||||
if(!AudioInputAndroid::jniClass){
|
||||
@ -90,15 +212,27 @@ extern "C" JNIEXPORT jlong Java_org_telegram_messenger_voip_VoIPController_nativ
|
||||
AudioOutputAndroid::stopMethod=env->GetMethodID(cls, "stop", "()V");
|
||||
}
|
||||
|
||||
setStateMethod=env->GetMethodID(env->GetObjectClass(thiz), "handleStateChange", "(I)V");
|
||||
setSignalBarsMethod=env->GetMethodID(env->GetObjectClass(thiz), "handleSignalBarsChange", "(I)V");
|
||||
jclass thisClass=env->FindClass("org/telegram/messenger/voip/VoIPController");
|
||||
setStateMethod=env->GetMethodID(thisClass, "handleStateChange", "(I)V");
|
||||
setSignalBarsMethod=env->GetMethodID(thisClass, "handleSignalBarsChange", "(I)V");
|
||||
groupCallKeyReceivedMethod=env->GetMethodID(thisClass, "groupCallKeyReceived", "([B)V");
|
||||
groupCallKeySentMethod=env->GetMethodID(thisClass, "groupCallKeySent", "()V");
|
||||
callUpgradeRequestReceivedMethod=env->GetMethodID(thisClass, "callUpgradeRequestReceived", "()V");
|
||||
|
||||
if(!jniUtilitiesClass)
|
||||
jniUtilitiesClass=(jclass) env->NewGlobalRef(env->FindClass("org/telegram/messenger/voip/JNIUtilities"));
|
||||
|
||||
impl_data_android_t* impl=(impl_data_android_t*) malloc(sizeof(impl_data_android_t));
|
||||
impl->javaObject=env->NewGlobalRef(thiz);
|
||||
VoIPController* cntrlr=new VoIPController();
|
||||
cntrlr->implData=impl;
|
||||
cntrlr->SetStateCallback(updateConnectionState);
|
||||
cntrlr->SetSignalBarsCountCallback(updateSignalBarCount);
|
||||
VoIPController::Callbacks callbacks;
|
||||
callbacks.connectionStateChanged=updateConnectionState;
|
||||
callbacks.signalBarCountChanged=updateSignalBarCount;
|
||||
callbacks.groupCallKeyReceived=groupCallKeyReceived;
|
||||
callbacks.groupCallKeySent=groupCallKeySent;
|
||||
callbacks.upgradeToGroupCallRequested=callUpgradeRequestReceived;
|
||||
cntrlr->SetCallbacks(callbacks);
|
||||
return (jlong)(intptr_t)cntrlr;
|
||||
}
|
||||
|
||||
@ -128,7 +262,7 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_native
|
||||
env->ReleaseByteArrayElements(key, akey, JNI_ABORT);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetRemoteEndpoints(JNIEnv* env, jobject thiz, jlong inst, jobjectArray endpoints, jboolean allowP2p){
|
||||
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetRemoteEndpoints(JNIEnv* env, jobject thiz, jlong inst, jobjectArray endpoints, jboolean allowP2p, jboolean tcp, jint connectionMaxLayer){
|
||||
size_t len=(size_t) env->GetArrayLength(endpoints);
|
||||
// voip_endpoint_t* eps=(voip_endpoint_t *) malloc(sizeof(voip_endpoint_t)*len);
|
||||
std::vector<Endpoint> eps;
|
||||
@ -166,23 +300,25 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_native
|
||||
memcpy(pTag, peerTagBytes, 16);
|
||||
env->ReleaseByteArrayElements(peerTag, peerTagBytes, JNI_ABORT);
|
||||
}
|
||||
eps.push_back(Endpoint((int64_t)id, (uint16_t)port, v4addr, v6addr, EP_TYPE_UDP_RELAY, pTag));
|
||||
eps.push_back(Endpoint((int64_t)id, (uint16_t)port, v4addr, v6addr, (char) (tcp ? Endpoint::TYPE_TCP_RELAY : Endpoint::TYPE_UDP_RELAY), pTag));
|
||||
}
|
||||
((VoIPController*)(intptr_t)inst)->SetRemoteEndpoints(eps, allowP2p);
|
||||
((VoIPController*)(intptr_t)inst)->SetRemoteEndpoints(eps, allowP2p, connectionMaxLayer);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetNativeBufferSize(JNIEnv* env, jclass thiz, jint size){
|
||||
AudioOutputOpenSLES::nativeBufferSize=size;
|
||||
AudioInputOpenSLES::nativeBufferSize=size;
|
||||
AudioOutputOpenSLES::nativeBufferSize=(unsigned int) size;
|
||||
AudioInputOpenSLES::nativeBufferSize=(unsigned int) size;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeRelease(JNIEnv* env, jobject thiz, jlong inst){
|
||||
//env->DeleteGlobalRef(AudioInputAndroid::jniClass);
|
||||
|
||||
VoIPController* ctlr=((VoIPController*)(intptr_t)inst);
|
||||
impl_data_android_t* impl=(impl_data_android_t*)ctlr->implData;
|
||||
jobject jobj=impl->javaObject;
|
||||
ctlr->Stop();
|
||||
delete ctlr;
|
||||
env->DeleteGlobalRef(impl->javaObject);
|
||||
free(impl);
|
||||
env->DeleteGlobalRef(jobj);
|
||||
}
|
||||
|
||||
|
||||
@ -226,6 +362,7 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_native
|
||||
cfg.enableAEC=enableAEC;
|
||||
cfg.enableNS=enableNS;
|
||||
cfg.enableAGC=enableAGC;
|
||||
cfg.enableCallUpgrade=false;
|
||||
if(logFilePath){
|
||||
char* path=(char *) env->GetStringUTFChars(logFilePath, NULL);
|
||||
strncpy(cfg.logFilePath, path, sizeof(cfg.logFilePath));
|
||||
@ -312,3 +449,131 @@ extern "C" JNIEXPORT jint Java_org_telegram_messenger_voip_Resampler_convert44to
|
||||
extern "C" JNIEXPORT jint Java_org_telegram_messenger_voip_Resampler_convert48to44(JNIEnv* env, jclass cls, jobject from, jobject to){
|
||||
return tgvoip::audio::Resampler::Convert48To44((int16_t *) env->GetDirectBufferAddress(from), (int16_t *) env->GetDirectBufferAddress(to), (size_t) (env->GetDirectBufferCapacity(from)/2), (size_t) (env->GetDirectBufferCapacity(to)/2));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong Java_org_telegram_messenger_voip_VoIPGroupController_nativeInit(JNIEnv* env, jobject thiz, jint timeDifference){
|
||||
env->GetJavaVM(&sharedJVM);
|
||||
if(!AudioInputAndroid::jniClass){
|
||||
jclass cls=env->FindClass("org/telegram/messenger/voip/AudioRecordJNI");
|
||||
AudioInputAndroid::jniClass=(jclass) env->NewGlobalRef(cls);
|
||||
AudioInputAndroid::initMethod=env->GetMethodID(cls, "init", "(IIII)V");
|
||||
AudioInputAndroid::releaseMethod=env->GetMethodID(cls, "release", "()V");
|
||||
AudioInputAndroid::startMethod=env->GetMethodID(cls, "start", "()Z");
|
||||
AudioInputAndroid::stopMethod=env->GetMethodID(cls, "stop", "()V");
|
||||
|
||||
cls=env->FindClass("org/telegram/messenger/voip/AudioTrackJNI");
|
||||
AudioOutputAndroid::jniClass=(jclass) env->NewGlobalRef(cls);
|
||||
AudioOutputAndroid::initMethod=env->GetMethodID(cls, "init", "(IIII)V");
|
||||
AudioOutputAndroid::releaseMethod=env->GetMethodID(cls, "release", "()V");
|
||||
AudioOutputAndroid::startMethod=env->GetMethodID(cls, "start", "()V");
|
||||
AudioOutputAndroid::stopMethod=env->GetMethodID(cls, "stop", "()V");
|
||||
}
|
||||
|
||||
setStateMethod=env->GetMethodID(env->GetObjectClass(thiz), "handleStateChange", "(I)V");
|
||||
setParticipantAudioEnabledMethod=env->GetMethodID(env->GetObjectClass(thiz), "setParticipantAudioEnabled", "(IZ)V");
|
||||
setSelfStreamsMethod=env->GetMethodID(env->GetObjectClass(thiz), "setSelfStreams", "([B)V");
|
||||
|
||||
impl_data_android_t* impl=(impl_data_android_t*) malloc(sizeof(impl_data_android_t));
|
||||
impl->javaObject=env->NewGlobalRef(thiz);
|
||||
VoIPGroupController* cntrlr=new VoIPGroupController(timeDifference);
|
||||
cntrlr->implData=impl;
|
||||
|
||||
VoIPGroupController::Callbacks callbacks;
|
||||
callbacks.connectionStateChanged=updateConnectionState;
|
||||
callbacks.updateStreams=updateGroupCallStreams;
|
||||
callbacks.participantAudioStateChanged=updateParticipantAudioState;
|
||||
callbacks.signalBarCountChanged=NULL;
|
||||
cntrlr->SetCallbacks(callbacks);
|
||||
|
||||
return (jlong)(intptr_t)cntrlr;
|
||||
}
|
||||
/*
|
||||
private native void nativeSetGroupCallInfo(long inst, byte[] encryptionKey, byte[] reflectorGroupTag, byte[] reflectorSelfTag, byte[] reflectorSelfSecret, String reflectorAddress, String reflectorAddressV6, int reflectorPort);
|
||||
private native void addGroupCallParticipant(long inst, int userID, byte[] memberTagHash);
|
||||
private native void removeGroupCallParticipant(long inst, int userID);
|
||||
*/
|
||||
|
||||
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPGroupController_nativeSetGroupCallInfo(JNIEnv* env, jclass cls, jlong inst, jbyteArray _encryptionKey, jbyteArray _reflectorGroupTag, jbyteArray _reflectorSelfTag, jbyteArray _reflectorSelfSecret, jbyteArray _reflectorSelfTagHash, jint selfUserID, jstring reflectorAddress, jstring reflectorAddressV6, jint reflectorPort){
|
||||
VoIPGroupController* ctlr=((VoIPGroupController*)(intptr_t)inst);
|
||||
jbyte* encryptionKey=env->GetByteArrayElements(_encryptionKey, NULL);
|
||||
jbyte* reflectorGroupTag=env->GetByteArrayElements(_reflectorGroupTag, NULL);
|
||||
jbyte* reflectorSelfTag=env->GetByteArrayElements(_reflectorSelfTag, NULL);
|
||||
jbyte* reflectorSelfSecret=env->GetByteArrayElements(_reflectorSelfSecret, NULL);
|
||||
jbyte* reflectorSelfTagHash=env->GetByteArrayElements(_reflectorSelfTagHash, NULL);
|
||||
|
||||
|
||||
const char* ipChars=env->GetStringUTFChars(reflectorAddress, NULL);
|
||||
std::string ipLiteral(ipChars);
|
||||
IPv4Address v4addr(ipLiteral);
|
||||
IPv6Address v6addr("::0");
|
||||
env->ReleaseStringUTFChars(reflectorAddress, ipChars);
|
||||
if(reflectorAddressV6 && env->GetStringLength(reflectorAddressV6)){
|
||||
const char* ipv6Chars=env->GetStringUTFChars(reflectorAddressV6, NULL);
|
||||
v6addr=IPv6Address(ipv6Chars);
|
||||
env->ReleaseStringUTFChars(reflectorAddressV6, ipv6Chars);
|
||||
}
|
||||
ctlr->SetGroupCallInfo((unsigned char *) encryptionKey, (unsigned char *) reflectorGroupTag, (unsigned char *) reflectorSelfTag, (unsigned char *) reflectorSelfSecret, (unsigned char*) reflectorSelfTagHash, selfUserID, v4addr, v6addr, (uint16_t)reflectorPort);
|
||||
|
||||
env->ReleaseByteArrayElements(_encryptionKey, encryptionKey, JNI_ABORT);
|
||||
env->ReleaseByteArrayElements(_reflectorGroupTag, reflectorGroupTag, JNI_ABORT);
|
||||
env->ReleaseByteArrayElements(_reflectorSelfTag, reflectorSelfTag, JNI_ABORT);
|
||||
env->ReleaseByteArrayElements(_reflectorSelfSecret, reflectorSelfSecret, JNI_ABORT);
|
||||
env->ReleaseByteArrayElements(_reflectorSelfTagHash, reflectorSelfTagHash, JNI_ABORT);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPGroupController_nativeAddGroupCallParticipant(JNIEnv* env, jclass cls, jlong inst, jint userID, jbyteArray _memberTagHash, jbyteArray _streams){
|
||||
VoIPGroupController* ctlr=((VoIPGroupController*)(intptr_t)inst);
|
||||
jbyte* memberTagHash=env->GetByteArrayElements(_memberTagHash, NULL);
|
||||
jbyte* streams=_streams ? env->GetByteArrayElements(_streams, NULL) : NULL;
|
||||
|
||||
ctlr->AddGroupCallParticipant(userID, (unsigned char *) memberTagHash, (unsigned char *) streams, (size_t) env->GetArrayLength(_streams));
|
||||
|
||||
env->ReleaseByteArrayElements(_memberTagHash, memberTagHash, JNI_ABORT);
|
||||
if(_streams)
|
||||
env->ReleaseByteArrayElements(_streams, streams, JNI_ABORT);
|
||||
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPGroupController_nativeRemoveGroupCallParticipant(JNIEnv* env, jclass cls, jlong inst, jint userID){
|
||||
VoIPGroupController* ctlr=((VoIPGroupController*)(intptr_t)inst);
|
||||
ctlr->RemoveGroupCallParticipant(userID);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jfloat Java_org_telegram_messenger_voip_VoIPGroupController_nativeGetParticipantAudioLevel(JNIEnv* env, jclass cls, jlong inst, jint userID){
|
||||
return ((VoIPGroupController*)(intptr_t)inst)->GetParticipantAudioLevel(userID);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPGroupController_nativeSetParticipantVolume(JNIEnv* env, jclass cls, jlong inst, jint userID, jfloat volume){
|
||||
((VoIPGroupController*)(intptr_t)inst)->SetParticipantVolume(userID, volume);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jbyteArray Java_org_telegram_messenger_voip_VoIPGroupController_getInitialStreams(JNIEnv* env, jclass cls){
|
||||
unsigned char buf[1024];
|
||||
size_t len=VoIPGroupController::GetInitialStreams(buf, sizeof(buf));
|
||||
jbyteArray arr=env->NewByteArray(len);
|
||||
jbyte* arrElems=env->GetByteArrayElements(arr, NULL);
|
||||
memcpy(arrElems, buf, len);
|
||||
env->ReleaseByteArrayElements(arr, arrElems, 0);
|
||||
return arr;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPGroupController_nativeSetParticipantStreams(JNIEnv* env, jclass cls, jlong inst, jint userID, jbyteArray _streams){
|
||||
jbyte* streams=env->GetByteArrayElements(_streams, NULL);
|
||||
|
||||
((VoIPGroupController*)(intptr_t)inst)->SetParticipantStreams(userID, (unsigned char *) streams, (size_t) env->GetArrayLength(_streams));
|
||||
|
||||
env->ReleaseByteArrayElements(_streams, streams, JNI_ABORT);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint Java_org_telegram_messenger_voip_VoIPController_nativeGetPeerCapabilities(JNIEnv* env, jclass cls, jlong inst){
|
||||
return ((VoIPController*)(intptr_t)inst)->GetPeerCapabilities();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSendGroupCallKey(JNIEnv* env, jclass cls, jlong inst, jbyteArray _key){
|
||||
jbyte* key=env->GetByteArrayElements(_key, NULL);
|
||||
((VoIPController*)(intptr_t)inst)->SendGroupCallKey((unsigned char *) key);
|
||||
env->ReleaseByteArrayElements(_key, key, JNI_ABORT);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeRequestCallUpgrade(JNIEnv* env, jclass cls, jlong inst){
|
||||
((VoIPController*)(intptr_t)inst)->RequestCallUpgrade();
|
||||
}
|
@ -26,7 +26,6 @@
|
||||
692AB8D91E6759DD00706ACC /* CongestionControl.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB8981E6759DD00706ACC /* CongestionControl.h */; };
|
||||
692AB8DA1E6759DD00706ACC /* EchoCanceller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 692AB8991E6759DD00706ACC /* EchoCanceller.cpp */; };
|
||||
692AB8DB1E6759DD00706ACC /* EchoCanceller.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB89A1E6759DD00706ACC /* EchoCanceller.h */; };
|
||||
692AB8E51E6759DD00706ACC /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 692AB8A71E6759DD00706ACC /* Info.plist */; };
|
||||
692AB8E61E6759DD00706ACC /* JitterBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 692AB8A81E6759DD00706ACC /* JitterBuffer.cpp */; };
|
||||
692AB8E71E6759DD00706ACC /* JitterBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB8A91E6759DD00706ACC /* JitterBuffer.h */; };
|
||||
692AB8E81E6759DD00706ACC /* logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB8AA1E6759DD00706ACC /* logging.h */; };
|
||||
@ -192,6 +191,7 @@
|
||||
69A6DE1C1E95ECF000000E69 /* wav_file.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A6DE181E95ECF000000E69 /* wav_file.h */; };
|
||||
69A6DE1D1E95ECF000000E69 /* wav_header.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69A6DE191E95ECF000000E69 /* wav_header.cc */; };
|
||||
69A6DE1E1E95ECF000000E69 /* wav_header.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A6DE1A1E95ECF000000E69 /* wav_header.h */; };
|
||||
D00ACA4F20222F5D0045D427 /* SetupLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = D00ACA4D20222F5D0045D427 /* SetupLogging.h */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -434,6 +434,7 @@
|
||||
69A6DE191E95ECF000000E69 /* wav_header.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wav_header.cc; sourceTree = "<group>"; };
|
||||
69A6DE1A1E95ECF000000E69 /* wav_header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wav_header.h; sourceTree = "<group>"; };
|
||||
69F842361E67540700C110F7 /* libtgvoip.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = libtgvoip.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D00ACA4D20222F5D0045D427 /* SetupLogging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SetupLogging.h; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -535,6 +536,7 @@
|
||||
692AB8C51E6759DD00706ACC /* TGLogWrapper.m */,
|
||||
69960A021EF85C2900F9D091 /* DarwinSpecific.h */,
|
||||
69960A031EF85C2900F9D091 /* DarwinSpecific.mm */,
|
||||
D00ACA4D20222F5D0045D427 /* SetupLogging.h */,
|
||||
);
|
||||
path = darwin;
|
||||
sourceTree = "<group>";
|
||||
@ -905,6 +907,7 @@
|
||||
69A6DDC11E95EC7700000E69 /* spl_inl_armv7.h in Headers */,
|
||||
69A6DE031E95EC7800000E69 /* three_band_filter_bank.h in Headers */,
|
||||
69A6DDFB1E95EC7700000E69 /* nsx_core.h in Headers */,
|
||||
D00ACA4F20222F5D0045D427 /* SetupLogging.h in Headers */,
|
||||
69A6DDE41E95EC7700000E69 /* echo_cancellation.h in Headers */,
|
||||
69A6DDF71E95EC7700000E69 /* noise_suppression_x.h in Headers */,
|
||||
69A6DD9B1E95EC7700000E69 /* safe_conversions.h in Headers */,
|
||||
@ -1074,7 +1077,6 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
692AB8E51E6759DD00706ACC /* Info.plist in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1301,6 +1303,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/../../Telegraph",
|
||||
webrtc_dsp,
|
||||
"$(PROJECT_DIR)/../TelegramUI/third-party/opus/include/opus",
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
@ -1336,6 +1339,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/../../Telegraph",
|
||||
webrtc_dsp,
|
||||
"$(PROJECT_DIR)/../TelegramUI/third-party/opus/include/opus",
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
@ -1356,6 +1360,336 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
D00ACA51202234510045D427 /* Debug Hockeyapp */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = "Debug Hockeyapp";
|
||||
};
|
||||
D00ACA52202234510045D427 /* Debug Hockeyapp */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(PROJECT_DIR)/../../Telegraph/thirdparty/opus/include/opus",
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/../../Telegraph",
|
||||
webrtc_dsp,
|
||||
"$(PROJECT_DIR)/../TelegramUI/third-party/opus/include/opus",
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
MACH_O_TYPE = staticlib;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.6;
|
||||
OTHER_CFLAGS = (
|
||||
"-DTGVOIP_USE_CUSTOM_CRYPTO",
|
||||
"-DWEBRTC_APM_DEBUG_DUMP=0",
|
||||
"-DWEBRTC_POSIX",
|
||||
"-DTGVOIP_HAVE_TGLOG",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = me.grishka.libtgvoip;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = "Debug Hockeyapp";
|
||||
};
|
||||
D00ACA532022347C0045D427 /* Release Hockeyapp */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = "Release Hockeyapp";
|
||||
};
|
||||
D00ACA542022347C0045D427 /* Release Hockeyapp */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(PROJECT_DIR)/../../Telegraph/thirdparty/opus/include/opus",
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/../../Telegraph",
|
||||
webrtc_dsp,
|
||||
"$(PROJECT_DIR)/../TelegramUI/third-party/opus/include/opus",
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
MACH_O_TYPE = staticlib;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.6;
|
||||
OTHER_CFLAGS = (
|
||||
"-DTGVOIP_USE_CUSTOM_CRYPTO",
|
||||
"-DWEBRTC_APM_DEBUG_DUMP=0",
|
||||
"-DWEBRTC_POSIX",
|
||||
"-DTGVOIP_HAVE_TGLOG",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = me.grishka.libtgvoip;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = "Release Hockeyapp";
|
||||
};
|
||||
D00ACA55202234840045D427 /* Release Hockeyapp Internal */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = "Release Hockeyapp Internal";
|
||||
};
|
||||
D00ACA56202234840045D427 /* Release Hockeyapp Internal */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(PROJECT_DIR)/../../Telegraph/thirdparty/opus/include/opus",
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/../../Telegraph",
|
||||
webrtc_dsp,
|
||||
"$(PROJECT_DIR)/../TelegramUI/third-party/opus/include/opus",
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
MACH_O_TYPE = staticlib;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.6;
|
||||
OTHER_CFLAGS = (
|
||||
"-DTGVOIP_USE_CUSTOM_CRYPTO",
|
||||
"-DWEBRTC_APM_DEBUG_DUMP=0",
|
||||
"-DWEBRTC_POSIX",
|
||||
"-DTGVOIP_HAVE_TGLOG",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = me.grishka.libtgvoip;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = "Release Hockeyapp Internal";
|
||||
};
|
||||
D00ACA5B2022A70D0045D427 /* Release AppStore */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = "Release AppStore";
|
||||
};
|
||||
D00ACA5C2022A70D0045D427 /* Release AppStore */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(PROJECT_DIR)/../../Telegraph/thirdparty/opus/include/opus",
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/../../Telegraph",
|
||||
webrtc_dsp,
|
||||
"$(PROJECT_DIR)/../TelegramUI/third-party/opus/include/opus",
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
MACH_O_TYPE = staticlib;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.6;
|
||||
OTHER_CFLAGS = (
|
||||
"-DTGVOIP_USE_CUSTOM_CRYPTO",
|
||||
"-DWEBRTC_APM_DEBUG_DUMP=0",
|
||||
"-DWEBRTC_POSIX",
|
||||
"-DTGVOIP_HAVE_TGLOG",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = me.grishka.libtgvoip;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = "Release AppStore";
|
||||
};
|
||||
D04D01C31E678C0D0086DDC0 /* Debug AppStore */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@ -1422,6 +1756,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/../../Telegraph",
|
||||
webrtc_dsp,
|
||||
"$(PROJECT_DIR)/../TelegramUI/third-party/opus/include/opus",
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
@ -1502,6 +1837,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/../../Telegraph",
|
||||
webrtc_dsp,
|
||||
"$(PROJECT_DIR)/../TelegramUI/third-party/opus/include/opus",
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
@ -1522,6 +1858,86 @@
|
||||
};
|
||||
name = Hockeyapp;
|
||||
};
|
||||
D077B8DF1F45EA870046D27A /* Release Hockeyapp */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = "Release Hockeyapp";
|
||||
};
|
||||
D077B8E01F45EA870046D27A /* Release Hockeyapp */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(PROJECT_DIR)/../../Telegraph/thirdparty/opus/include/opus",
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/../../Telegraph",
|
||||
webrtc_dsp,
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
MACH_O_TYPE = staticlib;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.6;
|
||||
OTHER_CFLAGS = (
|
||||
"-DTGVOIP_USE_CUSTOM_CRYPTO",
|
||||
"-DWEBRTC_APM_DEBUG_DUMP=0",
|
||||
"-DWEBRTC_POSIX",
|
||||
"-DTGVOIP_HAVE_TGLOG",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = me.grishka.libtgvoip;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = "Release Hockeyapp";
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
@ -1529,9 +1945,14 @@
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
69F8423C1E67540700C110F7 /* Debug */,
|
||||
D00ACA51202234510045D427 /* Debug Hockeyapp */,
|
||||
D04D01C31E678C0D0086DDC0 /* Debug AppStore */,
|
||||
69F8423D1E67540700C110F7 /* Release */,
|
||||
D00ACA5B2022A70D0045D427 /* Release AppStore */,
|
||||
D00ACA532022347C0045D427 /* Release Hockeyapp */,
|
||||
D00ACA55202234840045D427 /* Release Hockeyapp Internal */,
|
||||
D04D01CB1E678C230086DDC0 /* Hockeyapp */,
|
||||
D077B8DF1F45EA870046D27A /* Release Hockeyapp */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
@ -1540,9 +1961,14 @@
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
69F8423F1E67540700C110F7 /* Debug */,
|
||||
D00ACA52202234510045D427 /* Debug Hockeyapp */,
|
||||
D04D01C41E678C0D0086DDC0 /* Debug AppStore */,
|
||||
69F842401E67540700C110F7 /* Release */,
|
||||
D00ACA5C2022A70D0045D427 /* Release AppStore */,
|
||||
D00ACA542022347C0045D427 /* Release Hockeyapp */,
|
||||
D00ACA56202234840045D427 /* Release Hockeyapp Internal */,
|
||||
D04D01CC1E678C230086DDC0 /* Hockeyapp */,
|
||||
D077B8E01F45EA870046D27A /* Release Hockeyapp */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
|
@ -7,7 +7,7 @@
|
||||
<key>libtgvoip.xcscheme</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
@ -37,8 +37,8 @@ void tgvoip_log_file_printf(char level, const char* msg, ...){
|
||||
}
|
||||
}
|
||||
|
||||
void tgvoip_log_file_write_header(){
|
||||
if(tgvoipLogFile){
|
||||
void tgvoip_log_file_write_header(FILE* file){
|
||||
if(file){
|
||||
time_t t = time(0);
|
||||
struct tm *now = localtime(&t);
|
||||
#if defined(_WIN32)
|
||||
@ -94,6 +94,6 @@ void tgvoip_log_file_write_header(){
|
||||
const char* cpuArch="Unknown CPU";
|
||||
#endif
|
||||
|
||||
fprintf(tgvoipLogFile, "---------------\nlibtgvoip v" LIBTGVOIP_VERSION " on %s %s\nLog started on %d/%02d/%d at %d:%02d:%02d\n---------------\n", systemVersion, cpuArch, now->tm_mday, now->tm_mon+1, now->tm_year+1900, now->tm_hour, now->tm_min, now->tm_sec);
|
||||
fprintf(file, "---------------\nlibtgvoip v" LIBTGVOIP_VERSION " on %s %s\nLog started on %d/%02d/%d at %d:%02d:%02d\n---------------\n", systemVersion, cpuArch, now->tm_mday, now->tm_mon+1, now->tm_year+1900, now->tm_hour, now->tm_min, now->tm_sec);
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,10 @@
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void tgvoip_log_file_printf(char level, const char* msg, ...);
|
||||
void tgvoip_log_file_write_header();
|
||||
void tgvoip_log_file_write_header(FILE* file);
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
|
@ -36,7 +36,6 @@ AudioInputAndroid::AudioInputAndroid(){
|
||||
sharedJVM->DetachCurrentThread();
|
||||
}
|
||||
running=false;
|
||||
init_mutex(mutex);
|
||||
}
|
||||
|
||||
AudioInputAndroid::~AudioInputAndroid(){
|
||||
@ -58,7 +57,6 @@ AudioInputAndroid::~AudioInputAndroid(){
|
||||
sharedJVM->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
free_mutex(mutex);
|
||||
}
|
||||
|
||||
void AudioInputAndroid::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
private:
|
||||
jobject javaObject;
|
||||
bool running;
|
||||
tgvoip_mutex_t mutex;
|
||||
Mutex mutex;
|
||||
|
||||
};
|
||||
}}
|
||||
|
@ -18,7 +18,7 @@
|
||||
using namespace tgvoip;
|
||||
using namespace tgvoip::audio;
|
||||
|
||||
int AudioInputOpenSLES::nativeBufferSize;
|
||||
unsigned int AudioInputOpenSLES::nativeBufferSize;
|
||||
|
||||
AudioInputOpenSLES::AudioInputOpenSLES(){
|
||||
slEngine=OpenSLEngineWrapper::CreateEngine();
|
||||
|
@ -22,7 +22,7 @@ public:
|
||||
virtual void Start();
|
||||
virtual void Stop();
|
||||
|
||||
static int nativeBufferSize;
|
||||
static unsigned int nativeBufferSize;
|
||||
|
||||
private:
|
||||
static void BufferCallback(SLAndroidSimpleBufferQueueItf bq, void *context);
|
||||
|
@ -13,13 +13,13 @@
|
||||
#include "OpenSLEngineWrapper.h"
|
||||
#include "AudioInputAndroid.h"
|
||||
|
||||
#define CHECK_SL_ERROR(res, msg) if(res!=SL_RESULT_SUCCESS){ LOGE(msg); return; }
|
||||
#define CHECK_SL_ERROR(res, msg) if(res!=SL_RESULT_SUCCESS){ LOGE(msg); failed=true; return; }
|
||||
#define BUFFER_SIZE 960 // 20 ms
|
||||
|
||||
using namespace tgvoip;
|
||||
using namespace tgvoip::audio;
|
||||
|
||||
int AudioOutputOpenSLES::nativeBufferSize;
|
||||
unsigned int AudioOutputOpenSLES::nativeBufferSize;
|
||||
|
||||
AudioOutputOpenSLES::AudioOutputOpenSLES(){
|
||||
SLresult result;
|
||||
@ -63,7 +63,7 @@ AudioOutputOpenSLES::~AudioOutputOpenSLES(){
|
||||
}
|
||||
|
||||
|
||||
void AudioOutputOpenSLES::SetNativeBufferSize(int size){
|
||||
void AudioOutputOpenSLES::SetNativeBufferSize(unsigned int size){
|
||||
AudioOutputOpenSLES::nativeBufferSize=size;
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,8 @@ public:
|
||||
virtual bool IsPlaying();
|
||||
virtual float GetLevel();
|
||||
|
||||
static void SetNativeBufferSize(int size);
|
||||
static int nativeBufferSize;
|
||||
static void SetNativeBufferSize(unsigned int size);
|
||||
static unsigned int nativeBufferSize;
|
||||
|
||||
private:
|
||||
static void BufferCallback(SLAndroidSimpleBufferQueueItf bq, void *context);
|
||||
|
@ -16,10 +16,10 @@
|
||||
using namespace tgvoip;
|
||||
using namespace tgvoip::audio;
|
||||
|
||||
AudioInputAudioUnit::AudioInputAudioUnit(std::string deviceID){
|
||||
AudioInputAudioUnit::AudioInputAudioUnit(std::string deviceID, AudioUnitIO* io){
|
||||
remainingDataSize=0;
|
||||
isRecording=false;
|
||||
this->io=AudioUnitIO::Get();
|
||||
this->io=io;
|
||||
#if TARGET_OS_OSX
|
||||
io->SetCurrentDevice(true, deviceID);
|
||||
#endif
|
||||
@ -29,7 +29,6 @@ AudioInputAudioUnit::AudioInputAudioUnit(std::string deviceID){
|
||||
|
||||
AudioInputAudioUnit::~AudioInputAudioUnit(){
|
||||
io->DetachInput();
|
||||
AudioUnitIO::Release();
|
||||
}
|
||||
|
||||
void AudioInputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
|
||||
|
@ -16,7 +16,7 @@ class AudioUnitIO;
|
||||
class AudioInputAudioUnit : public AudioInput{
|
||||
|
||||
public:
|
||||
AudioInputAudioUnit(std::string deviceID);
|
||||
AudioInputAudioUnit(std::string deviceID, AudioUnitIO* io);
|
||||
virtual ~AudioInputAudioUnit();
|
||||
virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels);
|
||||
virtual void Start();
|
||||
|
@ -12,16 +12,15 @@
|
||||
#include "AudioUnitIO.h"
|
||||
|
||||
#define BUFFER_SIZE 960
|
||||
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};
|
||||
|
||||
using namespace tgvoip;
|
||||
using namespace tgvoip::audio;
|
||||
|
||||
AudioOutputAudioUnit::AudioOutputAudioUnit(std::string deviceID){
|
||||
AudioOutputAudioUnit::AudioOutputAudioUnit(std::string deviceID, AudioUnitIO* io){
|
||||
isPlaying=false;
|
||||
remainingDataSize=0;
|
||||
level=0.0;
|
||||
this->io=AudioUnitIO::Get();
|
||||
this->io=io;
|
||||
#if TARGET_OS_OSX
|
||||
io->SetCurrentDevice(false, deviceID);
|
||||
#endif
|
||||
@ -31,7 +30,6 @@ AudioOutputAudioUnit::AudioOutputAudioUnit(std::string deviceID){
|
||||
|
||||
AudioOutputAudioUnit::~AudioOutputAudioUnit(){
|
||||
io->DetachOutput();
|
||||
AudioUnitIO::Release();
|
||||
}
|
||||
|
||||
void AudioOutputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
|
||||
@ -67,8 +65,6 @@ float AudioOutputAudioUnit::GetLevel(){
|
||||
|
||||
void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){
|
||||
int i;
|
||||
unsigned int k;
|
||||
int16_t absVal=0;
|
||||
for(i=0;i<ioData->mNumberBuffers;i++){
|
||||
AudioBuffer buf=ioData->mBuffers[i];
|
||||
if(!isPlaying){
|
||||
@ -76,6 +72,7 @@ void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){
|
||||
return;
|
||||
}
|
||||
#if TARGET_OS_OSX
|
||||
unsigned int k;
|
||||
while(remainingDataSize<buf.mDataByteSize/2){
|
||||
assert(remainingDataSize+BUFFER_SIZE*2<sizeof(remainingData));
|
||||
InvokeCallback(remainingData+remainingDataSize, BUFFER_SIZE*2);
|
||||
@ -98,28 +95,6 @@ void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){
|
||||
remainingDataSize-=buf.mDataByteSize;
|
||||
memmove(remainingData, remainingData+buf.mDataByteSize, remainingDataSize);
|
||||
#endif
|
||||
|
||||
/*unsigned int samples=buf.mDataByteSize/sizeof(int16_t);
|
||||
for (k=0;k<samples;k++){
|
||||
int16_t absolute=(int16_t)abs(*((int16_t *)buf.mData+k));
|
||||
if (absolute>absVal)
|
||||
absVal=absolute;
|
||||
}
|
||||
|
||||
if (absVal>absMax)
|
||||
absMax=absVal;
|
||||
|
||||
count++;
|
||||
if (count>=10) {
|
||||
count=0;
|
||||
|
||||
short position=absMax/1000;
|
||||
if (position==0 && absMax>250) {
|
||||
position=1;
|
||||
}
|
||||
level=permutation[position];
|
||||
absMax>>=2;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ class AudioUnitIO;
|
||||
|
||||
class AudioOutputAudioUnit : public AudioOutput{
|
||||
public:
|
||||
AudioOutputAudioUnit(std::string deviceID);
|
||||
AudioOutputAudioUnit(std::string deviceID, AudioUnitIO* io);
|
||||
virtual ~AudioOutputAudioUnit();
|
||||
virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels);
|
||||
virtual bool IsPhone();
|
||||
|
@ -26,9 +26,6 @@
|
||||
using namespace tgvoip;
|
||||
using namespace tgvoip::audio;
|
||||
|
||||
int AudioUnitIO::refCount=0;
|
||||
AudioUnitIO* AudioUnitIO::sharedInstance=NULL;
|
||||
|
||||
AudioUnitIO::AudioUnitIO(){
|
||||
input=NULL;
|
||||
output=NULL;
|
||||
@ -130,24 +127,6 @@ AudioUnitIO::~AudioUnitIO(){
|
||||
free(inBufferList.mBuffers[0].mData);
|
||||
}
|
||||
|
||||
AudioUnitIO* AudioUnitIO::Get(){
|
||||
if(refCount==0){
|
||||
sharedInstance=new AudioUnitIO();
|
||||
}
|
||||
refCount++;
|
||||
assert(refCount>0);
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
void AudioUnitIO::Release(){
|
||||
refCount--;
|
||||
assert(refCount>=0);
|
||||
if(refCount==0){
|
||||
delete sharedInstance;
|
||||
sharedInstance=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioUnitIO::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
|
||||
|
||||
}
|
||||
|
@ -28,8 +28,6 @@ public:
|
||||
void EnableInput(bool enabled);
|
||||
void EnableOutput(bool enabled);
|
||||
bool IsFailed();
|
||||
static AudioUnitIO* Get();
|
||||
static void Release();
|
||||
#if TARGET_OS_OSX
|
||||
void SetCurrentDevice(bool input, std::string deviceID);
|
||||
#endif
|
||||
@ -51,8 +49,6 @@ private:
|
||||
bool outputEnabled;
|
||||
bool failed;
|
||||
bool started;
|
||||
static int refCount;
|
||||
static AudioUnitIO* sharedInstance;
|
||||
};
|
||||
}}
|
||||
|
||||
|
3
os/darwin/SetupLogging.h
Normal file
3
os/darwin/SetupLogging.h
Normal file
@ -0,0 +1,3 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern void (*TGVoipLoggingFunction)(NSString *);
|
@ -11,8 +11,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void (*TGVoipLoggingFunction)(NSString *);
|
||||
|
||||
void __tgvoip_call_tglog(const char* format, ...);
|
||||
|
||||
#if defined __cplusplus
|
||||
|
@ -3,10 +3,11 @@
|
||||
void (*TGVoipLoggingFunction)(NSString *) = NULL;
|
||||
|
||||
void __tgvoip_call_tglog(const char* format, ...){
|
||||
if (TGVoipLoggingFunction != nil) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
TGVoipLoggingFunction([[NSString alloc]initWithFormat:[[NSString alloc] initWithUTF8String:format] arguments:args]);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
NSString *string = [[NSString alloc] initWithFormat:[[NSString alloc]initWithUTF8String:format] arguments:args];
|
||||
va_end(args);
|
||||
if (TGVoipLoggingFunction) {
|
||||
TGVoipLoggingFunction(string);
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,9 @@ void AudioInputALSA::Start(){
|
||||
return;
|
||||
|
||||
isRecording=true;
|
||||
start_thread(thread, AudioInputALSA::StartThread, this);
|
||||
thread=new Thread(new MethodPointer<AudioInputALSA>(&AudioInputALSA::RunThread, this), NULL);
|
||||
thread->SetName("AudioInputALSA");
|
||||
thread->Start();
|
||||
}
|
||||
|
||||
void AudioInputALSA::Stop(){
|
||||
@ -66,15 +68,12 @@ void AudioInputALSA::Stop(){
|
||||
return;
|
||||
|
||||
isRecording=false;
|
||||
join_thread(thread);
|
||||
thread->Join();
|
||||
delete thread;
|
||||
thread=NULL;
|
||||
}
|
||||
|
||||
void* AudioInputALSA::StartThread(void* arg){
|
||||
((AudioInputALSA*)arg)->RunThread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void AudioInputALSA::RunThread(){
|
||||
void AudioInputALSA::RunThread(void* arg){
|
||||
unsigned char buffer[BUFFER_SIZE*2];
|
||||
snd_pcm_sframes_t frames;
|
||||
while(isRecording){
|
||||
@ -94,7 +93,7 @@ void AudioInputALSA::SetCurrentDevice(std::string devID){
|
||||
bool wasRecording=isRecording;
|
||||
isRecording=false;
|
||||
if(handle){
|
||||
join_thread(thread);
|
||||
thread->Join();
|
||||
_snd_pcm_close(handle);
|
||||
}
|
||||
currentDevice=devID;
|
||||
@ -109,7 +108,7 @@ void AudioInputALSA::SetCurrentDevice(std::string devID){
|
||||
|
||||
if(wasRecording){
|
||||
isRecording=true;
|
||||
start_thread(thread, AudioInputALSA::StartThread, this);
|
||||
thread->Start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,7 @@ public:
|
||||
static void EnumerateDevices(std::vector<AudioInputDevice>& devs);
|
||||
|
||||
private:
|
||||
static void* StartThread(void* arg);
|
||||
void RunThread();
|
||||
void RunThread(void* arg);
|
||||
|
||||
int (*_snd_pcm_open)(snd_pcm_t** pcm, const char* name, snd_pcm_stream_t stream, int mode);
|
||||
int (*_snd_pcm_set_params)(snd_pcm_t* pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int channels, unsigned int rate, int soft_resample, unsigned int latency);
|
||||
@ -38,7 +37,7 @@ private:
|
||||
void* lib;
|
||||
|
||||
snd_pcm_t* handle;
|
||||
tgvoip_thread_t thread;
|
||||
Thread* thread;
|
||||
bool isRecording;
|
||||
};
|
||||
|
||||
|
@ -57,7 +57,9 @@ void AudioOutputALSA::Start(){
|
||||
return;
|
||||
|
||||
isPlaying=true;
|
||||
start_thread(thread, AudioOutputALSA::StartThread, this);
|
||||
thread=new Thread(new MethodPointer<AudioOutputALSA>(&AudioOutputALSA::RunThread, this), NULL);
|
||||
thread->SetName("AudioOutputALSA");
|
||||
thread->Start();
|
||||
}
|
||||
|
||||
void AudioOutputALSA::Stop(){
|
||||
@ -65,19 +67,15 @@ void AudioOutputALSA::Stop(){
|
||||
return;
|
||||
|
||||
isPlaying=false;
|
||||
join_thread(thread);
|
||||
thread->Join();
|
||||
delete thread;
|
||||
thread=NULL;
|
||||
}
|
||||
|
||||
bool AudioOutputALSA::IsPlaying(){
|
||||
return isPlaying;
|
||||
}
|
||||
|
||||
void* AudioOutputALSA::StartThread(void* arg){
|
||||
((AudioOutputALSA*)arg)->RunThread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void AudioOutputALSA::RunThread(){
|
||||
void AudioOutputALSA::RunThread(void* arg){
|
||||
unsigned char buffer[BUFFER_SIZE*2];
|
||||
snd_pcm_sframes_t frames;
|
||||
while(isPlaying){
|
||||
@ -97,7 +95,7 @@ void AudioOutputALSA::SetCurrentDevice(std::string devID){
|
||||
bool wasPlaying=isPlaying;
|
||||
isPlaying=false;
|
||||
if(handle){
|
||||
join_thread(thread);
|
||||
thread->Join();
|
||||
_snd_pcm_close(handle);
|
||||
}
|
||||
currentDevice=devID;
|
||||
@ -112,7 +110,7 @@ void AudioOutputALSA::SetCurrentDevice(std::string devID){
|
||||
|
||||
if(wasPlaying){
|
||||
isPlaying=true;
|
||||
start_thread(thread, AudioOutputALSA::StartThread, this);
|
||||
thread->Start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,7 @@ public:
|
||||
static void EnumerateDevices(std::vector<AudioOutputDevice>& devs);
|
||||
|
||||
private:
|
||||
static void* StartThread(void* arg);
|
||||
void RunThread();
|
||||
void RunThread(void* arg);
|
||||
|
||||
int (*_snd_pcm_open)(snd_pcm_t** pcm, const char* name, snd_pcm_stream_t stream, int mode);
|
||||
int (*_snd_pcm_set_params)(snd_pcm_t* pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int channels, unsigned int rate, int soft_resample, unsigned int latency);
|
||||
@ -38,7 +37,7 @@ private:
|
||||
void* lib;
|
||||
|
||||
snd_pcm_t* handle;
|
||||
tgvoip_thread_t thread;
|
||||
Thread* thread;
|
||||
bool isPlaying;
|
||||
};
|
||||
|
||||
|
@ -18,6 +18,13 @@
|
||||
#include "../../BufferInputStream.h"
|
||||
#include "../../BufferOutputStream.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <jni.h>
|
||||
#include <sys/system_properties.h>
|
||||
extern JavaVM* sharedJVM;
|
||||
extern jclass jniUtilitiesClass;
|
||||
#endif
|
||||
|
||||
using namespace tgvoip;
|
||||
|
||||
|
||||
@ -61,7 +68,7 @@ void NetworkSocketPosix::SetMaxPriority(){
|
||||
}
|
||||
|
||||
void NetworkSocketPosix::Send(NetworkPacket *packet){
|
||||
if(!packet || !packet->address){
|
||||
if(!packet || (protocol==PROTO_UDP && !packet->address)){
|
||||
LOGW("tried to send null packet");
|
||||
return;
|
||||
}
|
||||
@ -222,7 +229,6 @@ void NetworkSocketPosix::Open(){
|
||||
}
|
||||
size_t addrLen=sizeof(sockaddr_in6);
|
||||
getsockname(fd, (sockaddr*)&addr, (socklen_t*) &addrLen);
|
||||
uint16_t localUdpPort=ntohs(addr.sin6_port);
|
||||
LOGD("Bound to local UDP port %u", ntohs(addr.sin6_port));
|
||||
|
||||
needUpdateNat64Prefix=true;
|
||||
@ -237,6 +243,7 @@ void NetworkSocketPosix::Close(){
|
||||
if (fd>=0) {
|
||||
shutdown(fd, SHUT_RDWR);
|
||||
close(fd);
|
||||
fd=-1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,13 +306,45 @@ void NetworkSocketPosix::OnActiveInterfaceChanged(){
|
||||
}
|
||||
|
||||
std::string NetworkSocketPosix::GetLocalInterfaceInfo(IPv4Address *v4addr, IPv6Address *v6addr){
|
||||
#ifdef __ANDROID__
|
||||
char sdkNum[PROP_VALUE_MAX];
|
||||
__system_property_get("ro.build.version.sdk", sdkNum);
|
||||
int systemVersion=atoi(sdkNum);
|
||||
char androidInterfaceName[128];
|
||||
if(systemVersion>23){
|
||||
JNIEnv *env=NULL;
|
||||
bool didAttach=false;
|
||||
sharedJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
|
||||
if(!env){
|
||||
sharedJVM->AttachCurrentThread(&env, NULL);
|
||||
didAttach=true;
|
||||
}
|
||||
|
||||
jmethodID getActiveInterfaceMethod=env->GetStaticMethodID(jniUtilitiesClass, "getCurrentNetworkInterfaceName", "()Ljava/lang/String;");
|
||||
jstring jitf=(jstring) env->CallStaticObjectMethod(jniUtilitiesClass, getActiveInterfaceMethod);
|
||||
if(jitf){
|
||||
const char* itfchars=env->GetStringUTFChars(jitf, NULL);
|
||||
strncpy(androidInterfaceName, itfchars, sizeof(androidInterfaceName));
|
||||
env->ReleaseStringUTFChars(jitf, itfchars);
|
||||
}else{
|
||||
memset(androidInterfaceName, 0, sizeof(androidInterfaceName));
|
||||
}
|
||||
LOGV("Android active network interface: '%s'", androidInterfaceName);
|
||||
|
||||
if(didAttach){
|
||||
sharedJVM->DetachCurrentThread();
|
||||
}
|
||||
}else{
|
||||
memset(androidInterfaceName, 0, sizeof(androidInterfaceName));
|
||||
}
|
||||
#endif
|
||||
struct ifconf ifc;
|
||||
struct ifreq* ifr;
|
||||
char buf[16384];
|
||||
int sd;
|
||||
std::string name="";
|
||||
sd=socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if(sd>0){
|
||||
if(sd>=0){
|
||||
ifc.ifc_len=sizeof(buf);
|
||||
ifc.ifc_ifcu.ifcu_buf=buf;
|
||||
if(ioctl(sd, SIOCGIFCONF, &ifc)==0){
|
||||
@ -319,6 +358,14 @@ std::string NetworkSocketPosix::GetLocalInterfaceInfo(IPv4Address *v4addr, IPv6A
|
||||
len=sizeof(*ifr);
|
||||
#endif
|
||||
if(ifr->ifr_addr.sa_family==AF_INET){
|
||||
#ifdef __ANDROID__
|
||||
if(strlen(androidInterfaceName) && strcmp(androidInterfaceName, ifr->ifr_name)!=0){
|
||||
LOGI("Skipping interface %s as non-active [android-only]", ifr->ifr_name);
|
||||
ifr=(struct ifreq*)((char*)ifr+len);
|
||||
i+=len;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if(ioctl(sd, SIOCGIFADDR, ifr)==0){
|
||||
struct sockaddr_in* addr=(struct sockaddr_in *)(&ifr->ifr_addr);
|
||||
LOGI("Interface %s, address %s\n", ifr->ifr_name, inet_ntoa(addr->sin_addr));
|
||||
@ -327,6 +374,8 @@ std::string NetworkSocketPosix::GetLocalInterfaceInfo(IPv4Address *v4addr, IPv6A
|
||||
//LOGV("flags = %08X", ifr->ifr_flags);
|
||||
if((ntohl(addr->sin_addr.s_addr) & 0xFFFF0000)==0xA9FE0000){
|
||||
LOGV("skipping link-local");
|
||||
ifr=(struct ifreq*)((char*)ifr+len);
|
||||
i+=len;
|
||||
continue;
|
||||
}
|
||||
if(v4addr){
|
||||
@ -345,8 +394,8 @@ std::string NetworkSocketPosix::GetLocalInterfaceInfo(IPv4Address *v4addr, IPv6A
|
||||
}else{
|
||||
LOGE("Error getting LAN address: %d", errno);
|
||||
}
|
||||
close(sd);
|
||||
}
|
||||
close(sd);
|
||||
return name;
|
||||
}
|
||||
|
||||
@ -458,7 +507,7 @@ bool NetworkSocketPosix::Select(std::vector<NetworkSocket *> &readFds, std::vect
|
||||
maxfd=sfd;
|
||||
}
|
||||
|
||||
int res=select(maxfd+1, &readSet, NULL, &errorSet, NULL);
|
||||
select(maxfd+1, &readSet, NULL, &errorSet, NULL);
|
||||
|
||||
if(canceller && FD_ISSET(canceller->pipeRead, &readSet) && !anyFailed){
|
||||
char c;
|
||||
@ -496,7 +545,10 @@ bool NetworkSocketPosix::Select(std::vector<NetworkSocket *> &readFds, std::vect
|
||||
SocketSelectCancellerPosix::SocketSelectCancellerPosix(){
|
||||
int p[2];
|
||||
int pipeRes=pipe(p);
|
||||
assert(pipeRes==0);
|
||||
if(pipeRes!=0){
|
||||
LOGE("pipe() failed");
|
||||
abort();
|
||||
}
|
||||
pipeRead=p[0];
|
||||
pipeWrite=p[1];
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ void VoIPControllerWrapper::SetPublicEndpoints(const Platform::Array<libtgvoip::
|
||||
libtgvoip::Endpoint^ _ep = endpoints[i];
|
||||
tgvoip::Endpoint ep;
|
||||
ep.id = _ep->id;
|
||||
ep.type = EP_TYPE_UDP_RELAY;
|
||||
ep.type = Endpoint::TYPE_UDP_RELAY;
|
||||
char buf[128];
|
||||
if (_ep->ipv4){
|
||||
WideCharToMultiByte(CP_UTF8, 0, _ep->ipv4->Data(), -1, buf, sizeof(buf), NULL, NULL);
|
||||
|
241
threading.h
241
threading.h
@ -7,34 +7,108 @@
|
||||
#ifndef __THREADING_H
|
||||
#define __THREADING_H
|
||||
|
||||
namespace tgvoip{
|
||||
class MethodPointerBase{
|
||||
public:
|
||||
virtual ~MethodPointerBase(){
|
||||
|
||||
}
|
||||
virtual void Invoke(void* arg)=0;
|
||||
};
|
||||
|
||||
template<typename T> class MethodPointer : public MethodPointerBase{
|
||||
public:
|
||||
MethodPointer(void (T::*method)(void*), T* obj){
|
||||
this->method=method;
|
||||
this->obj=obj;
|
||||
}
|
||||
|
||||
virtual void Invoke(void* arg){
|
||||
(obj->*method)(arg);
|
||||
}
|
||||
|
||||
private:
|
||||
void (T::*method)(void*);
|
||||
T* obj;
|
||||
};
|
||||
}
|
||||
|
||||
#if defined(_POSIX_THREADS) || defined(_POSIX_VERSION) || defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <sched.h>
|
||||
|
||||
typedef pthread_t tgvoip_thread_t;
|
||||
typedef pthread_mutex_t tgvoip_mutex_t;
|
||||
typedef pthread_cond_t tgvoip_lock_t;
|
||||
namespace tgvoip{
|
||||
class Mutex{
|
||||
public:
|
||||
Mutex(){
|
||||
pthread_mutex_init(&mtx, NULL);
|
||||
}
|
||||
|
||||
#define start_thread(ref, entry, arg) pthread_create(&ref, NULL, entry, arg)
|
||||
#define join_thread(thread) pthread_join(thread, NULL)
|
||||
~Mutex(){
|
||||
pthread_mutex_destroy(&mtx);
|
||||
}
|
||||
|
||||
void Lock(){
|
||||
pthread_mutex_lock(&mtx);
|
||||
}
|
||||
|
||||
void Unlock(){
|
||||
pthread_mutex_unlock(&mtx);
|
||||
}
|
||||
|
||||
private:
|
||||
Mutex(const Mutex& other);
|
||||
pthread_mutex_t mtx;
|
||||
};
|
||||
|
||||
class Thread{
|
||||
public:
|
||||
Thread(MethodPointerBase* entry, void* arg) : entry(entry), arg(arg){
|
||||
name=NULL;
|
||||
}
|
||||
|
||||
~Thread(){
|
||||
delete entry;
|
||||
}
|
||||
|
||||
void Start(){
|
||||
pthread_create(&thread, NULL, Thread::ActualEntryPoint, this);
|
||||
}
|
||||
|
||||
void Join(){
|
||||
pthread_join(thread, NULL);
|
||||
}
|
||||
|
||||
void SetName(const char* name){
|
||||
this->name=name;
|
||||
}
|
||||
|
||||
|
||||
void SetMaxPriority(){
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
static void* ActualEntryPoint(void* arg){
|
||||
Thread* self=reinterpret_cast<Thread*>(arg);
|
||||
if(self->name){
|
||||
#ifndef __APPLE__
|
||||
#define set_thread_name(thread, name) pthread_setname_np(thread, name)
|
||||
pthread_setname_np(self->thread, self->name);
|
||||
#else
|
||||
#define set_thread_name(thread, name)
|
||||
pthread_setname_np(self->name);
|
||||
#endif
|
||||
#define set_thread_priority(thread, priority) {sched_param __param; __param.sched_priority=priority; int __result=pthread_setschedparam(thread, SCHED_RR, &__param); if(__result!=0){LOGE("can't set thread priority: %s", strerror(__result));}};
|
||||
#define get_thread_max_priority() sched_get_priority_max(SCHED_RR)
|
||||
#define get_thread_min_priority() sched_get_priority_min(SCHED_RR)
|
||||
#define init_mutex(mutex) pthread_mutex_init(&mutex, NULL)
|
||||
#define free_mutex(mutex) pthread_mutex_destroy(&mutex)
|
||||
#define lock_mutex(mutex) pthread_mutex_lock(&mutex)
|
||||
#define unlock_mutex(mutex) pthread_mutex_unlock(&mutex)
|
||||
#define init_lock(lock) pthread_cond_init(&lock, NULL)
|
||||
#define free_lock(lock) pthread_cond_destroy(&lock)
|
||||
#define wait_lock(lock, mutex) pthread_cond_wait(&lock, &mutex)
|
||||
#define notify_lock(lock) pthread_cond_broadcast(&lock)
|
||||
}
|
||||
self->entry->Invoke(self->arg);
|
||||
return NULL;
|
||||
}
|
||||
MethodPointerBase* entry;
|
||||
void* arg;
|
||||
pthread_t thread;
|
||||
const char* name;
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <dispatch/dispatch.h>
|
||||
@ -113,39 +187,100 @@ private:
|
||||
|
||||
#include <Windows.h>
|
||||
#include <assert.h>
|
||||
typedef HANDLE tgvoip_thread_t;
|
||||
typedef CRITICAL_SECTION tgvoip_mutex_t;
|
||||
typedef HANDLE tgvoip_lock_t; // uncomment for XP compatibility
|
||||
//typedef CONDITION_VARIABLE tgvoip_lock_t;
|
||||
|
||||
#define start_thread(ref, entry, arg) (ref=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)entry, arg, 0, NULL))
|
||||
#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
|
||||
#define join_thread(thread) {WaitForSingleObject(thread, INFINITE); CloseHandle(thread);}
|
||||
#else
|
||||
#define join_thread(thread) {WaitForSingleObjectEx(thread, INFINITE, false); CloseHandle(thread);}
|
||||
#endif
|
||||
#define set_thread_name(thread, name) // threads in Windows don't have names
|
||||
#define set_thread_priority(thread, priority) SetThreadPriority(thread, priority)
|
||||
#define get_thread_max_priority() THREAD_PRIORITY_HIGHEST
|
||||
#define get_thread_min_priority() THREAD_PRIORITY_LOWEST
|
||||
#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
|
||||
#define init_mutex(mutex) InitializeCriticalSection(&mutex)
|
||||
#else
|
||||
#define init_mutex(mutex) InitializeCriticalSectionEx(&mutex, 0, 0)
|
||||
#endif
|
||||
#define free_mutex(mutex) DeleteCriticalSection(&mutex)
|
||||
#define lock_mutex(mutex) EnterCriticalSection(&mutex)
|
||||
#define unlock_mutex(mutex) LeaveCriticalSection(&mutex)
|
||||
#define init_lock(lock) (lock=CreateEvent(NULL, false, false, NULL))
|
||||
#define free_lock(lock) CloseHandle(lock)
|
||||
#define wait_lock(lock, mutex) {LeaveCriticalSection(&mutex); WaitForSingleObject(lock, INFINITE); EnterCriticalSection(&mutex);}
|
||||
#define notify_lock(lock) PulseEvent(lock)
|
||||
//#define init_lock(lock) InitializeConditionVariable(&lock)
|
||||
//#define free_lock(lock) // ?
|
||||
//#define wait_lock(lock, mutex) SleepConditionVariableCS(&lock, &mutex, INFINITE)
|
||||
//#define notify_lock(lock) WakeAllConditionVariable(&lock)
|
||||
|
||||
namespace tgvoip{
|
||||
class Mutex{
|
||||
public:
|
||||
Mutex(){
|
||||
#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
|
||||
InitializeCriticalSection(§ion);
|
||||
#else
|
||||
InitializeCriticalSectionEx(§ion, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
~Mutex(){
|
||||
DeleteCriticalSection(§ion);
|
||||
}
|
||||
|
||||
void Lock(){
|
||||
EnterCriticalSection(§ion);
|
||||
}
|
||||
|
||||
void Unlock(){
|
||||
LeaveCriticalSection(§ion);
|
||||
}
|
||||
|
||||
private:
|
||||
Mutex(const Mutex& other);
|
||||
CRITICAL_SECTION section;
|
||||
};
|
||||
|
||||
class Thread{
|
||||
public:
|
||||
Thread(MethodPointerBase* entry, void* arg) : entry(entry), arg(arg){
|
||||
name=NULL;
|
||||
}
|
||||
|
||||
~Thread(){
|
||||
delete entry;
|
||||
}
|
||||
|
||||
void Start(){
|
||||
thread=CreateThread(NULL, 0, Thread::ActualEntryPoint, this, 0, NULL);
|
||||
}
|
||||
|
||||
void Join(){
|
||||
#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
#else
|
||||
WaitForSingleObjectEx(thread, INFINITE, false);
|
||||
#endif
|
||||
CloseHandle(thread);
|
||||
}
|
||||
|
||||
void SetName(const char* name){
|
||||
this->name=name;
|
||||
}
|
||||
|
||||
void SetMaxPriority(){
|
||||
SetThreadPriority(thread, THREAD_PRIORITY_HIGHEST);
|
||||
}
|
||||
|
||||
private:
|
||||
static const DWORD MS_VC_EXCEPTION=0x406D1388;
|
||||
|
||||
#pragma pack(push,8)
|
||||
typedef struct tagTHREADNAME_INFO
|
||||
{
|
||||
DWORD dwType; // Must be 0x1000.
|
||||
LPCSTR szName; // Pointer to name (in user addr space).
|
||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||
} THREADNAME_INFO;
|
||||
#pragma pack(pop)
|
||||
|
||||
static DWORD WINAPI ActualEntryPoint(void* arg){
|
||||
Thread* self=reinterpret_cast<Thread*>(arg);
|
||||
if(self->name){
|
||||
THREADNAME_INFO info;
|
||||
info.dwType=0x1000;
|
||||
info.szName=self->name;
|
||||
info.dwThreadID=-1;
|
||||
info.dwFlags=0;
|
||||
__try{
|
||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||
}__except(EXCEPTION_EXECUTE_HANDLER){}
|
||||
}
|
||||
self->entry->Invoke(self->arg);
|
||||
return 0;
|
||||
}
|
||||
MethodPointerBase* entry;
|
||||
void* arg;
|
||||
HANDLE thread;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
class Semaphore{
|
||||
public:
|
||||
Semaphore(unsigned int maxCount, unsigned int initValue){
|
||||
@ -193,14 +328,14 @@ private:
|
||||
namespace tgvoip{
|
||||
class MutexGuard{
|
||||
public:
|
||||
MutexGuard(tgvoip_mutex_t &mutex) : mutex(mutex) {
|
||||
lock_mutex(mutex);
|
||||
MutexGuard(Mutex &mutex) : mutex(mutex) {
|
||||
mutex.Lock();
|
||||
}
|
||||
~MutexGuard(){
|
||||
unlock_mutex(mutex);
|
||||
mutex.Unlock();
|
||||
}
|
||||
private:
|
||||
tgvoip_mutex_t &mutex;
|
||||
Mutex &mutex;
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user