mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-02 12:48:45 +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){
|
BlockingQueue(size_t capacity) : semaphore(capacity, 0){
|
||||||
this->capacity=capacity;
|
this->capacity=capacity;
|
||||||
overflowCallback=NULL;
|
overflowCallback=NULL;
|
||||||
init_mutex(mutex);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
~BlockingQueue(){
|
~BlockingQueue(){
|
||||||
semaphore.Release();
|
semaphore.Release();
|
||||||
free_mutex(mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Put(T thing){
|
void Put(T thing){
|
||||||
@ -86,7 +84,7 @@ private:
|
|||||||
size_t capacity;
|
size_t capacity;
|
||||||
//tgvoip_lock_t lock;
|
//tgvoip_lock_t lock;
|
||||||
Semaphore semaphore;
|
Semaphore semaphore;
|
||||||
tgvoip_mutex_t mutex;
|
Mutex mutex;
|
||||||
void (*overflowCallback)(T);
|
void (*overflowCallback)(T);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -98,6 +98,13 @@ void BufferInputStream::ReadBytes(unsigned char *to, size_t count){
|
|||||||
offset+=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){
|
void BufferInputStream::EnsureEnoughRemaining(size_t need){
|
||||||
if(length-offset<need){
|
if(length-offset<need){
|
||||||
|
|||||||
@ -26,6 +26,7 @@ public:
|
|||||||
int16_t ReadInt16();
|
int16_t ReadInt16();
|
||||||
int32_t ReadTlLength();
|
int32_t ReadTlLength();
|
||||||
void ReadBytes(unsigned char* to, size_t count);
|
void ReadBytes(unsigned char* to, size_t count);
|
||||||
|
BufferInputStream GetPartBuffer(size_t length, bool advance);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void EnsureEnoughRemaining(size_t need);
|
void EnsureEnoughRemaining(size_t need);
|
||||||
|
|||||||
@ -97,3 +97,8 @@ void BufferOutputStream::Reset(){
|
|||||||
offset=0;
|
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();
|
unsigned char* GetBuffer();
|
||||||
size_t GetLength();
|
size_t GetLength();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
void Rewind(size_t numBytes);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ExpandBufferIfNeeded(size_t need);
|
void ExpandBufferIfNeeded(size_t need);
|
||||||
|
|||||||
@ -13,10 +13,9 @@ using namespace tgvoip;
|
|||||||
|
|
||||||
BufferPool::BufferPool(unsigned int size, unsigned int count){
|
BufferPool::BufferPool(unsigned int size, unsigned int count){
|
||||||
assert(count<=64);
|
assert(count<=64);
|
||||||
init_mutex(mutex);
|
|
||||||
buffers[0]=(unsigned char*) malloc(size*count);
|
buffers[0]=(unsigned char*) malloc(size*count);
|
||||||
bufferCount=count;
|
bufferCount=count;
|
||||||
int i;
|
unsigned int i;
|
||||||
for(i=1;i<count;i++){
|
for(i=1;i<count;i++){
|
||||||
buffers[i]=buffers[0]+i*size;
|
buffers[i]=buffers[0]+i*size;
|
||||||
}
|
}
|
||||||
@ -25,31 +24,27 @@ BufferPool::BufferPool(unsigned int size, unsigned int count){
|
|||||||
}
|
}
|
||||||
|
|
||||||
BufferPool::~BufferPool(){
|
BufferPool::~BufferPool(){
|
||||||
free_mutex(mutex);
|
|
||||||
free(buffers[0]);
|
free(buffers[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* BufferPool::Get(){
|
unsigned char* BufferPool::Get(){
|
||||||
lock_mutex(mutex);
|
MutexGuard m(mutex);
|
||||||
int i;
|
int i;
|
||||||
for(i=0;i<bufferCount;i++){
|
for(i=0;i<bufferCount;i++){
|
||||||
if(!((usedBuffers >> i) & 1)){
|
if(!((usedBuffers >> i) & 1)){
|
||||||
usedBuffers|=(1LL << i);
|
usedBuffers|=(1LL << i);
|
||||||
unlock_mutex(mutex);
|
|
||||||
return buffers[i];
|
return buffers[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unlock_mutex(mutex);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferPool::Reuse(unsigned char* buffer){
|
void BufferPool::Reuse(unsigned char* buffer){
|
||||||
lock_mutex(mutex);
|
MutexGuard m(mutex);
|
||||||
int i;
|
int i;
|
||||||
for(i=0;i<bufferCount;i++){
|
for(i=0;i<bufferCount;i++){
|
||||||
if(buffers[i]==buffer){
|
if(buffers[i]==buffer){
|
||||||
usedBuffers&= ~(1LL << i);
|
usedBuffers&= ~(1LL << i);
|
||||||
unlock_mutex(mutex);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ private:
|
|||||||
int bufferCount;
|
int bufferCount;
|
||||||
size_t size;
|
size_t size;
|
||||||
unsigned char* buffers[64];
|
unsigned char* buffers[64];
|
||||||
tgvoip_mutex_t mutex;
|
Mutex mutex;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,11 +30,9 @@ CongestionControl::CongestionControl(){
|
|||||||
inflightDataSize=0;
|
inflightDataSize=0;
|
||||||
lossCount=0;
|
lossCount=0;
|
||||||
cwnd=(size_t) ServerConfig::GetSharedInstance()->GetInt("audio_congestion_window", 1024);
|
cwnd=(size_t) ServerConfig::GetSharedInstance()->GetInt("audio_congestion_window", 1024);
|
||||||
init_mutex(mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CongestionControl::~CongestionControl(){
|
CongestionControl::~CongestionControl(){
|
||||||
free_mutex(mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t CongestionControl::GetAcknowledgedDataSize(){
|
size_t CongestionControl::GetAcknowledgedDataSize(){
|
||||||
|
|||||||
@ -64,7 +64,7 @@ private:
|
|||||||
uint32_t tickCount;
|
uint32_t tickCount;
|
||||||
size_t inflightDataSize;
|
size_t inflightDataSize;
|
||||||
size_t cwnd;
|
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);
|
splittingFilterFarendOut=new webrtc::IFChannelBuffer(960, 1, 3);
|
||||||
|
|
||||||
if(enableAEC){
|
if(enableAEC){
|
||||||
init_mutex(aecMutex);
|
|
||||||
#ifndef TGVOIP_USE_DESKTOP_DSP
|
#ifndef TGVOIP_USE_DESKTOP_DSP
|
||||||
aec=WebRtcAecm_Create();
|
aec=WebRtcAecm_Create();
|
||||||
WebRtcAecm_Init(aec, 16000);
|
WebRtcAecm_Init(aec, 16000);
|
||||||
@ -79,7 +78,8 @@ EchoCanceller::EchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){
|
|||||||
farendBufferPool=new BufferPool(960*2, 10);
|
farendBufferPool=new BufferPool(960*2, 10);
|
||||||
running=true;
|
running=true;
|
||||||
|
|
||||||
start_thread(bufferFarendThread, EchoCanceller::StartBufferFarendThread, this);
|
bufferFarendThread=new Thread(new MethodPointer<EchoCanceller>(&EchoCanceller::RunBufferFarendThread, this), NULL);
|
||||||
|
bufferFarendThread->Start();
|
||||||
}else{
|
}else{
|
||||||
aec=NULL;
|
aec=NULL;
|
||||||
}
|
}
|
||||||
@ -117,7 +117,8 @@ EchoCanceller::~EchoCanceller(){
|
|||||||
if(enableAEC){
|
if(enableAEC){
|
||||||
running=false;
|
running=false;
|
||||||
farendQueue->Put(NULL);
|
farendQueue->Put(NULL);
|
||||||
join_thread(bufferFarendThread);
|
bufferFarendThread->Join();
|
||||||
|
delete bufferFarendThread;
|
||||||
delete farendQueue;
|
delete farendQueue;
|
||||||
delete farendBufferPool;
|
delete farendBufferPool;
|
||||||
#ifndef TGVOIP_USE_DESKTOP_DSP
|
#ifndef TGVOIP_USE_DESKTOP_DSP
|
||||||
@ -145,10 +146,6 @@ EchoCanceller::~EchoCanceller(){
|
|||||||
delete (webrtc::IFChannelBuffer*)splittingFilterOut;
|
delete (webrtc::IFChannelBuffer*)splittingFilterOut;
|
||||||
delete (webrtc::IFChannelBuffer*)splittingFilterFarendIn;
|
delete (webrtc::IFChannelBuffer*)splittingFilterFarendIn;
|
||||||
delete (webrtc::IFChannelBuffer*)splittingFilterFarendOut;
|
delete (webrtc::IFChannelBuffer*)splittingFilterFarendOut;
|
||||||
|
|
||||||
if (this->enableAEC) {
|
|
||||||
free_mutex(aecMutex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EchoCanceller::Start(){
|
void EchoCanceller::Start(){
|
||||||
@ -175,12 +172,7 @@ void EchoCanceller::SpeakerOutCallback(unsigned char* data, size_t len){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *EchoCanceller::StartBufferFarendThread(void *arg){
|
void EchoCanceller::RunBufferFarendThread(void* arg){
|
||||||
((EchoCanceller*)arg)->RunBufferFarendThread();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EchoCanceller::RunBufferFarendThread(){
|
|
||||||
while(running){
|
while(running){
|
||||||
int16_t* samplesIn=farendQueue->GetBlocking();
|
int16_t* samplesIn=farendQueue->GetBlocking();
|
||||||
if(samplesIn){
|
if(samplesIn){
|
||||||
@ -189,7 +181,7 @@ void EchoCanceller::RunBufferFarendThread(){
|
|||||||
memcpy(bufIn->ibuf()->bands(0)[0], samplesIn, 960*2);
|
memcpy(bufIn->ibuf()->bands(0)[0], samplesIn, 960*2);
|
||||||
farendBufferPool->Reuse((unsigned char *) samplesIn);
|
farendBufferPool->Reuse((unsigned char *) samplesIn);
|
||||||
((webrtc::SplittingFilter*)splittingFilterFarend)->Analysis(bufIn, bufOut);
|
((webrtc::SplittingFilter*)splittingFilterFarend)->Analysis(bufIn, bufOut);
|
||||||
lock_mutex(aecMutex);
|
aecMutex.Lock();
|
||||||
#ifndef TGVOIP_USE_DESKTOP_DSP
|
#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);
|
||||||
WebRtcAecm_BufferFarend(aec, bufOut->ibuf_const()->bands(0)[0]+160, 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);
|
||||||
webrtc::WebRtcAec_BufferFarend(aec, bufOut->fbuf_const()->bands(0)[0]+160, 160);
|
webrtc::WebRtcAec_BufferFarend(aec, bufOut->fbuf_const()->bands(0)[0]+160, 160);
|
||||||
#endif
|
#endif
|
||||||
unlock_mutex(aecMutex);
|
aecMutex.Unlock();
|
||||||
didBufferFarend=true;
|
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);
|
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], _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()));
|
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);
|
memcpy(bufOut->ibuf()->bands(0)[0], samplesOut, 320*2);
|
||||||
}else if(enableAEC){
|
}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], 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()));
|
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);
|
memcpy(bufOut->ibuf()->bands(0)[0], samplesOut, 320*2);
|
||||||
}else if(enableNS){
|
}else if(enableNS){
|
||||||
int16_t _nsOut[3][320];
|
int16_t _nsOut[3][320];
|
||||||
|
|||||||
@ -30,10 +30,9 @@ private:
|
|||||||
bool enableAGC;
|
bool enableAGC;
|
||||||
bool enableNS;
|
bool enableNS;
|
||||||
#ifndef TGVOIP_NO_DSP
|
#ifndef TGVOIP_NO_DSP
|
||||||
static void* StartBufferFarendThread(void* arg);
|
void RunBufferFarendThread(void* arg);
|
||||||
void RunBufferFarendThread();
|
|
||||||
bool didBufferFarend;
|
bool didBufferFarend;
|
||||||
tgvoip_mutex_t aecMutex;
|
Mutex aecMutex;
|
||||||
void* aec;
|
void* aec;
|
||||||
void* splittingFilter; // webrtc::SplittingFilter
|
void* splittingFilter; // webrtc::SplittingFilter
|
||||||
void* splittingFilterIn; // webrtc::IFChannelBuffer
|
void* splittingFilterIn; // webrtc::IFChannelBuffer
|
||||||
@ -41,7 +40,7 @@ private:
|
|||||||
void* splittingFilterFarend; // webrtc::SplittingFilter
|
void* splittingFilterFarend; // webrtc::SplittingFilter
|
||||||
void* splittingFilterFarendIn; // webrtc::IFChannelBuffer
|
void* splittingFilterFarendIn; // webrtc::IFChannelBuffer
|
||||||
void* splittingFilterFarendOut; // webrtc::IFChannelBuffer
|
void* splittingFilterFarendOut; // webrtc::IFChannelBuffer
|
||||||
tgvoip_thread_t bufferFarendThread;
|
Thread* bufferFarendThread;
|
||||||
BlockingQueue<int16_t*>* farendQueue;
|
BlockingQueue<int16_t*>* farendQueue;
|
||||||
BufferPool* farendBufferPool;
|
BufferPool* farendBufferPool;
|
||||||
bool running;
|
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);
|
lossesToReset=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_losses_to_reset", 20);
|
||||||
resyncThreshold=ServerConfig::GetSharedInstance()->GetDouble("jitter_resync_threshold", 1.0);
|
resyncThreshold=ServerConfig::GetSharedInstance()->GetDouble("jitter_resync_threshold", 1.0);
|
||||||
//dump=fopen("/sdcard/tgvoip_jitter_dump.txt", "a");
|
#ifdef TGVOIP_DUMP_JITTER_STATS
|
||||||
//fprintf(dump, "==================================\n");
|
#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();
|
Reset();
|
||||||
init_mutex(mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JitterBuffer::~JitterBuffer(){
|
JitterBuffer::~JitterBuffer(){
|
||||||
Reset();
|
Reset();
|
||||||
free_mutex(mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitterBuffer::SetMinPacketCount(uint32_t count){
|
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.size=len;
|
||||||
pkt.buffer=data;
|
pkt.buffer=data;
|
||||||
pkt.timestamp=timestamp;
|
pkt.timestamp=timestamp;
|
||||||
lock_mutex(mutex);
|
mutex.Lock();
|
||||||
PutInternal(&pkt);
|
PutInternal(&pkt);
|
||||||
unlock_mutex(mutex);
|
mutex.Unlock();
|
||||||
//LOGV("in, ts=%d", timestamp);
|
//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;
|
jitter_packet_t pkt;
|
||||||
pkt.buffer=buffer;
|
pkt.buffer=buffer;
|
||||||
pkt.size=len;
|
pkt.size=len;
|
||||||
lock_mutex(mutex);
|
MutexGuard m(mutex);
|
||||||
int result=GetInternal(&pkt, offsetInSteps);
|
int result=GetInternal(&pkt, offsetInSteps, advance);
|
||||||
if(playbackScaledDuration){
|
if(playbackScaledDuration){
|
||||||
if(outstandingDelayChange!=0){
|
if(outstandingDelayChange!=0){
|
||||||
if(outstandingDelayChange<0){
|
if(outstandingDelayChange<0){
|
||||||
@ -121,12 +128,14 @@ size_t JitterBuffer::HandleOutput(unsigned char *buffer, size_t len, int offsetI
|
|||||||
*playbackScaledDuration=80;
|
*playbackScaledDuration=80;
|
||||||
outstandingDelayChange-=20;
|
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{
|
}else{
|
||||||
*playbackScaledDuration=60;
|
*playbackScaledDuration=60;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unlock_mutex(mutex);
|
|
||||||
if(result==JR_OK){
|
if(result==JR_OK){
|
||||||
return pkt.size;
|
return pkt.size;
|
||||||
}else{
|
}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){
|
/*if(needBuffering && lastPutTimestamp<nextTimestamp){
|
||||||
LOGV("jitter: don't have timestamp %lld, buffering", (long long int)nextTimestamp);
|
LOGV("jitter: don't have timestamp %lld, buffering", (long long int)nextTimestamp);
|
||||||
Advance();
|
Advance();
|
||||||
@ -172,9 +181,9 @@ int JitterBuffer::GetInternal(jitter_packet_t* pkt, int offset){
|
|||||||
return JR_OK;
|
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();
|
Advance();
|
||||||
|
|
||||||
if(!needBuffering){
|
if(!needBuffering){
|
||||||
@ -242,11 +251,11 @@ void JitterBuffer::PutInternal(jitter_packet_t* pkt){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(pkt->timestamp<nextTimestamp){
|
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++;
|
latePacketCount++;
|
||||||
lostPackets--;
|
lostPackets--;
|
||||||
}else if(pkt->timestamp<nextTimestamp-1){
|
}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++;
|
latePacketCount++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -280,7 +289,9 @@ void JitterBuffer::PutInternal(jitter_packet_t* pkt){
|
|||||||
memcpy(slots[i].buffer, pkt->buffer, pkt->size);
|
memcpy(slots[i].buffer, pkt->buffer, pkt->size);
|
||||||
else
|
else
|
||||||
LOGE("WTF!!");
|
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;
|
prevRecvTime=time;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,8 +301,8 @@ void JitterBuffer::Advance(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int JitterBuffer::GetCurrentDelay(){
|
unsigned int JitterBuffer::GetCurrentDelay(){
|
||||||
int delay=0;
|
unsigned int delay=0;
|
||||||
int i;
|
int i;
|
||||||
for(i=0;i<JITTER_SLOT_COUNT;i++){
|
for(i=0;i<JITTER_SLOT_COUNT;i++){
|
||||||
if(slots[i].buffer!=NULL)
|
if(slots[i].buffer!=NULL)
|
||||||
@ -301,11 +312,9 @@ int JitterBuffer::GetCurrentDelay(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JitterBuffer::Tick(){
|
void JitterBuffer::Tick(){
|
||||||
lock_mutex(mutex);
|
MutexGuard m(mutex);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
int count=0;
|
|
||||||
|
|
||||||
memmove(&lateHistory[1], lateHistory, 63*sizeof(int));
|
memmove(&lateHistory[1], lateHistory, 63*sizeof(int));
|
||||||
lateHistory[0]=latePacketCount;
|
lateHistory[0]=latePacketCount;
|
||||||
latePacketCount=0;
|
latePacketCount=0;
|
||||||
@ -329,26 +338,6 @@ void JitterBuffer::Tick(){
|
|||||||
if(avgLate16>=resyncThreshold){
|
if(avgLate16>=resyncThreshold){
|
||||||
wasReset=true;
|
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(absolutelyNoLatePackets){
|
||||||
if(dontDecMinDelay>0)
|
if(dontDecMinDelay>0)
|
||||||
@ -444,7 +433,6 @@ void JitterBuffer::Tick(){
|
|||||||
|
|
||||||
tickCount++;
|
tickCount++;
|
||||||
|
|
||||||
unlock_mutex(mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -468,10 +456,9 @@ void JitterBuffer::GetAverageLateCount(double *out){
|
|||||||
|
|
||||||
|
|
||||||
int JitterBuffer::GetAndResetLostPacketCount(){
|
int JitterBuffer::GetAndResetLostPacketCount(){
|
||||||
lock_mutex(mutex);
|
MutexGuard m(mutex);
|
||||||
int r=lostPackets;
|
int r=lostPackets;
|
||||||
lostPackets=0;
|
lostPackets=0;
|
||||||
unlock_mutex(mutex);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,11 +36,11 @@ public:
|
|||||||
~JitterBuffer();
|
~JitterBuffer();
|
||||||
void SetMinPacketCount(uint32_t count);
|
void SetMinPacketCount(uint32_t count);
|
||||||
int GetMinPacketCount();
|
int GetMinPacketCount();
|
||||||
int GetCurrentDelay();
|
unsigned int GetCurrentDelay();
|
||||||
double GetAverageDelay();
|
double GetAverageDelay();
|
||||||
void Reset();
|
void Reset();
|
||||||
void HandleInput(unsigned char* data, size_t len, uint32_t timestamp);
|
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 Tick();
|
||||||
void GetAverageLateCount(double* out);
|
void GetAverageLateCount(double* out);
|
||||||
int GetAndResetLostPacketCount();
|
int GetAndResetLostPacketCount();
|
||||||
@ -51,24 +51,24 @@ private:
|
|||||||
static size_t CallbackIn(unsigned char* data, size_t len, void* param);
|
static size_t CallbackIn(unsigned char* data, size_t len, void* param);
|
||||||
static size_t CallbackOut(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);
|
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();
|
void Advance();
|
||||||
|
|
||||||
BufferPool bufferPool;
|
BufferPool bufferPool;
|
||||||
tgvoip_mutex_t mutex;
|
Mutex mutex;
|
||||||
jitter_packet_t slots[JITTER_SLOT_COUNT];
|
jitter_packet_t slots[JITTER_SLOT_COUNT];
|
||||||
int64_t nextTimestamp;
|
int64_t nextTimestamp;
|
||||||
uint32_t step;
|
uint32_t step;
|
||||||
uint32_t minDelay;
|
double minDelay;
|
||||||
uint32_t minMinDelay;
|
uint32_t minMinDelay;
|
||||||
uint32_t maxMinDelay;
|
uint32_t maxMinDelay;
|
||||||
uint32_t maxUsedSlots;
|
uint32_t maxUsedSlots;
|
||||||
uint32_t lastPutTimestamp;
|
uint32_t lastPutTimestamp;
|
||||||
uint32_t lossesToReset;
|
uint32_t lossesToReset;
|
||||||
double resyncThreshold;
|
double resyncThreshold;
|
||||||
int lostCount;
|
unsigned int lostCount;
|
||||||
int lostSinceReset;
|
unsigned int lostSinceReset;
|
||||||
int gotSinceReset;
|
unsigned int gotSinceReset;
|
||||||
bool wasReset;
|
bool wasReset;
|
||||||
bool needBuffering;
|
bool needBuffering;
|
||||||
int delayHistory[64];
|
int delayHistory[64];
|
||||||
@ -88,7 +88,9 @@ private:
|
|||||||
int outstandingDelayChange;
|
int outstandingDelayChange;
|
||||||
unsigned int dontChangeDelay;
|
unsigned int dontChangeDelay;
|
||||||
double avgDelay;
|
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.
|
// you should have received with this source code distribution.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "logging.h"
|
||||||
#include "MediaStreamItf.h"
|
#include "MediaStreamItf.h"
|
||||||
|
#include "EchoCanceller.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <math.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
using namespace tgvoip;
|
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){
|
size_t MediaStreamItf::InvokeCallback(unsigned char *data, size_t length){
|
||||||
return (*callback)(data, length, callbackParam);
|
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
|
#define LIBTGVOIP_MEDIASTREAMINPUT_H
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "threading.h"
|
||||||
|
#include "BlockingQueue.h"
|
||||||
|
#include "BufferPool.h"
|
||||||
|
|
||||||
namespace tgvoip{
|
namespace tgvoip{
|
||||||
|
|
||||||
|
class EchoCanceller;
|
||||||
|
|
||||||
class MediaStreamItf{
|
class MediaStreamItf{
|
||||||
public:
|
public:
|
||||||
virtual void Start()=0;
|
virtual void Start()=0;
|
||||||
@ -23,7 +31,58 @@ private:
|
|||||||
size_t (*callback)(unsigned char*, size_t, void*);
|
size_t (*callback)(unsigned char*, size_t, void*);
|
||||||
void* callbackParam;
|
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
|
#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){
|
size_t NetworkSocket::Receive(unsigned char *buffer, size_t len){
|
||||||
NetworkPacket pkt;
|
NetworkPacket pkt={0};
|
||||||
pkt.data=buffer;
|
pkt.data=buffer;
|
||||||
pkt.length=len;
|
pkt.length=len;
|
||||||
Receive(&pkt);
|
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){
|
size_t NetworkSocket::Send(unsigned char *buffer, size_t len){
|
||||||
NetworkPacket pkt;
|
NetworkPacket pkt={0};
|
||||||
pkt.data=buffer;
|
pkt.data=buffer;
|
||||||
pkt.length=len;
|
pkt.length=len;
|
||||||
Send(&pkt);
|
Send(&pkt);
|
||||||
@ -361,7 +361,7 @@ void NetworkSocketSOCKS5Proxy::Send(NetworkPacket *packet){
|
|||||||
}
|
}
|
||||||
out.WriteInt16(htons(packet->port));
|
out.WriteInt16(htons(packet->port));
|
||||||
out.WriteBytes(packet->data, packet->length);
|
out.WriteBytes(packet->data, packet->length);
|
||||||
NetworkPacket p;
|
NetworkPacket p={0};
|
||||||
p.data=buf;
|
p.data=buf;
|
||||||
p.length=out.GetLength();
|
p.length=out.GetLength();
|
||||||
p.address=connectedAddress;
|
p.address=connectedAddress;
|
||||||
@ -376,7 +376,7 @@ void NetworkSocketSOCKS5Proxy::Receive(NetworkPacket *packet){
|
|||||||
tcp->Receive(packet);
|
tcp->Receive(packet);
|
||||||
}else if(protocol==PROTO_UDP){
|
}else if(protocol==PROTO_UDP){
|
||||||
unsigned char buf[1500];
|
unsigned char buf[1500];
|
||||||
NetworkPacket p;
|
NetworkPacket p={0};
|
||||||
p.data=buf;
|
p.data=buf;
|
||||||
p.length=sizeof(buf);
|
p.length=sizeof(buf);
|
||||||
udp->Receive(&p);
|
udp->Receive(&p);
|
||||||
@ -587,6 +587,7 @@ void NetworkSocketSOCKS5Proxy::InitConnection(){
|
|||||||
failed=true;
|
failed=true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
LOGV("socks5: authentication succeeded");
|
||||||
}else{
|
}else{
|
||||||
LOGW("socks5: unsupported auth method");
|
LOGW("socks5: unsupported auth method");
|
||||||
failed=true;
|
failed=true;
|
||||||
|
|||||||
331
OpusDecoder.cpp
331
OpusDecoder.cpp
@ -10,32 +10,49 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "VoIPController.h"
|
||||||
|
|
||||||
#define PACKET_SIZE (960*2)
|
#define PACKET_SIZE (960*2)
|
||||||
|
|
||||||
using namespace tgvoip;
|
using namespace tgvoip;
|
||||||
|
|
||||||
tgvoip::OpusDecoder::OpusDecoder(MediaStreamItf *dst) : semaphore(32, 0){
|
tgvoip::OpusDecoder::OpusDecoder(MediaStreamItf *dst, bool isAsync){
|
||||||
//this->source=source;
|
async=isAsync;
|
||||||
dst->SetCallback(OpusDecoder::Callback, this);
|
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);
|
dec=opus_decoder_create(48000, 1, NULL);
|
||||||
//test=fopen("/sdcard/test.raw", "wb");
|
|
||||||
buffer=(unsigned char *) malloc(8192);
|
buffer=(unsigned char *) malloc(8192);
|
||||||
//lastDecoded=(unsigned char*) malloc(960*2);
|
|
||||||
lastDecoded=NULL;
|
lastDecoded=NULL;
|
||||||
lastDecodedLen=0;
|
|
||||||
outputBufferSize=0;
|
outputBufferSize=0;
|
||||||
lastDecodedOffset=0;
|
|
||||||
decodedQueue=new BlockingQueue<unsigned char*>(33);
|
|
||||||
bufferPool=new BufferPool(PACKET_SIZE, 32);
|
|
||||||
echoCanceller=NULL;
|
echoCanceller=NULL;
|
||||||
frameDuration=20;
|
frameDuration=20;
|
||||||
|
consecutiveLostPackets=0;
|
||||||
|
enableDTX=false;
|
||||||
|
silentPacketCount=0;
|
||||||
|
levelMeter=NULL;
|
||||||
|
nextLen=0;
|
||||||
|
running=false;
|
||||||
|
remainingDataLen=0;
|
||||||
|
processedBuffer=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tgvoip::OpusDecoder::~OpusDecoder(){
|
tgvoip::OpusDecoder::~OpusDecoder(){
|
||||||
opus_decoder_destroy(dec);
|
opus_decoder_destroy(dec);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
delete bufferPool;
|
if(bufferPool)
|
||||||
delete decodedQueue;
|
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){
|
size_t tgvoip::OpusDecoder::Callback(unsigned char *data, size_t len, void *param){
|
||||||
((OpusDecoder*)param)->HandleCallback(data, len);
|
return ((OpusDecoder*)param)->HandleCallback(data, len);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tgvoip::OpusDecoder::HandleCallback(unsigned char *data, size_t len){
|
size_t tgvoip::OpusDecoder::HandleCallback(unsigned char *data, size_t len){
|
||||||
if(!running){
|
if(async){
|
||||||
memset(data, 0, len);
|
if(!running){
|
||||||
return;
|
memset(data, 0, len);
|
||||||
}
|
return 0;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
semaphore.Release(count);
|
if(outputBufferSize==0){
|
||||||
}else if(len==PACKET_SIZE){
|
outputBufferSize=len;
|
||||||
lastDecoded=(unsigned char*) decodedQueue->GetBlocking();
|
int packetsNeeded;
|
||||||
if(!lastDecoded)
|
if(len>PACKET_SIZE)
|
||||||
return;
|
packetsNeeded=len/PACKET_SIZE;
|
||||||
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);
|
|
||||||
else
|
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;
|
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{
|
}else{
|
||||||
LOGW("skipping callback");
|
if(remainingDataLen==0 && silentPacketCount==0){
|
||||||
if(len>PACKET_SIZE)
|
int duration=DecodeNextFrame();
|
||||||
packetsNeeded=len/PACKET_SIZE;
|
remainingDataLen=(size_t) (duration/20*960*2);
|
||||||
else
|
}
|
||||||
packetsNeeded=1;
|
if(silentPacketCount>0 || remainingDataLen==0 || !processedBuffer){
|
||||||
}*/
|
if(silentPacketCount>0)
|
||||||
/*if(packetsNeeded>0){
|
silentPacketCount--;
|
||||||
lock_mutex(mutex);
|
memset(data, 0, 960*2);
|
||||||
notify_lock(lock);
|
if(levelMeter)
|
||||||
unlock_mutex(mutex);
|
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(){
|
void tgvoip::OpusDecoder::Start(){
|
||||||
init_mutex(mutex);
|
if(!async)
|
||||||
|
return;
|
||||||
running=true;
|
running=true;
|
||||||
start_thread(thread, OpusDecoder::StartThread, this);
|
thread=new Thread(new MethodPointer<tgvoip::OpusDecoder>(&tgvoip::OpusDecoder::RunThread, this), NULL);
|
||||||
set_thread_priority(thread, get_thread_max_priority());
|
thread->SetName("opus_decoder");
|
||||||
set_thread_name(thread, "opus_decoder");
|
thread->SetMaxPriority();
|
||||||
|
thread->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tgvoip::OpusDecoder::Stop(){
|
void tgvoip::OpusDecoder::Stop(){
|
||||||
if(!running)
|
if(!running || !async)
|
||||||
return;
|
return;
|
||||||
running=false;
|
running=false;
|
||||||
semaphore.Release();
|
semaphore->Release();
|
||||||
join_thread(thread);
|
thread->Join();
|
||||||
free_mutex(mutex);
|
delete thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tgvoip::OpusDecoder::RunThread(void* param){
|
||||||
void* tgvoip::OpusDecoder::StartThread(void *param){
|
|
||||||
((tgvoip::OpusDecoder*)param)->RunThread();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tgvoip::OpusDecoder::RunThread(){
|
|
||||||
unsigned char nextBuffer[8192];
|
|
||||||
unsigned char decodeBuffer[8192];
|
|
||||||
int i;
|
int i;
|
||||||
int packetsPerFrame=frameDuration/20;
|
|
||||||
bool first=true;
|
|
||||||
LOGI("decoder: packets per frame %d", packetsPerFrame);
|
LOGI("decoder: packets per frame %d", packetsPerFrame);
|
||||||
size_t nextLen=0;
|
|
||||||
while(running){
|
while(running){
|
||||||
//LOGV("after wait, running=%d", running);
|
int playbackDuration=DecodeNextFrame();
|
||||||
//LOGD("Will get %d packets", packetsNeeded);
|
for(i=0;i<playbackDuration/20;i++){
|
||||||
//lastDecodedLen=0;
|
semaphore->Acquire();
|
||||||
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();
|
|
||||||
if(!running){
|
if(!running){
|
||||||
LOGI("==== decoder exiting ====");
|
LOGI("==== decoder exiting ====");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unsigned char *buf=bufferPool->Get();
|
unsigned char *buf=bufferPool->Get();
|
||||||
if(buf){
|
if(buf){
|
||||||
if(size>0){
|
if(remainingDataLen>0){
|
||||||
for(std::vector<AudioEffect*>::iterator effect=postProcEffects.begin();effect!=postProcEffects.end();++effect){
|
for(std::vector<AudioEffect*>::iterator effect=postProcEffects.begin();effect!=postProcEffects.end();++effect){
|
||||||
(*effect)->Process(reinterpret_cast<int16_t*>(processedBuffer+(PACKET_SIZE*i)), 960);
|
(*effect)->Process(reinterpret_cast<int16_t*>(processedBuffer+(PACKET_SIZE*i)), 960);
|
||||||
}
|
}
|
||||||
memcpy(buf, processedBuffer+(PACKET_SIZE*i), PACKET_SIZE);
|
memcpy(buf, processedBuffer+(PACKET_SIZE*i), PACKET_SIZE);
|
||||||
}else{
|
}else{
|
||||||
LOGE("Error decoding, result=%d", size);
|
//LOGE("Error decoding, result=%d", size);
|
||||||
memset(buf, 0, PACKET_SIZE);
|
memset(buf, 0, PACKET_SIZE);
|
||||||
}
|
}
|
||||||
decodedQueue->Put(buf);
|
decodedQueue->Put(buf);
|
||||||
}else{
|
}else{
|
||||||
LOGW("decoder: no buffers left!");
|
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){
|
void tgvoip::OpusDecoder::SetFrameDuration(uint32_t duration){
|
||||||
frameDuration=duration;
|
frameDuration=duration;
|
||||||
}
|
packetsPerFrame=frameDuration/20;
|
||||||
|
|
||||||
|
|
||||||
void tgvoip::OpusDecoder::ResetQueue(){
|
|
||||||
/*lock_mutex(mutex);
|
|
||||||
packetsNeeded=0;
|
|
||||||
unlock_mutex(mutex);
|
|
||||||
while(decodedQueue->Size()>0){
|
|
||||||
bufferPool->Reuse((unsigned char *) decodedQueue->Get());
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -260,6 +239,14 @@ void tgvoip::OpusDecoder::SetJitterBuffer(JitterBuffer* jitterBuffer){
|
|||||||
this->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){
|
void tgvoip::OpusDecoder::AddAudioEffect(AudioEffect *effect){
|
||||||
postProcEffects.push_back(effect);
|
postProcEffects.push_back(effect);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,35 +25,46 @@ public:
|
|||||||
|
|
||||||
virtual void Stop();
|
virtual void Stop();
|
||||||
|
|
||||||
OpusDecoder(MediaStreamItf* dst);
|
OpusDecoder(MediaStreamItf* dst, bool isAsync);
|
||||||
virtual ~OpusDecoder();
|
virtual ~OpusDecoder();
|
||||||
void HandleCallback(unsigned char* data, size_t len);
|
size_t HandleCallback(unsigned char* data, size_t len);
|
||||||
void SetEchoCanceller(EchoCanceller* canceller);
|
void SetEchoCanceller(EchoCanceller* canceller);
|
||||||
void SetFrameDuration(uint32_t duration);
|
void SetFrameDuration(uint32_t duration);
|
||||||
void ResetQueue();
|
|
||||||
void SetJitterBuffer(JitterBuffer* jitterBuffer);
|
void SetJitterBuffer(JitterBuffer* jitterBuffer);
|
||||||
|
void SetDTX(bool enable);
|
||||||
|
void SetLevelMeter(AudioLevelMeter* levelMeter);
|
||||||
void AddAudioEffect(AudioEffect* effect);
|
void AddAudioEffect(AudioEffect* effect);
|
||||||
void RemoveAudioEffect(AudioEffect* effect);
|
void RemoveAudioEffect(AudioEffect* effect);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static size_t Callback(unsigned char* data, size_t len, void* param);
|
static size_t Callback(unsigned char* data, size_t len, void* param);
|
||||||
static void* StartThread(void* param);
|
void RunThread(void* param);
|
||||||
void RunThread();
|
int DecodeNextFrame();
|
||||||
::OpusDecoder* dec;
|
::OpusDecoder* dec;
|
||||||
BlockingQueue<unsigned char*>* decodedQueue;
|
BlockingQueue<unsigned char*>* decodedQueue;
|
||||||
BufferPool* bufferPool;
|
BufferPool* bufferPool;
|
||||||
unsigned char* buffer;
|
unsigned char* buffer;
|
||||||
unsigned char* lastDecoded;
|
unsigned char* lastDecoded;
|
||||||
size_t lastDecodedLen, lastDecodedOffset;
|
unsigned char* processedBuffer;
|
||||||
size_t outputBufferSize;
|
size_t outputBufferSize;
|
||||||
bool running;
|
bool running;
|
||||||
tgvoip_thread_t thread;
|
Thread* thread;
|
||||||
Semaphore semaphore;
|
Semaphore* semaphore;
|
||||||
tgvoip_mutex_t mutex;
|
|
||||||
uint32_t frameDuration;
|
uint32_t frameDuration;
|
||||||
EchoCanceller* echoCanceller;
|
EchoCanceller* echoCanceller;
|
||||||
JitterBuffer* jitterBuffer;
|
JitterBuffer* jitterBuffer;
|
||||||
|
AudioLevelMeter* levelMeter;
|
||||||
|
int consecutiveLostPackets;
|
||||||
|
bool enableDTX;
|
||||||
|
size_t silentPacketCount;
|
||||||
std::vector<AudioEffect*> postProcEffects;
|
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;
|
echoCanceller=NULL;
|
||||||
complexity=10;
|
complexity=10;
|
||||||
frameDuration=20;
|
frameDuration=20;
|
||||||
|
levelMeter=NULL;
|
||||||
mediumCorrectionBitrate=ServerConfig::GetSharedInstance()->GetInt("audio_medium_fec_bitrate", 10000);
|
mediumCorrectionBitrate=ServerConfig::GetSharedInstance()->GetInt("audio_medium_fec_bitrate", 10000);
|
||||||
strongCorrectionBitrate=ServerConfig::GetSharedInstance()->GetInt("audio_strong_fec_bitrate", 8000);
|
strongCorrectionBitrate=ServerConfig::GetSharedInstance()->GetInt("audio_strong_fec_bitrate", 8000);
|
||||||
mediumCorrectionMultiplier=ServerConfig::GetSharedInstance()->GetDouble("audio_medium_fec_multiplier", 1.5);
|
mediumCorrectionMultiplier=ServerConfig::GetSharedInstance()->GetDouble("audio_medium_fec_multiplier", 1.5);
|
||||||
@ -38,9 +39,10 @@ void tgvoip::OpusEncoder::Start(){
|
|||||||
if(running)
|
if(running)
|
||||||
return;
|
return;
|
||||||
running=true;
|
running=true;
|
||||||
start_thread(thread, StartThread, this);
|
thread=new Thread(new MethodPointer<tgvoip::OpusEncoder>(&tgvoip::OpusEncoder::RunThread, this), NULL);
|
||||||
set_thread_priority(thread, get_thread_max_priority());
|
thread->SetName("OpusEncoder");
|
||||||
set_thread_name(thread, "opus_encoder");
|
thread->Start();
|
||||||
|
thread->SetMaxPriority();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tgvoip::OpusEncoder::Stop(){
|
void tgvoip::OpusEncoder::Stop(){
|
||||||
@ -48,7 +50,8 @@ void tgvoip::OpusEncoder::Stop(){
|
|||||||
return;
|
return;
|
||||||
running=false;
|
running=false;
|
||||||
queue.Put(NULL);
|
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;
|
currentBitrate=requestedBitrate;
|
||||||
LOGV("opus_encoder: setting bitrate to %u", currentBitrate);
|
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);
|
int32_t r=opus_encode(enc, (int16_t*)data, len/2, buffer, 4096);
|
||||||
if(r<=0){
|
if(r<=0){
|
||||||
LOGE("Error encoding: %d", r);
|
LOGE("Error encoding: %d", r);
|
||||||
@ -99,12 +104,7 @@ void tgvoip::OpusEncoder::SetEchoCanceller(EchoCanceller* aec){
|
|||||||
echoCanceller=aec;
|
echoCanceller=aec;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* tgvoip::OpusEncoder::StartThread(void* arg){
|
void tgvoip::OpusEncoder::RunThread(void* arg){
|
||||||
((OpusEncoder*)arg)->RunThread();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tgvoip::OpusEncoder::RunThread(){
|
|
||||||
unsigned char buf[960*2];
|
unsigned char buf[960*2];
|
||||||
uint32_t bufferedCount=0;
|
uint32_t bufferedCount=0;
|
||||||
uint32_t packetsPerFrame=frameDuration/20;
|
uint32_t packetsPerFrame=frameDuration/20;
|
||||||
@ -158,3 +158,11 @@ void tgvoip::OpusEncoder::SetPacketLoss(int percent){
|
|||||||
int tgvoip::OpusEncoder::GetPacketLoss(){
|
int tgvoip::OpusEncoder::GetPacketLoss(){
|
||||||
return packetLossPercent;
|
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);
|
void SetPacketLoss(int percent);
|
||||||
int GetPacketLoss();
|
int GetPacketLoss();
|
||||||
uint32_t GetBitrate();
|
uint32_t GetBitrate();
|
||||||
|
void SetDTX(bool enable);
|
||||||
|
void SetLevelMeter(AudioLevelMeter* levelMeter);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static size_t Callback(unsigned char* data, size_t len, void* param);
|
static size_t Callback(unsigned char* data, size_t len, void* param);
|
||||||
static void* StartThread(void* arg);
|
void RunThread(void* arg);
|
||||||
void RunThread();
|
|
||||||
void Encode(unsigned char* data, size_t len);
|
void Encode(unsigned char* data, size_t len);
|
||||||
MediaStreamItf* source;
|
MediaStreamItf* source;
|
||||||
::OpusEncoder* enc;
|
::OpusEncoder* enc;
|
||||||
unsigned char buffer[4096];
|
unsigned char buffer[4096];
|
||||||
uint32_t requestedBitrate;
|
uint32_t requestedBitrate;
|
||||||
uint32_t currentBitrate;
|
uint32_t currentBitrate;
|
||||||
tgvoip_thread_t thread;
|
Thread* thread;
|
||||||
BlockingQueue<unsigned char*> queue;
|
BlockingQueue<unsigned char*> queue;
|
||||||
BufferPool bufferPool;
|
BufferPool bufferPool;
|
||||||
EchoCanceller* echoCanceller;
|
EchoCanceller* echoCanceller;
|
||||||
@ -53,6 +54,7 @@ private:
|
|||||||
uint32_t strongCorrectionBitrate;
|
uint32_t strongCorrectionBitrate;
|
||||||
double mediumCorrectionMultiplier;
|
double mediumCorrectionMultiplier;
|
||||||
double strongCorrectionMultiplier;
|
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
|
#endif
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <TargetConditionals.h>
|
#include <TargetConditionals.h>
|
||||||
|
#include "os/darwin/AudioUnitIO.h"
|
||||||
#endif
|
#endif
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -28,55 +29,15 @@
|
|||||||
#include "EchoCanceller.h"
|
#include "EchoCanceller.h"
|
||||||
#include "CongestionControl.h"
|
#include "CongestionControl.h"
|
||||||
#include "NetworkSocket.h"
|
#include "NetworkSocket.h"
|
||||||
|
#include "BufferInputStream.h"
|
||||||
|
|
||||||
#define LIBTGVOIP_VERSION "1.0.3"
|
#define LIBTGVOIP_VERSION "2.0-alpha4"
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#undef GetCurrentTime
|
#undef GetCurrentTime
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct voip_stream_t{
|
#define TGVOIP_PEER_CAP_GROUP_CALLS 1
|
||||||
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;
|
|
||||||
|
|
||||||
struct voip_queued_packet_t{
|
struct voip_queued_packet_t{
|
||||||
unsigned char type;
|
unsigned char type;
|
||||||
@ -100,21 +61,11 @@ struct voip_config_t{
|
|||||||
bool enableAEC;
|
bool enableAEC;
|
||||||
bool enableNS;
|
bool enableNS;
|
||||||
bool enableAGC;
|
bool enableAGC;
|
||||||
|
|
||||||
|
bool enableCallUpgrade;
|
||||||
};
|
};
|
||||||
typedef struct voip_config_t voip_config_t;
|
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{
|
struct voip_stats_t{
|
||||||
uint64_t bytesSentWifi;
|
uint64_t bytesSentWifi;
|
||||||
uint64_t bytesRecvdWifi;
|
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_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_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_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;
|
typedef struct voip_crypto_functions_t voip_crypto_functions_t;
|
||||||
|
|
||||||
@ -147,193 +100,229 @@ namespace tgvoip{
|
|||||||
//PROXY_HTTP
|
//PROXY_HTTP
|
||||||
};
|
};
|
||||||
|
|
||||||
class Endpoint{
|
enum{
|
||||||
friend class VoIPController;
|
STATE_WAIT_INIT=1,
|
||||||
public:
|
STATE_WAIT_INIT_ACK,
|
||||||
Endpoint(int64_t id, uint16_t port, IPv4Address& address, IPv6Address& v6address, char type, unsigned char* peerTag);
|
STATE_ESTABLISHED,
|
||||||
Endpoint();
|
STATE_FAILED,
|
||||||
int64_t id;
|
STATE_RECONNECTING
|
||||||
uint16_t port;
|
};
|
||||||
IPv4Address address;
|
|
||||||
IPv6Address v6address;
|
|
||||||
char type;
|
|
||||||
unsigned char peerTag[16];
|
|
||||||
|
|
||||||
private:
|
enum{
|
||||||
double lastPingTime;
|
ERROR_UNKNOWN=0,
|
||||||
uint32_t lastPingSeq;
|
ERROR_INCOMPATIBLE,
|
||||||
double rtts[6];
|
ERROR_TIMEOUT,
|
||||||
double averageRTT;
|
ERROR_AUDIO_IO
|
||||||
NetworkSocket* socket;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
class AudioDevice{
|
enum{
|
||||||
public:
|
NET_TYPE_UNKNOWN=0,
|
||||||
std::string id;
|
NET_TYPE_GPRS,
|
||||||
std::string displayName;
|
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
|
private:
|
||||||
{
|
double lastPingTime;
|
||||||
public:
|
uint32_t lastPingSeq;
|
||||||
VoIPController();
|
double rtts[6];
|
||||||
~VoIPController();
|
double averageRTT;
|
||||||
|
NetworkSocket* socket;
|
||||||
|
int udpPongCount;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
class AudioDevice{
|
||||||
* Set the initial endpoints (relays)
|
public:
|
||||||
* @param endpoints Endpoints converted from phone.PhoneConnection TL objects
|
std::string id;
|
||||||
* @param allowP2p Whether p2p connectivity is allowed
|
std::string displayName;
|
||||||
*/
|
};
|
||||||
void SetRemoteEndpoints(std::vector<Endpoint> endpoints, bool allowP2p);
|
|
||||||
/**
|
class AudioOutputDevice : public AudioDevice{
|
||||||
* Initialize and start all the internal threads
|
|
||||||
*/
|
};
|
||||||
void Start();
|
|
||||||
/**
|
class AudioInputDevice : public AudioDevice{
|
||||||
* Initiate connection
|
|
||||||
*/
|
};
|
||||||
void Connect();
|
|
||||||
Endpoint& GetRemoteEndpoint();
|
class VoIPController{
|
||||||
/**
|
friend class VoIPGroupController;
|
||||||
* Get the debug info string to be displayed in client UI
|
public:
|
||||||
* @param buffer The buffer to put the string into
|
VoIPController();
|
||||||
* @param len The length of the buffer
|
virtual ~VoIPController();
|
||||||
*/
|
|
||||||
void GetDebugString(char* buffer, size_t len);
|
/**
|
||||||
/**
|
* Set the initial endpoints (relays)
|
||||||
* Notify the library of network type change
|
* @param endpoints Endpoints converted from phone.PhoneConnection TL objects
|
||||||
* @param type The new network type
|
* @param allowP2p Whether p2p connectivity is allowed
|
||||||
*/
|
*/
|
||||||
void SetNetworkType(int type);
|
void SetRemoteEndpoints(std::vector<Endpoint> endpoints, bool allowP2p, int32_t connectionMaxLayer);
|
||||||
/**
|
/**
|
||||||
* Get the average round-trip time for network packets
|
* Initialize and start all the internal threads
|
||||||
* @return
|
*/
|
||||||
*/
|
void Start();
|
||||||
double GetAverageRTT();
|
/**
|
||||||
/**
|
* Stop any internal threads. Don't call any other methods after this.
|
||||||
* Set the function to be called whenever the connection state changes
|
*/
|
||||||
* @param f
|
void Stop();
|
||||||
*/
|
/**
|
||||||
void SetStateCallback(void (*f)(VoIPController*, int));
|
* Initiate connection
|
||||||
static double GetCurrentTime();
|
*/
|
||||||
/**
|
void Connect();
|
||||||
* Use this field to store any of your context data associated with this call
|
Endpoint& GetRemoteEndpoint();
|
||||||
*/
|
/**
|
||||||
void* implData;
|
* 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
|
||||||
* @param mute
|
*/
|
||||||
*/
|
virtual void GetDebugString(char* buffer, size_t len);
|
||||||
void SetMicMute(bool mute);
|
/**
|
||||||
/**
|
* Notify the library of network type change
|
||||||
*
|
* @param type The new network type
|
||||||
* @param key
|
*/
|
||||||
* @param isOutgoing
|
virtual void SetNetworkType(int type);
|
||||||
*/
|
/**
|
||||||
void SetEncryptionKey(char* key, bool isOutgoing);
|
* Get the average round-trip time for network packets
|
||||||
/**
|
* @return
|
||||||
*
|
*/
|
||||||
* @param cfg
|
double GetAverageRTT();
|
||||||
*/
|
static double GetCurrentTime();
|
||||||
void SetConfig(voip_config_t* cfg);
|
/**
|
||||||
float GetOutputLevel();
|
* Use this field to store any of your context data associated with this call
|
||||||
void DebugCtl(int request, int param);
|
*/
|
||||||
/**
|
void* implData;
|
||||||
*
|
/**
|
||||||
* @param stats
|
*
|
||||||
*/
|
* @param mute
|
||||||
void GetStats(voip_stats_t* stats);
|
*/
|
||||||
/**
|
virtual void SetMicMute(bool mute);
|
||||||
*
|
/**
|
||||||
* @return
|
*
|
||||||
*/
|
* @param key
|
||||||
int64_t GetPreferredRelayID();
|
* @param isOutgoing
|
||||||
/**
|
*/
|
||||||
*
|
void SetEncryptionKey(char* key, bool isOutgoing);
|
||||||
* @return
|
/**
|
||||||
*/
|
*
|
||||||
int GetLastError();
|
* @param cfg
|
||||||
/**
|
*/
|
||||||
*
|
void SetConfig(voip_config_t* cfg);
|
||||||
*/
|
float GetOutputLevel();
|
||||||
static voip_crypto_functions_t crypto;
|
void DebugCtl(int request, int param);
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return
|
* @param stats
|
||||||
*/
|
*/
|
||||||
static const char* GetVersion();
|
void GetStats(voip_stats_t* stats);
|
||||||
#ifdef TGVOIP_USE_AUDIO_SESSION
|
|
||||||
void SetAcquireAudioSession(void (^)(void (^)()));
|
|
||||||
void ReleaseAudioSession(void (^completion)());
|
|
||||||
#endif
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return
|
* @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
|
* @param buffer
|
||||||
*/
|
*/
|
||||||
void GetDebugLog(char* buffer);
|
void GetDebugLog(char* buffer);
|
||||||
size_t GetDebugLogLength();
|
size_t GetDebugLogLength();
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static std::vector<AudioInputDevice> EnumerateAudioInputs();
|
static std::vector<AudioInputDevice> EnumerateAudioInputs();
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static std::vector<AudioOutputDevice> EnumerateAudioOutputs();
|
static std::vector<AudioOutputDevice> EnumerateAudioOutputs();
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param id
|
* @param id
|
||||||
*/
|
*/
|
||||||
void SetCurrentAudioInput(std::string id);
|
void SetCurrentAudioInput(std::string id);
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param id
|
* @param id
|
||||||
*/
|
*/
|
||||||
void SetCurrentAudioOutput(std::string id);
|
void SetCurrentAudioOutput(std::string id);
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
std::string GetCurrentAudioInputID();
|
std::string GetCurrentAudioInputID();
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
std::string GetCurrentAudioOutputID();
|
std::string GetCurrentAudioOutputID();
|
||||||
/**
|
/**
|
||||||
* Set the proxy server to route the data through. Call this before connecting.
|
* Set the proxy server to route the data through. Call this before connecting.
|
||||||
* @param protocol PROXY_NONE or PROXY_SOCKS5
|
* @param protocol PROXY_NONE or PROXY_SOCKS5
|
||||||
* @param address IP address or domain name of the server
|
* @param address IP address or domain name of the server
|
||||||
* @param port Port of the server
|
* @param port Port of the server
|
||||||
* @param username Username; empty string for anonymous
|
* @param username Username; empty string for anonymous
|
||||||
* @param password Password; empty string if none
|
* @param password Password; empty string if none
|
||||||
*/
|
*/
|
||||||
void SetProxy(int protocol, std::string address, uint16_t port, std::string username, std::string password);
|
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.
|
* Get the number of signal bars to display in the client UI.
|
||||||
* @return the number of signal bars, from 1 to 4
|
* @return the number of signal bars, from 1 to 4
|
||||||
*/
|
*/
|
||||||
int GetSignalBarsCount();
|
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.
|
* 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.
|
* 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
|
* @param enabled I usually pick argument names to be self-explanatory
|
||||||
*/
|
*/
|
||||||
void SetAudioOutputGainControlEnabled(bool enabled);
|
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);
|
void SetEchoCancellationStrength(int strength);
|
||||||
|
|
||||||
private:
|
struct Callbacks{
|
||||||
struct PendingOutgoingPacket{
|
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;
|
uint32_t seq;
|
||||||
unsigned char type;
|
uint32_t lastRemoteSeq;
|
||||||
size_t len;
|
uint32_t lastRemoteAckSeq;
|
||||||
unsigned char* data;
|
uint32_t lastSentSeq;
|
||||||
Endpoint* endpoint;
|
std::vector<RecentOutgoingPacket> recentOutgoingPackets;
|
||||||
};
|
double recvPacketTimes[32];
|
||||||
enum{
|
uint32_t sendLossCountHistory[32];
|
||||||
UDP_UNKNOWN=0,
|
uint32_t audioTimestampIn;
|
||||||
UDP_PING_SENT,
|
uint32_t audioTimestampOut;
|
||||||
UDP_AVAILABIE,
|
tgvoip::audio::AudioInput* audioInput;
|
||||||
UDP_NOT_AVAILABLE
|
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);
|
BufferPool outgoingPacketsBufferPool;
|
||||||
static void* StartSendThread(void* arg);
|
int udpConnectivityState;
|
||||||
static void* StartTickThread(void* arg);
|
double lastUdpPingTime;
|
||||||
void RunRecvThread();
|
int udpPingCount;
|
||||||
void RunSendThread();
|
int echoCancellationStrength;
|
||||||
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 proxyProtocol;
|
||||||
int udpConnectivityState;
|
std::string proxyAddress;
|
||||||
double lastUdpPingTime;
|
uint16_t proxyPort;
|
||||||
int udpPingCount;
|
std::string proxyUsername;
|
||||||
int echoCancellationStrength;
|
std::string proxyPassword;
|
||||||
|
IPv4Address* resolvedProxyAddress;
|
||||||
int proxyProtocol;
|
|
||||||
std::string proxyAddress;
|
|
||||||
uint16_t proxyPort;
|
|
||||||
std::string proxyUsername;
|
|
||||||
std::string proxyPassword;
|
|
||||||
IPv4Address* resolvedProxyAddress;
|
|
||||||
|
|
||||||
int signalBarCount;
|
int signalBarCount;
|
||||||
void (*signalBarCountCallback)(VoIPController*, int);
|
|
||||||
|
|
||||||
AutomaticGainControl* outputAGC;
|
AutomaticGainControl* outputAGC;
|
||||||
bool outputAGCEnabled;
|
bool outputAGCEnabled;
|
||||||
|
uint32_t peerCapabilities;
|
||||||
/*** server config values ***/
|
Callbacks callbacks;
|
||||||
uint32_t maxAudioBitrate;
|
bool didReceiveGroupCallKey;
|
||||||
uint32_t maxAudioBitrateEDGE;
|
bool didReceiveGroupCallKeyAck;
|
||||||
uint32_t maxAudioBitrateGPRS;
|
bool didSendGroupCallKey;
|
||||||
uint32_t maxAudioBitrateSaving;
|
bool didSendUpgradeRequest;
|
||||||
uint32_t initAudioBitrate;
|
bool didInvokeUpdateCallback;
|
||||||
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;
|
|
||||||
|
|
||||||
#ifdef TGVOIP_USE_AUDIO_SESSION
|
int32_t connectionMaxLayer;
|
||||||
void (^acquireAudioSession)(void (^)());
|
bool useMTProto2;
|
||||||
bool needNotifyAcquiredAudioSession;
|
bool setCurrentEndpointToTCP;
|
||||||
#endif
|
|
||||||
|
|
||||||
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__
|
#ifdef __APPLE__
|
||||||
static double machTimebase;
|
audio::AudioUnitIO* appleAudioIO;
|
||||||
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);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
#ifdef __APPLE__
|
||||||
|
static double machTimebase;
|
||||||
|
static uint64_t machTimestart;
|
||||||
#endif
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static int64_t win32TimeScale;
|
static int64_t win32TimeScale;
|
||||||
static bool didInitWin32TimeScale;
|
static bool didInitWin32TimeScale;
|
||||||
#endif
|
#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
|
#endif
|
||||||
|
|||||||
@ -13,11 +13,9 @@ using namespace tgvoip;
|
|||||||
ServerConfig* ServerConfig::sharedInstance=NULL;
|
ServerConfig* ServerConfig::sharedInstance=NULL;
|
||||||
|
|
||||||
ServerConfig::ServerConfig(){
|
ServerConfig::ServerConfig(){
|
||||||
init_mutex(mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerConfig::~ServerConfig(){
|
ServerConfig::~ServerConfig(){
|
||||||
free_mutex(mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerConfig *ServerConfig::GetSharedInstance(){
|
ServerConfig *ServerConfig::GetSharedInstance(){
|
||||||
|
|||||||
@ -30,7 +30,7 @@ private:
|
|||||||
static ServerConfig* sharedInstance;
|
static ServerConfig* sharedInstance;
|
||||||
bool ContainsKey(std::string key);
|
bool ContainsKey(std::string key);
|
||||||
std::map<std::string, std::string> config;
|
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;
|
failed=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioInput *AudioInput::Create(std::string deviceID){
|
AudioInput *AudioInput::Create(std::string deviceID, void* platformSpecific){
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
return new AudioInputAndroid();
|
return new AudioInputAndroid();
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
@ -47,7 +47,7 @@ AudioInput *AudioInput::Create(std::string deviceID){
|
|||||||
if(kCFCoreFoundationVersionNumber<kCFCoreFoundationVersionNumber10_7)
|
if(kCFCoreFoundationVersionNumber<kCFCoreFoundationVersionNumber10_7)
|
||||||
return new AudioInputAudioUnitLegacy(deviceID);
|
return new AudioInputAudioUnitLegacy(deviceID);
|
||||||
#endif
|
#endif
|
||||||
return new AudioInputAudioUnit(deviceID);
|
return new AudioInputAudioUnit(deviceID, reinterpret_cast<AudioUnitIO*>(platformSpecific));
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
#ifdef TGVOIP_WINXP_COMPAT
|
#ifdef TGVOIP_WINXP_COMPAT
|
||||||
if(LOBYTE(LOWORD(GetVersion()))<6)
|
if(LOBYTE(LOWORD(GetVersion()))<6)
|
||||||
|
|||||||
@ -28,7 +28,7 @@ public:
|
|||||||
bool IsInitialized();
|
bool IsInitialized();
|
||||||
virtual std::string GetCurrentDevice();
|
virtual std::string GetCurrentDevice();
|
||||||
virtual void SetCurrentDevice(std::string deviceID);
|
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 void EnumerateDevices(std::vector<AudioInputDevice>& devs);
|
||||||
static int32_t GetEstimatedDelay();
|
static int32_t GetEstimatedDelay();
|
||||||
|
|
||||||
|
|||||||
@ -6,9 +6,11 @@
|
|||||||
|
|
||||||
#include "AudioOutput.h"
|
#include "AudioOutput.h"
|
||||||
#include "../logging.h"
|
#include "../logging.h"
|
||||||
|
#include <stdlib.h>
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
#include "../os/android/AudioOutputOpenSLES.h"
|
#include "../os/android/AudioOutputOpenSLES.h"
|
||||||
#include "../os/android/AudioOutputAndroid.h"
|
#include "../os/android/AudioOutputAndroid.h"
|
||||||
|
#include <sys/system_properties.h>
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
#include <TargetConditionals.h>
|
#include <TargetConditionals.h>
|
||||||
#include "../os/darwin/AudioOutputAudioUnit.h"
|
#include "../os/darwin/AudioOutputAudioUnit.h"
|
||||||
@ -30,13 +32,13 @@
|
|||||||
using namespace tgvoip;
|
using namespace tgvoip;
|
||||||
using namespace tgvoip::audio;
|
using namespace tgvoip::audio;
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
int AudioOutput::systemVersion;
|
|
||||||
#endif
|
|
||||||
int32_t AudioOutput::estimatedDelay=60;
|
int32_t AudioOutput::estimatedDelay=60;
|
||||||
|
|
||||||
AudioOutput *AudioOutput::Create(std::string deviceID){
|
AudioOutput *AudioOutput::Create(std::string deviceID, void* platformSpecific){
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
|
char sdkNum[PROP_VALUE_MAX];
|
||||||
|
__system_property_get("ro.build.version.sdk", sdkNum);
|
||||||
|
int systemVersion=atoi(sdkNum);
|
||||||
//if(systemVersion<21)
|
//if(systemVersion<21)
|
||||||
return new AudioOutputAndroid();
|
return new AudioOutputAndroid();
|
||||||
//return new AudioOutputOpenSLES();
|
//return new AudioOutputOpenSLES();
|
||||||
@ -45,7 +47,7 @@ AudioOutput *AudioOutput::Create(std::string deviceID){
|
|||||||
if(kCFCoreFoundationVersionNumber<kCFCoreFoundationVersionNumber10_7)
|
if(kCFCoreFoundationVersionNumber<kCFCoreFoundationVersionNumber10_7)
|
||||||
return new AudioOutputAudioUnitLegacy(deviceID);
|
return new AudioOutputAudioUnitLegacy(deviceID);
|
||||||
#endif
|
#endif
|
||||||
return new AudioOutputAudioUnit(deviceID);
|
return new AudioOutputAudioUnit(deviceID, reinterpret_cast<AudioUnitIO*>(platformSpecific));
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
#ifdef TGVOIP_WINXP_COMPAT
|
#ifdef TGVOIP_WINXP_COMPAT
|
||||||
if(LOBYTE(LOWORD(GetVersion()))<6)
|
if(LOBYTE(LOWORD(GetVersion()))<6)
|
||||||
@ -80,6 +82,9 @@ AudioOutput::~AudioOutput(){
|
|||||||
|
|
||||||
int32_t AudioOutput::GetEstimatedDelay(){
|
int32_t AudioOutput::GetEstimatedDelay(){
|
||||||
#if defined(__ANDROID__)
|
#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;
|
return systemVersion<21 ? 150 : 50;
|
||||||
#endif
|
#endif
|
||||||
return estimatedDelay;
|
return estimatedDelay;
|
||||||
|
|||||||
@ -29,14 +29,10 @@ public:
|
|||||||
static int32_t GetEstimatedDelay();
|
static int32_t GetEstimatedDelay();
|
||||||
virtual std::string GetCurrentDevice();
|
virtual std::string GetCurrentDevice();
|
||||||
virtual void SetCurrentDevice(std::string deviceID);
|
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);
|
static void EnumerateDevices(std::vector<AudioOutputDevice>& devs);
|
||||||
bool IsInitialized();
|
bool IsInitialized();
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
static int systemVersion;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string currentDevice;
|
std::string currentDevice;
|
||||||
bool failed;
|
bool failed;
|
||||||
|
|||||||
@ -22,6 +22,12 @@ jfieldID audioRecordInstanceFld=NULL;
|
|||||||
jfieldID audioTrackInstanceFld=NULL;
|
jfieldID audioTrackInstanceFld=NULL;
|
||||||
jmethodID setStateMethod=NULL;
|
jmethodID setStateMethod=NULL;
|
||||||
jmethodID setSignalBarsMethod=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{
|
struct impl_data_android_t{
|
||||||
jobject javaObject;
|
jobject javaObject;
|
||||||
@ -30,48 +36,164 @@ struct impl_data_android_t{
|
|||||||
using namespace tgvoip;
|
using namespace tgvoip;
|
||||||
using namespace tgvoip::audio;
|
using namespace tgvoip::audio;
|
||||||
|
|
||||||
void updateConnectionState(VoIPController* cntrlr, int state){
|
namespace tgvoip {
|
||||||
impl_data_android_t* impl=(impl_data_android_t*) cntrlr->implData;
|
void updateConnectionState(VoIPController *cntrlr, int state){
|
||||||
if(!impl->javaObject)
|
impl_data_android_t *impl=(impl_data_android_t *) cntrlr->implData;
|
||||||
return;
|
if(!impl->javaObject)
|
||||||
JNIEnv* env=NULL;
|
return;
|
||||||
bool didAttach=false;
|
JNIEnv *env=NULL;
|
||||||
sharedJVM->GetEnv((void**) &env, JNI_VERSION_1_6);
|
bool didAttach=false;
|
||||||
if(!env){
|
sharedJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
|
||||||
sharedJVM->AttachCurrentThread(&env, NULL);
|
if(!env){
|
||||||
didAttach=true;
|
sharedJVM->AttachCurrentThread(&env, NULL);
|
||||||
|
didAttach=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(setStateMethod)
|
||||||
|
env->CallVoidMethod(impl->javaObject, setStateMethod, state);
|
||||||
|
|
||||||
|
if(didAttach){
|
||||||
|
sharedJVM->DetachCurrentThread();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(setStateMethod)
|
void updateSignalBarCount(VoIPController *cntrlr, int count){
|
||||||
env->CallVoidMethod(impl->javaObject, setStateMethod, 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(didAttach){
|
if(setSignalBarsMethod)
|
||||||
sharedJVM->DetachCurrentThread();
|
env->CallVoidMethod(impl->javaObject, setSignalBarsMethod, count);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateSignalBarCount(VoIPController* cntrlr, int count){
|
if(didAttach){
|
||||||
impl_data_android_t* impl=(impl_data_android_t*) cntrlr->implData;
|
sharedJVM->DetachCurrentThread();
|
||||||
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(setSignalBarsMethod)
|
void updateGroupCallStreams(VoIPGroupController *cntrlr, unsigned char *streams, size_t len){
|
||||||
env->CallVoidMethod(impl->javaObject, setSignalBarsMethod, 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){
|
if(setSelfStreamsMethod){
|
||||||
sharedJVM->DetachCurrentThread();
|
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){
|
extern "C" JNIEXPORT jlong Java_org_telegram_messenger_voip_VoIPController_nativeInit(JNIEnv* env, jobject thiz, jint systemVersion){
|
||||||
AudioOutputAndroid::systemVersion=systemVersion;
|
|
||||||
|
|
||||||
env->GetJavaVM(&sharedJVM);
|
env->GetJavaVM(&sharedJVM);
|
||||||
if(!AudioInputAndroid::jniClass){
|
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");
|
AudioOutputAndroid::stopMethod=env->GetMethodID(cls, "stop", "()V");
|
||||||
}
|
}
|
||||||
|
|
||||||
setStateMethod=env->GetMethodID(env->GetObjectClass(thiz), "handleStateChange", "(I)V");
|
jclass thisClass=env->FindClass("org/telegram/messenger/voip/VoIPController");
|
||||||
setSignalBarsMethod=env->GetMethodID(env->GetObjectClass(thiz), "handleSignalBarsChange", "(I)V");
|
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_data_android_t* impl=(impl_data_android_t*) malloc(sizeof(impl_data_android_t));
|
||||||
impl->javaObject=env->NewGlobalRef(thiz);
|
impl->javaObject=env->NewGlobalRef(thiz);
|
||||||
VoIPController* cntrlr=new VoIPController();
|
VoIPController* cntrlr=new VoIPController();
|
||||||
cntrlr->implData=impl;
|
cntrlr->implData=impl;
|
||||||
cntrlr->SetStateCallback(updateConnectionState);
|
VoIPController::Callbacks callbacks;
|
||||||
cntrlr->SetSignalBarsCountCallback(updateSignalBarCount);
|
callbacks.connectionStateChanged=updateConnectionState;
|
||||||
|
callbacks.signalBarCountChanged=updateSignalBarCount;
|
||||||
|
callbacks.groupCallKeyReceived=groupCallKeyReceived;
|
||||||
|
callbacks.groupCallKeySent=groupCallKeySent;
|
||||||
|
callbacks.upgradeToGroupCallRequested=callUpgradeRequestReceived;
|
||||||
|
cntrlr->SetCallbacks(callbacks);
|
||||||
return (jlong)(intptr_t)cntrlr;
|
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);
|
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);
|
size_t len=(size_t) env->GetArrayLength(endpoints);
|
||||||
// voip_endpoint_t* eps=(voip_endpoint_t *) malloc(sizeof(voip_endpoint_t)*len);
|
// voip_endpoint_t* eps=(voip_endpoint_t *) malloc(sizeof(voip_endpoint_t)*len);
|
||||||
std::vector<Endpoint> eps;
|
std::vector<Endpoint> eps;
|
||||||
@ -166,23 +300,25 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_native
|
|||||||
memcpy(pTag, peerTagBytes, 16);
|
memcpy(pTag, peerTagBytes, 16);
|
||||||
env->ReleaseByteArrayElements(peerTag, peerTagBytes, JNI_ABORT);
|
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){
|
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetNativeBufferSize(JNIEnv* env, jclass thiz, jint size){
|
||||||
AudioOutputOpenSLES::nativeBufferSize=size;
|
AudioOutputOpenSLES::nativeBufferSize=(unsigned int) size;
|
||||||
AudioInputOpenSLES::nativeBufferSize=size;
|
AudioInputOpenSLES::nativeBufferSize=(unsigned int) size;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeRelease(JNIEnv* env, jobject thiz, jlong inst){
|
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);
|
VoIPController* ctlr=((VoIPController*)(intptr_t)inst);
|
||||||
impl_data_android_t* impl=(impl_data_android_t*)ctlr->implData;
|
impl_data_android_t* impl=(impl_data_android_t*)ctlr->implData;
|
||||||
jobject jobj=impl->javaObject;
|
ctlr->Stop();
|
||||||
delete ctlr;
|
delete ctlr;
|
||||||
|
env->DeleteGlobalRef(impl->javaObject);
|
||||||
free(impl);
|
free(impl);
|
||||||
env->DeleteGlobalRef(jobj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -226,6 +362,7 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_native
|
|||||||
cfg.enableAEC=enableAEC;
|
cfg.enableAEC=enableAEC;
|
||||||
cfg.enableNS=enableNS;
|
cfg.enableNS=enableNS;
|
||||||
cfg.enableAGC=enableAGC;
|
cfg.enableAGC=enableAGC;
|
||||||
|
cfg.enableCallUpgrade=false;
|
||||||
if(logFilePath){
|
if(logFilePath){
|
||||||
char* path=(char *) env->GetStringUTFChars(logFilePath, NULL);
|
char* path=(char *) env->GetStringUTFChars(logFilePath, NULL);
|
||||||
strncpy(cfg.logFilePath, path, sizeof(cfg.logFilePath));
|
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){
|
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));
|
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 */; };
|
692AB8D91E6759DD00706ACC /* CongestionControl.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB8981E6759DD00706ACC /* CongestionControl.h */; };
|
||||||
692AB8DA1E6759DD00706ACC /* EchoCanceller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 692AB8991E6759DD00706ACC /* EchoCanceller.cpp */; };
|
692AB8DA1E6759DD00706ACC /* EchoCanceller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 692AB8991E6759DD00706ACC /* EchoCanceller.cpp */; };
|
||||||
692AB8DB1E6759DD00706ACC /* EchoCanceller.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB89A1E6759DD00706ACC /* EchoCanceller.h */; };
|
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 */; };
|
692AB8E61E6759DD00706ACC /* JitterBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 692AB8A81E6759DD00706ACC /* JitterBuffer.cpp */; };
|
||||||
692AB8E71E6759DD00706ACC /* JitterBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB8A91E6759DD00706ACC /* JitterBuffer.h */; };
|
692AB8E71E6759DD00706ACC /* JitterBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB8A91E6759DD00706ACC /* JitterBuffer.h */; };
|
||||||
692AB8E81E6759DD00706ACC /* logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB8AA1E6759DD00706ACC /* logging.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 */; };
|
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 */; };
|
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 */; };
|
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 */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy 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>"; };
|
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>"; };
|
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; };
|
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 */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -535,6 +536,7 @@
|
|||||||
692AB8C51E6759DD00706ACC /* TGLogWrapper.m */,
|
692AB8C51E6759DD00706ACC /* TGLogWrapper.m */,
|
||||||
69960A021EF85C2900F9D091 /* DarwinSpecific.h */,
|
69960A021EF85C2900F9D091 /* DarwinSpecific.h */,
|
||||||
69960A031EF85C2900F9D091 /* DarwinSpecific.mm */,
|
69960A031EF85C2900F9D091 /* DarwinSpecific.mm */,
|
||||||
|
D00ACA4D20222F5D0045D427 /* SetupLogging.h */,
|
||||||
);
|
);
|
||||||
path = darwin;
|
path = darwin;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -905,6 +907,7 @@
|
|||||||
69A6DDC11E95EC7700000E69 /* spl_inl_armv7.h in Headers */,
|
69A6DDC11E95EC7700000E69 /* spl_inl_armv7.h in Headers */,
|
||||||
69A6DE031E95EC7800000E69 /* three_band_filter_bank.h in Headers */,
|
69A6DE031E95EC7800000E69 /* three_band_filter_bank.h in Headers */,
|
||||||
69A6DDFB1E95EC7700000E69 /* nsx_core.h in Headers */,
|
69A6DDFB1E95EC7700000E69 /* nsx_core.h in Headers */,
|
||||||
|
D00ACA4F20222F5D0045D427 /* SetupLogging.h in Headers */,
|
||||||
69A6DDE41E95EC7700000E69 /* echo_cancellation.h in Headers */,
|
69A6DDE41E95EC7700000E69 /* echo_cancellation.h in Headers */,
|
||||||
69A6DDF71E95EC7700000E69 /* noise_suppression_x.h in Headers */,
|
69A6DDF71E95EC7700000E69 /* noise_suppression_x.h in Headers */,
|
||||||
69A6DD9B1E95EC7700000E69 /* safe_conversions.h in Headers */,
|
69A6DD9B1E95EC7700000E69 /* safe_conversions.h in Headers */,
|
||||||
@ -1074,7 +1077,6 @@
|
|||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
692AB8E51E6759DD00706ACC /* Info.plist in Resources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -1301,6 +1303,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/../../Telegraph",
|
"$(PROJECT_DIR)/../../Telegraph",
|
||||||
webrtc_dsp,
|
webrtc_dsp,
|
||||||
|
"$(PROJECT_DIR)/../TelegramUI/third-party/opus/include/opus",
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -1336,6 +1339,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/../../Telegraph",
|
"$(PROJECT_DIR)/../../Telegraph",
|
||||||
webrtc_dsp,
|
webrtc_dsp,
|
||||||
|
"$(PROJECT_DIR)/../TelegramUI/third-party/opus/include/opus",
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -1356,6 +1360,336 @@
|
|||||||
};
|
};
|
||||||
name = Release;
|
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 */ = {
|
D04D01C31E678C0D0086DDC0 /* Debug AppStore */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
@ -1422,6 +1756,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/../../Telegraph",
|
"$(PROJECT_DIR)/../../Telegraph",
|
||||||
webrtc_dsp,
|
webrtc_dsp,
|
||||||
|
"$(PROJECT_DIR)/../TelegramUI/third-party/opus/include/opus",
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -1502,6 +1837,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/../../Telegraph",
|
"$(PROJECT_DIR)/../../Telegraph",
|
||||||
webrtc_dsp,
|
webrtc_dsp,
|
||||||
|
"$(PROJECT_DIR)/../TelegramUI/third-party/opus/include/opus",
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
@ -1522,6 +1858,86 @@
|
|||||||
};
|
};
|
||||||
name = Hockeyapp;
|
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 */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
@ -1529,9 +1945,14 @@
|
|||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
69F8423C1E67540700C110F7 /* Debug */,
|
69F8423C1E67540700C110F7 /* Debug */,
|
||||||
|
D00ACA51202234510045D427 /* Debug Hockeyapp */,
|
||||||
D04D01C31E678C0D0086DDC0 /* Debug AppStore */,
|
D04D01C31E678C0D0086DDC0 /* Debug AppStore */,
|
||||||
69F8423D1E67540700C110F7 /* Release */,
|
69F8423D1E67540700C110F7 /* Release */,
|
||||||
|
D00ACA5B2022A70D0045D427 /* Release AppStore */,
|
||||||
|
D00ACA532022347C0045D427 /* Release Hockeyapp */,
|
||||||
|
D00ACA55202234840045D427 /* Release Hockeyapp Internal */,
|
||||||
D04D01CB1E678C230086DDC0 /* Hockeyapp */,
|
D04D01CB1E678C230086DDC0 /* Hockeyapp */,
|
||||||
|
D077B8DF1F45EA870046D27A /* Release Hockeyapp */,
|
||||||
);
|
);
|
||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
@ -1540,9 +1961,14 @@
|
|||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
69F8423F1E67540700C110F7 /* Debug */,
|
69F8423F1E67540700C110F7 /* Debug */,
|
||||||
|
D00ACA52202234510045D427 /* Debug Hockeyapp */,
|
||||||
D04D01C41E678C0D0086DDC0 /* Debug AppStore */,
|
D04D01C41E678C0D0086DDC0 /* Debug AppStore */,
|
||||||
69F842401E67540700C110F7 /* Release */,
|
69F842401E67540700C110F7 /* Release */,
|
||||||
|
D00ACA5C2022A70D0045D427 /* Release AppStore */,
|
||||||
|
D00ACA542022347C0045D427 /* Release Hockeyapp */,
|
||||||
|
D00ACA56202234840045D427 /* Release Hockeyapp Internal */,
|
||||||
D04D01CC1E678C230086DDC0 /* Hockeyapp */,
|
D04D01CC1E678C230086DDC0 /* Hockeyapp */,
|
||||||
|
D077B8E01F45EA870046D27A /* Release Hockeyapp */,
|
||||||
);
|
);
|
||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<key>libtgvoip.xcscheme</key>
|
<key>libtgvoip.xcscheme</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>0</integer>
|
<integer>1</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>SuppressBuildableAutocreation</key>
|
<key>SuppressBuildableAutocreation</key>
|
||||||
|
|||||||
@ -37,8 +37,8 @@ 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(tgvoipLogFile){
|
if(file){
|
||||||
time_t t = time(0);
|
time_t t = time(0);
|
||||||
struct tm *now = localtime(&t);
|
struct tm *now = localtime(&t);
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@ -94,6 +94,6 @@ void tgvoip_log_file_write_header(){
|
|||||||
const char* cpuArch="Unknown CPU";
|
const char* cpuArch="Unknown CPU";
|
||||||
#endif
|
#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>
|
#include <TargetConditionals.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
void tgvoip_log_file_printf(char level, const char* msg, ...);
|
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__)
|
#if defined(__ANDROID__)
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,6 @@ AudioInputAndroid::AudioInputAndroid(){
|
|||||||
sharedJVM->DetachCurrentThread();
|
sharedJVM->DetachCurrentThread();
|
||||||
}
|
}
|
||||||
running=false;
|
running=false;
|
||||||
init_mutex(mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioInputAndroid::~AudioInputAndroid(){
|
AudioInputAndroid::~AudioInputAndroid(){
|
||||||
@ -58,7 +57,6 @@ AudioInputAndroid::~AudioInputAndroid(){
|
|||||||
sharedJVM->DetachCurrentThread();
|
sharedJVM->DetachCurrentThread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free_mutex(mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioInputAndroid::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
|
void AudioInputAndroid::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
|
||||||
|
|||||||
@ -30,7 +30,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
jobject javaObject;
|
jobject javaObject;
|
||||||
bool running;
|
bool running;
|
||||||
tgvoip_mutex_t mutex;
|
Mutex mutex;
|
||||||
|
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
using namespace tgvoip;
|
using namespace tgvoip;
|
||||||
using namespace tgvoip::audio;
|
using namespace tgvoip::audio;
|
||||||
|
|
||||||
int AudioInputOpenSLES::nativeBufferSize;
|
unsigned int AudioInputOpenSLES::nativeBufferSize;
|
||||||
|
|
||||||
AudioInputOpenSLES::AudioInputOpenSLES(){
|
AudioInputOpenSLES::AudioInputOpenSLES(){
|
||||||
slEngine=OpenSLEngineWrapper::CreateEngine();
|
slEngine=OpenSLEngineWrapper::CreateEngine();
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public:
|
|||||||
virtual void Start();
|
virtual void Start();
|
||||||
virtual void Stop();
|
virtual void Stop();
|
||||||
|
|
||||||
static int nativeBufferSize;
|
static unsigned int nativeBufferSize;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void BufferCallback(SLAndroidSimpleBufferQueueItf bq, void *context);
|
static void BufferCallback(SLAndroidSimpleBufferQueueItf bq, void *context);
|
||||||
|
|||||||
@ -13,13 +13,13 @@
|
|||||||
#include "OpenSLEngineWrapper.h"
|
#include "OpenSLEngineWrapper.h"
|
||||||
#include "AudioInputAndroid.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
|
#define BUFFER_SIZE 960 // 20 ms
|
||||||
|
|
||||||
using namespace tgvoip;
|
using namespace tgvoip;
|
||||||
using namespace tgvoip::audio;
|
using namespace tgvoip::audio;
|
||||||
|
|
||||||
int AudioOutputOpenSLES::nativeBufferSize;
|
unsigned int AudioOutputOpenSLES::nativeBufferSize;
|
||||||
|
|
||||||
AudioOutputOpenSLES::AudioOutputOpenSLES(){
|
AudioOutputOpenSLES::AudioOutputOpenSLES(){
|
||||||
SLresult result;
|
SLresult result;
|
||||||
@ -63,7 +63,7 @@ AudioOutputOpenSLES::~AudioOutputOpenSLES(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioOutputOpenSLES::SetNativeBufferSize(int size){
|
void AudioOutputOpenSLES::SetNativeBufferSize(unsigned int size){
|
||||||
AudioOutputOpenSLES::nativeBufferSize=size;
|
AudioOutputOpenSLES::nativeBufferSize=size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,8 +25,8 @@ public:
|
|||||||
virtual bool IsPlaying();
|
virtual bool IsPlaying();
|
||||||
virtual float GetLevel();
|
virtual float GetLevel();
|
||||||
|
|
||||||
static void SetNativeBufferSize(int size);
|
static void SetNativeBufferSize(unsigned int size);
|
||||||
static int nativeBufferSize;
|
static unsigned int nativeBufferSize;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void BufferCallback(SLAndroidSimpleBufferQueueItf bq, void *context);
|
static void BufferCallback(SLAndroidSimpleBufferQueueItf bq, void *context);
|
||||||
|
|||||||
@ -16,10 +16,10 @@
|
|||||||
using namespace tgvoip;
|
using namespace tgvoip;
|
||||||
using namespace tgvoip::audio;
|
using namespace tgvoip::audio;
|
||||||
|
|
||||||
AudioInputAudioUnit::AudioInputAudioUnit(std::string deviceID){
|
AudioInputAudioUnit::AudioInputAudioUnit(std::string deviceID, AudioUnitIO* io){
|
||||||
remainingDataSize=0;
|
remainingDataSize=0;
|
||||||
isRecording=false;
|
isRecording=false;
|
||||||
this->io=AudioUnitIO::Get();
|
this->io=io;
|
||||||
#if TARGET_OS_OSX
|
#if TARGET_OS_OSX
|
||||||
io->SetCurrentDevice(true, deviceID);
|
io->SetCurrentDevice(true, deviceID);
|
||||||
#endif
|
#endif
|
||||||
@ -29,7 +29,6 @@ AudioInputAudioUnit::AudioInputAudioUnit(std::string deviceID){
|
|||||||
|
|
||||||
AudioInputAudioUnit::~AudioInputAudioUnit(){
|
AudioInputAudioUnit::~AudioInputAudioUnit(){
|
||||||
io->DetachInput();
|
io->DetachInput();
|
||||||
AudioUnitIO::Release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioInputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
|
void AudioInputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class AudioUnitIO;
|
|||||||
class AudioInputAudioUnit : public AudioInput{
|
class AudioInputAudioUnit : public AudioInput{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AudioInputAudioUnit(std::string deviceID);
|
AudioInputAudioUnit(std::string deviceID, AudioUnitIO* io);
|
||||||
virtual ~AudioInputAudioUnit();
|
virtual ~AudioInputAudioUnit();
|
||||||
virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels);
|
virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels);
|
||||||
virtual void Start();
|
virtual void Start();
|
||||||
|
|||||||
@ -12,16 +12,15 @@
|
|||||||
#include "AudioUnitIO.h"
|
#include "AudioUnitIO.h"
|
||||||
|
|
||||||
#define BUFFER_SIZE 960
|
#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;
|
||||||
using namespace tgvoip::audio;
|
using namespace tgvoip::audio;
|
||||||
|
|
||||||
AudioOutputAudioUnit::AudioOutputAudioUnit(std::string deviceID){
|
AudioOutputAudioUnit::AudioOutputAudioUnit(std::string deviceID, AudioUnitIO* io){
|
||||||
isPlaying=false;
|
isPlaying=false;
|
||||||
remainingDataSize=0;
|
remainingDataSize=0;
|
||||||
level=0.0;
|
level=0.0;
|
||||||
this->io=AudioUnitIO::Get();
|
this->io=io;
|
||||||
#if TARGET_OS_OSX
|
#if TARGET_OS_OSX
|
||||||
io->SetCurrentDevice(false, deviceID);
|
io->SetCurrentDevice(false, deviceID);
|
||||||
#endif
|
#endif
|
||||||
@ -31,7 +30,6 @@ AudioOutputAudioUnit::AudioOutputAudioUnit(std::string deviceID){
|
|||||||
|
|
||||||
AudioOutputAudioUnit::~AudioOutputAudioUnit(){
|
AudioOutputAudioUnit::~AudioOutputAudioUnit(){
|
||||||
io->DetachOutput();
|
io->DetachOutput();
|
||||||
AudioUnitIO::Release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioOutputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
|
void AudioOutputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
|
||||||
@ -67,8 +65,6 @@ float AudioOutputAudioUnit::GetLevel(){
|
|||||||
|
|
||||||
void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){
|
void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){
|
||||||
int i;
|
int i;
|
||||||
unsigned int k;
|
|
||||||
int16_t absVal=0;
|
|
||||||
for(i=0;i<ioData->mNumberBuffers;i++){
|
for(i=0;i<ioData->mNumberBuffers;i++){
|
||||||
AudioBuffer buf=ioData->mBuffers[i];
|
AudioBuffer buf=ioData->mBuffers[i];
|
||||||
if(!isPlaying){
|
if(!isPlaying){
|
||||||
@ -76,6 +72,7 @@ void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#if TARGET_OS_OSX
|
#if TARGET_OS_OSX
|
||||||
|
unsigned int k;
|
||||||
while(remainingDataSize<buf.mDataByteSize/2){
|
while(remainingDataSize<buf.mDataByteSize/2){
|
||||||
assert(remainingDataSize+BUFFER_SIZE*2<sizeof(remainingData));
|
assert(remainingDataSize+BUFFER_SIZE*2<sizeof(remainingData));
|
||||||
InvokeCallback(remainingData+remainingDataSize, BUFFER_SIZE*2);
|
InvokeCallback(remainingData+remainingDataSize, BUFFER_SIZE*2);
|
||||||
@ -98,28 +95,6 @@ void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){
|
|||||||
remainingDataSize-=buf.mDataByteSize;
|
remainingDataSize-=buf.mDataByteSize;
|
||||||
memmove(remainingData, remainingData+buf.mDataByteSize, remainingDataSize);
|
memmove(remainingData, remainingData+buf.mDataByteSize, remainingDataSize);
|
||||||
#endif
|
#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{
|
class AudioOutputAudioUnit : public AudioOutput{
|
||||||
public:
|
public:
|
||||||
AudioOutputAudioUnit(std::string deviceID);
|
AudioOutputAudioUnit(std::string deviceID, AudioUnitIO* io);
|
||||||
virtual ~AudioOutputAudioUnit();
|
virtual ~AudioOutputAudioUnit();
|
||||||
virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels);
|
virtual void Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels);
|
||||||
virtual bool IsPhone();
|
virtual bool IsPhone();
|
||||||
|
|||||||
@ -26,9 +26,6 @@
|
|||||||
using namespace tgvoip;
|
using namespace tgvoip;
|
||||||
using namespace tgvoip::audio;
|
using namespace tgvoip::audio;
|
||||||
|
|
||||||
int AudioUnitIO::refCount=0;
|
|
||||||
AudioUnitIO* AudioUnitIO::sharedInstance=NULL;
|
|
||||||
|
|
||||||
AudioUnitIO::AudioUnitIO(){
|
AudioUnitIO::AudioUnitIO(){
|
||||||
input=NULL;
|
input=NULL;
|
||||||
output=NULL;
|
output=NULL;
|
||||||
@ -130,24 +127,6 @@ AudioUnitIO::~AudioUnitIO(){
|
|||||||
free(inBufferList.mBuffers[0].mData);
|
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){
|
void AudioUnitIO::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,8 +28,6 @@ public:
|
|||||||
void EnableInput(bool enabled);
|
void EnableInput(bool enabled);
|
||||||
void EnableOutput(bool enabled);
|
void EnableOutput(bool enabled);
|
||||||
bool IsFailed();
|
bool IsFailed();
|
||||||
static AudioUnitIO* Get();
|
|
||||||
static void Release();
|
|
||||||
#if TARGET_OS_OSX
|
#if TARGET_OS_OSX
|
||||||
void SetCurrentDevice(bool input, std::string deviceID);
|
void SetCurrentDevice(bool input, std::string deviceID);
|
||||||
#endif
|
#endif
|
||||||
@ -51,8 +49,6 @@ private:
|
|||||||
bool outputEnabled;
|
bool outputEnabled;
|
||||||
bool failed;
|
bool failed;
|
||||||
bool started;
|
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" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void (*TGVoipLoggingFunction)(NSString *);
|
|
||||||
|
|
||||||
void __tgvoip_call_tglog(const char* format, ...);
|
void __tgvoip_call_tglog(const char* format, ...);
|
||||||
|
|
||||||
#if defined __cplusplus
|
#if defined __cplusplus
|
||||||
|
|||||||
@ -3,10 +3,11 @@
|
|||||||
void (*TGVoipLoggingFunction)(NSString *) = NULL;
|
void (*TGVoipLoggingFunction)(NSString *) = NULL;
|
||||||
|
|
||||||
void __tgvoip_call_tglog(const char* format, ...){
|
void __tgvoip_call_tglog(const char* format, ...){
|
||||||
if (TGVoipLoggingFunction != nil) {
|
va_list args;
|
||||||
va_list args;
|
va_start(args, format);
|
||||||
va_start(args, format);
|
NSString *string = [[NSString alloc] initWithFormat:[[NSString alloc]initWithUTF8String:format] arguments:args];
|
||||||
TGVoipLoggingFunction([[NSString alloc]initWithFormat:[[NSString alloc] initWithUTF8String:format] arguments:args]);
|
va_end(args);
|
||||||
va_end(args);
|
if (TGVoipLoggingFunction) {
|
||||||
|
TGVoipLoggingFunction(string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,7 +58,9 @@ void AudioInputALSA::Start(){
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
isRecording=true;
|
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(){
|
void AudioInputALSA::Stop(){
|
||||||
@ -66,15 +68,12 @@ void AudioInputALSA::Stop(){
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
isRecording=false;
|
isRecording=false;
|
||||||
join_thread(thread);
|
thread->Join();
|
||||||
|
delete thread;
|
||||||
|
thread=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* AudioInputALSA::StartThread(void* arg){
|
void AudioInputALSA::RunThread(void* arg){
|
||||||
((AudioInputALSA*)arg)->RunThread();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioInputALSA::RunThread(){
|
|
||||||
unsigned char buffer[BUFFER_SIZE*2];
|
unsigned char buffer[BUFFER_SIZE*2];
|
||||||
snd_pcm_sframes_t frames;
|
snd_pcm_sframes_t frames;
|
||||||
while(isRecording){
|
while(isRecording){
|
||||||
@ -94,7 +93,7 @@ void AudioInputALSA::SetCurrentDevice(std::string devID){
|
|||||||
bool wasRecording=isRecording;
|
bool wasRecording=isRecording;
|
||||||
isRecording=false;
|
isRecording=false;
|
||||||
if(handle){
|
if(handle){
|
||||||
join_thread(thread);
|
thread->Join();
|
||||||
_snd_pcm_close(handle);
|
_snd_pcm_close(handle);
|
||||||
}
|
}
|
||||||
currentDevice=devID;
|
currentDevice=devID;
|
||||||
@ -109,7 +108,7 @@ void AudioInputALSA::SetCurrentDevice(std::string devID){
|
|||||||
|
|
||||||
if(wasRecording){
|
if(wasRecording){
|
||||||
isRecording=true;
|
isRecording=true;
|
||||||
start_thread(thread, AudioInputALSA::StartThread, this);
|
thread->Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,8 +26,7 @@ public:
|
|||||||
static void EnumerateDevices(std::vector<AudioInputDevice>& devs);
|
static void EnumerateDevices(std::vector<AudioInputDevice>& devs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void* StartThread(void* arg);
|
void RunThread(void* arg);
|
||||||
void RunThread();
|
|
||||||
|
|
||||||
int (*_snd_pcm_open)(snd_pcm_t** pcm, const char* name, snd_pcm_stream_t stream, int mode);
|
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);
|
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;
|
void* lib;
|
||||||
|
|
||||||
snd_pcm_t* handle;
|
snd_pcm_t* handle;
|
||||||
tgvoip_thread_t thread;
|
Thread* thread;
|
||||||
bool isRecording;
|
bool isRecording;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -57,7 +57,9 @@ void AudioOutputALSA::Start(){
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
isPlaying=true;
|
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(){
|
void AudioOutputALSA::Stop(){
|
||||||
@ -65,19 +67,15 @@ void AudioOutputALSA::Stop(){
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
isPlaying=false;
|
isPlaying=false;
|
||||||
join_thread(thread);
|
thread->Join();
|
||||||
|
delete thread;
|
||||||
|
thread=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioOutputALSA::IsPlaying(){
|
bool AudioOutputALSA::IsPlaying(){
|
||||||
return isPlaying;
|
return isPlaying;
|
||||||
}
|
}
|
||||||
|
void AudioOutputALSA::RunThread(void* arg){
|
||||||
void* AudioOutputALSA::StartThread(void* arg){
|
|
||||||
((AudioOutputALSA*)arg)->RunThread();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioOutputALSA::RunThread(){
|
|
||||||
unsigned char buffer[BUFFER_SIZE*2];
|
unsigned char buffer[BUFFER_SIZE*2];
|
||||||
snd_pcm_sframes_t frames;
|
snd_pcm_sframes_t frames;
|
||||||
while(isPlaying){
|
while(isPlaying){
|
||||||
@ -97,7 +95,7 @@ void AudioOutputALSA::SetCurrentDevice(std::string devID){
|
|||||||
bool wasPlaying=isPlaying;
|
bool wasPlaying=isPlaying;
|
||||||
isPlaying=false;
|
isPlaying=false;
|
||||||
if(handle){
|
if(handle){
|
||||||
join_thread(thread);
|
thread->Join();
|
||||||
_snd_pcm_close(handle);
|
_snd_pcm_close(handle);
|
||||||
}
|
}
|
||||||
currentDevice=devID;
|
currentDevice=devID;
|
||||||
@ -112,7 +110,7 @@ void AudioOutputALSA::SetCurrentDevice(std::string devID){
|
|||||||
|
|
||||||
if(wasPlaying){
|
if(wasPlaying){
|
||||||
isPlaying=true;
|
isPlaying=true;
|
||||||
start_thread(thread, AudioOutputALSA::StartThread, this);
|
thread->Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,8 +26,7 @@ public:
|
|||||||
static void EnumerateDevices(std::vector<AudioOutputDevice>& devs);
|
static void EnumerateDevices(std::vector<AudioOutputDevice>& devs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void* StartThread(void* arg);
|
void RunThread(void* arg);
|
||||||
void RunThread();
|
|
||||||
|
|
||||||
int (*_snd_pcm_open)(snd_pcm_t** pcm, const char* name, snd_pcm_stream_t stream, int mode);
|
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);
|
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;
|
void* lib;
|
||||||
|
|
||||||
snd_pcm_t* handle;
|
snd_pcm_t* handle;
|
||||||
tgvoip_thread_t thread;
|
Thread* thread;
|
||||||
bool isPlaying;
|
bool isPlaying;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,13 @@
|
|||||||
#include "../../BufferInputStream.h"
|
#include "../../BufferInputStream.h"
|
||||||
#include "../../BufferOutputStream.h"
|
#include "../../BufferOutputStream.h"
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
#include <jni.h>
|
||||||
|
#include <sys/system_properties.h>
|
||||||
|
extern JavaVM* sharedJVM;
|
||||||
|
extern jclass jniUtilitiesClass;
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace tgvoip;
|
using namespace tgvoip;
|
||||||
|
|
||||||
|
|
||||||
@ -61,7 +68,7 @@ void NetworkSocketPosix::SetMaxPriority(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void NetworkSocketPosix::Send(NetworkPacket *packet){
|
void NetworkSocketPosix::Send(NetworkPacket *packet){
|
||||||
if(!packet || !packet->address){
|
if(!packet || (protocol==PROTO_UDP && !packet->address)){
|
||||||
LOGW("tried to send null packet");
|
LOGW("tried to send null packet");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -222,7 +229,6 @@ void NetworkSocketPosix::Open(){
|
|||||||
}
|
}
|
||||||
size_t addrLen=sizeof(sockaddr_in6);
|
size_t addrLen=sizeof(sockaddr_in6);
|
||||||
getsockname(fd, (sockaddr*)&addr, (socklen_t*) &addrLen);
|
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));
|
LOGD("Bound to local UDP port %u", ntohs(addr.sin6_port));
|
||||||
|
|
||||||
needUpdateNat64Prefix=true;
|
needUpdateNat64Prefix=true;
|
||||||
@ -237,6 +243,7 @@ void NetworkSocketPosix::Close(){
|
|||||||
if (fd>=0) {
|
if (fd>=0) {
|
||||||
shutdown(fd, SHUT_RDWR);
|
shutdown(fd, SHUT_RDWR);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
fd=-1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,13 +306,45 @@ void NetworkSocketPosix::OnActiveInterfaceChanged(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string NetworkSocketPosix::GetLocalInterfaceInfo(IPv4Address *v4addr, IPv6Address *v6addr){
|
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 ifconf ifc;
|
||||||
struct ifreq* ifr;
|
struct ifreq* ifr;
|
||||||
char buf[16384];
|
char buf[16384];
|
||||||
int sd;
|
int sd;
|
||||||
std::string name="";
|
std::string name="";
|
||||||
sd=socket(PF_INET, SOCK_DGRAM, 0);
|
sd=socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
if(sd>0){
|
if(sd>=0){
|
||||||
ifc.ifc_len=sizeof(buf);
|
ifc.ifc_len=sizeof(buf);
|
||||||
ifc.ifc_ifcu.ifcu_buf=buf;
|
ifc.ifc_ifcu.ifcu_buf=buf;
|
||||||
if(ioctl(sd, SIOCGIFCONF, &ifc)==0){
|
if(ioctl(sd, SIOCGIFCONF, &ifc)==0){
|
||||||
@ -319,6 +358,14 @@ std::string NetworkSocketPosix::GetLocalInterfaceInfo(IPv4Address *v4addr, IPv6A
|
|||||||
len=sizeof(*ifr);
|
len=sizeof(*ifr);
|
||||||
#endif
|
#endif
|
||||||
if(ifr->ifr_addr.sa_family==AF_INET){
|
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){
|
if(ioctl(sd, SIOCGIFADDR, ifr)==0){
|
||||||
struct sockaddr_in* addr=(struct sockaddr_in *)(&ifr->ifr_addr);
|
struct sockaddr_in* addr=(struct sockaddr_in *)(&ifr->ifr_addr);
|
||||||
LOGI("Interface %s, address %s\n", ifr->ifr_name, inet_ntoa(addr->sin_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);
|
//LOGV("flags = %08X", ifr->ifr_flags);
|
||||||
if((ntohl(addr->sin_addr.s_addr) & 0xFFFF0000)==0xA9FE0000){
|
if((ntohl(addr->sin_addr.s_addr) & 0xFFFF0000)==0xA9FE0000){
|
||||||
LOGV("skipping link-local");
|
LOGV("skipping link-local");
|
||||||
|
ifr=(struct ifreq*)((char*)ifr+len);
|
||||||
|
i+=len;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(v4addr){
|
if(v4addr){
|
||||||
@ -345,8 +394,8 @@ std::string NetworkSocketPosix::GetLocalInterfaceInfo(IPv4Address *v4addr, IPv6A
|
|||||||
}else{
|
}else{
|
||||||
LOGE("Error getting LAN address: %d", errno);
|
LOGE("Error getting LAN address: %d", errno);
|
||||||
}
|
}
|
||||||
|
close(sd);
|
||||||
}
|
}
|
||||||
close(sd);
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,7 +507,7 @@ bool NetworkSocketPosix::Select(std::vector<NetworkSocket *> &readFds, std::vect
|
|||||||
maxfd=sfd;
|
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){
|
if(canceller && FD_ISSET(canceller->pipeRead, &readSet) && !anyFailed){
|
||||||
char c;
|
char c;
|
||||||
@ -496,7 +545,10 @@ bool NetworkSocketPosix::Select(std::vector<NetworkSocket *> &readFds, std::vect
|
|||||||
SocketSelectCancellerPosix::SocketSelectCancellerPosix(){
|
SocketSelectCancellerPosix::SocketSelectCancellerPosix(){
|
||||||
int p[2];
|
int p[2];
|
||||||
int pipeRes=pipe(p);
|
int pipeRes=pipe(p);
|
||||||
assert(pipeRes==0);
|
if(pipeRes!=0){
|
||||||
|
LOGE("pipe() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
pipeRead=p[0];
|
pipeRead=p[0];
|
||||||
pipeWrite=p[1];
|
pipeWrite=p[1];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,7 +62,7 @@ void VoIPControllerWrapper::SetPublicEndpoints(const Platform::Array<libtgvoip::
|
|||||||
libtgvoip::Endpoint^ _ep = endpoints[i];
|
libtgvoip::Endpoint^ _ep = endpoints[i];
|
||||||
tgvoip::Endpoint ep;
|
tgvoip::Endpoint ep;
|
||||||
ep.id = _ep->id;
|
ep.id = _ep->id;
|
||||||
ep.type = EP_TYPE_UDP_RELAY;
|
ep.type = Endpoint::TYPE_UDP_RELAY;
|
||||||
char buf[128];
|
char buf[128];
|
||||||
if (_ep->ipv4){
|
if (_ep->ipv4){
|
||||||
WideCharToMultiByte(CP_UTF8, 0, _ep->ipv4->Data(), -1, buf, sizeof(buf), NULL, NULL);
|
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
|
#ifndef __THREADING_H
|
||||||
#define __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__))
|
#if defined(_POSIX_THREADS) || defined(_POSIX_VERSION) || defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
|
|
||||||
typedef pthread_t tgvoip_thread_t;
|
namespace tgvoip{
|
||||||
typedef pthread_mutex_t tgvoip_mutex_t;
|
class Mutex{
|
||||||
typedef pthread_cond_t tgvoip_lock_t;
|
public:
|
||||||
|
Mutex(){
|
||||||
|
pthread_mutex_init(&mtx, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#define start_thread(ref, entry, arg) pthread_create(&ref, NULL, entry, arg)
|
~Mutex(){
|
||||||
#define join_thread(thread) pthread_join(thread, NULL)
|
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__
|
#ifndef __APPLE__
|
||||||
#define set_thread_name(thread, name) pthread_setname_np(thread, name)
|
pthread_setname_np(self->thread, self->name);
|
||||||
#else
|
#else
|
||||||
#define set_thread_name(thread, name)
|
pthread_setname_np(self->name);
|
||||||
#endif
|
#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)
|
self->entry->Invoke(self->arg);
|
||||||
#define get_thread_min_priority() sched_get_priority_min(SCHED_RR)
|
return NULL;
|
||||||
#define init_mutex(mutex) pthread_mutex_init(&mutex, NULL)
|
}
|
||||||
#define free_mutex(mutex) pthread_mutex_destroy(&mutex)
|
MethodPointerBase* entry;
|
||||||
#define lock_mutex(mutex) pthread_mutex_lock(&mutex)
|
void* arg;
|
||||||
#define unlock_mutex(mutex) pthread_mutex_unlock(&mutex)
|
pthread_t thread;
|
||||||
#define init_lock(lock) pthread_cond_init(&lock, NULL)
|
const char* name;
|
||||||
#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)
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <dispatch/dispatch.h>
|
#include <dispatch/dispatch.h>
|
||||||
@ -113,39 +187,100 @@ private:
|
|||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <assert.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{
|
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{
|
class Semaphore{
|
||||||
public:
|
public:
|
||||||
Semaphore(unsigned int maxCount, unsigned int initValue){
|
Semaphore(unsigned int maxCount, unsigned int initValue){
|
||||||
@ -193,14 +328,14 @@ private:
|
|||||||
namespace tgvoip{
|
namespace tgvoip{
|
||||||
class MutexGuard{
|
class MutexGuard{
|
||||||
public:
|
public:
|
||||||
MutexGuard(tgvoip_mutex_t &mutex) : mutex(mutex) {
|
MutexGuard(Mutex &mutex) : mutex(mutex) {
|
||||||
lock_mutex(mutex);
|
mutex.Lock();
|
||||||
}
|
}
|
||||||
~MutexGuard(){
|
~MutexGuard(){
|
||||||
unlock_mutex(mutex);
|
mutex.Unlock();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
tgvoip_mutex_t &mutex;
|
Mutex &mutex;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user