2.0-alpha4

This commit is contained in:
Grishka 2018-05-15 21:23:46 +03:00
parent a3feec022c
commit b52eb581fa
55 changed files with 4190 additions and 1867 deletions

View File

@ -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);
}; };
} }

View File

@ -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){

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
} }
} }

View File

@ -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;
}; };
} }

View File

@ -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(){

View File

@ -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;
}; };
} }

View File

@ -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];

View File

@ -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;

View File

@ -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;
} }

View File

@ -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
}; };
} }

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;

View File

@ -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);
} }

View File

@ -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;
}; };
} }

View File

@ -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;
}

View File

@ -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;
}; };
} }

File diff suppressed because it is too large Load Diff

View File

@ -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;
Callbacks callbacks;
bool didReceiveGroupCallKey;
bool didReceiveGroupCallKeyAck;
bool didSendGroupCallKey;
bool didSendUpgradeRequest;
bool didInvokeUpdateCallback;
/*** server config values ***/ int32_t connectionMaxLayer;
uint32_t maxAudioBitrate; bool useMTProto2;
uint32_t maxAudioBitrateEDGE; bool setCurrentEndpointToTCP;
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;
#ifdef TGVOIP_USE_AUDIO_SESSION /*** server config values ***/
void (^acquireAudioSession)(void (^)()); uint32_t maxAudioBitrate;
bool needNotifyAcquiredAudioSession; uint32_t maxAudioBitrateEDGE;
#endif 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;
public: /*** 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

View File

@ -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(){

View File

@ -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;
}; };
} }

View File

@ -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)

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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();
}

View File

@ -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;

View File

@ -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>

View File

@ -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);
} }
} }

View File

@ -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__)

View File

@ -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){

View File

@ -30,7 +30,7 @@ public:
private: private:
jobject javaObject; jobject javaObject;
bool running; bool running;
tgvoip_mutex_t mutex; Mutex mutex;
}; };
}} }}

View File

@ -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();

View File

@ -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);

View File

@ -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;
} }

View File

@ -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);

View File

@ -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){

View File

@ -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();

View File

@ -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;
}*/
} }
} }

View File

@ -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();

View File

@ -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){
} }

View File

@ -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
View File

@ -0,0 +1,3 @@
#import <Foundation/Foundation.h>
extern void (*TGVoipLoggingFunction)(NSString *);

View File

@ -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

View File

@ -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);
} }
} }

View File

@ -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();
} }
} }

View File

@ -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;
}; };

View File

@ -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();
} }
} }

View File

@ -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;
}; };

View File

@ -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];
} }

View File

@ -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);

View File

@ -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(&section);
#else
InitializeCriticalSectionEx(&section, 0, 0);
#endif
}
~Mutex(){
DeleteCriticalSection(&section);
}
void Lock(){
EnterCriticalSection(&section);
}
void Unlock(){
LeaveCriticalSection(&section);
}
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;
}; };
} }