From 342cc5a2952c9ef351f41e90d48219e889d97c09 Mon Sep 17 00:00:00 2001 From: Grishka Date: Mon, 4 Jun 2018 22:37:43 +0300 Subject: [PATCH] 2.1 --- Buffers.cpp | 270 +++ Buffers.h | 162 ++ CongestionControl.cpp | 1 + EchoCanceller.h | 2 +- JitterBuffer.cpp | 73 +- JitterBuffer.h | 22 +- MediaStreamItf.cpp | 12 +- MediaStreamItf.h | 14 +- NetworkSocket.cpp | 19 +- NetworkSocket.h | 6 +- OpusDecoder.cpp | 67 +- OpusDecoder.h | 14 +- OpusEncoder.cpp | 43 +- OpusEncoder.h | 14 +- PacketReassembler.cpp | 23 + PacketReassembler.h | 29 + PrivateDefines.h | 110 + VoIPController.cpp | 1940 +++++++---------- VoIPController.h | 243 ++- VoIPGroupController.cpp | 813 +++++++ audio/AudioOutput.cpp | 21 +- audio/AudioOutput.h | 3 +- client/android/tg_voip_jni.cpp | 27 +- libtgvoip.gyp | 12 +- libtgvoip.xcodeproj/project.pbxproj | 40 +- .../xcschemes/xcschememanagement.plist | 2 +- os/posix/NetworkSocketPosix.cpp | 137 +- os/windows/AudioInputWASAPI.cpp | 4 +- os/windows/AudioInputWASAPI.h | 2 +- os/windows/AudioOutputWASAPI.cpp | 4 +- os/windows/AudioOutputWASAPI.h | 2 +- os/windows/CXWrapper.cpp | 8 +- 32 files changed, 2594 insertions(+), 1545 deletions(-) create mode 100644 Buffers.cpp create mode 100644 Buffers.h create mode 100644 PacketReassembler.cpp create mode 100644 PacketReassembler.h create mode 100644 PrivateDefines.h create mode 100644 VoIPGroupController.cpp diff --git a/Buffers.cpp b/Buffers.cpp new file mode 100644 index 0000000000..5375df1214 --- /dev/null +++ b/Buffers.cpp @@ -0,0 +1,270 @@ +// +// libtgvoip is free and unencumbered public domain software. +// For more information, see http://unlicense.org or the UNLICENSE file +// you should have received with this source code distribution. +// + +#include "Buffers.h" +#include +#include +#include +#include +#include +#include "logging.h" + +using namespace tgvoip; + +#pragma mark -- BufferInputStream + +BufferInputStream::BufferInputStream(unsigned char* data, size_t length){ + this->buffer=data; + this->length=length; + offset=0; +} + +BufferInputStream::~BufferInputStream(){ + +} + + +void BufferInputStream::Seek(size_t offset){ + if(offset>length){ + throw std::out_of_range("Not enough bytes in buffer"); + } + this->offset=offset; +} + +size_t BufferInputStream::GetLength(){ + return length; +} + +size_t BufferInputStream::GetOffset(){ + return offset; +} + +size_t BufferInputStream::Remaining(){ + return length-offset; +} + +unsigned char BufferInputStream::ReadByte(){ + EnsureEnoughRemaining(1); + return (unsigned char)buffer[offset++]; +} + +int32_t BufferInputStream::ReadInt32(){ + EnsureEnoughRemaining(4); + int32_t res=((int32_t)buffer[offset] & 0xFF) | + (((int32_t)buffer[offset+1] & 0xFF) << 8) | + (((int32_t)buffer[offset+2] & 0xFF) << 16) | + (((int32_t)buffer[offset+3] & 0xFF) << 24); + offset+=4; + return res; +} + +int64_t BufferInputStream::ReadInt64(){ + EnsureEnoughRemaining(8); + int64_t res=((int64_t)buffer[offset] & 0xFF) | + (((int64_t)buffer[offset+1] & 0xFF) << 8) | + (((int64_t)buffer[offset+2] & 0xFF) << 16) | + (((int64_t)buffer[offset+3] & 0xFF) << 24) | + (((int64_t)buffer[offset+4] & 0xFF) << 32) | + (((int64_t)buffer[offset+5] & 0xFF) << 40) | + (((int64_t)buffer[offset+6] & 0xFF) << 48) | + (((int64_t)buffer[offset+7] & 0xFF) << 56); + offset+=8; + return res; +} + +int16_t BufferInputStream::ReadInt16(){ + EnsureEnoughRemaining(2); + int16_t res=(uint16_t)buffer[offset] | ((uint16_t)buffer[offset+1] << 8); + offset+=2; + return res; +} + + +int32_t BufferInputStream::ReadTlLength(){ + unsigned char l=ReadByte(); + if(l<254) + return l; + assert(length-offset>=3); + EnsureEnoughRemaining(3); + int32_t res=((int32_t)buffer[offset] & 0xFF) | + (((int32_t)buffer[offset+1] & 0xFF) << 8) | + (((int32_t)buffer[offset+2] & 0xFF) << 16); + offset+=3; + return res; +} + +void BufferInputStream::ReadBytes(unsigned char *to, size_t count){ + EnsureEnoughRemaining(count); + memcpy(to, buffer+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){ + if(length-offsetsize=size; + bufferProvided=false; +} + +BufferOutputStream::BufferOutputStream(unsigned char *buffer, size_t size){ + this->buffer=buffer; + this->size=size; + offset=0; + bufferProvided=true; +} + +BufferOutputStream::~BufferOutputStream(){ + if(!bufferProvided && buffer) + free(buffer); +} + +void BufferOutputStream::WriteByte(unsigned char byte){ + this->ExpandBufferIfNeeded(1); + buffer[offset++]=byte; +} + +void BufferOutputStream::WriteInt32(int32_t i){ + this->ExpandBufferIfNeeded(4); + buffer[offset+3]=(unsigned char)((i >> 24) & 0xFF); + buffer[offset+2]=(unsigned char)((i >> 16) & 0xFF); + buffer[offset+1]=(unsigned char)((i >> 8) & 0xFF); + buffer[offset]=(unsigned char)(i & 0xFF); + offset+=4; +} + +void BufferOutputStream::WriteInt64(int64_t i){ + this->ExpandBufferIfNeeded(8); + buffer[offset+7]=(unsigned char)((i >> 56) & 0xFF); + buffer[offset+6]=(unsigned char)((i >> 48) & 0xFF); + buffer[offset+5]=(unsigned char)((i >> 40) & 0xFF); + buffer[offset+4]=(unsigned char)((i >> 32) & 0xFF); + buffer[offset+3]=(unsigned char)((i >> 24) & 0xFF); + buffer[offset+2]=(unsigned char)((i >> 16) & 0xFF); + buffer[offset+1]=(unsigned char)((i >> 8) & 0xFF); + buffer[offset]=(unsigned char)(i & 0xFF); + offset+=8; +} + +void BufferOutputStream::WriteInt16(int16_t i){ + this->ExpandBufferIfNeeded(2); + buffer[offset+1]=(unsigned char)((i >> 8) & 0xFF); + buffer[offset]=(unsigned char)(i & 0xFF); + offset+=2; +} + +void BufferOutputStream::WriteBytes(unsigned char *bytes, size_t count){ + this->ExpandBufferIfNeeded(count); + memcpy(buffer+offset, bytes, count); + offset+=count; +} + +void BufferOutputStream::WriteBytes(Buffer &buffer){ + WriteBytes(*buffer, buffer.Length()); +} + +unsigned char *BufferOutputStream::GetBuffer(){ + return buffer; +} + +size_t BufferOutputStream::GetLength(){ + return offset; +} + +void BufferOutputStream::ExpandBufferIfNeeded(size_t need){ + if(offset+need>size){ + if(bufferProvided){ + throw std::out_of_range("buffer overflow"); + } + if(need<1024){ + buffer=(unsigned char *) realloc(buffer, size+1024); + size+=1024; + }else{ + buffer=(unsigned char *) realloc(buffer, size+need); + size+=need; + } + } +} + + +void BufferOutputStream::Reset(){ + offset=0; +} + +void BufferOutputStream::Rewind(size_t numBytes){ + if(numBytes>offset) + throw std::out_of_range("buffer underflow"); + offset-=numBytes; +} + +#pragma mark -- BufferPool + +BufferPool::BufferPool(unsigned int size, unsigned int count){ + assert(count<=64); + buffers[0]=(unsigned char*) malloc(size*count); + bufferCount=count; + unsigned int i; + for(i=1;isize=size; +} + +BufferPool::~BufferPool(){ + free(buffers[0]); +} + +unsigned char* BufferPool::Get(){ + MutexGuard m(mutex); + int i; + for(i=0;i> i) & 1)){ + usedBuffers|=(1LL << i); + return buffers[i]; + } + } + return NULL; +} + +void BufferPool::Reuse(unsigned char* buffer){ + MutexGuard m(mutex); + int i; + for(i=0;i +#include +#include +#include +#include +#include "threading.h" + +namespace tgvoip{ + class Buffer; + + class BufferInputStream{ + + public: + BufferInputStream(unsigned char* data, size_t length); + ~BufferInputStream(); + void Seek(size_t offset); + size_t GetLength(); + size_t GetOffset(); + size_t Remaining(); + unsigned char ReadByte(); + int64_t ReadInt64(); + int32_t ReadInt32(); + int16_t ReadInt16(); + int32_t ReadTlLength(); + void ReadBytes(unsigned char* to, size_t count); + BufferInputStream GetPartBuffer(size_t length, bool advance); + + private: + void EnsureEnoughRemaining(size_t need); + unsigned char* buffer; + size_t length; + size_t offset; + }; + + class BufferOutputStream{ + friend class Buffer; + public: + BufferOutputStream(size_t size); + BufferOutputStream(unsigned char* buffer, size_t size); + ~BufferOutputStream(); + void WriteByte(unsigned char byte); + void WriteInt64(int64_t i); + void WriteInt32(int32_t i); + void WriteInt16(int16_t i); + void WriteBytes(unsigned char* bytes, size_t count); + void WriteBytes(Buffer& buffer); + unsigned char* GetBuffer(); + size_t GetLength(); + void Reset(); + void Rewind(size_t numBytes); + + private: + void ExpandBufferIfNeeded(size_t need); + unsigned char* buffer; + size_t size; + size_t offset; + bool bufferProvided; + }; + + class BufferPool{ + public: + BufferPool(unsigned int size, unsigned int count); + ~BufferPool(); + unsigned char* Get(); + void Reuse(unsigned char* buffer); + size_t GetSingleBufferSize(); + size_t GetBufferCount(); + + private: + uint64_t usedBuffers; + int bufferCount; + size_t size; + unsigned char* buffers[64]; + Mutex mutex; + }; + + class Buffer{ + public: + Buffer(size_t capacity){ + data=(unsigned char *) malloc(capacity); + length=capacity; + }; + Buffer(const Buffer& other)=delete; + Buffer(Buffer&& other) noexcept { + data=other.data; + length=other.length; + other.data=NULL; + }; + Buffer(BufferOutputStream&& stream){ + data=stream.buffer; + length=stream.offset; + stream.buffer=NULL; + } + Buffer(){ + data=NULL; + length=0; + } + ~Buffer(){ + if(data) + free(data); + }; + Buffer& operator=(Buffer&& other){ + if(this!=&other){ + if(data) + free(data); + data=other.data; + length=other.length; + other.data=NULL; + } + return *this; + } + unsigned char& operator[](size_t i){ + if(i>=length) + throw std::out_of_range(""); + return data[i]; + } + const unsigned char& operator[](size_t i) const{ + if(i>=length) + throw std::out_of_range(""); + return data[i]; + } + unsigned char* operator*(){ + return data; + } + const unsigned char* operator*() const{ + return data; + } + void CopyFrom(Buffer& other, size_t count, size_t srcOffset=0, size_t dstOffset=0){ + if(!other.data) + throw std::invalid_argument("CopyFrom can't copy from NULL"); + if(other.length #include diff --git a/EchoCanceller.h b/EchoCanceller.h index 4c475c79a7..a774abac2e 100644 --- a/EchoCanceller.h +++ b/EchoCanceller.h @@ -8,7 +8,7 @@ #define LIBTGVOIP_ECHOCANCELLER_H #include "threading.h" -#include "BufferPool.h" +#include "Buffers.h" #include "BlockingQueue.h" #include "MediaStreamItf.h" diff --git a/JitterBuffer.cpp b/JitterBuffer.cpp index bbc813a618..24e2ca8909 100644 --- a/JitterBuffer.cpp +++ b/JitterBuffer.cpp @@ -62,7 +62,7 @@ void JitterBuffer::SetMinPacketCount(uint32_t count){ if(minDelay==count) return; minDelay=count; - Reset(); + //Reset(); } int JitterBuffer::GetMinPacketCount(){ @@ -78,15 +78,16 @@ size_t JitterBuffer::CallbackOut(unsigned char *data, size_t len, void *param){ return 0; //((JitterBuffer*)param)->HandleOutput(data, len, 0, NULL); } -void JitterBuffer::HandleInput(unsigned char *data, size_t len, uint32_t timestamp){ +void JitterBuffer::HandleInput(unsigned char *data, size_t len, uint32_t timestamp, bool isEC){ + MutexGuard m(mutex); jitter_packet_t pkt; pkt.size=len; pkt.buffer=data; pkt.timestamp=timestamp; - mutex.Lock(); - PutInternal(&pkt); - mutex.Unlock(); - //LOGV("in, ts=%d", timestamp); + pkt.isEC=isEC; + PutInternal(&pkt, !isEC); + //LOGV("in, ts=%d, ec=%d", timestamp, isEC); + } void JitterBuffer::Reset(){ @@ -113,30 +114,38 @@ void JitterBuffer::Reset(){ } -size_t JitterBuffer::HandleOutput(unsigned char *buffer, size_t len, int offsetInSteps, bool advance, int* playbackScaledDuration){ +size_t JitterBuffer::HandleOutput(unsigned char *buffer, size_t len, int offsetInSteps, bool advance, int& playbackScaledDuration, bool& isEC){ jitter_packet_t pkt; pkt.buffer=buffer; pkt.size=len; MutexGuard m(mutex); int result=GetInternal(&pkt, offsetInSteps, advance); - if(playbackScaledDuration){ - if(outstandingDelayChange!=0){ - if(outstandingDelayChange<0){ - *playbackScaledDuration=40; - outstandingDelayChange+=20; - }else{ - *playbackScaledDuration=80; - outstandingDelayChange-=20; - } - //LOGV("outstanding delay change: %d", outstandingDelayChange); - }else if(advance && GetCurrentDelay()==0){ - //LOGV("stretching packet because the next one is late"); - *playbackScaledDuration=80; + if(outstandingDelayChange!=0){ + if(outstandingDelayChange<0){ + playbackScaledDuration=40; + outstandingDelayChange+=20; + + + + + + + + + }else{ - *playbackScaledDuration=60; + playbackScaledDuration=80; + outstandingDelayChange-=20; } + //LOGV("outstanding delay change: %d", outstandingDelayChange); + }else if(advance && GetCurrentDelay()==0){ + //LOGV("stretching packet because the next one is late"); + playbackScaledDuration=80; + }else{ + playbackScaledDuration=60; } if(result==JR_OK){ + isEC=pkt.isEC; return pkt.size; }else{ return 0; @@ -170,6 +179,7 @@ int JitterBuffer::GetInternal(jitter_packet_t* pkt, int offset, bool advance){ pkt->size = slots[i].size; pkt->timestamp = slots[i].timestamp; memcpy(pkt->buffer, slots[i].buffer, slots[i].size); + pkt->isEC=slots[i].isEC; } } bufferPool.Reuse(slots[i].buffer); @@ -208,18 +218,30 @@ int JitterBuffer::GetInternal(jitter_packet_t* pkt, int offset, bool advance){ return JR_BUFFERING; } -void JitterBuffer::PutInternal(jitter_packet_t* pkt){ +void JitterBuffer::PutInternal(jitter_packet_t* pkt, bool overwriteExisting){ if(pkt->size>JITTER_SLOT_SIZE){ LOGE("The packet is too big to fit into the jitter buffer"); return; } - gotSinceReset++; + int i; + for(i=0;itimestamp){ + //LOGV("Found existing packet for timestamp %u, overwrite %d", pkt->timestamp, overwriteExisting); + if(overwriteExisting){ + memcpy(slots[i].buffer, pkt->buffer, pkt->size); + slots[i].size=pkt->size; + slots[i].isEC=pkt->isEC; + } + return; + } + } + gotSinceReset++; if(wasReset){ wasReset=false; outstandingDelayChange=0; nextTimestamp=((int64_t)pkt->timestamp)-step*minDelay; - LOGI("jitter: resyncing, next timestamp = %lld (step=%d, minDelay=%d)", (long long int)nextTimestamp, step, int(minDelay)); + LOGI("jitter: resyncing, next timestamp = %lld (step=%d, minDelay=%f)", (long long int)nextTimestamp, step, minDelay); } for(i=0;isize; slots[i].buffer=bufferPool.Get(); slots[i].recvTimeDiff=time-prevRecvTime; + slots[i].isEC=pkt->isEC; if(slots[i].buffer) memcpy(slots[i].buffer, pkt->buffer, pkt->size); else @@ -386,7 +409,7 @@ void JitterBuffer::Tick(){ minDelay+=diff; outstandingDelayChange+=diff*60; dontChangeDelay+=32; - LOGD("new delay from stddev %d", int(minDelay)); + LOGD("new delay from stddev %f", minDelay); if(diff<0){ dontDecMinDelay+=25; } diff --git a/JitterBuffer.h b/JitterBuffer.h index 6abab45413..3b9bf7186e 100644 --- a/JitterBuffer.h +++ b/JitterBuffer.h @@ -12,7 +12,7 @@ #include #include "MediaStreamItf.h" #include "BlockingQueue.h" -#include "BufferPool.h" +#include "Buffers.h" #include "threading.h" #define JITTER_SLOT_COUNT 64 @@ -21,13 +21,6 @@ #define JR_MISSING 2 #define JR_BUFFERING 3 -struct jitter_packet_t{ - unsigned char* buffer; - size_t size; - uint32_t timestamp; - double recvTimeDiff; -}; -typedef struct jitter_packet_t jitter_packet_t; namespace tgvoip{ class JitterBuffer{ @@ -39,8 +32,8 @@ public: unsigned int GetCurrentDelay(); double GetAverageDelay(); void Reset(); - void HandleInput(unsigned char* data, size_t len, uint32_t timestamp); - size_t HandleOutput(unsigned char* buffer, size_t len, int offsetInSteps, bool advance, int* playbackScaledDuration); + void HandleInput(unsigned char* data, size_t len, uint32_t timestamp, bool isEC); + size_t HandleOutput(unsigned char* buffer, size_t len, int offsetInSteps, bool advance, int& playbackScaledDuration, bool& isEC); void Tick(); void GetAverageLateCount(double* out); int GetAndResetLostPacketCount(); @@ -48,9 +41,16 @@ public: double GetLastMeasuredDelay(); private: + struct jitter_packet_t{ + unsigned char* buffer; + size_t size; + uint32_t timestamp; + bool isEC; + double recvTimeDiff; + }; static size_t CallbackIn(unsigned char* data, size_t len, void* param); static size_t CallbackOut(unsigned char* data, size_t len, void* param); - void PutInternal(jitter_packet_t* pkt); + void PutInternal(jitter_packet_t* pkt, bool overwriteExisting); int GetInternal(jitter_packet_t* pkt, int offset, bool advance); void Advance(); diff --git a/MediaStreamItf.cpp b/MediaStreamItf.cpp index 7e8121ca44..a70f8dbb47 100644 --- a/MediaStreamItf.cpp +++ b/MediaStreamItf.cpp @@ -24,17 +24,13 @@ size_t MediaStreamItf::InvokeCallback(unsigned char *data, size_t length){ } 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; +void AudioMixer::SetOutput(const std::unique_ptr& output){ output->SetCallback(OutputCallback, this); } @@ -75,7 +71,7 @@ size_t AudioMixer::OutputCallback(unsigned char *data, size_t length, void *arg) return 960*2; } -void AudioMixer::AddInput(MediaStreamItf *input){ +void AudioMixer::AddInput(std::shared_ptr input){ MutexGuard m(inputsMutex); MixerInput in; in.multiplier=1; @@ -83,7 +79,7 @@ void AudioMixer::AddInput(MediaStreamItf *input){ inputs.push_back(in); } -void AudioMixer::RemoveInput(MediaStreamItf *input){ +void AudioMixer::RemoveInput(std::shared_ptr input){ MutexGuard m(inputsMutex); for(std::vector::iterator i=inputs.begin();i!=inputs.end();++i){ if(i->source==input){ @@ -93,7 +89,7 @@ void AudioMixer::RemoveInput(MediaStreamItf *input){ } } -void AudioMixer::SetInputVolume(MediaStreamItf *input, float volumeDB){ +void AudioMixer::SetInputVolume(std::shared_ptr input, float volumeDB){ MutexGuard m(inputsMutex); for(std::vector::iterator i=inputs.begin();i!=inputs.end();++i){ if(i->source==input){ diff --git a/MediaStreamItf.h b/MediaStreamItf.h index 7592545a23..ad1ab35cc4 100644 --- a/MediaStreamItf.h +++ b/MediaStreamItf.h @@ -9,10 +9,11 @@ #include #include +#include #include #include "threading.h" #include "BlockingQueue.h" -#include "BufferPool.h" +#include "Buffers.h" namespace tgvoip{ @@ -36,23 +37,22 @@ private: public: AudioMixer(); virtual ~AudioMixer(); - void SetOutput(MediaStreamItf* output); + void SetOutput(const std::unique_ptr& output); virtual void Start(); virtual void Stop(); - void AddInput(MediaStreamItf* input); - void RemoveInput(MediaStreamItf* input); - void SetInputVolume(MediaStreamItf* input, float volumeDB); + void AddInput(std::shared_ptr input); + void RemoveInput(std::shared_ptr input); + void SetInputVolume(std::shared_ptr input, float volumeDB); void SetEchoCanceller(EchoCanceller* aec); private: void RunThread(void* arg); struct MixerInput{ - MediaStreamItf* source; + std::shared_ptr 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 inputs; Thread* thread; BufferPool bufferPool; diff --git a/NetworkSocket.cpp b/NetworkSocket.cpp index 815c47c47c..239614635c 100644 --- a/NetworkSocket.cpp +++ b/NetworkSocket.cpp @@ -16,7 +16,7 @@ #include "logging.h" #include "VoIPServerConfig.h" #include "VoIPController.h" -#include "BufferInputStream.h" +#include "Buffers.h" #define MIN_UDP_PORT 16384 #define MAX_UDP_PORT 32768 @@ -180,6 +180,10 @@ uint32_t IPv4Address::GetAddress(){ return address; } +bool IPv4Address::IsEmpty(){ + return address==0; +} + IPv6Address::IPv6Address(std::string addr){ #ifndef _WIN32 NetworkSocketPosix::StringToV6Address(addr, this->address); @@ -188,7 +192,7 @@ IPv6Address::IPv6Address(std::string addr){ #endif } -IPv6Address::IPv6Address(uint8_t addr[16]){ +IPv6Address::IPv6Address(const uint8_t* addr){ memcpy(address, addr, 16); } @@ -197,7 +201,16 @@ IPv6Address::IPv6Address(){ } std::string IPv6Address::ToString(){ - return ""; +#ifndef _WIN32 + return NetworkSocketPosix::V6AddressToString(address); +#else + return NetworkSocketWinsock::V6AddressToString(address); +#endif +} + +bool IPv6Address::IsEmpty(){ + uint64_t* a=reinterpret_cast(address); + return a[0]==0LL && a[1]==0LL; } /*sockaddr &IPv6Address::ToSockAddr(uint16_t port){ diff --git a/NetworkSocket.h b/NetworkSocket.h index 6c89d747e6..e539b97266 100644 --- a/NetworkSocket.h +++ b/NetworkSocket.h @@ -29,6 +29,7 @@ namespace tgvoip { bool operator==(const NetworkAddress& other); bool operator!=(const NetworkAddress& other); virtual ~NetworkAddress()=default; + virtual bool IsEmpty()=0; }; class IPv4Address : public NetworkAddress{ @@ -39,7 +40,7 @@ namespace tgvoip { virtual std::string ToString(); //virtual sockaddr& ToSockAddr(uint16_t port); uint32_t GetAddress(); - + virtual bool IsEmpty(); private: uint32_t address; }; @@ -47,11 +48,12 @@ namespace tgvoip { class IPv6Address : public NetworkAddress{ public: IPv6Address(std::string addr); - IPv6Address(uint8_t addr[16]); + IPv6Address(const uint8_t* addr); IPv6Address(); virtual std::string ToString(); //virtual sockaddr& ToSockAddr(uint16_t port); const uint8_t* GetAddress(); + virtual bool IsEmpty(); private: uint8_t address[16]; }; diff --git a/OpusDecoder.cpp b/OpusDecoder.cpp index 701611997a..32ee251a2c 100644 --- a/OpusDecoder.cpp +++ b/OpusDecoder.cpp @@ -16,9 +16,18 @@ using namespace tgvoip; -tgvoip::OpusDecoder::OpusDecoder(MediaStreamItf *dst, bool isAsync){ - async=isAsync; +tgvoip::OpusDecoder::OpusDecoder(const std::shared_ptr& dst, bool isAsync, bool needEC){ dst->SetCallback(OpusDecoder::Callback, this); + Initialize(isAsync, needEC); +} + +tgvoip::OpusDecoder::OpusDecoder(const std::unique_ptr& dst, bool isAsync, bool needEC){ + dst->SetCallback(OpusDecoder::Callback, this); + Initialize(isAsync, needEC); +} + +void tgvoip::OpusDecoder::Initialize(bool isAsync, bool needEC){ + async=isAsync; if(async){ decodedQueue=new BlockingQueue(33); bufferPool=new BufferPool(PACKET_SIZE, 32); @@ -29,6 +38,10 @@ tgvoip::OpusDecoder::OpusDecoder(MediaStreamItf *dst, bool isAsync){ semaphore=NULL; } dec=opus_decoder_create(48000, 1, NULL); + if(needEC) + ecDec=opus_decoder_create(48000, 1, NULL); + else + ecDec=NULL; buffer=(unsigned char *) malloc(8192); lastDecoded=NULL; outputBufferSize=0; @@ -42,10 +55,14 @@ tgvoip::OpusDecoder::OpusDecoder(MediaStreamItf *dst, bool isAsync){ running=false; remainingDataLen=0; processedBuffer=NULL; + prevWasEC=false; + prevLastSample=0; } tgvoip::OpusDecoder::~OpusDecoder(){ opus_decoder_destroy(dec); + if(ecDec) + opus_decoder_destroy(ecDec); free(buffer); if(bufferPool) delete bufferPool; @@ -176,40 +193,44 @@ void tgvoip::OpusDecoder::RunThread(void* param){ } 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 isEC=false; + size_t len=jitterBuffer->HandleOutput(buffer, 8192, 0, true, playbackDuration, isEC); bool fec=false; if(!len){ fec=true; - len=jitterBuffer->HandleOutput(buffer, 8192, 0, false, &playbackDuration); - if(len) - LOGV("Trying FEC..."); + len=jitterBuffer->HandleOutput(buffer, 8192, 0, false, playbackDuration, isEC); + //if(len) + // LOGV("Trying FEC..."); } int size; if(len){ - size=opus_decode(dec, buffer, len, (opus_int16 *) decodeBuffer, packetsPerFrame*960, fec ? 1 : 0); + size=opus_decode(isEC ? ecDec : dec, buffer, len, (opus_int16 *) decodeBuffer, packetsPerFrame*960, fec ? 1 : 0); consecutiveLostPackets=0; + if(prevWasEC!=isEC && size){ + // It turns out the waveforms generated by the PLC feature are also great to help smooth out the + // otherwise audible transition between the frames from different decoders. Those are basically an extrapolation + // of the previous successfully decoded data -- which is exactly what we need here. + size=opus_decode(prevWasEC ? ecDec : dec, NULL, 0, (opus_int16*)nextBuffer, packetsPerFrame*960, 0); + if(size){ + int16_t* plcSamples=reinterpret_cast(nextBuffer); + int16_t* samples=reinterpret_cast(decodeBuffer); + constexpr float coeffs[]={0.999802, 0.995062, 0.984031, 0.966778, 0.943413, 0.914084, 0.878975, 0.838309, 0.792344, + 0.741368, 0.685706, 0.625708, 0.561754, 0.494249, 0.423619, 0.350311, 0.274788, 0.197527, 0.119018, 0.039757}; + for(int i=0;i<20;i++){ + samples[i]=(int16_t)round((plcSamples[i]*coeffs[i]+(float)samples[i]*(1.0-coeffs[i]))); + } + } + } + prevWasEC=isEC; + prevLastSample=decodeBuffer[size-1]; }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); + size=opus_decode(prevWasEC ? ecDec : dec, NULL, 0, (opus_int16 *) decodeBuffer, packetsPerFrame*960, 0); //LOGV("PLC"); } } @@ -235,7 +256,7 @@ void tgvoip::OpusDecoder::SetFrameDuration(uint32_t duration){ } -void tgvoip::OpusDecoder::SetJitterBuffer(JitterBuffer* jitterBuffer){ +void tgvoip::OpusDecoder::SetJitterBuffer(std::shared_ptr jitterBuffer){ this->jitterBuffer=jitterBuffer; } diff --git a/OpusDecoder.h b/OpusDecoder.h index 69346eed1f..6425c97a12 100644 --- a/OpusDecoder.h +++ b/OpusDecoder.h @@ -12,11 +12,12 @@ #include "opus.h" #include "threading.h" #include "BlockingQueue.h" -#include "BufferPool.h" +#include "Buffers.h" #include "EchoCanceller.h" #include "JitterBuffer.h" #include #include +#include namespace tgvoip{ class OpusDecoder { @@ -25,22 +26,25 @@ public: virtual void Stop(); - OpusDecoder(MediaStreamItf* dst, bool isAsync); + OpusDecoder(const std::shared_ptr& dst, bool isAsync, bool needEC); + OpusDecoder(const std::unique_ptr& dst, bool isAsync, bool needEC); virtual ~OpusDecoder(); size_t HandleCallback(unsigned char* data, size_t len); void SetEchoCanceller(EchoCanceller* canceller); void SetFrameDuration(uint32_t duration); - void SetJitterBuffer(JitterBuffer* jitterBuffer); + void SetJitterBuffer(std::shared_ptr jitterBuffer); void SetDTX(bool enable); void SetLevelMeter(AudioLevelMeter* levelMeter); void AddAudioEffect(AudioEffect* effect); void RemoveAudioEffect(AudioEffect* effect); private: + void Initialize(bool isAsync, bool needEC); static size_t Callback(unsigned char* data, size_t len, void* param); void RunThread(void* param); int DecodeNextFrame(); ::OpusDecoder* dec; + ::OpusDecoder* ecDec; BlockingQueue* decodedQueue; BufferPool* bufferPool; unsigned char* buffer; @@ -52,7 +56,7 @@ private: Semaphore* semaphore; uint32_t frameDuration; EchoCanceller* echoCanceller; - JitterBuffer* jitterBuffer; + std::shared_ptr jitterBuffer; AudioLevelMeter* levelMeter; int consecutiveLostPackets; bool enableDTX; @@ -65,6 +69,8 @@ private: size_t nextLen; unsigned int packetsPerFrame; ptrdiff_t remainingDataLen; + bool prevWasEC; + int16_t prevLastSample; }; } diff --git a/OpusEncoder.cpp b/OpusEncoder.cpp index eb9bec13a5..db00a687fa 100644 --- a/OpusEncoder.cpp +++ b/OpusEncoder.cpp @@ -9,7 +9,7 @@ #include "logging.h" #include "VoIPServerConfig.h" -tgvoip::OpusEncoder::OpusEncoder(MediaStreamItf *source):queue(11), bufferPool(960*2, 10){ +tgvoip::OpusEncoder::OpusEncoder(MediaStreamItf *source, bool needSecondary):queue(11), bufferPool(960*2, 10){ this->source=source; source->SetCallback(tgvoip::OpusEncoder::Callback, this); enc=opus_encoder_create(48000, 1, OPUS_APPLICATION_VOIP, NULL); @@ -29,10 +29,30 @@ tgvoip::OpusEncoder::OpusEncoder(MediaStreamItf *source):queue(11), bufferPool(9 strongCorrectionBitrate=ServerConfig::GetSharedInstance()->GetInt("audio_strong_fec_bitrate", 8000); mediumCorrectionMultiplier=ServerConfig::GetSharedInstance()->GetDouble("audio_medium_fec_multiplier", 1.5); strongCorrectionMultiplier=ServerConfig::GetSharedInstance()->GetDouble("audio_strong_fec_multiplier", 2.0); + secondaryEncoderEnabled=false; + + if(needSecondary){ + secondaryEncoder=opus_encoder_create(48000, 1, OPUS_APPLICATION_VOIP, NULL); + opus_encoder_ctl(secondaryEncoder, OPUS_SET_COMPLEXITY(10)); + opus_encoder_ctl(secondaryEncoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_encoder_ctl(secondaryEncoder, OPUS_SET_VBR(0)); + opus_encoder_ctl(secondaryEncoder, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_encoder_ctl(secondaryEncoder, OPUS_SET_BITRATE(8000)); + opus_encoder_ctl(secondaryEncoder, OPUS_SET_INBAND_FEC(1)); + opus_encoder_ctl(secondaryEncoder, OPUS_SET_PACKET_LOSS_PERC(15)); + + opus_int32 delay, ecDelay; + opus_encoder_ctl(secondaryEncoder, OPUS_GET_LOOKAHEAD(&ecDelay)); + opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&delay)); + }else{ + secondaryEncoder=NULL; + } } tgvoip::OpusEncoder::~OpusEncoder(){ opus_encoder_destroy(enc); + if(secondaryEncoder) + opus_encoder_destroy(secondaryEncoder); } void tgvoip::OpusEncoder::Start(){ @@ -74,7 +94,13 @@ void tgvoip::OpusEncoder::Encode(unsigned char *data, size_t len){ LOGW("DTX"); }else if(running){ //LOGV("Packet size = %d", r); - InvokeCallback(buffer, (size_t)r); + int32_t secondaryLen=0; + unsigned char secondaryBuffer[128]; + if(secondaryEncoderEnabled && secondaryEncoder){ + secondaryLen=opus_encode(secondaryEncoder, (int16_t*)data, len/2, secondaryBuffer, sizeof(secondaryBuffer)); + //LOGV("secondaryLen %d", secondaryLen); + } + InvokeCallback(buffer, (size_t)r, secondaryBuffer, (size_t)secondaryLen); } } @@ -166,3 +192,16 @@ void tgvoip::OpusEncoder::SetDTX(bool enable){ void tgvoip::OpusEncoder::SetLevelMeter(tgvoip::AudioLevelMeter *levelMeter){ this->levelMeter=levelMeter; } + +void tgvoip::OpusEncoder::SetCallback(void (*f)(unsigned char *, size_t, unsigned char *, size_t, void *), void *param){ + callback=f; + callbackParam=param; +} + +void tgvoip::OpusEncoder::InvokeCallback(unsigned char *data, size_t length, unsigned char *secondaryData, size_t secondaryLength){ + callback(data, length, secondaryData, secondaryLength, callbackParam); +} + +void tgvoip::OpusEncoder::SetSecondaryEncoderEnabled(bool enabled){ + secondaryEncoderEnabled=enabled; +} diff --git a/OpusEncoder.h b/OpusEncoder.h index aaf3da162f..4726f6b83a 100644 --- a/OpusEncoder.h +++ b/OpusEncoder.h @@ -12,15 +12,15 @@ #include "opus.h" #include "threading.h" #include "BlockingQueue.h" -#include "BufferPool.h" +#include "Buffers.h" #include "EchoCanceller.h" #include namespace tgvoip{ -class OpusEncoder : public MediaStreamItf{ +class OpusEncoder{ public: - OpusEncoder(MediaStreamItf* source); + OpusEncoder(MediaStreamItf* source, bool needSecondary); virtual ~OpusEncoder(); virtual void Start(); virtual void Stop(); @@ -32,13 +32,17 @@ public: uint32_t GetBitrate(); void SetDTX(bool enable); void SetLevelMeter(AudioLevelMeter* levelMeter); + void SetCallback(void (*f)(unsigned char*, size_t, unsigned char*, size_t, void*), void* param); + void SetSecondaryEncoderEnabled(bool enabled); private: static size_t Callback(unsigned char* data, size_t len, void* param); void RunThread(void* arg); void Encode(unsigned char* data, size_t len); + void InvokeCallback(unsigned char* data, size_t length, unsigned char* secondaryData, size_t secondaryLength); MediaStreamItf* source; ::OpusEncoder* enc; + ::OpusEncoder* secondaryEncoder; unsigned char buffer[4096]; uint32_t requestedBitrate; uint32_t currentBitrate; @@ -55,6 +59,10 @@ private: double mediumCorrectionMultiplier; double strongCorrectionMultiplier; AudioLevelMeter* levelMeter; + bool secondaryEncoderEnabled; + + void (*callback)(unsigned char*, size_t, unsigned char*, size_t, void*); + void* callbackParam; }; } diff --git a/PacketReassembler.cpp b/PacketReassembler.cpp new file mode 100644 index 0000000000..8ef2cea3e0 --- /dev/null +++ b/PacketReassembler.cpp @@ -0,0 +1,23 @@ +// +// Created by Grishka on 19.03.2018. +// + +#include "PacketReassembler.h" + +using namespace tgvoip; + +PacketReassembler::PacketReassembler(){ + +} + +PacketReassembler::~PacketReassembler(){ + +} + +void PacketReassembler::Reset(){ + +} + +void PacketReassembler::AddPacket(unsigned char *data, size_t offset, size_t len, uint32_t pts){ + +} diff --git a/PacketReassembler.h b/PacketReassembler.h new file mode 100644 index 0000000000..44e027fee4 --- /dev/null +++ b/PacketReassembler.h @@ -0,0 +1,29 @@ +// +// Created by Grishka on 19.03.2018. +// + +#ifndef TGVOIP_PACKETREASSEMBLER_H +#define TGVOIP_PACKETREASSEMBLER_H + +#include "MediaStreamItf.h" + +namespace tgvoip { + class PacketReassembler : public MediaStreamItf{ + public: + PacketReassembler(); + virtual ~PacketReassembler(); + + void Start(){}; + void Stop(){}; + + void Reset(); + void AddPacket(unsigned char* data, size_t offset, size_t len, uint32_t pts); + + private: + unsigned char* buffer; + size_t currentSize; + size_t finalSize; + }; +} + +#endif //TGVOIP_PACKETREASSEMBLER_H diff --git a/PrivateDefines.h b/PrivateDefines.h new file mode 100644 index 0000000000..49990eba0b --- /dev/null +++ b/PrivateDefines.h @@ -0,0 +1,110 @@ +// +// Created by Grishka on 20.04.2018. +// + +#ifndef TGVOIP_PRIVATEDEFINES_H +#define TGVOIP_PRIVATEDEFINES_H + +#define PKT_INIT 1 +#define PKT_INIT_ACK 2 +#define PKT_STREAM_STATE 3 +#define PKT_STREAM_DATA 4 +#define PKT_UPDATE_STREAMS 5 +#define PKT_PING 6 +#define PKT_PONG 7 +#define PKT_STREAM_DATA_X2 8 +#define PKT_STREAM_DATA_X3 9 +#define PKT_LAN_ENDPOINT 10 +#define PKT_NETWORK_CHANGED 11 +#define PKT_SWITCH_PREF_RELAY 12 +#define PKT_SWITCH_TO_P2P 13 +#define PKT_NOP 14 +//#define PKT_GROUP_CALL_KEY 15 // replaced with 'extra' in 2.1 (protocol v6) +//#define PKT_REQUEST_GROUP 16 +#define PKT_STREAM_EC 17 + +#define IS_MOBILE_NETWORK(x) (x==NET_TYPE_GPRS || x==NET_TYPE_EDGE || x==NET_TYPE_3G || x==NET_TYPE_HSPA || x==NET_TYPE_LTE || x==NET_TYPE_OTHER_MOBILE) + +#define PROTOCOL_NAME 0x50567247 // "GrVP" in little endian (reversed here) +#define PROTOCOL_VERSION 6 +#define MIN_PROTOCOL_VERSION 3 + +#define STREAM_DATA_FLAG_LEN16 0x40 +#define STREAM_DATA_FLAG_HAS_MORE_FLAGS 0x80 +#define STREAM_DATA_XFLAG_KEYFRAME 0x01 +#define STREAM_DATA_XFLAG_FRAGMENTED 0x02 + +#define STREAM_TYPE_AUDIO 1 +#define STREAM_TYPE_VIDEO 2 + +#define FOURCC(a,b,c,d) ((uint32_t)d | ((uint32_t)c << 8) | ((uint32_t)b << 16) | ((uint32_t)a << 24)) + +#define CODEC_OPUS_OLD 1 +#define CODEC_OPUS FOURCC('O','P','U','S') +#define CODEC_AVC FOURCC('A','V','C',' ') +#define CODEC_HEVC FOURCC('H','E','V','C') +#define CODEC_VP8 FOURCC('V','P','8','0') + +#define DEFAULT_MTU 1100 + +/*flags:# voice_call_id:flags.2?int128 in_seq_no:flags.4?int out_seq_no:flags.4?int + * recent_received_mask:flags.5?int proto:flags.3?int extra:flags.1?string raw_data:flags.0?string*/ +#define PFLAG_HAS_DATA 1 +#define PFLAG_HAS_EXTRA 2 +#define PFLAG_HAS_CALL_ID 4 +#define PFLAG_HAS_PROTO 8 +#define PFLAG_HAS_SEQ 16 +#define PFLAG_HAS_RECENT_RECV 32 +#define PFLAG_HAS_SENDER_TAG_HASH 64 + +#define XPFLAG_HAS_EXTRA 1 + +#define EXTRA_TYPE_STREAM_FLAGS 1 +#define EXTRA_TYPE_STREAM_CSD 2 +#define EXTRA_TYPE_LAN_ENDPOINT 3 +#define EXTRA_TYPE_NETWORK_CHANGED 4 +#define EXTRA_TYPE_GROUP_CALL_KEY 5 +#define EXTRA_TYPE_REQUEST_GROUP 6 +#define EXTRA_TYPE_IPV6_ENDPOINT 7 + +#define STREAM_FLAG_ENABLED 1 +#define STREAM_FLAG_DTX 2 +#define STREAM_FLAG_EXTRA_EC 4 + +#define STREAM_RFLAG_SUPPORTED 1 + +#define INIT_FLAG_DATA_SAVING_ENABLED 1 +#define INIT_FLAG_GROUP_CALLS_SUPPORTED 2 + +#define TLID_DECRYPTED_AUDIO_BLOCK 0xDBF948C1 +#define TLID_SIMPLE_AUDIO_BLOCK 0xCC0D0E76 +#define TLID_UDP_REFLECTOR_PEER_INFO 0x27D9371C +#define TLID_UDP_REFLECTOR_PEER_INFO_IPV6 0x83fc73b1 +#define TLID_UDP_REFLECTOR_SELF_INFO 0xc01572c7 +#define TLID_UDP_REFLECTOR_REQUEST_PACKETS_INFO 0x1a06fc96 +#define TLID_UDP_REFLECTOR_LAST_PACKETS_INFO 0x0e107305 +#define TLID_VECTOR 0x1cb5c415 +#define PAD4(x) (4-(x+(x<=253 ? 1 : 0))%4) + +#define MAX_RECENT_PACKETS 64 + +#define MAX(a,b) (a>b ? a : b) +#define MIN(a,b) (as2) && (s1-s2<=SEQ_MAX/2)) || ((s1SEQ_MAX/2)); +} + + +#endif //TGVOIP_PRIVATEDEFINES_H diff --git a/VoIPController.cpp b/VoIPController.cpp index 29a5271e06..820f8b770e 100644 --- a/VoIPController.cpp +++ b/VoIPController.cpp @@ -14,11 +14,11 @@ #include "VoIPController.h" #include "logging.h" #include "threading.h" -#include "BufferOutputStream.h" -#include "BufferInputStream.h" +#include "Buffers.h" #include "OpusEncoder.h" #include "OpusDecoder.h" #include "VoIPServerConfig.h" +#include "PrivateDefines.h" #include #include #include @@ -27,72 +27,6 @@ #include -#define PKT_INIT 1 -#define PKT_INIT_ACK 2 -#define PKT_STREAM_STATE 3 -#define PKT_STREAM_DATA 4 -#define PKT_UPDATE_STREAMS 5 -#define PKT_PING 6 -#define PKT_PONG 7 -#define PKT_STREAM_DATA_X2 8 -#define PKT_STREAM_DATA_X3 9 -#define PKT_LAN_ENDPOINT 10 -#define PKT_NETWORK_CHANGED 11 -#define PKT_SWITCH_PREF_RELAY 12 -#define PKT_SWITCH_TO_P2P 13 -#define PKT_NOP 14 -#define PKT_GROUP_CALL_KEY 15 -#define PKT_REQUEST_GROUP 16 - -#define IS_MOBILE_NETWORK(x) (x==NET_TYPE_GPRS || x==NET_TYPE_EDGE || x==NET_TYPE_3G || x==NET_TYPE_HSPA || x==NET_TYPE_LTE || x==NET_TYPE_OTHER_MOBILE) - -#define PROTOCOL_NAME 0x50567247 // "GrVP" in little endian (reversed here) -#define PROTOCOL_VERSION 5 -#define MIN_PROTOCOL_VERSION 3 - -#define STREAM_DATA_FLAG_LEN16 0x40 -#define STREAM_DATA_FLAG_HAS_MORE_FLAGS 0x80 - -#define STREAM_TYPE_AUDIO 1 -#define STREAM_TYPE_VIDEO 2 - -#define FOURCC(a,b,c,d) ((uint32_t)d | ((uint32_t)c << 8) | ((uint32_t)b << 16) | ((uint32_t)a << 24)) - -#define CODEC_OPUS_OLD 1 -#define CODEC_OPUS FOURCC('O','P','U','S') - -/*flags:# voice_call_id:flags.2?int128 in_seq_no:flags.4?int out_seq_no:flags.4?int - * recent_received_mask:flags.5?int proto:flags.3?int extra:flags.1?string raw_data:flags.0?string*/ -#define PFLAG_HAS_DATA 1 -#define PFLAG_HAS_EXTRA 2 -#define PFLAG_HAS_CALL_ID 4 -#define PFLAG_HAS_PROTO 8 -#define PFLAG_HAS_SEQ 16 -#define PFLAG_HAS_RECENT_RECV 32 -#define PFLAG_HAS_SENDER_TAG_HASH 64 - -#define STREAM_FLAG_ENABLED 1 -#define STREAM_FLAG_DTX 2 - -#define STREAM_RFLAG_SUPPORTED 1 - -#define INIT_FLAG_DATA_SAVING_ENABLED 1 -#define INIT_FLAG_GROUP_CALLS_SUPPORTED 2 - -#define TLID_DECRYPTED_AUDIO_BLOCK 0xDBF948C1 -#define TLID_SIMPLE_AUDIO_BLOCK 0xCC0D0E76 -#define TLID_UDP_REFLECTOR_PEER_INFO 0x27D9371C -#define TLID_UDP_REFLECTOR_PEER_INFO_IPV6 0x83fc73b1 -#define TLID_UDP_REFLECTOR_SELF_INFO 0xc01572c7 -#define TLID_UDP_REFLECTOR_REQUEST_PACKETS_INFO 0x1a06fc96 -#define TLID_UDP_REFLECTOR_LAST_PACKETS_INFO 0x0e107305 -#define TLID_VECTOR 0x1cb5c415 -#define PAD4(x) (4-(x+(x<=253 ? 1 : 0))%4) - -#define MAX_RECENT_PACKETS 64 - -#define MAX(a,b) (a>b ? a : b) -#define MIN(a,b) (a @@ -169,7 +101,7 @@ void tgvoip_openssl_aes_cbc_decrypt(uint8_t* in, uint8_t* out, size_t length, ui AES_cbc_encrypt(in, out, length, &akey, iv, AES_DECRYPT); } -voip_crypto_functions_t VoIPController::crypto={ +CryptoFunctions VoIPController::crypto={ tgvoip_openssl_rand_bytes, tgvoip_openssl_sha1, tgvoip_openssl_sha256, @@ -181,14 +113,9 @@ voip_crypto_functions_t VoIPController::crypto={ }; #else -voip_crypto_functions_t VoIPController::crypto; // set it yourself upon initialization +CryptoFunctions VoIPController::crypto; // set it yourself upon initialization #endif -#ifdef _MSC_VER -#define MSC_STACK_FALLBACK(a, b) (b) -#else -#define MSC_STACK_FALLBACK(a, b) (a) -#endif extern FILE* tgvoipLogFile; @@ -213,11 +140,11 @@ VoIPController::VoIPController() : activeNetItfName(""), memset(recvPacketTimes, 0, sizeof(double)*32); memset(rttHistory, 0, sizeof(double)*32); memset(sendLossCountHistory, 0, sizeof(uint32_t)*32); - memset(&stats, 0, sizeof(voip_stats_t)); + memset(&stats, 0, sizeof(TrafficStats)); lastRemoteAckSeq=0; lastSentSeq=0; recvLossCount=0; - packetsRecieved=0; + packetsReceived=0; waitingForAcks=false; networkType=NET_TYPE_UNKNOWN; echoCanceller=NULL; @@ -266,11 +193,16 @@ VoIPController::VoIPController() : activeNetItfName(""), didReceiveGroupCallKeyAck=false; didSendGroupCallKey=false; didSendUpgradeRequest=false; - didInvokeUpdateCallback=false; + didInvokeUpgradeCallback=false; connectionMaxLayer=0; useMTProto2=false; setCurrentEndpointToTCP=false; + useIPv6=false; + peerIPv6Available=false; + shittyInternetMode=false; + didAddIPv6Relays=false; + didSendIPv6Endpoint=false; sendThread=NULL; recvThread=NULL; @@ -300,44 +232,29 @@ VoIPController::VoIPController() : activeNetItfName(""), appleAudioIO=new audio::AudioUnitIO(); #if TARGET_OS_OSX }else{ - appleAudioIO=NULL; + appleAudioIO=NULL; } #endif #endif - Stream stm; - stm.id=1; - stm.type=STREAM_TYPE_AUDIO; - stm.codec=CODEC_OPUS; - stm.enabled=1; - stm.frameDuration=60; + shared_ptr stm=make_shared(); + stm->id=1; + stm->type=STREAM_TYPE_AUDIO; + stm->codec=CODEC_OPUS; + stm->enabled=1; + stm->frameDuration=60; outgoingStreams.push_back(stm); + /*Stream vstm={0}; + vstm.id=2; + vstm.type=STREAM_TYPE_VIDEO; + vstm.codec=CODEC_AVC; + vstm.enabled=1; + outgoingStreams.push_back(vstm);*/ + memset(signalBarsHistory, 0, sizeof(signalBarsHistory)); } -VoIPGroupController::VoIPGroupController(int32_t timeDifference){ - audioMixer=new AudioMixer(); - memset(&callbacks, 0, sizeof(callbacks)); - userSelfID=0; - this->timeDifference=timeDifference; - LOGV("Created VoIPGroupController; timeDifference=%d", timeDifference); -} - -VoIPGroupController::~VoIPGroupController(){ - if(audioOutput){ - audioOutput->Stop(); - } - LOGD("before stop audio mixer"); - audioMixer->Stop(); - delete audioMixer; - - for(std::vector::iterator p=participants.begin();p!=participants.end();p++){ - if(p->levelMeter) - delete p->levelMeter; - } -} - VoIPController::~VoIPController(){ LOGD("Entered VoIPController::~VoIPController"); if(!stopping){ @@ -349,11 +266,12 @@ VoIPController::~VoIPController(){ delete udpSocket; if(udpSocket!=realUdpSocket) delete realUdpSocket; - for(std::vector::iterator stm=incomingStreams.begin();stm!=incomingStreams.end();++stm){ - LOGD("before delete jitter buffer"); - if(stm->jitterBuffer){ + for(vector>::iterator _stm=incomingStreams.begin();_stm!=incomingStreams.end();++_stm){ + //LOGD("before delete jitter buffer"); + shared_ptr stm=*_stm; + /*if(stm->jitterBuffer){ delete stm->jitterBuffer; - } + }*/ LOGD("before stop decoder"); if(stm->decoder){ stm->decoder->Stop(); @@ -368,42 +286,41 @@ VoIPController::~VoIPController(){ encoder->Stop(); delete encoder; } - LOGD("before delete audio output"); - if(audioOutput){ - delete audioOutput; - } + //LOGD("before delete audio output"); + //if(audioOutput){ + // delete audioOutput; + //} #ifdef __APPLE__ LOGD("before delete AudioUnitIO"); if(appleAudioIO){ delete appleAudioIO; } #endif - for(std::vector::iterator stm=incomingStreams.begin();stm!=incomingStreams.end();++stm){ + /*for(vector>::iterator stm=incomingStreams.begin();stm!=incomingStreams.end();++stm){ LOGD("before delete decoder"); - if(stm->decoder){ - delete stm->decoder; + if((*stm)->decoder){ + delete (*stm)->decoder; } - } + }*/ LOGD("before delete echo canceller"); if(echoCanceller){ echoCanceller->Stop(); delete echoCanceller; } delete sendQueue; - unsigned int i; - for(i=0;idata) free(queuedPackets[i]->data); free(queuedPackets[i]); - } + }*/ delete conctl; - for(std::vector::iterator itr=endpoints.begin();itr!=endpoints.end();++itr){ + /*for(vector::iterator itr=endpoints.begin();itr!=endpoints.end();++itr){ if((*itr)->socket){ (*itr)->socket->Close(); delete (*itr)->socket; } delete *itr; - } + }*/ if(tgvoipLogFile){ FILE* log=tgvoipLogFile; tgvoipLogFile=NULL; @@ -458,7 +375,7 @@ void VoIPController::Stop(){ LOGD("Left VoIPController::Stop"); } -void VoIPController::SetRemoteEndpoints(std::vector endpoints, bool allowP2p, int32_t connectionMaxLayer){ +void VoIPController::SetRemoteEndpoints(vector endpoints, bool allowP2p, int32_t connectionMaxLayer){ LOGW("Set remote endpoints, allowP2P=%d, connectionMaxLayer=%u", allowP2p ? 1 : 0, connectionMaxLayer); preferredRelay=NULL; { @@ -466,8 +383,8 @@ void VoIPController::SetRemoteEndpoints(std::vector endpoints, bool al this->endpoints.clear(); didAddTcpRelays=false; useTCP=true; - for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ - this->endpoints.push_back(new Endpoint(*itrtr)); + for(vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ + this->endpoints.push_back(make_shared(*itrtr)); if(itrtr->type==Endpoint::TYPE_TCP_RELAY) didAddTcpRelays=true; if(itrtr->type==Endpoint::TYPE_UDP_RELAY) @@ -482,6 +399,7 @@ void VoIPController::SetRemoteEndpoints(std::vector endpoints, bool al if(connectionMaxLayer>=74){ useMTProto2=true; } + AddIPv6Relays(); } void VoIPController::Start(){ @@ -506,18 +424,18 @@ void VoIPController::Start(){ tickThread->Start(); } -size_t VoIPController::AudioInputCallback(unsigned char* data, size_t length, void* param){ - ((VoIPController*)param)->HandleAudioInput(data, length); - return 0; +void VoIPController::AudioInputCallback(unsigned char* data, size_t length, unsigned char* secondaryData, size_t secondaryLength, void* param){ + ((VoIPController*)param)->HandleAudioInput(data, length, secondaryData, secondaryLength); } -void VoIPController::HandleAudioInput(unsigned char *data, size_t len){ +void VoIPController::HandleAudioInput(unsigned char *data, size_t len, unsigned char* secondaryData, size_t secondaryLen){ if(stopping) return; if(waitingForAcks || dontSendPackets>0){ LOGV("waiting for RLC, dropping outgoing audio packet"); return; } + //LOGV("Audio packet size %u", (unsigned int)len); unsigned char* buf=outgoingPacketsBufferPool.Get(); if(buf){ @@ -537,12 +455,50 @@ void VoIPController::HandleAudioInput(unsigned char *data, size_t len){ /*.type=*/PKT_STREAM_DATA, /*.len=*/pkt.GetLength(), /*.data=*/buf, - /*.endpoint=*/NULL, + /*.endpoint=*/0, }; sendQueue->Put(p); } + if(secondaryData && secondaryLen && shittyInternetMode){ + Buffer ecBuf(secondaryLen); + ecBuf.CopyFrom(secondaryData, 0, secondaryLen); + ecAudioPackets.push_back(move(ecBuf)); + while(ecAudioPackets.size()>4) + ecAudioPackets.erase(ecAudioPackets.begin()); + buf=outgoingPacketsBufferPool.Get(); + if(buf){ + BufferOutputStream pkt(buf, outgoingPacketsBufferPool.GetSingleBufferSize()); + pkt.WriteByte(outgoingStreams[0]->id); + pkt.WriteInt32(audioTimestampOut); + pkt.WriteByte((unsigned char)ecAudioPackets.size()); + for(Buffer& ecData:ecAudioPackets){ + pkt.WriteByte((unsigned char)ecData.Length()); + pkt.WriteBytes(ecData); + } + + PendingOutgoingPacket p{ + GenerateOutSeq(), + PKT_STREAM_EC, + pkt.GetLength(), + buf, + 0 + }; + sendQueue->Put(p); + } + } + + audioTimestampOut+=outgoingStreams[0]->frameDuration; +} + +void VoIPController::HandleVideoInput(EncodedVideoFrame& frame){ + if(stopping) + return; + if(waitingForAcks || dontSendPackets>0 || networkType==NET_TYPE_EDGE || networkType==NET_TYPE_GPRS){ + LOGV("dropping outgoing video packet"); + return; + } + - audioTimestampOut+=outgoingStreams[0].frameDuration; } void VoIPController::Connect(){ @@ -572,181 +528,6 @@ void VoIPController::SetEncryptionKey(char *key, bool isOutgoing){ this->isOutgoing=isOutgoing; } -void VoIPGroupController::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){ - Endpoint* e=new Endpoint(); - e->address=reflectorAddress; - e->v6address=reflectorAddressV6; - e->port=reflectorPort; - memcpy(e->peerTag, reflectorGroupTag, 16); - e->type=Endpoint::TYPE_UDP_RELAY; - endpoints.push_back(e); - groupReflector=e; - currentEndpoint=e; - - memcpy(this->encryptionKey, encryptionKey, 256); - memcpy(this->reflectorSelfTag, reflectorSelfTag, 16); - memcpy(this->reflectorSelfSecret, reflectorSelfSecret, 16); - memcpy(this->reflectorSelfTagHash, reflectorSelfTagHash, 16); - uint8_t sha256[SHA256_LENGTH]; - crypto.sha256((uint8_t*) encryptionKey, 256, sha256); - memcpy(callID, sha256+(SHA256_LENGTH-16), 16); - memcpy(keyFingerprint, sha256+(SHA256_LENGTH-16), 8); - this->userSelfID=selfUserID; - - //LOGD("reflectorSelfTag = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", reflectorSelfTag[0], reflectorSelfTag[1], reflectorSelfTag[2], reflectorSelfTag[3], reflectorSelfTag[4], reflectorSelfTag[5], reflectorSelfTag[6], reflectorSelfTag[7], reflectorSelfTag[8], reflectorSelfTag[9], reflectorSelfTag[10], reflectorSelfTag[11], reflectorSelfTag[12], reflectorSelfTag[13], reflectorSelfTag[14], reflectorSelfTag[15]); - //LOGD("reflectorSelfSecret = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", reflectorSelfSecret[0], reflectorSelfSecret[1], reflectorSelfSecret[2], reflectorSelfSecret[3], reflectorSelfSecret[4], reflectorSelfSecret[5], reflectorSelfSecret[6], reflectorSelfSecret[7], reflectorSelfSecret[8], reflectorSelfSecret[9], reflectorSelfSecret[10], reflectorSelfSecret[11], reflectorSelfSecret[12], reflectorSelfSecret[13], reflectorSelfSecret[14], reflectorSelfSecret[15]); - //LOGD("reflectorSelfTagHash = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", reflectorSelfTagHash[0], reflectorSelfTagHash[1], reflectorSelfTagHash[2], reflectorSelfTagHash[3], reflectorSelfTagHash[4], reflectorSelfTagHash[5], reflectorSelfTagHash[6], reflectorSelfTagHash[7], reflectorSelfTagHash[8], reflectorSelfTagHash[9], reflectorSelfTagHash[10], reflectorSelfTagHash[11], reflectorSelfTagHash[12], reflectorSelfTagHash[13], reflectorSelfTagHash[14], reflectorSelfTagHash[15]); -} - -void VoIPGroupController::AddGroupCallParticipant(int32_t userID, unsigned char *memberTagHash, unsigned char* serializedStreams, size_t streamsLength){ - if(userID==userSelfID) - return; - if(userSelfID==0) - return; - //if(streamsLength==0) - // return; - MutexGuard m(participantsMutex); - //LOGV("Adding group call user %d, streams length %u, streams %X", userID, streamsLength, serializedStreams); - - for(std::vector::iterator p=participants.begin();p!=participants.end();++p){ - if(p->userID==userID){ - LOGE("user %d already added", userID); - abort(); - break; - } - } - - GroupCallParticipant p; - p.userID=userID; - memcpy(p.memberTagHash, memberTagHash, sizeof(p.memberTagHash)); - p.levelMeter=new AudioLevelMeter(); - - BufferInputStream ss(serializedStreams, streamsLength); - std::vector streams=DeserializeStreams(ss); - - unsigned char audioStreamID=0; - - for(std::vector::iterator s=streams.begin();s!=streams.end();++s){ - s->userID=userID; - if(s->type==STREAM_TYPE_AUDIO && s->codec==CODEC_OPUS && !audioStreamID){ - audioStreamID=s->id; - s->jitterBuffer=new JitterBuffer(NULL, s->frameDuration); - if(s->frameDuration>50) - s->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_60", 2)); - else if(s->frameDuration>30) - s->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_40", 4)); - else - s->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_20", 6)); - s->callbackWrapper=new CallbackWrapper(); - s->decoder=new OpusDecoder(s->callbackWrapper, false); - s->decoder->SetJitterBuffer(s->jitterBuffer); - s->decoder->SetFrameDuration(s->frameDuration); - s->decoder->SetDTX(true); - s->decoder->SetLevelMeter(p.levelMeter); - audioMixer->AddInput(s->callbackWrapper); - } - incomingStreams.push_back(*s); - } - - if(!audioStreamID){ - LOGW("User %d has no usable audio stream", userID); - } - - p.streams.insert(p.streams.end(), streams.begin(), streams.end()); - participants.push_back(p); - LOGI("Added group call participant %d", userID); -} - -void VoIPGroupController::RemoveGroupCallParticipant(int32_t userID){ - MutexGuard m(participantsMutex); - std::vector::iterator stm=incomingStreams.begin(); - while(stm!=incomingStreams.end()){ - if(stm->userID==userID){ - LOGI("Removed stream %d belonging to user %d", stm->id, userID); - audioMixer->RemoveInput(stm->callbackWrapper); - stm->decoder->Stop(); - delete stm->decoder; - delete stm->jitterBuffer; - delete stm->callbackWrapper; - stm=incomingStreams.erase(stm); - continue; - } - ++stm; - } - for(std::vector::iterator p=participants.begin();p!=participants.end();++p){ - if(p->userID==userID){ - if(p->levelMeter) - delete p->levelMeter; - participants.erase(p); - LOGI("Removed group call participant %d", userID); - break; - } - } -} - -std::vector VoIPGroupController::DeserializeStreams(BufferInputStream& in){ - std::vector res; - try{ - unsigned char count=in.ReadByte(); - for(unsigned char i=0;i::iterator p=participants.begin();p!=participants.end();++p){ - if(p->userID==userID){ - BufferInputStream in(serializedStreams, length); - std::vector streams=DeserializeStreams(in); - for(std::vector::iterator ns=streams.begin();ns!=streams.end();++ns){ - bool found=false; - for(std::vector::iterator s=p->streams.begin();s!=p->streams.end();++s){ - if(s->id==ns->id){ - s->enabled=ns->enabled; - if(groupCallbacks.participantAudioStateChanged) - groupCallbacks.participantAudioStateChanged(this, userID, s->enabled); - found=true; - break; - } - } - if(!found){ - LOGW("Tried to add stream %d for user %d but adding/removing streams is not supported", ns->id, userID); - } - } - break; - } - } -} - -size_t VoIPGroupController::GetInitialStreams(unsigned char *buf, size_t size){ - BufferOutputStream s(buf, size); - s.WriteByte(1); // streams count - - s.WriteInt16(12); // this object length - s.WriteByte(1); // stream id - s.WriteByte(STREAM_TYPE_AUDIO); - s.WriteInt32(CODEC_OPUS); - s.WriteInt32(STREAM_FLAG_ENABLED | STREAM_FLAG_DTX); // flags - s.WriteInt16(60); // frame duration - - return s.GetLength(); -} - uint32_t VoIPController::GenerateOutSeq(){ return seq++; } @@ -822,6 +603,23 @@ void VoIPController::WritePacketHeader(uint32_t pseq, BufferOutputStream *s, uns s->WriteInt32(lastRemoteSeq); s->WriteInt32(pseq); s->WriteInt32(acks); + if(peerVersion>=6){ + if(currentExtras.empty()){ + s->WriteByte(0); + }else{ + s->WriteByte(XPFLAG_HAS_EXTRA); + s->WriteByte(static_cast(currentExtras.size())); + for(vector::iterator x=currentExtras.begin();x!=currentExtras.end();++x){ + LOGV("Writing extra into header: type %u, length %lu", x->type, x->data.Length()); + assert(x->data.Length()<=254); + s->WriteByte(static_cast(x->data.Length()+1)); + s->WriteByte(x->type); + s->WriteBytes(*x->data, x->data.Length()); + if(x->firstContainingSeq==0) + x->firstContainingSeq=pseq; + } + } + } } if(type==PKT_STREAM_DATA || type==PKT_STREAM_DATA_X2 || type==PKT_STREAM_DATA_X3) @@ -864,8 +662,8 @@ void VoIPController::SendInit(){ { MutexGuard m(endpointsMutex); uint32_t initSeq=GenerateOutSeq(); - for(std::vector::iterator itr=endpoints.begin(); itr!=endpoints.end(); ++itr){ - if((*itr)->type==Endpoint::TYPE_TCP_RELAY && !useTCP) + for(shared_ptr& e:endpoints){ + if(e->type==Endpoint::TYPE_TCP_RELAY && !useTCP) continue; unsigned char *pkt=outgoingPacketsBufferPool.Get(); if(!pkt){ @@ -888,10 +686,16 @@ void VoIPController::SendInit(){ out.WriteByte(0); out.WriteByte(0); out.WriteInt32(CODEC_OPUS); - out.WriteByte(0); // video codecs count + out.WriteByte(0); // video codecs count (decode) + out.WriteByte(0); // video codecs count (encode) }else{ out.WriteByte(1); out.WriteInt32(CODEC_OPUS); + /*out.WriteByte(1); + out.WriteInt32(CODEC_AVC); + out.WriteByte(1); + out.WriteInt32(CODEC_AVC);*/ + out.WriteByte(0); out.WriteByte(0); } sendQueue->Put(PendingOutgoingPacket{ @@ -899,17 +703,13 @@ void VoIPController::SendInit(){ /*.type=*/PKT_INIT, /*.len=*/out.GetLength(), /*.data=*/pkt, - /*.endpoint=*/*itr + /*.endpoint=*/e->id }); } } SetState(STATE_WAIT_INIT_ACK); } -void VoIPGroupController::SendInit(){ - SendRecentPacketsRequest(); -} - void VoIPController::InitUDPProxy(){ if(realUdpSocket!=udpSocket){ udpSocket->Close(); @@ -919,6 +719,7 @@ void VoIPController::InitUDPProxy(){ NetworkSocket* tcp=NetworkSocket::Create(PROTO_TCP); tcp->Connect(resolvedProxyAddress, proxyPort); if(tcp->IsFailed()){ + lastError=ERROR_PROXY; SetState(STATE_FAILED); tcp->Close(); delete tcp; @@ -940,38 +741,42 @@ void VoIPController::InitUDPProxy(){ void VoIPController::RunRecvThread(void* arg){ LOGI("Receive thread starting"); - unsigned char *buffer = (unsigned char *)malloc(1500); + unsigned char *buffer = (unsigned char *)malloc(1500); NetworkPacket packet={0}; while(runReceiver){ packet.data=buffer; packet.length=1500; - std::vector readSockets; - std::vector errorSockets; + vector readSockets; + vector errorSockets; readSockets.push_back(realUdpSocket); errorSockets.push_back(realUdpSocket); - //if(useTCP){ - for(std::vector::iterator itr=endpoints.begin();itr!=endpoints.end();++itr){ - if((*itr)->type==Endpoint::TYPE_TCP_RELAY){ - if((*itr)->socket){ - readSockets.push_back((*itr)->socket); - errorSockets.push_back((*itr)->socket); + { + MutexGuard m(endpointsMutex); + for(shared_ptr& e:endpoints){ + if(e->type==Endpoint::TYPE_TCP_RELAY){ + if(e->socket){ + readSockets.push_back(e->socket); + errorSockets.push_back(e->socket); } } } - //} + } - bool selRes=NetworkSocket::Select(readSockets, errorSockets, selectCanceller); - if(!selRes){ - LOGV("Select canceled"); - continue; + { + MutexGuard m(socketSelectMutex); + bool selRes=NetworkSocket::Select(readSockets, errorSockets, selectCanceller); + if(!selRes){ + LOGV("Select canceled"); + continue; + } } if(!runReceiver) return; if(!errorSockets.empty()){ - if(std::find(errorSockets.begin(), errorSockets.end(), realUdpSocket)!=errorSockets.end()){ + if(find(errorSockets.begin(), errorSockets.end(), realUdpSocket)!=errorSockets.end()){ LOGW("UDP socket failed"); SetState(STATE_FAILED); return; @@ -980,20 +785,20 @@ void VoIPController::RunRecvThread(void* arg){ NetworkSocket* socket=NULL; - if(std::find(readSockets.begin(), readSockets.end(), realUdpSocket)!=readSockets.end()){ + if(find(readSockets.begin(), readSockets.end(), realUdpSocket)!=readSockets.end()){ socket=udpSocket; }else if(readSockets.size()>0){ socket=readSockets[0]; }else{ LOGI("no sockets to read from"); MutexGuard m(endpointsMutex); - for(std::vector::iterator itr=errorSockets.begin();itr!=errorSockets.end();++itr){ - for(std::vector::iterator e=endpoints.begin();e!=endpoints.end();++e){ - if((*e)->socket && (*e)->socket==*itr){ - (*e)->socket->Close(); - delete (*e)->socket; - (*e)->socket=NULL; - LOGI("Closing failed TCP socket for %s:%u", (*e)->address.ToString().c_str(), (*e)->port); + for(vector::iterator itr=errorSockets.begin();itr!=errorSockets.end();++itr){ + for(shared_ptr& e:endpoints){ + if(e->socket && e->socket==*itr){ + e->socket->Close(); + delete e->socket; + e->socket=NULL; + LOGI("Closing failed TCP socket for %s:%u", e->GetAddress().ToString().c_str(), e->port); break; } } @@ -1012,19 +817,32 @@ void VoIPController::RunRecvThread(void* arg){ continue; } //LOGV("Received %d bytes from %s:%d at %.5lf", len, packet.address->ToString().c_str(), packet.port, GetCurrentTime()); - Endpoint* srcEndpoint=NULL; + shared_ptr srcEndpoint; IPv4Address* src4=dynamic_cast(packet.address); if(src4){ MutexGuard m(endpointsMutex); - for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ - if((*itrtr)->address==*src4 && (*itrtr)->port==packet.port){ - if(((*itrtr)->type!=Endpoint::TYPE_TCP_RELAY && packet.protocol==PROTO_UDP) || ((*itrtr)->type==Endpoint::TYPE_TCP_RELAY && packet.protocol==PROTO_TCP)){ - srcEndpoint=*itrtr; + for(shared_ptr& e:endpoints){ + if(e->address==*src4 && e->port==packet.port){ + if((e->type!=Endpoint::TYPE_TCP_RELAY && packet.protocol==PROTO_UDP) || (e->type==Endpoint::TYPE_TCP_RELAY && packet.protocol==PROTO_TCP)){ + srcEndpoint=e; break; } } } + }else{ + IPv6Address* src6=dynamic_cast(packet.address); + if(src6){ + MutexGuard m(endpointsMutex); + for(shared_ptr& e:endpoints){ + if(e->v6address==*src6 && e->port==packet.port && e->address.IsEmpty()){ + if((e->type!=Endpoint::TYPE_TCP_RELAY && packet.protocol==PROTO_UDP) || (e->type==Endpoint::TYPE_TCP_RELAY && packet.protocol==PROTO_TCP)){ + srcEndpoint=e; + break; + } + } + } + } } if(!srcEndpoint){ @@ -1041,11 +859,11 @@ void VoIPController::RunRecvThread(void* arg){ stats.bytesRecvdWifi+=(uint64_t)len; try{ ProcessIncomingPacket(packet, srcEndpoint); - }catch(std::out_of_range x){ + }catch(out_of_range x){ LOGW("Error parsing packet: %s", x.what()); } } - free(buffer); + free(buffer); LOGI("=== recv thread exiting ==="); } @@ -1054,8 +872,13 @@ void VoIPController::RunSendThread(void* arg){ while(runReceiver){ PendingOutgoingPacket pkt=sendQueue->GetBlocking(); if(pkt.data){ - MutexGuard m(endpointsMutex); - Endpoint *endpoint=pkt.endpoint ? pkt.endpoint : currentEndpoint; + shared_ptr endpoint; + if(pkt.endpoint){ + endpoint=GetEndpointByID(pkt.endpoint); + } + if(!endpoint){ // either packet has no endpoint specified or it no longer exists + endpoint=currentEndpoint; + } if((endpoint->type==Endpoint::TYPE_TCP_RELAY && useTCP) || (endpoint->type!=Endpoint::TYPE_TCP_RELAY && useUDP)){ BufferOutputStream p(buf, sizeof(buf)); WritePacketHeader(pkt.seq, &p, pkt.type, (uint32_t)pkt.len); @@ -1070,7 +893,7 @@ void VoIPController::RunSendThread(void* arg){ LOGI("=== send thread exiting ==="); } -void VoIPController::ProcessIncomingPacket(NetworkPacket &packet, Endpoint* srcEndpoint){ +void VoIPController::ProcessIncomingPacket(NetworkPacket &packet, shared_ptr srcEndpoint){ unsigned char* buffer=packet.data; size_t len=packet.length; BufferInputStream in(buffer, (size_t)len); @@ -1087,14 +910,29 @@ void VoIPController::ProcessIncomingPacket(NetworkPacket &packet, Endpoint* srcE if(tlid==TLID_UDP_REFLECTOR_SELF_INFO){ if(srcEndpoint->type==Endpoint::TYPE_UDP_RELAY /*&& udpConnectivityState==UDP_PING_SENT*/ && in.Remaining()>=32){ - /*int32_t date=*/in.ReadInt32(); - /*int64_t queryID=*/in.ReadInt64(); + int32_t date=in.ReadInt32(); + int64_t queryID=in.ReadInt64(); unsigned char myIP[16]; in.ReadBytes(myIP, 16); - /*int32_t myPort=*/in.ReadInt32(); + int32_t myPort=in.ReadInt32(); //udpConnectivityState=UDP_AVAILABLE; - //LOGV("Received UDP ping reply from %s:%d: date=%d, queryID=%lld, my IP=%s, my port=%d", srcEndpoint->address.ToString().c_str(), srcEndpoint->port, date, queryID, IPv6Address(myIP).ToString().c_str(), myPort); + LOGV("Received UDP ping reply from %s:%d: date=%d, queryID=%lld, my IP=%s, my port=%d", srcEndpoint->address.ToString().c_str(), srcEndpoint->port, date, queryID, IPv4Address(*reinterpret_cast(myIP+12)).ToString().c_str(), myPort); srcEndpoint->udpPongCount++; + if(srcEndpoint->IsIPv6Only() && !didSendIPv6Endpoint){ + IPv6Address realAddr(myIP); + if(realAddr==myIPv6){ + LOGI("Public IPv6 matches local address"); + useIPv6=true; + if(allowP2p){ + didSendIPv6Endpoint=true; + BufferOutputStream o(18); + o.WriteBytes(myIP, 16); + o.WriteInt16(udpSocket->GetLocalPort()); + Buffer b(move(o)); + SendExtra(b, EXTRA_TYPE_IPV6_ENDPOINT); + } + } + } } }else if(tlid==TLID_UDP_REFLECTOR_PEER_INFO){ if(waitingForRelayPeerInfo && in.Remaining()>=16){ @@ -1103,30 +941,28 @@ void VoIPController::ProcessIncomingPacket(NetworkPacket &packet, Endpoint* srcE uint32_t myPort=(uint32_t) in.ReadInt32(); uint32_t peerAddr=(uint32_t) in.ReadInt32(); uint32_t peerPort=(uint32_t) in.ReadInt32(); - for(std::vector::iterator itrtr=endpoints.begin(); itrtr!=endpoints.end(); ++itrtr){ - Endpoint *ep=*itrtr; - if(ep->type==Endpoint::TYPE_UDP_P2P_INET){ + for(vector>::iterator itrtr=endpoints.begin(); itrtr!=endpoints.end(); ++itrtr){ + shared_ptr ep=*itrtr; + if(ep->type==Endpoint::TYPE_UDP_P2P_INET && !ep->IsIPv6Only()){ if(currentEndpoint==ep) currentEndpoint=preferredRelay; - delete ep; endpoints.erase(itrtr); break; } } - for(std::vector::iterator itrtr=endpoints.begin(); itrtr!=endpoints.end(); ++itrtr){ - Endpoint *ep=*itrtr; + for(vector>::iterator itrtr=endpoints.begin(); itrtr!=endpoints.end(); ++itrtr){ + shared_ptr ep=*itrtr; if(ep->type==Endpoint::TYPE_UDP_P2P_LAN){ if(currentEndpoint==ep) currentEndpoint=preferredRelay; - delete ep; endpoints.erase(itrtr); break; } } IPv4Address _peerAddr(peerAddr); - IPv6Address emptyV6("::0"); + IPv6Address emptyV6(string("::0")); unsigned char peerTag[16]; - endpoints.push_back(new Endpoint(0, (uint16_t) peerPort, _peerAddr, emptyV6, Endpoint::TYPE_UDP_P2P_INET, peerTag)); + endpoints.push_back(make_shared((int64_t)(FOURCC('P','2','P','4')) << 32, (uint16_t) peerPort, _peerAddr, emptyV6, Endpoint::TYPE_UDP_P2P_INET, peerTag)); LOGW("Received reflector peer info, my=%08X:%u, peer=%08X:%u", myAddr, myPort, peerAddr, peerPort); if(myAddr==peerAddr){ LOGW("Detected LAN"); @@ -1136,7 +972,12 @@ void VoIPController::ProcessIncomingPacket(NetworkPacket &packet, Endpoint* srcE BufferOutputStream pkt(8); pkt.WriteInt32(lanAddr.GetAddress()); pkt.WriteInt32(udpSocket->GetLocalPort()); - SendPacketReliably(PKT_LAN_ENDPOINT, pkt.GetBuffer(), pkt.GetLength(), 0.5, 10); + if(peerVersion<6){ + SendPacketReliably(PKT_LAN_ENDPOINT, pkt.GetBuffer(), pkt.GetLength(), 0.5, 10); + }else{ + Buffer buf(move(pkt)); + SendExtra(buf, EXTRA_TYPE_LAN_ENDPOINT); + } } waitingForRelayPeerInfo=false; } @@ -1203,13 +1044,13 @@ void VoIPController::ProcessIncomingPacket(NetworkPacket &packet, Endpoint* srcE return; //LOGV("-> MSG KEY: %08x %08x %08x %08x, hashed %u", *reinterpret_cast(msgKey), *reinterpret_cast(msgKey+4), *reinterpret_cast(msgKey+8), *reinterpret_cast(msgKey+12), decryptedLen-4); - uint8_t *decryptOffset = packet.data + in.GetOffset(); - if ((((intptr_t)decryptOffset) % sizeof(long)) != 0) { - LOGE("alignment2 packet.data+in.GetOffset()"); - } - if (decryptedLen % sizeof(long) != 0) { - LOGE("alignment2 decryptedLen"); - } + /*uint8_t *decryptOffset = packet.data + in.GetOffset(); + if ((((intptr_t)decryptOffset) % sizeof(long)) != 0) { + LOGE("alignment2 packet.data+in.GetOffset()"); + } + if (decryptedLen % sizeof(long) != 0) { + LOGE("alignment2 decryptedLen"); + }*/ crypto.aes_ige_decrypt(packet.data+in.GetOffset(), decrypted, decryptedLen, aesKey, aesIv); in=BufferInputStream(decrypted, decryptedLen); @@ -1229,7 +1070,7 @@ void VoIPController::ProcessIncomingPacket(NetworkPacket &packet, Endpoint* srcE uint32_t innerLen=(uint32_t) in.ReadInt32(); if(innerLen>decryptedLen-4){ - LOGW("Received packet has wrong inner length (%d with total of %u)", innerLen, (unsigned int)decryptedLen); + LOGW("Received packet has wrong inner length (%d with total of %u)", (int)innerLen, (unsigned int)decryptedLen); return; } if(decryptedLen-innerLen<12){ @@ -1252,7 +1093,7 @@ void VoIPController::ProcessIncomingPacket(NetworkPacket &packet, Endpoint* srcE simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedAudioBlock; */ uint32_t ackId, pseq, acks; - unsigned char type; + unsigned char type, pflags; uint32_t tlid=(uint32_t) in.ReadInt32(); uint32_t packetInnerLen=0; if(tlid==TLID_DECRYPTED_AUDIO_BLOCK){ @@ -1297,6 +1138,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA if(flags & PFLAG_HAS_DATA){ packetInnerLen=in.ReadTlLength(); } + pflags=0; }else if(tlid==TLID_SIMPLE_AUDIO_BLOCK){ in.ReadInt64(); // random id uint32_t randLen=(uint32_t) in.ReadTlLength(); @@ -1306,16 +1148,16 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA ackId=(uint32_t) in.ReadInt32(); pseq=(uint32_t) in.ReadInt32(); acks=(uint32_t) in.ReadInt32(); + if(peerVersion>=6) + pflags=in.ReadByte(); + else + pflags=0; }else{ LOGW("Received a packet of unknown type %08X", tlid); return; } - if(type==PKT_GROUP_CALL_KEY && didSendGroupCallKey){ - LOGE("Received group call key after we sent one"); - return; - } - packetsRecieved++; + packetsReceived++; if(seqgt(pseq, lastRemoteSeq)){ uint32_t diff=pseq-lastRemoteSeq; if(diff>31){ @@ -1362,7 +1204,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA conctl->PacketAcknowledged(ackId); unsigned int i; for(i=0;i<31;i++){ - for(std::vector::iterator itr=recentOutgoingPackets.begin();itr!=recentOutgoingPackets.end();++itr){ + for(vector::iterator itr=recentOutgoingPackets.begin();itr!=recentOutgoingPackets.end();++itr){ if(itr->ackTime!=0) continue; if(((acks >> (31-i)) & 1) && itr->seq==ackId-(i+1)){ @@ -1378,19 +1220,19 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA }*/ } for(i=0;iseqs[j]); - if(qp->seqs[j]==0) + LOGD("queued packet %u, seq %u=%u", i, j, qp.seqs[j]); + if(qp.seqs[j]==0) break; - int remoteAcksIndex=lastRemoteAckSeq-qp->seqs[j]; + int remoteAcksIndex=lastRemoteAckSeq-qp.seqs[j]; //LOGV("remote acks index %u, value %f", remoteAcksIndex, remoteAcksIndex>=0 && remoteAcksIndex<32 ? remoteAcks[remoteAcksIndex] : -1); - if(seqgt(lastRemoteAckSeq, qp->seqs[j]) && remoteAcksIndex>=0 && remoteAcksIndex<32){ - for(std::vector::iterator itr=recentOutgoingPackets.begin();itr!=recentOutgoingPackets.end();++itr){ - if(itr->seq==qp->seqs[j] && itr->ackTime>0){ - LOGD("did ack seq %u, removing", qp->seqs[j]); + if(seqgt(lastRemoteAckSeq, qp.seqs[j]) && remoteAcksIndex>=0 && remoteAcksIndex<32){ + for(RecentOutgoingPacket& opkt:recentOutgoingPackets){ + if(opkt.seq==qp.seqs[j] && opkt.ackTime>0){ + LOGD("did ack seq %u, removing", qp.seqs[j]); didAck=true; break; } @@ -1400,19 +1242,20 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA } } if(didAck){ - if(qp->type==PKT_GROUP_CALL_KEY && !didReceiveGroupCallKeyAck){ - didReceiveGroupCallKeyAck=true; - if(callbacks.groupCallKeySent) - callbacks.groupCallKeySent(this); - } - if(qp->data) - free(qp->data); - free(qp); queuedPackets.erase(queuedPackets.begin()+i); i--; continue; } } + for(vector::iterator x=currentExtras.begin();x!=currentExtras.end();){ + if(x->firstContainingSeq!=0 && (lastRemoteAckSeq==x->firstContainingSeq || seqgt(lastRemoteAckSeq, x->firstContainingSeq))){ + LOGV("Peer acknowledged extra type %u length %lu", x->type, x->data.Length()); + ProcessAcknowledgedOutgoingExtra(*x); + x=currentExtras.erase(x); + continue; + } + ++x; + } } if(srcEndpoint!=currentEndpoint && (srcEndpoint->type==Endpoint::TYPE_UDP_RELAY || srcEndpoint->type==Endpoint::TYPE_TCP_RELAY) && ((currentEndpoint->type!=Endpoint::TYPE_UDP_RELAY && currentEndpoint->type!=Endpoint::TYPE_TCP_RELAY) || currentEndpoint->averageRTT==0)){ @@ -1424,6 +1267,16 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA } } + if(pflags & XPFLAG_HAS_EXTRA){ + unsigned char extraCount=in.ReadByte(); + for(int i=0;i %.2lf, %.2lf, %.2lf, %.2lf, %.2lf, %.2lf, %.2lf, %.2lf", lastRemoteAckSeq, remoteAcks[0], remoteAcks[1], remoteAcks[2], remoteAcks[3], remoteAcks[4], remoteAcks[5], remoteAcks[6], remoteAcks[7]); //LOGD("recv: %u -> %.2lf, %.2lf, %.2lf, %.2lf, %.2lf, %.2lf, %.2lf, %.2lf", lastRemoteSeq, recvPacketTimes[0], recvPacketTimes[1], recvPacketTimes[2], recvPacketTimes[3], recvPacketTimes[4], recvPacketTimes[5], recvPacketTimes[6], recvPacketTimes[7]); //LOGI("RTT = %.3lf", GetAverageRTT()); @@ -1483,22 +1336,22 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA out.WriteInt32(MIN_PROTOCOL_VERSION); out.WriteByte((unsigned char) outgoingStreams.size()); - for(i=0; i>::iterator s=outgoingStreams.begin();s!=outgoingStreams.end();++s){ + out.WriteByte((*s)->id); + out.WriteByte((*s)->type); if(peerVersion<5) - out.WriteByte((unsigned char) (outgoingStreams[i].codec==CODEC_OPUS ? CODEC_OPUS_OLD : 0)); + out.WriteByte((unsigned char) ((*s)->codec==CODEC_OPUS ? CODEC_OPUS_OLD : 0)); else - out.WriteInt32(outgoingStreams[i].codec); - out.WriteInt16(outgoingStreams[i].frameDuration); - out.WriteByte((unsigned char) (outgoingStreams[i].enabled ? 1 : 0)); + out.WriteInt32((*s)->codec); + out.WriteInt16((*s)->frameDuration); + out.WriteByte((unsigned char) ((*s)->enabled ? 1 : 0)); } sendQueue->Put(PendingOutgoingPacket{ /*.seq=*/GenerateOutSeq(), /*.type=*/PKT_INIT_ACK, /*.len=*/out.GetLength(), /*.data=*/buf, - /*.endpoint=*/NULL + /*.endpoint=*/0 }); } } @@ -1527,31 +1380,40 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA return; int i; - Stream *incomingAudioStream=NULL; + shared_ptr incomingAudioStream=NULL; for(i=0; i stm=make_shared(); + stm->id=in.ReadByte(); + stm->type=in.ReadByte(); if(peerVersion<5){ unsigned char codec=in.ReadByte(); if(codec==CODEC_OPUS_OLD) - stm.codec=CODEC_OPUS; + stm->codec=CODEC_OPUS; }else{ - stm.codec=(uint32_t) in.ReadInt32(); + stm->codec=(uint32_t) in.ReadInt32(); + } + stm->frameDuration=(uint16_t) in.ReadInt16(); + stm->enabled=in.ReadByte()==1; + if(stm->type==STREAM_TYPE_AUDIO){ + stm->jitterBuffer=make_shared(nullptr, stm->frameDuration); + if(stm->frameDuration>50) + stm->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_60", 3)); + else if(stm->frameDuration>30) + stm->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_40", 4)); + else + stm->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_20", 6)); + stm->decoder=NULL; + }else if(stm->type==STREAM_TYPE_VIDEO){ + if(!stm->packetReassembler){ + stm->packetReassembler=make_shared(); + } + }else{ + LOGW("Unknown incoming stream type: %d", stm->type); + continue; } - stm.frameDuration=(uint16_t) in.ReadInt16(); - stm.enabled=in.ReadByte()==1; - stm.jitterBuffer=new JitterBuffer(NULL, stm.frameDuration); - if(stm.frameDuration>50) - stm.jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_60", 3)); - else if(stm.frameDuration>30) - stm.jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_40", 4)); - else - stm.jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_20", 6)); - stm.decoder=NULL; incomingStreams.push_back(stm); - if(stm.type==STREAM_TYPE_AUDIO && !incomingAudioStream) - incomingAudioStream=&stm; + if(stm->type==STREAM_TYPE_AUDIO && !incomingAudioStream) + incomingAudioStream=stm; } if(!incomingAudioStream) return; @@ -1607,14 +1469,14 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA if(in.GetOffset()+sdlen>len){ return; } - if(incomingStreams.size()>0 && incomingStreams[0].jitterBuffer) - incomingStreams[0].jitterBuffer->HandleInput((unsigned char*) (buffer+in.GetOffset()), sdlen, pts); + if(incomingStreams.size()>0 && incomingStreams[0]->jitterBuffer /*&& !incomingStreams[0]->extraECEnabled*/) + incomingStreams[0]->jitterBuffer->HandleInput((unsigned char*) (buffer+in.GetOffset()), sdlen, pts, false); if(iToString().c_str(), srcEndpoint->port); + //LOGD("Received ping from %s:%d", srcEndpoint->address.ToString().c_str(), srcEndpoint->port); if(srcEndpoint->type!=Endpoint::TYPE_UDP_RELAY && srcEndpoint->type!=Endpoint::TYPE_TCP_RELAY && !allowP2p){ LOGW("Received p2p ping but p2p is disabled by manual override"); return; @@ -1631,7 +1493,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA /*.type=*/PKT_PONG, /*.len=*/pkt.GetLength(), /*.data=*/buf, - /*.endpoint=*/srcEndpoint, + /*.endpoint=*/srcEndpoint->id, }); } if(type==PKT_PONG){ @@ -1655,10 +1517,9 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA if(type==PKT_STREAM_STATE){ unsigned char id=in.ReadByte(); unsigned char enabled=in.ReadByte(); - unsigned int i; - for(i=0;i>::iterator s=incomingStreams.begin();s!=incomingStreams.end();++s){ + if((*s)->id==id){ + (*s)->enabled=enabled==1; UpdateAudioOutputState(); break; } @@ -1670,20 +1531,20 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA uint16_t peerPort=(uint16_t) in.ReadInt32(); MutexGuard m(endpointsMutex); bool found=false; - for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ - if((*itrtr)->type==Endpoint::TYPE_UDP_P2P_LAN){ - if(currentEndpoint==*itrtr) + for(shared_ptr& e:endpoints){ + if(e->type==Endpoint::TYPE_UDP_P2P_LAN){ + if(currentEndpoint==e) currentEndpoint=preferredRelay; found=true; - (*itrtr)->address=peerAddr; + e->address=peerAddr; break; } } if(!found){ - IPv4Address v4addr(peerAddr); - IPv6Address v6addr("::0"); - unsigned char peerTag[16]; - endpoints.push_back(new Endpoint(0, peerPort, v4addr, v6addr, Endpoint::TYPE_UDP_P2P_LAN, peerTag)); + IPv4Address v4addr(peerAddr); + IPv6Address v6addr(string("::0")); + unsigned char peerTag[16]; + endpoints.push_back(make_shared((int64_t)(FOURCC('L','A','N','4')) << 32, peerPort, v4addr, v6addr, Endpoint::TYPE_UDP_P2P_LAN, peerTag)); } } if(type==PKT_NETWORK_CHANGED && currentEndpoint->type!=Endpoint::TYPE_UDP_RELAY && currentEndpoint->type!=Endpoint::TYPE_TCP_RELAY){ @@ -1697,265 +1558,146 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA UpdateAudioBitrate(); } } - if(type==PKT_GROUP_CALL_KEY && !didReceiveGroupCallKey && !didSendGroupCallKey){ - unsigned char groupKey[256]; - in.ReadBytes(groupKey, 256); - if(callbacks.groupCallKeyReceived) - callbacks.groupCallKeyReceived(this, groupKey); - didReceiveGroupCallKey=true; - } - if(type==PKT_REQUEST_GROUP && !didInvokeUpdateCallback){ - if(callbacks.upgradeToGroupCallRequested) - callbacks.upgradeToGroupCallRequested(this); - didInvokeUpdateCallback=true; + if(type==PKT_STREAM_EC){ + unsigned char streamID=in.ReadByte(); + uint32_t lastTimestamp=(uint32_t)in.ReadInt32(); + unsigned char count=in.ReadByte(); + for(shared_ptr& stm:incomingStreams){ + if(stm->id==streamID){ + for(unsigned int i=0;ijitterBuffer){ + stm->jitterBuffer->HandleInput(data, dlen, lastTimestamp-(count-i-1)*stm->frameDuration, true); + } + } + break; + } + } } } -void VoIPGroupController::ProcessIncomingPacket(NetworkPacket &packet, Endpoint *srcEndpoint){ - //LOGD("Received incoming packet from %s:%u, %u bytes", packet.address->ToString().c_str(), packet.port, packet.length); - if(packet.length<17 || packet.length>2000){ - LOGW("Received packet has wrong length %d", (int)packet.length); +void VoIPController::ProcessExtraData(Buffer &data){ + BufferInputStream in(*data, data.Length()); + unsigned char type=in.ReadByte(); + unsigned char fullHash[SHA1_LENGTH]; + crypto.sha1(*data, data.Length(), fullHash); + uint64_t hash=*reinterpret_cast(fullHash); + if(lastReceivedExtrasByType[type]==hash){ return; } - BufferOutputStream sigData(packet.length); - sigData.WriteBytes(packet.data, packet.length-16); - sigData.WriteBytes(reflectorSelfSecret, 16); - unsigned char sig[32]; - crypto.sha256(sigData.GetBuffer(), sigData.GetLength(), sig); - if(memcmp(sig, packet.data+(packet.length-16), 16)!=0){ - LOGW("Received packet has incorrect signature"); - return; - } - - // reflector special response - if(memcmp(packet.data, reflectorSelfTagHash, 16)==0 && packet.length>60){ - //LOGI("possible reflector special response"); - unsigned char firstBlock[16]; - unsigned char iv[16]; - memcpy(iv, packet.data+16, 16); - unsigned char key[32]; - crypto.sha256(reflectorSelfSecret, 16, key); - crypto.aes_cbc_decrypt(packet.data+32, firstBlock, 16, key, iv); - BufferInputStream in(firstBlock, 16); - in.Seek(8); - size_t len=(size_t) in.ReadInt32(); - int32_t tlid=in.ReadInt32(); - //LOGD("special response: len=%d, tlid=0x%08X", len, tlid); - if(len%4==0 && len+60<=packet.length && packet.length<=1500){ - lastRecvPacketTime=GetCurrentTime(); - memcpy(iv, packet.data+16, 16); - unsigned char buf[1500]; - crypto.aes_cbc_decrypt(packet.data+32, buf, len+16, key, iv); - try{ - if(tlid==TLID_UDP_REFLECTOR_LAST_PACKETS_INFO){ - MutexGuard m(sentPacketsMutex); - //LOGV("received udpReflector.lastPacketsInfo"); - in=BufferInputStream(buf, len+16); - in.Seek(16); - /*int32_t date=*/in.ReadInt32(); - /*int64_t queryID=*/in.ReadInt64(); - int32_t vectorMagic=in.ReadInt32(); - if(vectorMagic!=TLID_VECTOR){ - LOGW("last packets info: expected vector, got %08X", vectorMagic); - return; + lastReceivedExtrasByType[type]=hash; + if(type==EXTRA_TYPE_STREAM_FLAGS){ + unsigned char id=in.ReadByte(); + uint32_t flags=static_cast(in.ReadInt32()); + for(shared_ptr& s:incomingStreams){ + if(s->id==id){ + s->enabled=(flags & STREAM_FLAG_ENABLED)==STREAM_FLAG_ENABLED; + if(flags & STREAM_FLAG_EXTRA_EC){ + if(!s->extraECEnabled){ + s->extraECEnabled=true; + if(s->jitterBuffer) + s->jitterBuffer->SetMinPacketCount(4); } - int32_t recvCount=in.ReadInt32(); - //LOGV("%d received packets", recvCount); - for(int i=0;i::iterator pkt=recentSentPackets.begin();pkt!=recentSentPackets.end();++pkt){ - //LOGV("== sent id %04X", pkt->id); - if(pkt->id==id){ - if(!pkt->ackTime){ - pkt->ackTime=GetCurrentTime(); - conctl->PacketAcknowledged(pkt->seq); - //LOGV("relay acknowledged packet %u", pkt->seq); - if(seqgt(pkt->seq, lastRemoteAckSeq)) - lastRemoteAckSeq=pkt->seq; - } - break; - } - } - } - vectorMagic=in.ReadInt32(); - if(vectorMagic!=TLID_VECTOR){ - LOGW("last packets info: expected vector, got %08X", vectorMagic); - return; - } - int32_t sentCount=in.ReadInt32(); - //LOGV("%d sent packets", sentCount); - for(int i=0;iStart(); - } + }else{ + if(s->extraECEnabled){ + s->extraECEnabled=false; + if(s->jitterBuffer) + s->jitterBuffer->SetMinPacketCount(2); } } - }catch(std::out_of_range& x){ - LOGE("Error parsing special response: %s", x.what()); + UpdateAudioOutputState(); + break; } + } + }else if(type==EXTRA_TYPE_STREAM_CSD){ + + }else if(type==EXTRA_TYPE_LAN_ENDPOINT){ + if(!allowP2p) return; - } - } - - if(packet.length<32) - return; - - // it's a packet relayed from another participant - find the sender - MutexGuard m(participantsMutex); - GroupCallParticipant* sender=NULL; - for(std::vector::iterator p=participants.begin();p!=participants.end();++p){ - if(memcmp(packet.data, p->memberTagHash, 16)==0){ - //LOGV("received data packet from user %d", p->userID); - sender=&*p; - break; - } - } - if(!sender){ - LOGV("Received data packet is from unknown user"); - return; - } - - if(memcmp(packet.data+16, keyFingerprint, 8)!=0){ - LOGW("received packet has wrong key fingerprint"); - return; - } - - BufferInputStream in(packet.data, packet.length-16); - in.Seek(16+8); // peer tag + key fingerprint - - unsigned char msgKey[16]; - in.ReadBytes(msgKey, 16); - - unsigned char decrypted[1500]; - unsigned char aesKey[32], aesIv[32]; - KDF2(msgKey, 0, aesKey, aesIv); - size_t decryptedLen=in.Remaining()-16; - if(decryptedLen>sizeof(decrypted)) - return; - //LOGV("-> MSG KEY: %08x %08x %08x %08x, hashed %u", *reinterpret_cast(msgKey), *reinterpret_cast(msgKey+4), *reinterpret_cast(msgKey+8), *reinterpret_cast(msgKey+12), decryptedLen-4); - uint8_t *decryptOffset = packet.data + in.GetOffset(); - if ((((intptr_t)decryptOffset) % sizeof(long)) != 0) { - LOGE("alignment2 packet.data+in.GetOffset()"); - } - if (decryptedLen % sizeof(long) != 0) { - LOGE("alignment2 decryptedLen"); - } - crypto.aes_ige_decrypt(packet.data+in.GetOffset(), decrypted, decryptedLen, aesKey, aesIv); - - in=BufferInputStream(decrypted, decryptedLen); - //LOGD("received packet length: %d", in.ReadInt32()); - - BufferOutputStream buf(decryptedLen+32); - size_t x=0; - buf.WriteBytes(encryptionKey+88+x, 32); - buf.WriteBytes(decrypted+4, decryptedLen-4); - unsigned char msgKeyLarge[32]; - crypto.sha256(buf.GetBuffer(), buf.GetLength(), msgKeyLarge); - - if(memcmp(msgKey, msgKeyLarge+8, 16)!=0){ - LOGW("Received packet from user %d has wrong hash", sender->userID); - return; - } - - uint32_t innerLen=(uint32_t) in.ReadInt32(); - if(innerLen>decryptedLen-4){ - LOGW("Received packet has wrong inner length (%d with total of %u)", innerLen, (unsigned int)decryptedLen); - return; - } - if(decryptedLen-innerLen<12){ - LOGW("Received packet has too little padding (%u)", (unsigned int)(decryptedLen-innerLen)); - return; - } - in=BufferInputStream(decrypted+4, (size_t) innerLen); - - uint32_t tlid=(uint32_t) in.ReadInt32(); - if(tlid!=TLID_DECRYPTED_AUDIO_BLOCK){ - LOGW("Received packet has unknown TL ID 0x%08x", tlid); - return; - } - in.Seek(in.GetOffset()+16); // random bytes - int32_t flags=in.ReadInt32(); - if(!(flags & PFLAG_HAS_SEQ) || !(flags & PFLAG_HAS_SENDER_TAG_HASH)){ - LOGW("Received packet has wrong flags"); - return; - } - /*uint32_t seq=(uint32_t) */in.ReadInt32(); - unsigned char senderTagHash[16]; - in.ReadBytes(senderTagHash, 16); - if(memcmp(senderTagHash, sender->memberTagHash, 16)!=0){ - LOGW("Received packet has wrong inner sender tag hash"); - return; - } - - //int32_t oneMoreInnerLengthWhyDoWeEvenNeedThis; - if(flags & PFLAG_HAS_DATA){ - /*oneMoreInnerLengthWhyDoWeEvenNeedThis=*/in.ReadTlLength(); - } - unsigned char type=(unsigned char) ((flags >> 24) & 0xFF); - lastRecvPacketTime=GetCurrentTime(); - - if(type==PKT_STREAM_DATA || type==PKT_STREAM_DATA_X2 || type==PKT_STREAM_DATA_X3){ - if(state!=STATE_ESTABLISHED && receivedInitAck) - SetState(STATE_ESTABLISHED); - int count; - switch(type){ - case PKT_STREAM_DATA_X2: - count=2; - break; - case PKT_STREAM_DATA_X3: - count=3; - break; - case PKT_STREAM_DATA: - default: - count=1; + LOGV("received lan endpoint (extra)"); + uint32_t peerAddr=(uint32_t) in.ReadInt32(); + uint16_t peerPort=(uint16_t) in.ReadInt32(); + MutexGuard m(endpointsMutex); + bool found=false; + for(shared_ptr& e:endpoints){ + if(e->type==Endpoint::TYPE_UDP_P2P_LAN){ + if(currentEndpoint==e) + currentEndpoint=preferredRelay; + found=true; + e->address=peerAddr; break; + } } - int i; - //if(srcEndpoint->type==Endpoint::TYPE_UDP_RELAY && srcEndpoint!=peerPreferredRelay){ - // peerPreferredRelay=srcEndpoint; - //} - for(i=0;iStart(); - audioOutStarted=true; - }*/ - if(in.GetOffset()+sdlen>in.GetLength()){ + if(!found){ + IPv4Address v4addr(peerAddr); + IPv6Address v6addr(string("::0")); + unsigned char peerTag[16]; + endpoints.push_back(make_shared((int64_t)(FOURCC('L','A','N','4')) << 32, peerPort, v4addr, v6addr, Endpoint::TYPE_UDP_P2P_LAN, peerTag)); + } + }else if(type==EXTRA_TYPE_NETWORK_CHANGED){ + if(currentEndpoint->type!=Endpoint::TYPE_UDP_RELAY && currentEndpoint->type!=Endpoint::TYPE_TCP_RELAY){ + currentEndpoint=preferredRelay; + if(allowP2p) + SendPublicEndpointsRequest(); + //if(peerVersion>=2){ + uint32_t flags=(uint32_t) in.ReadInt32(); + dataSavingRequestedByPeer=(flags & INIT_FLAG_DATA_SAVING_ENABLED)==INIT_FLAG_DATA_SAVING_ENABLED; + UpdateDataSavingState(); + UpdateAudioBitrate(); + //} + } + }else if(type==EXTRA_TYPE_GROUP_CALL_KEY){ + if(!didReceiveGroupCallKey && !didSendGroupCallKey){ + unsigned char groupKey[256]; + in.ReadBytes(groupKey, 256); + if(callbacks.groupCallKeyReceived) + callbacks.groupCallKeyReceived(this, groupKey); + didReceiveGroupCallKey=true; + } + }else if(type==EXTRA_TYPE_REQUEST_GROUP){ + if(!didInvokeUpgradeCallback){ + if(callbacks.upgradeToGroupCallRequested) + callbacks.upgradeToGroupCallRequested(this); + didInvokeUpgradeCallback=true; + } + }else if(type==EXTRA_TYPE_IPV6_ENDPOINT){ + if(!allowP2p) + return; + unsigned char _addr[16]; + in.ReadBytes(_addr, 16); + IPv6Address addr(_addr); + uint16_t port=static_cast(in.ReadInt16()); + MutexGuard m(endpointsMutex); + peerIPv6Available=true; + for(shared_ptr& e:endpoints){ + if(e->type==Endpoint::TYPE_UDP_P2P_INET && e->IsIPv6Only()){ + e->v6address=addr; + if(!myIPv6.IsEmpty()) + currentEndpoint=e; return; } - for(std::vector::iterator stm=sender->streams.begin();stm!=sender->streams.end();++stm){ - if(stm->id==streamID){ - if(stm->jitterBuffer){ - stm->jitterBuffer->HandleInput(decrypted+4+in.GetOffset(), sdlen, pts); - } - break; - } - } - if(i ep=make_shared(); + ep->type=Endpoint::TYPE_UDP_P2P_INET; + ep->port=port; + ep->v6address=addr; + ep->id=(int64_t)(FOURCC('P','2','P','6')) << 32; + endpoints.push_back(ep); + if(!myIPv6.IsEmpty()) + currentEndpoint=ep; } } -void VoIPGroupController::SendUdpPing(Endpoint *endpoint){ - +void VoIPController::ProcessAcknowledgedOutgoingExtra(VoIPController::UnacknowledgedExtraData &extra){ + if(extra.type==EXTRA_TYPE_GROUP_CALL_KEY){ + if(!didReceiveGroupCallKeyAck){ + didReceiveGroupCallKeyAck=true; + if(callbacks.groupCallKeySent) + callbacks.groupCallKeySent(this); + } + } } @@ -1995,9 +1737,9 @@ void VoIPController::RunTickThread(void* arg){ waitingForAcks=false; } //LOGI("%.3lf/%.3lf, rtt diff %.3lf, waiting=%d, queue=%d", rttHistory[0], rttHistory[8], v, waitingForAcks, sendQueue->Size()); - for(std::vector::iterator stm=incomingStreams.begin();stm!=incomingStreams.end();++stm){ - if(stm->jitterBuffer){ - int lostCount=stm->jitterBuffer->GetAndResetLostPacketCount(); + for(vector>::iterator stm=incomingStreams.begin();stm!=incomingStreams.end();++stm){ + if((*stm)->jitterBuffer){ + int lostCount=(*stm)->jitterBuffer->GetAndResetLostPacketCount(); if(lostCount>0 || (lostCount<0 && recvLossCount>((uint32_t) -lostCount))) recvLossCount+=lostCount; } @@ -2011,17 +1753,18 @@ void VoIPController::RunTickThread(void* arg){ conctl->Tick(); if(useTCP && !didAddTcpRelays){ - std::vector relays; - for(std::vector::iterator itr=endpoints.begin(); itr!=endpoints.end(); ++itr){ - if((*itr)->type!=Endpoint::TYPE_UDP_RELAY) + vector> relays; + for(shared_ptr& e:endpoints){ + if(e->type!=Endpoint::TYPE_UDP_RELAY) continue; - Endpoint *tcpRelay=new Endpoint(**itr); + shared_ptr tcpRelay=make_shared(*e); tcpRelay->type=Endpoint::TYPE_TCP_RELAY; tcpRelay->averageRTT=0; tcpRelay->lastPingSeq=0; tcpRelay->lastPingTime=0; memset(tcpRelay->rtts, 0, sizeof(tcpRelay->rtts)); tcpRelay->udpPongCount=0; + tcpRelay->id=tcpRelay->id ^ ((int64_t)(FOURCC('T','C','P',0)) << 32); if(setCurrentEndpointToTCP && currentEndpoint->type!=Endpoint::TYPE_TCP_RELAY){ setCurrentEndpointToTCP=false; currentEndpoint=tcpRelay; @@ -2041,7 +1784,9 @@ void VoIPController::RunTickThread(void* arg){ } int act=conctl->GetBandwidthControlAction(); - if(act==TGVOIP_CONCTL_ACT_DECREASE){ + if(shittyInternetMode){ + encoder->SetBitrate(8000); + }else if(act==TGVOIP_CONCTL_ACT_DECREASE){ uint32_t bitrate=encoder->GetBitrate(); if(bitrate>8000) encoder->SetBitrate(bitrate<(minAudioBitrate+audioBitrateStepDecr) ? minAudioBitrate : (bitrate-audioBitrateStepDecr)); @@ -2050,6 +1795,7 @@ void VoIPController::RunTickThread(void* arg){ if(bitrateSetBitrate(bitrate+audioBitrateStepIncr); } + //encoder->SetBitrate(6000); if(tickCount%10==0 && encoder){ uint32_t sendLossCount=conctl->GetSendLossCount(); @@ -2060,11 +1806,28 @@ void VoIPController::RunTickThread(void* arg){ for(i=0;i<10;i++){ avgSendLossCount+=sendLossCountHistory[i]; } - double packetsPerSec=1000/(double)outgoingStreams[0].frameDuration; + double packetsPerSec=1000/(double)outgoingStreams[0]->frameDuration; avgSendLossCount=avgSendLossCount/10/packetsPerSec; //LOGV("avg send loss: %.1f%%", avgSendLossCount*100); - if(avgSendLossCount>0.1){ + if(avgSendLossCount>0.125 && networkType!=NET_TYPE_GPRS && networkType!=NET_TYPE_EDGE){ + encoder->SetPacketLoss(40); + signalBarCount=1; + if(!shittyInternetMode){ + // Shitty Internet Modeâ„¢. Redundant redundancy you can trust. + shittyInternetMode=true; + for(shared_ptr& s:outgoingStreams){ + if(s->type==STREAM_TYPE_AUDIO){ + s->extraECEnabled=true; + SendStreamFlags(*s); + break; + } + } + if(encoder) + encoder->SetSecondaryEncoderEnabled(true); + LOGW("Enabling extra EC"); + } + }else if(avgSendLossCount>0.1){ encoder->SetPacketLoss(40); signalBarCount=1; }else if(avgSendLossCount>0.075){ @@ -2085,6 +1848,20 @@ void VoIPController::RunTickThread(void* arg){ encoder->SetPacketLoss(15); } + if((avgSendLossCount<0.15 || networkType==NET_TYPE_EDGE || networkType==NET_TYPE_GPRS) && shittyInternetMode){ + shittyInternetMode=false; + for(shared_ptr& s:outgoingStreams){ + if(s->type==STREAM_TYPE_AUDIO){ + s->extraECEnabled=false; + SendStreamFlags(*s); + break; + } + } + if(encoder) + encoder->SetSecondaryEncoderEnabled(false); + LOGW("Disabling extra EC"); + } + } } @@ -2095,7 +1872,7 @@ void VoIPController::RunTickThread(void* arg){ bool areThereAnyEnabledStreams=false; for(i=0;ienabled) areThereAnyEnabledStreams=true; } @@ -2107,7 +1884,7 @@ void VoIPController::RunTickThread(void* arg){ /*.type=*/PKT_NOP, /*.len=*/0, /*.data=*/buf, - /*.endpoint=*/NULL + /*.endpoint=*/0 }); } } @@ -2117,57 +1894,56 @@ void VoIPController::RunTickThread(void* arg){ } if(waitingForRelayPeerInfo && GetCurrentTime()-publicEndpointsReqTime>5){ - LOGD("Resending peer relay info request"); - SendPublicEndpointsRequest(); + if(publicEndpointsReqCount>=10){ + publicEndpointsReqCount=0; + waitingForRelayPeerInfo=false; + }else{ + LOGD("Resending peer relay info request"); + SendPublicEndpointsRequest(); + publicEndpointsReqCount++; + } } { MutexGuard m(queuedPacketsMutex); for(i=0; itimeout>0 && qp->firstSentTime>0 && GetCurrentTime()-qp->firstSentTime>=qp->timeout){ + QueuedPacket& qp=queuedPackets[i]; + if(qp.timeout>0 && qp.firstSentTime>0 && GetCurrentTime()-qp.firstSentTime>=qp.timeout){ LOGD("Removing queued packet because of timeout"); - if(qp->data) - free(qp->data); - free(qp); queuedPackets.erase(queuedPackets.begin()+i); i--; continue; } - if(qp->type==PKT_GROUP_CALL_KEY && didReceiveGroupCallKey){ - LOGW("Not sending group call key packet because we already received one"); - continue; - } - if(GetCurrentTime()-qp->lastSentTime>=qp->retryInterval){ + if(GetCurrentTime()-qp.lastSentTime>=qp.retryInterval){ unsigned char *buf=outgoingPacketsBufferPool.Get(); if(buf){ uint32_t seq=GenerateOutSeq(); - memmove(&qp->seqs[1], qp->seqs, 4*9); - qp->seqs[0]=seq; - qp->lastSentTime=GetCurrentTime(); - LOGD("Sending queued packet, seq=%u, type=%u, len=%u", seq, qp->type, unsigned(qp->length)); - if(qp->firstSentTime==0) - qp->firstSentTime=qp->lastSentTime; - if(qp->length) - memcpy(buf, qp->data, qp->length); + memmove(&qp.seqs[1], qp.seqs, 4*9); + qp.seqs[0]=seq; + qp.lastSentTime=GetCurrentTime(); + //LOGD("Sending queued packet, seq=%u, type=%u, len=%u", seq, qp.type, qp.data.Length()); + if(qp.firstSentTime==0) + qp.firstSentTime=qp.lastSentTime; + if(qp.data.Length()) + memcpy(buf, *qp.data, qp.data.Length()); sendQueue->Put(PendingOutgoingPacket{ /*.seq=*/seq, - /*.type=*/qp->type, - /*.len=*/qp->length, + /*.type=*/qp.type, + /*.len=*/qp.data.Length(), /*.data=*/buf, - /*.endpoint=*/NULL + /*.endpoint=*/0 }); } } } } - for(std::vector::iterator stm=incomingStreams.begin();stm!=incomingStreams.end();++stm){ - if(stm->jitterBuffer){ - stm->jitterBuffer->Tick(); + for(vector>::iterator stm=incomingStreams.begin();stm!=incomingStreams.end();++stm){ + if((*stm)->jitterBuffer){ + (*stm)->jitterBuffer->Tick(); //double avgDelay=stm->jitterBuffer->GetAverageDelay(); double avgLateCount[3]; - stm->jitterBuffer->GetAverageLateCount(avgLateCount); + (*stm)->jitterBuffer->GetAverageLateCount(avgLateCount); /*if(avgDelay>=5) signalBarCount=1; else if(avgDelay>=4) @@ -2186,9 +1962,9 @@ void VoIPController::RunTickThread(void* arg){ MutexGuard m(endpointsMutex); SendRelayPings(); if(udpConnectivityState==UDP_UNKNOWN){ - for(std::vector::iterator itr=endpoints.begin(); itr!=endpoints.end(); ++itr){ - if((*itr)->type==Endpoint::TYPE_UDP_RELAY){ - SendUdpPing(*itr); + for(shared_ptr& e:endpoints){ + if(e->type==Endpoint::TYPE_UDP_RELAY){ + SendUdpPing(e); } } udpConnectivityState=UDP_PING_SENT; @@ -2198,9 +1974,9 @@ void VoIPController::RunTickThread(void* arg){ int targetPingCount=udpConnectivityState==UDP_BAD ? 10 : 4; if(time-lastUdpPingTime>=(udpPingCount::iterator itr=endpoints.begin(); itr!=endpoints.end(); ++itr){ - if((*itr)->type==Endpoint::TYPE_UDP_RELAY){ - SendUdpPing(*itr); + for(shared_ptr& e:endpoints){ + if(e->type==Endpoint::TYPE_UDP_RELAY){ + SendUdpPing(e); } } udpPingCount++; @@ -2208,10 +1984,10 @@ void VoIPController::RunTickThread(void* arg){ }else{ double avgPongs=0; int count=0; - for(std::vector::iterator itr=endpoints.begin();itr!=endpoints.end();++itr){ - if((*itr)->type==Endpoint::TYPE_UDP_RELAY){ - if((*itr)->udpPongCount>0){ - avgPongs+=(double) (*itr)->udpPongCount; + for(shared_ptr& e:endpoints){ + if(e->type==Endpoint::TYPE_UDP_RELAY){ + if(e->udpPongCount>0){ + avgPongs+=(double) e->udpPongCount; count++; } } @@ -2249,12 +2025,11 @@ void VoIPController::RunTickThread(void* arg){ } if(state==STATE_ESTABLISHED || state==STATE_RECONNECTING){ - if(time-lastRecvPacketTime>=config.recv_timeout){ + if(time-lastRecvPacketTime>=config.recvTimeout){ if(currentEndpoint && currentEndpoint->type!=Endpoint::TYPE_UDP_RELAY && currentEndpoint->type!=Endpoint::TYPE_TCP_RELAY){ LOGW("Packet receive timeout, switching to relay"); currentEndpoint=preferredRelay; - for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ - Endpoint* e=*itrtr; + for(shared_ptr& e:endpoints){ if(e->type==Endpoint::TYPE_UDP_P2P_INET || e->type==Endpoint::TYPE_UDP_P2P_LAN){ e->averageRTT=0; memset(e->rtts, 0, sizeof(e->rtts)); @@ -2267,7 +2042,12 @@ void VoIPController::RunTickThread(void* arg){ UpdateAudioBitrate(); BufferOutputStream s(4); s.WriteInt32(dataSavingMode ? INIT_FLAG_DATA_SAVING_ENABLED : 0); - SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20); + if(peerVersion<6){ + SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20); + }else{ + Buffer buf(move(s)); + SendExtra(buf, EXTRA_TYPE_NETWORK_CHANGED); + } lastRecvPacketTime=time; }else{ LOGW("Packet receive timeout, disconnecting"); @@ -2276,7 +2056,7 @@ void VoIPController::RunTickThread(void* arg){ } } }else if(state==STATE_WAIT_INIT || state==STATE_WAIT_INIT_ACK){ - if(GetCurrentTime()-connectionInitTime>=config.init_timeout){ + if(GetCurrentTime()-connectionInitTime>=config.initTimeout){ LOGW("Init timeout, disconnecting"); lastError=ERROR_TIMEOUT; SetState(STATE_FAILED); @@ -2305,7 +2085,7 @@ void VoIPController::RunTickThread(void* arg){ if(statsDump && incomingStreams.size()==1){ - JitterBuffer* jitterBuffer=incomingStreams[0].jitterBuffer; + shared_ptr& jitterBuffer=incomingStreams[0]->jitterBuffer; //fprintf(statsDump, "Time\tRTT\tLISeq\tLASeq\tCWnd\tBitrate\tJitter\tJDelay\tAJDelay\n"); fprintf(statsDump, "%.3f\t%.3f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%.3f\t%.3f\t%.3f\n", GetCurrentTime()-startTime, @@ -2333,7 +2113,7 @@ Endpoint& VoIPController::GetRemoteEndpoint(){ } -void VoIPController::SendPacket(unsigned char *data, size_t len, Endpoint* ep, PendingOutgoingPacket& srcPacket){ +void VoIPController::SendPacket(unsigned char *data, size_t len, shared_ptr ep, PendingOutgoingPacket& srcPacket){ if(stopping) return; if(ep->type==Endpoint::TYPE_TCP_RELAY && !useTCP) @@ -2396,7 +2176,7 @@ void VoIPController::SendPacket(unsigned char *data, size_t len, Endpoint* ep, P //LOGV("Sending %d bytes to %s:%d", out.GetLength(), ep->address.ToString().c_str(), ep->port); NetworkPacket pkt={0}; - pkt.address=(NetworkAddress*)&ep->address; + pkt.address=&ep->GetAddress(); pkt.port=ep->port; pkt.length=out.GetLength(); pkt.data=out.GetBuffer(); @@ -2404,7 +2184,7 @@ void VoIPController::SendPacket(unsigned char *data, size_t len, Endpoint* ep, P ActuallySendPacket(pkt, ep); } -void VoIPController::ActuallySendPacket(NetworkPacket &pkt, Endpoint* ep){ +void VoIPController::ActuallySendPacket(NetworkPacket &pkt, shared_ptr ep){ //LOGI("Sending packet of %d bytes", pkt.length); if(IS_MOBILE_NETWORK(networkType)) stats.bytesSentMobile+=(uint64_t)pkt.length; @@ -2484,7 +2264,9 @@ void VoIPController::SetNetworkType(int type){ networkType=type; UpdateDataSavingState(); UpdateAudioBitrate(); - std::string itfName=udpSocket->GetLocalInterfaceInfo(NULL, NULL); + myIPv6=IPv6Address(); + string itfName=udpSocket->GetLocalInterfaceInfo(NULL, &myIPv6); + LOGI("Local IPv6 address: %s", myIPv6.ToString().c_str()); if(itfName!=activeNetItfName){ udpSocket->OnActiveInterfaceChanged(); LOGI("Active network interface changed: %s -> %s", activeNetItfName.c_str(), itfName.c_str()); @@ -2496,8 +2278,8 @@ void VoIPController::SetNetworkType(int type){ if(preferredRelay->type==Endpoint::TYPE_UDP_RELAY) currentEndpoint=preferredRelay; MutexGuard m(endpointsMutex); - for(std::vector::iterator itr=endpoints.begin();itr!=endpoints.end();){ - Endpoint* endpoint=*itr; + for(vector>::iterator itr=endpoints.begin();itr!=endpoints.end();){ + shared_ptr endpoint=*itr; if(endpoint->type==Endpoint::TYPE_UDP_RELAY && useTCP){ useTCP=false; if(preferredRelay->type==Endpoint::TYPE_TCP_RELAY){ @@ -2512,7 +2294,6 @@ void VoIPController::SetNetworkType(int type){ memset(endpoint->rtts, 0, sizeof(endpoint->rtts)); //} if(endpoint->type==Endpoint::TYPE_UDP_P2P_LAN){ - delete endpoint; itr=endpoints.erase(itr); }else{ ++itr; @@ -2529,30 +2310,52 @@ void VoIPController::SetNetworkType(int type){ } BufferOutputStream s(4); s.WriteInt32(dataSavingMode ? INIT_FLAG_DATA_SAVING_ENABLED : 0); - SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20); + if(peerVersion<6){ + SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20); + }else{ + Buffer buf(move(s)); + SendExtra(buf, EXTRA_TYPE_NETWORK_CHANGED); + } selectCanceller->CancelSelect(); + didSendIPv6Endpoint=false; + udpPingCount=0; + + AddIPv6Relays(); } LOGI("set network type: %d, active interface %s", type, activeNetItfName.c_str()); } -void VoIPGroupController::SetNetworkType(int type){ - networkType=type; - UpdateDataSavingState(); - UpdateAudioBitrate(); - std::string itfName=udpSocket->GetLocalInterfaceInfo(NULL, NULL); - if(itfName!=activeNetItfName){ - udpSocket->OnActiveInterfaceChanged(); - LOGI("Active network interface changed: %s -> %s", activeNetItfName.c_str(), itfName.c_str()); - bool isFirstChange=activeNetItfName.length()==0; - activeNetItfName=itfName; - if(isFirstChange) - return; - udpConnectivityState=UDP_UNKNOWN; - udpPingCount=0; - lastUdpPingTime=0; - if(proxyProtocol==PROXY_SOCKS5) - InitUDPProxy(); - selectCanceller->CancelSelect(); +void VoIPController::AddIPv6Relays(){ + if(!myIPv6.IsEmpty() && !didAddIPv6Relays){ + unordered_map>> endpointsByAddress; + MutexGuard m(endpointsMutex); + for(shared_ptr& e:endpoints){ + if((e->type==Endpoint::TYPE_UDP_RELAY || e->type==Endpoint::TYPE_TCP_RELAY) && !e->v6address.IsEmpty() && !e->address.IsEmpty()){ + endpointsByAddress[e->v6address.ToString()].push_back(e); + } + } + int globalId=callID[15]; + for(unordered_map>>::iterator addr=endpointsByAddress.begin();addr!=endpointsByAddress.end();++addr){ + shared_ptr best=NULL; + int bestDiff=256; + for(shared_ptr& e:addr->second){ + int epId=(int) (e->id & 0xFF); + int diff=abs(globalId-epId); + //if(diff v6only=make_shared(*best); + v6only->address=IPv4Address(0); + v6only->id=v6only->id ^ ((int64_t)(FOURCC('I','P','v','6')) << 32); + endpoints.push_back(v6only); + LOGD("Adding IPv6-only endpoint [%s]:%u", v6only->v6address.ToString().c_str(), v6only->port); + } + } + } } } @@ -2587,11 +2390,11 @@ double VoIPController::GetAverageRTT(){ #if defined(__APPLE__) static void initMachTimestart() { - mach_timebase_info_data_t tb = { 0, 0 }; - mach_timebase_info(&tb); - VoIPController::machTimebase = tb.numer; - VoIPController::machTimebase /= tb.denom; - VoIPController::machTimestart = mach_absolute_time(); + mach_timebase_info_data_t tb = { 0, 0 }; + mach_timebase_info(&tb); + VoIPController::machTimebase = tb.numer; + VoIPController::machTimebase /= tb.denom; + VoIPController::machTimestart = mach_absolute_time(); } #endif @@ -2601,8 +2404,8 @@ double VoIPController::GetCurrentTime(){ clock_gettime(CLOCK_MONOTONIC, &ts); return ts.tv_sec+(double)ts.tv_nsec/1000000000.0; #elif defined(__APPLE__) - static pthread_once_t token = PTHREAD_ONCE_INIT; - pthread_once(&token, &initMachTimestart); + static pthread_once_t token = PTHREAD_ONCE_INIT; + pthread_once(&token, &initMachTimestart); return (mach_absolute_time() - machTimestart) * machTimebase / 1000000000.0f; #elif defined(_WIN32) if(!didInitWin32TimeScale){ @@ -2645,14 +2448,17 @@ void VoIPController::SetMicMute(bool mute){ if(echoCanceller) echoCanceller->Enable(!mute); if(state==STATE_ESTABLISHED){ - unsigned int i; - for(i=0; i& s:outgoingStreams){ + if(s->type==STREAM_TYPE_AUDIO){ + s->enabled=!mute; + if(peerVersion<6){ + unsigned char buf[2]; + buf[0]=s->id; + buf[1]=(char) (mute ? 0 : 1); + SendPacketReliably(PKT_STREAM_STATE, buf, 2, .5f, 20); + }else{ + SendStreamFlags(*s); + } } } } @@ -2661,9 +2467,8 @@ void VoIPController::SetMicMute(bool mute){ void VoIPController::UpdateAudioOutputState(){ bool areAnyAudioStreamsEnabled=false; - unsigned int i; - for(i=0;i>::iterator s=incomingStreams.begin();s!=incomingStreams.end();++s){ + if((*s)->type==STREAM_TYPE_AUDIO && (*s)->enabled) areAnyAudioStreamsEnabled=true; } /*if(jitterBuffer){ @@ -2682,6 +2487,19 @@ void VoIPController::UpdateAudioOutputState(){ } } +void VoIPController::SendStreamFlags(Stream& stream){ + BufferOutputStream s(5); + s.WriteByte(stream.id); + uint32_t flags=0; + if(stream.enabled) + flags|=STREAM_FLAG_ENABLED; + if(stream.extraECEnabled) + flags|=STREAM_FLAG_EXTRA_EC; + s.WriteInt32(flags); + Buffer buf(move(s)); + SendExtra(buf, EXTRA_TYPE_STREAM_FLAGS); +} + void VoIPController::KDF(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv){ uint8_t sA[SHA1_LENGTH], sB[SHA1_LENGTH], sC[SHA1_LENGTH], sD[SHA1_LENGTH]; BufferOutputStream buf(128); @@ -2738,12 +2556,11 @@ void VoIPController::KDF2(unsigned char* msgKey, size_t x, unsigned char *aesKey memcpy(aesIv, buf.GetBuffer(), 32); } -void VoIPController::GetDebugString(char *buffer, size_t len){ - char endpointsBuf[10240]; - memset(endpointsBuf, 0, 10240); - for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ +string VoIPController::GetDebugString(){ + string r="Remote endpoints: \n"; + char buffer[2048]; + for(shared_ptr& endpoint:endpoints){ const char* type; - Endpoint* endpoint=*itrtr; switch(endpoint->type){ case Endpoint::TYPE_UDP_P2P_INET: type="UDP_P2P_INET"; @@ -2761,18 +2578,19 @@ void VoIPController::GetDebugString(char *buffer, size_t len){ type="UNKNOWN"; break; } - if(strlen(endpointsBuf)>10240-1024) - break; - sprintf(endpointsBuf+strlen(endpointsBuf), "%s:%u %dms %d [%s%s]\n", endpoint->address.ToString().c_str(), endpoint->port, (int)(endpoint->averageRTT*1000), endpoint->udpPongCount, type, currentEndpoint==endpoint ? ", IN_USE" : ""); + snprintf(buffer, sizeof(buffer), "%s:%u %dms %d [%s%s]\n", endpoint->address.IsEmpty() ? ("["+endpoint->v6address.ToString()+"]").c_str() : endpoint->address.ToString().c_str(), endpoint->port, (int)(endpoint->averageRTT*1000), endpoint->udpPongCount, type, currentEndpoint==endpoint ? ", IN_USE" : ""); + r+=buffer; + } + if(shittyInternetMode){ + r+="ShittyInternetMode enabled\n"; } double avgLate[3]; - JitterBuffer* jitterBuffer=incomingStreams.size()==1 ? incomingStreams[0].jitterBuffer : NULL; + shared_ptr jitterBuffer=incomingStreams.size()==1 ? incomingStreams[0]->jitterBuffer : NULL; if(jitterBuffer) jitterBuffer->GetAverageLateCount(avgLate); else memset(avgLate, 0, 3*sizeof(double)); - snprintf(buffer, len, - "Remote endpoints: \n%s" + snprintf(buffer, sizeof(buffer), "Jitter buffer: %d/%.2f | %.1f, %.1f, %.1f\n" "RTT avg/min: %d/%d\n" "Congestion window: %d/%d bytes\n" @@ -2784,7 +2602,6 @@ void VoIPController::GetDebugString(char *buffer, size_t len){ // "Packet grouping: %d\n" "Frame size out/in: %d/%d\n" "Bytes sent/recvd: %llu/%llu", - endpointsBuf, jitterBuffer ? jitterBuffer->GetMinPacketCount() : 0, jitterBuffer ? jitterBuffer->GetAverageDelay() : 0, avgLate[0], avgLate[1], avgLate[2], // (int)(GetAverageRTT()*1000), 0, (int)(conctl->GetAverageRTT()*1000), (int)(conctl->GetMinimumRTT()*1000), @@ -2795,19 +2612,23 @@ void VoIPController::GetDebugString(char *buffer, size_t len){ conctl->GetSendLossCount(), recvLossCount, encoder ? encoder->GetPacketLoss() : 0, encoder ? (encoder->GetBitrate()/1000) : 0, // audioPacketGrouping, - outgoingStreams[0].frameDuration, incomingStreams.size()>0 ? incomingStreams[0].frameDuration : 0, + outgoingStreams[0]->frameDuration, incomingStreams.size()>0 ? incomingStreams[0]->frameDuration : 0, (long long unsigned int)(stats.bytesSentMobile+stats.bytesSentWifi), (long long unsigned int)(stats.bytesRecvdMobile+stats.bytesRecvdWifi)); + r+=buffer; + return r; } void VoIPController::SendPublicEndpointsRequest(){ + if(!allowP2p) + return; LOGI("Sending public endpoints request"); - if(preferredRelay){ - SendPublicEndpointsRequest(*preferredRelay); - } - if(peerPreferredRelay && peerPreferredRelay!=preferredRelay){ - SendPublicEndpointsRequest(*peerPreferredRelay); + MutexGuard m(endpointsMutex); + for(shared_ptr& e:endpoints){ + if(e->type==Endpoint::TYPE_UDP_RELAY && !e->IsIPv6Only()){ + SendPublicEndpointsRequest(*e); + } } } @@ -2829,52 +2650,73 @@ void VoIPController::SendPublicEndpointsRequest(Endpoint& relay){ udpSocket->Send(&pkt); } -Endpoint* VoIPController::GetEndpointByType(int type){ +shared_ptr VoIPController::GetEndpointByType(int type){ if(type==Endpoint::TYPE_UDP_RELAY && preferredRelay) return preferredRelay; - for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ - if((*itrtr)->type==type) - return *itrtr; + for(shared_ptr& e:endpoints){ + if(e->type==type) + return e; + } + return NULL; +} + +shared_ptr VoIPController::GetEndpointByID(int64_t id){ + for(shared_ptr& e:endpoints){ + if(e->id==id) + return e; } return NULL; } float VoIPController::GetOutputLevel(){ - if(!audioOutput || !audioOutStarted){ - return 0.0; - } - return audioOutput->GetLevel(); + if(!audioOutput || !audioOutStarted){ + return 0.0; + } + return audioOutput->GetLevel(); } void VoIPController::SendPacketReliably(unsigned char type, unsigned char *data, size_t len, double retryInterval, double timeout){ LOGD("Send reliably, type=%u, len=%u, retry=%.3f, timeout=%.3f", type, unsigned(len), retryInterval, timeout); - voip_queued_packet_t* pkt=(voip_queued_packet_t *) malloc(sizeof(voip_queued_packet_t)); - memset(pkt, 0, sizeof(voip_queued_packet_t)); - pkt->type=type; + QueuedPacket pkt; if(data){ - pkt->data=(unsigned char *) malloc(len); - memcpy(pkt->data, data, len); - pkt->length=len; + Buffer b(len); + b.CopyFrom(data, 0, len); + pkt={move(b)}; } - pkt->retryInterval=retryInterval; - pkt->timeout=timeout; - pkt->firstSentTime=0; - pkt->lastSentTime=0; + pkt.type=type; + pkt.retryInterval=retryInterval; + pkt.timeout=timeout; + pkt.firstSentTime=0; + pkt.lastSentTime=0; MutexGuard m(queuedPacketsMutex); - queuedPackets.push_back(pkt); + queuedPackets.push_back(move(pkt)); +} + +void VoIPController::SendExtra(Buffer &data, unsigned char type){ + MutexGuard m(queuedPacketsMutex); + LOGV("Sending extra type %u length %lu", type, data.Length()); + for(vector::iterator x=currentExtras.begin();x!=currentExtras.end();++x){ + if(x->type==type){ + x->firstContainingSeq=0; + x->data=move(data); + return; + } + } + UnacknowledgedExtraData xd={type, move(data), 0}; + currentExtras.push_back(move(xd)); } -void VoIPController::SetConfig(voip_config_t *cfg){ - memcpy(&config, cfg, sizeof(voip_config_t)); +void VoIPController::SetConfig(Config& cfg){ + config=cfg; if(tgvoipLogFile){ fclose(tgvoipLogFile); tgvoipLogFile=NULL; } - if(strlen(cfg->logFilePath)){ - tgvoipLogFile=fopen(cfg->logFilePath, "a"); + if(!config.logFilePath.empty()){ + tgvoipLogFile=fopen(config.logFilePath.c_str(), "a"); tgvoip_log_file_write_header(tgvoipLogFile); }else{ tgvoipLogFile=NULL; @@ -2883,12 +2725,12 @@ void VoIPController::SetConfig(voip_config_t *cfg){ fclose(statsDump); statsDump=NULL; } - if(strlen(cfg->statsDumpFilePath)){ - statsDump=fopen(cfg->statsDumpFilePath, "w"); + if(!config.statsDumpFilePath.empty()){ + statsDump=fopen(config.statsDumpFilePath.c_str(), "w"); if(statsDump) fprintf(statsDump, "Time\tRTT\tLRSeq\tLSSeq\tLASeq\tLostR\tLostS\tCWnd\tBitrate\tLoss%%\tJitter\tJDelay\tAJDelay\n"); else - LOGW("Failed to open stats dump file %s for writing", cfg->statsDumpFilePath); + LOGW("Failed to open stats dump file %s for writing", config.statsDumpFilePath.c_str()); }else{ statsDump=NULL; } @@ -2898,15 +2740,15 @@ void VoIPController::SetConfig(voip_config_t *cfg){ void VoIPController::UpdateDataSavingState(){ - if(config.data_saving==DATA_SAVING_ALWAYS){ + if(config.dataSaving==DATA_SAVING_ALWAYS){ dataSavingMode=true; - }else if(config.data_saving==DATA_SAVING_MOBILE){ + }else if(config.dataSaving==DATA_SAVING_MOBILE){ dataSavingMode=networkType==NET_TYPE_GPRS || networkType==NET_TYPE_EDGE || networkType==NET_TYPE_3G || networkType==NET_TYPE_HSPA || networkType==NET_TYPE_LTE || networkType==NET_TYPE_OTHER_MOBILE; }else{ dataSavingMode=false; } - LOGI("update data saving mode, config %d, enabled %d, reqd by peer %d", config.data_saving, dataSavingMode, dataSavingRequestedByPeer); + LOGI("update data saving mode, config %d, enabled %d, reqd by peer %d", config.dataSaving, dataSavingMode, dataSavingRequestedByPeer); } @@ -2954,24 +2796,24 @@ int VoIPController::GetLastError(){ } -void VoIPController::GetStats(voip_stats_t *stats){ - memcpy(stats, &this->stats, sizeof(voip_stats_t)); +void VoIPController::GetStats(TrafficStats *stats){ + memcpy(stats, &this->stats, sizeof(TrafficStats)); } #ifdef TGVOIP_USE_AUDIO_SESSION void VoIPController::SetAcquireAudioSession(void (^completion)(void (^)())) { - this->acquireAudioSession = [completion copy]; + this->acquireAudioSession = [completion copy]; } void VoIPController::ReleaseAudioSession(void (^completion)()) { - completion(); + completion(); } #endif void VoIPController::LogDebugInfo(){ - std::string json="{\"endpoints\":["; - for(std::vector::iterator itr=endpoints.begin();itr!=endpoints.end();++itr){ - Endpoint* e=*itr; + string json="{\"endpoints\":["; + for(vector>::iterator itr=endpoints.begin();itr!=endpoints.end();++itr){ + shared_ptr e=*itr; char buffer[1024]; const char* typeStr="unknown"; switch(e->type){ @@ -2988,7 +2830,7 @@ void VoIPController::LogDebugInfo(){ typeStr="tcp_relay"; break; } - snprintf(buffer, 1024, "{\"address\":\"%s\",\"port\":%u,\"type\":\"%s\",\"rtt\":%u%s%s}", e->address.ToString().c_str(), e->port, typeStr, (unsigned int)round(e->averageRTT*1000), currentEndpoint==&*e ? ",\"in_use\":true" : "", preferredRelay==&*e ? ",\"preferred\":true" : ""); + snprintf(buffer, 1024, "{\"address\":\"%s\",\"port\":%u,\"type\":\"%s\",\"rtt\":%u%s%s}", e->address.ToString().c_str(), e->port, typeStr, (unsigned int)round(e->averageRTT*1000), currentEndpoint==e ? ",\"in_use\":true" : "", preferredRelay==e ? ",\"preferred\":true" : ""); json+=buffer; if(itr!=endpoints.end()-1) json+=","; @@ -3039,10 +2881,10 @@ void VoIPController::LogDebugInfo(){ debugLogs.push_back(json); } -std::string VoIPController::GetDebugLog(){ - std::string log="{\"events\":["; +string VoIPController::GetDebugLog(){ + string log="{\"events\":["; - for(std::vector::iterator itr=debugLogs.begin();itr!=debugLogs.end();++itr){ + for(vector::iterator itr=debugLogs.begin();itr!=debugLogs.end();++itr){ log+=(*itr); if((itr+1)!=debugLogs.end()) log+=","; @@ -3057,45 +2899,45 @@ void VoIPController::GetDebugLog(char *buffer){ size_t VoIPController::GetDebugLogLength(){ size_t len=128; - for(std::vector::iterator itr=debugLogs.begin();itr!=debugLogs.end();++itr){ + for(vector::iterator itr=debugLogs.begin();itr!=debugLogs.end();++itr){ len+=(*itr).length()+1; } return len; } -std::vector VoIPController::EnumerateAudioInputs(){ +vector VoIPController::EnumerateAudioInputs(){ vector devs; audio::AudioInput::EnumerateDevices(devs); return devs; } -std::vector VoIPController::EnumerateAudioOutputs(){ +vector VoIPController::EnumerateAudioOutputs(){ vector devs; audio::AudioOutput::EnumerateDevices(devs); return devs; } -void VoIPController::SetCurrentAudioInput(std::string id){ +void VoIPController::SetCurrentAudioInput(string id){ currentAudioInput=id; if(audioInput) audioInput->SetCurrentDevice(id); } -void VoIPController::SetCurrentAudioOutput(std::string id){ +void VoIPController::SetCurrentAudioOutput(string id){ currentAudioOutput=id; if(audioOutput) audioOutput->SetCurrentDevice(id); } -std::string VoIPController::GetCurrentAudioInputID(){ +string VoIPController::GetCurrentAudioInputID(){ return currentAudioInput; } -std::string VoIPController::GetCurrentAudioOutputID(){ +string VoIPController::GetCurrentAudioOutputID(){ return currentAudioOutput; } -void VoIPController::SetProxy(int protocol, std::string address, uint16_t port, std::string username, std::string password){ +void VoIPController::SetProxy(int protocol, string address, uint16_t port, string username, string password){ proxyProtocol=protocol; proxyAddress=address; proxyPort=port; @@ -3103,10 +2945,10 @@ void VoIPController::SetProxy(int protocol, std::string address, uint16_t port, proxyPassword=password; } -void VoIPController::SendUdpPing(Endpoint *endpoint){ +void VoIPController::SendUdpPing(shared_ptr endpoint){ if(endpoint->type!=Endpoint::TYPE_UDP_RELAY) return; - LOGV("Sending UDP ping to %s:%d", endpoint->address.ToString().c_str(), endpoint->port); + LOGV("Sending UDP ping to %s:%d", endpoint->GetAddress().ToString().c_str(), endpoint->port); BufferOutputStream p(1024); p.WriteBytes(endpoint->peerTag, 16); p.WriteInt32(-1); @@ -3115,7 +2957,7 @@ void VoIPController::SendUdpPing(Endpoint *endpoint){ p.WriteInt32(-2); p.WriteInt64(12345); NetworkPacket pkt={0}; - pkt.address=&endpoint->address; + pkt.address=&endpoint->GetAddress(); pkt.port=endpoint->port; pkt.protocol=PROTO_UDP; pkt.data=p.GetBuffer(); @@ -3123,65 +2965,16 @@ void VoIPController::SendUdpPing(Endpoint *endpoint){ udpSocket->Send(&pkt); } -void VoIPGroupController::SendRecentPacketsRequest(){ - BufferOutputStream out(1024); - out.WriteInt32(TLID_UDP_REFLECTOR_REQUEST_PACKETS_INFO); // TL function - out.WriteInt32(GetCurrentUnixtime()); // date:int - out.WriteInt64(0); // query_id:long - out.WriteInt32(64); // recv_num:int - out.WriteInt32(0); // sent_num:int - SendSpecialReflectorRequest(out.GetBuffer(), out.GetLength()); -} - -void VoIPGroupController::SendSpecialReflectorRequest(unsigned char *data, size_t len){ - BufferOutputStream out(1024); - unsigned char buf[1500]; - crypto.rand_bytes(buf, 8); - out.WriteBytes(buf, 8); - out.WriteInt32((int32_t)len); - out.WriteBytes(data, len); - if(out.GetLength()%16!=0){ - size_t paddingLen=16-(out.GetLength()%16); - crypto.rand_bytes(buf, paddingLen); - out.WriteBytes(buf, paddingLen); - } - unsigned char iv[16]; - crypto.rand_bytes(iv, 16); - unsigned char key[32]; - crypto.sha256(reflectorSelfSecret, 16, key); - unsigned char _iv[16]; - memcpy(_iv, iv, 16); - size_t encryptedLen=out.GetLength(); - crypto.aes_cbc_encrypt(out.GetBuffer(), buf, encryptedLen, key, _iv); - out.Reset(); - out.WriteBytes(reflectorSelfTag, 16); - out.WriteBytes(iv, 16); - out.WriteBytes(buf, encryptedLen); - out.WriteBytes(reflectorSelfSecret, 16); - crypto.sha256(out.GetBuffer(), out.GetLength(), buf); - out.Rewind(16); - out.WriteBytes(buf, 16); - - NetworkPacket pkt={0}; - pkt.address=&groupReflector->address; - pkt.port=groupReflector->port; - pkt.protocol=PROTO_UDP; - pkt.data=out.GetBuffer(); - pkt.length=out.GetLength(); - ActuallySendPacket(pkt, groupReflector); -} - void VoIPController::SendRelayPings(){ //LOGV("Send relay pings 1"); if((state==STATE_ESTABLISHED || state==STATE_RECONNECTING) && endpoints.size()>1){ - Endpoint* minPingRelay=preferredRelay; + shared_ptr minPingRelay=preferredRelay; double minPing=preferredRelay->averageRTT*(preferredRelay->type==Endpoint::TYPE_TCP_RELAY ? 2 : 1); - for(std::vector::iterator e=endpoints.begin();e!=endpoints.end();++e){ - Endpoint* endpoint=*e; + for(shared_ptr& endpoint:endpoints){ if(endpoint->type==Endpoint::TYPE_TCP_RELAY && !useTCP) continue; if(GetCurrentTime()-endpoint->lastPingTime>=10){ - LOGV("Sending ping to %s", endpoint->address.ToString().c_str()); + LOGV("Sending ping to %s", endpoint->GetAddress().ToString().c_str()); unsigned char* buf=outgoingPacketsBufferPool.Get(); if(buf){ sendQueue->Put(PendingOutgoingPacket{ @@ -3189,7 +2982,7 @@ void VoIPController::SendRelayPings(){ /*.type=*/PKT_PING, /*.len=*/0, /*.data=*/buf, - /*.endpoint=*/endpoint + /*.endpoint=*/endpoint->id }); } endpoint->lastPingTime=GetCurrentTime(); @@ -3208,22 +3001,17 @@ void VoIPController::SendRelayPings(){ if(currentEndpoint->type==Endpoint::TYPE_UDP_RELAY || currentEndpoint->type==Endpoint::TYPE_TCP_RELAY) currentEndpoint=preferredRelay; LogDebugInfo(); - /*BufferOutputStream pkt(32); - pkt.WriteInt64(preferredRelay->id); - SendPacketReliably(PKT_SWITCH_PREF_RELAY, pkt.GetBuffer(), pkt.GetLength(), 1, 9);*/ } if(currentEndpoint->type==Endpoint::TYPE_UDP_RELAY){ - Endpoint* p2p=GetEndpointByType(Endpoint::TYPE_UDP_P2P_INET); + shared_ptr p2p=GetEndpointByType(Endpoint::TYPE_UDP_P2P_INET); if(p2p){ - Endpoint* lan=GetEndpointByType(Endpoint::TYPE_UDP_P2P_LAN); + shared_ptr lan=GetEndpointByType(Endpoint::TYPE_UDP_P2P_LAN); if(lan && lan->averageRTT>0 && lan->averageRTTaverageRTT>0 && p2p->averageRTTlastPingTime>=0.25){ - SendRecentPacketsRequest(); - groupReflector->lastPingTime=currentTime; - } -} - void VoIPController::StartAudio(){ - Stream& outgoingAudioStream=outgoingStreams[0]; + shared_ptr& outgoingAudioStream=outgoingStreams[0]; LOGI("before create audio io"); void* platformSpecific=NULL; #ifdef __APPLE__ @@ -3260,11 +3039,14 @@ void VoIPController::StartAudio(){ audioInput->Configure(48000, 16, 1); audioOutput=tgvoip::audio::AudioOutput::Create(currentAudioOutput, platformSpecific); audioOutput->Configure(48000, 16, 1); + LOGI("AEC: %d NS: %d AGC: %d", config.enableAEC, config.enableNS, config.enableAGC); echoCanceller=new EchoCanceller(config.enableAEC, config.enableNS, config.enableAGC); - encoder=new OpusEncoder(audioInput); + encoder=new OpusEncoder(audioInput, peerVersion>=6); encoder->SetCallback(AudioInputCallback, this); - encoder->SetOutputFrameDuration(outgoingAudioStream.frameDuration); + encoder->SetOutputFrameDuration(outgoingAudioStream->frameDuration); encoder->SetEchoCanceller(echoCanceller); + encoder->SetSecondaryEncoderEnabled(false); + encoder->Start(); if(!micMuted){ audioInput->Start(); @@ -3303,133 +3085,15 @@ void VoIPController::StartAudio(){ } void VoIPController::OnAudioOutputReady(){ - Stream& stm=incomingStreams[0]; + shared_ptr& stm=incomingStreams[0]; outputAGC=new AutomaticGainControl(); outputAGC->SetPassThrough(!outputAGCEnabled); - stm.decoder=new OpusDecoder(audioOutput, true); - stm.decoder->AddAudioEffect(outputAGC); - stm.decoder->SetEchoCanceller(echoCanceller); - stm.decoder->SetJitterBuffer(stm.jitterBuffer); - stm.decoder->SetFrameDuration(stm.frameDuration); - stm.decoder->Start(); -} - -void VoIPGroupController::OnAudioOutputReady(){ - encoder->SetDTX(true); - audioMixer->SetOutput(audioOutput); - audioMixer->SetEchoCanceller(echoCanceller); - audioMixer->Start(); - audioOutput->Start(); - audioOutStarted=true; - encoder->SetLevelMeter(&selfLevelMeter); -} - -void VoIPGroupController::WritePacketHeader(uint32_t seq, BufferOutputStream *s, unsigned char type, uint32_t length){ - s->WriteInt32(TLID_DECRYPTED_AUDIO_BLOCK); - int64_t randomID; - crypto.rand_bytes((uint8_t *) &randomID, 8); - s->WriteInt64(randomID); - unsigned char randBytes[7]; - crypto.rand_bytes(randBytes, 7); - s->WriteByte(7); - s->WriteBytes(randBytes, 7); - uint32_t pflags=PFLAG_HAS_SEQ | PFLAG_HAS_SENDER_TAG_HASH; - if(length>0) - pflags|=PFLAG_HAS_DATA; - pflags|=((uint32_t) type) << 24; - s->WriteInt32(pflags); - - if(type==PKT_STREAM_DATA || type==PKT_STREAM_DATA_X2 || type==PKT_STREAM_DATA_X3){ - conctl->PacketSent(seq, length); - } - - /*if(pflags & PFLAG_HAS_CALL_ID){ - s->WriteBytes(callID, 16); - }*/ - //s->WriteInt32(lastRemoteSeq); - s->WriteInt32(seq); - s->WriteBytes(reflectorSelfTagHash, 16); - if(length>0){ - if(length<=253){ - s->WriteByte((unsigned char) length); - }else{ - s->WriteByte(254); - s->WriteByte((unsigned char) (length & 0xFF)); - s->WriteByte((unsigned char) ((length >> 8) & 0xFF)); - s->WriteByte((unsigned char) ((length >> 16) & 0xFF)); - } - } -} - -void VoIPGroupController::SendPacket(unsigned char *data, size_t len, Endpoint *ep, PendingOutgoingPacket& srcPacket){ - if(stopping) - return; - if(ep->type==Endpoint::TYPE_TCP_RELAY && !useTCP) - return; - BufferOutputStream out(len+128); - //LOGV("send group packet %u", len); - - out.WriteBytes(reflectorSelfTag, 16); - - if(len>0){ - BufferOutputStream inner(len+128); - inner.WriteInt32((uint32_t)len); - inner.WriteBytes(data, len); - size_t padLen=16-inner.GetLength()%16; - if(padLen<12) - padLen+=16; - unsigned char padding[28]; - crypto.rand_bytes((uint8_t *) padding, padLen); - inner.WriteBytes(padding, padLen); - assert(inner.GetLength()%16==0); - - unsigned char key[32], iv[32], msgKey[16]; - out.WriteBytes(keyFingerprint, 8); - BufferOutputStream buf(len+32); - size_t x=0; - buf.WriteBytes(encryptionKey+88+x, 32); - buf.WriteBytes(inner.GetBuffer()+4, inner.GetLength()-4); - unsigned char msgKeyLarge[32]; - crypto.sha256(buf.GetBuffer(), buf.GetLength(), msgKeyLarge); - memcpy(msgKey, msgKeyLarge+8, 16); - KDF2(msgKey, 0, key, iv); - out.WriteBytes(msgKey, 16); - //LOGV("<- MSG KEY: %08x %08x %08x %08x, hashed %u", *reinterpret_cast(msgKey), *reinterpret_cast(msgKey+4), *reinterpret_cast(msgKey+8), *reinterpret_cast(msgKey+12), inner.GetLength()-4); - - unsigned char aesOut[MSC_STACK_FALLBACK(inner.GetLength(), 1500)]; - crypto.aes_ige_encrypt(inner.GetBuffer(), aesOut, inner.GetLength(), key, iv); - out.WriteBytes(aesOut, inner.GetLength()); - } - - // relay signature - out.WriteBytes(reflectorSelfSecret, 16); - unsigned char sig[32]; - crypto.sha256(out.GetBuffer(), out.GetLength(), sig); - out.Rewind(16); - out.WriteBytes(sig, 16); - - if(srcPacket.type==PKT_STREAM_DATA || srcPacket.type==PKT_STREAM_DATA_X2 || srcPacket.type==PKT_STREAM_DATA_X3){ - PacketIdMapping mapping={srcPacket.seq, *reinterpret_cast(sig+14), 0}; - MutexGuard m(sentPacketsMutex); - recentSentPackets.push_back(mapping); - //LOGD("sent packet with id: %04X", mapping.id); - while(recentSentPackets.size()>64) - recentSentPackets.erase(recentSentPackets.begin()); - } - lastSentSeq=srcPacket.seq; - - if(IS_MOBILE_NETWORK(networkType)) - stats.bytesSentMobile+=(uint64_t)out.GetLength(); - else - stats.bytesSentWifi+=(uint64_t)out.GetLength(); - - NetworkPacket pkt={0}; - pkt.address=(NetworkAddress*)&ep->address; - pkt.port=ep->port; - pkt.length=out.GetLength(); - pkt.data=out.GetBuffer(); - pkt.protocol=ep->type==Endpoint::TYPE_TCP_RELAY ? PROTO_TCP : PROTO_UDP; - ActuallySendPacket(pkt, ep); + stm->decoder=make_shared((unique_ptr&)audioOutput, true, peerVersion>=6); + stm->decoder->AddAudioEffect(outputAGC); + stm->decoder->SetEchoCanceller(echoCanceller); + stm->decoder->SetJitterBuffer(stm->jitterBuffer); + stm->decoder->SetFrameDuration(stm->frameDuration); + stm->decoder->Start(); } int VoIPController::GetSignalBarsCount(){ @@ -3439,85 +3103,6 @@ int VoIPController::GetSignalBarsCount(){ return avg >> 2; } -float VoIPGroupController::GetParticipantAudioLevel(int32_t userID){ - if(userID==userSelfID) - return selfLevelMeter.GetLevel(); - MutexGuard m(participantsMutex); - for(std::vector::iterator p=participants.begin(); p!=participants.end(); ++p){ - if(p->userID==userID){ - return p->levelMeter->GetLevel(); - } - } - return 0; -} - -void VoIPGroupController::SetMicMute(bool mute){ - micMuted=mute; - if(audioInput){ - if(mute) - audioInput->Stop(); - else - audioInput->Start(); - if(!audioInput->IsInitialized()){ - lastError=ERROR_AUDIO_IO; - SetState(STATE_FAILED); - return; - } - } - outgoingStreams[0].enabled=!mute; - SerializeAndUpdateOutgoingStreams(); -} - -void VoIPGroupController::SetParticipantVolume(int32_t userID, float volume){ - MutexGuard m(participantsMutex); - for(std::vector::iterator p=participants.begin();p!=participants.end();++p){ - if(p->userID==userID){ - for(std::vector::iterator s=p->streams.begin();s!=p->streams.end();++s){ - if(s->type==STREAM_TYPE_AUDIO){ - if(s->decoder){ - float db; - if(volume==0.0f) - db=-INFINITY; - else if(volume<1.0f) - db=-50.0f*(1.0f-volume); - else if(volume>1.0f && volume<=2.0f) - db=10.0f*(volume-1.0f); - else - db=0.0f; - //LOGV("Setting user %u audio volume to %.2f dB", userID, db); - audioMixer->SetInputVolume(s->callbackWrapper, db); - } - break; - } - } - break; - } - } -} - -void VoIPGroupController::SerializeAndUpdateOutgoingStreams(){ - BufferOutputStream out(1024); - out.WriteByte((unsigned char) outgoingStreams.size()); - - for(std::vector::iterator s=outgoingStreams.begin(); s!=outgoingStreams.end(); ++s){ - BufferOutputStream o(128); - o.WriteByte(s->id); - o.WriteByte(s->type); - o.WriteInt32(s->codec); - o.WriteInt32((unsigned char) ((s->enabled ? STREAM_FLAG_ENABLED : 0) | STREAM_FLAG_DTX)); - o.WriteInt16(s->frameDuration); - out.WriteInt16((int16_t) o.GetLength()); - out.WriteBytes(o.GetBuffer(), o.GetLength()); - } - if(groupCallbacks.updateStreams) - groupCallbacks.updateStreams(this, out.GetBuffer(), out.GetLength()); -} - -void VoIPGroupController::SetCallbacks(VoIPGroupController::Callbacks callbacks){ - VoIPController::SetCallbacks(callbacks); - this->groupCallbacks=callbacks; -} - void VoIPController::SetCallbacks(VoIPController::Callbacks callbacks){ this->callbacks=callbacks; if(callbacks.connectionStateChanged) @@ -3549,7 +3134,9 @@ void VoIPController::SendGroupCallKey(unsigned char *key){ return; } didSendGroupCallKey=true; - SendPacketReliably(PKT_GROUP_CALL_KEY, key, 256, 0.5, 20); + Buffer buf(256); + buf.CopyFrom(key, 0, 256); + SendExtra(buf, EXTRA_TYPE_GROUP_CALL_KEY); } void VoIPController::RequestCallUpgrade(){ @@ -3566,90 +3153,8 @@ void VoIPController::RequestCallUpgrade(){ return; } didSendUpgradeRequest=true; - SendPacketReliably(PKT_REQUEST_GROUP, NULL, 0, 0.5, 20); -} - -void VoIPGroupController::GetDebugString(char *buffer, size_t len){ - char endpointsBuf[10240]; - memset(endpointsBuf, 0, 10240); - for(std::vector::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ - const char* type; - Endpoint* endpoint=*itrtr; - switch(endpoint->type){ - case Endpoint::TYPE_UDP_P2P_INET: - type="UDP_P2P_INET"; - break; - case Endpoint::TYPE_UDP_P2P_LAN: - type="UDP_P2P_LAN"; - break; - case Endpoint::TYPE_UDP_RELAY: - type="UDP_RELAY"; - break; - case Endpoint::TYPE_TCP_RELAY: - type="TCP_RELAY"; - break; - default: - type="UNKNOWN"; - break; - } - if(strlen(endpointsBuf)>10240-1024) - break; - sprintf(endpointsBuf+strlen(endpointsBuf), "%s:%u %dms [%s%s]\n", endpoint->address.ToString().c_str(), endpoint->port, (int)(endpoint->averageRTT*1000), type, currentEndpoint==endpoint ? ", IN_USE" : ""); - } - double avgLate[3]; - JitterBuffer* jitterBuffer=incomingStreams.size()==1 ? incomingStreams[0].jitterBuffer : NULL; - if(jitterBuffer) - jitterBuffer->GetAverageLateCount(avgLate); - else - memset(avgLate, 0, 3*sizeof(double)); - snprintf(buffer, len, - "Remote endpoints: \n%s" - "RTT avg/min: %d/%d\n" - "Congestion window: %d/%d bytes\n" - "Key fingerprint: %02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX\n" - "Last sent/ack'd seq: %u/%u\n" - "Send/recv losses: %u/%u (%d%%)\n" - "Audio bitrate: %d kbit\n" - "Bytes sent/recvd: %llu/%llu\n\n", - endpointsBuf, - (int)(conctl->GetAverageRTT()*1000), (int)(conctl->GetMinimumRTT()*1000), - int(conctl->GetInflightDataSize()), int(conctl->GetCongestionWindow()), - keyFingerprint[0],keyFingerprint[1],keyFingerprint[2],keyFingerprint[3],keyFingerprint[4],keyFingerprint[5],keyFingerprint[6],keyFingerprint[7], - lastSentSeq, lastRemoteAckSeq, - conctl->GetSendLossCount(), recvLossCount, encoder ? encoder->GetPacketLoss() : 0, - encoder ? (encoder->GetBitrate()/1000) : 0, - (long long unsigned int)(stats.bytesSentMobile+stats.bytesSentWifi), - (long long unsigned int)(stats.bytesRecvdMobile+stats.bytesRecvdWifi)); - - MutexGuard m(participantsMutex); - for(std::vector::iterator p=participants.begin();p!=participants.end();++p){ - snprintf(endpointsBuf, sizeof(endpointsBuf), "Participant id: %d\n", p->userID); - if(strlen(buffer)+strlen(endpointsBuf)>len) - return; - strcat(buffer, endpointsBuf); - for(std::vector::iterator stm=p->streams.begin();stm!=p->streams.end();++stm){ - char* codec=reinterpret_cast(&stm->codec); - snprintf(endpointsBuf, sizeof(endpointsBuf), "Stream %d (type %d, codec '%c%c%c%c', %sabled)\n", - stm->id, stm->type, codec[3], codec[2], codec[1], codec[0], stm->enabled ? "en" : "dis"); - if(strlen(buffer)+strlen(endpointsBuf)>len) - return; - strcat(buffer, endpointsBuf); - if(stm->enabled){ - if(stm->jitterBuffer){ - snprintf(endpointsBuf, sizeof(endpointsBuf), "Jitter buffer: %d/%.2f\n", - stm->jitterBuffer->GetMinPacketCount(), stm->jitterBuffer->GetAverageDelay()); - if(strlen(buffer)+strlen(endpointsBuf)>len) - return; - strcat(buffer, endpointsBuf); - } - } - } - strcat(buffer, "\n"); - } -} - -int32_t VoIPGroupController::GetCurrentUnixtime(){ - return time(NULL)+timeDifference; + Buffer empty(0); + SendExtra(empty, EXTRA_TYPE_REQUEST_GROUP); } void VoIPController::SetEchoCancellationStrength(int strength){ @@ -3674,7 +3179,7 @@ Endpoint::Endpoint(int64_t id, uint16_t port, IPv4Address& _address, IPv6Address udpPongCount=0; } -Endpoint::Endpoint() : address(0), v6address("::0") { +Endpoint::Endpoint() : address(0), v6address(string("::0")) { lastPingSeq=0; lastPingTime=0; averageRTT=0; @@ -3682,3 +3187,18 @@ Endpoint::Endpoint() : address(0), v6address("::0") { socket=NULL; udpPongCount=0; } + +NetworkAddress &Endpoint::GetAddress(){ + return IsIPv6Only() ? (NetworkAddress&)v6address : (NetworkAddress&)address; +} + +bool Endpoint::IsIPv6Only(){ + return address.IsEmpty() && !v6address.IsEmpty(); +} + +Endpoint::~Endpoint(){ + if(socket){ + socket->Close(); + delete socket; + } +} diff --git a/VoIPController.h b/VoIPController.h index e38539e509..8ad1f60830 100644 --- a/VoIPController.h +++ b/VoIPController.h @@ -18,10 +18,10 @@ #include #include #include -#include +#include +#include #include "audio/AudioInput.h" #include "BlockingQueue.h" -#include "BufferOutputStream.h" #include "audio/AudioOutput.h" #include "JitterBuffer.h" #include "OpusDecoder.h" @@ -29,9 +29,10 @@ #include "EchoCanceller.h" #include "CongestionControl.h" #include "NetworkSocket.h" -#include "BufferInputStream.h" +#include "Buffers.h" +#include "PacketReassembler.h" -#define LIBTGVOIP_VERSION "2.0-alpha4" +#define LIBTGVOIP_VERSION "2.1" #ifdef _WIN32 #undef GetCurrentTime @@ -40,59 +41,6 @@ #define TGVOIP_PEER_CAP_GROUP_CALLS 1 -struct voip_queued_packet_t{ - unsigned char type; - unsigned char* data; - size_t length; - uint32_t seqs[16]; - double firstSentTime; - double lastSentTime; - double retryInterval; - double timeout; -}; -typedef struct voip_queued_packet_t voip_queued_packet_t; - -struct voip_config_t{ - double init_timeout; - double recv_timeout; - int data_saving; - char logFilePath[256]; - char statsDumpFilePath[256]; - - bool enableAEC; - bool enableNS; - bool enableAGC; - - bool enableCallUpgrade; -}; -typedef struct voip_config_t voip_config_t; - -struct voip_stats_t{ - uint64_t bytesSentWifi; - uint64_t bytesRecvdWifi; - uint64_t bytesSentMobile; - uint64_t bytesRecvdMobile; -}; -typedef struct voip_stats_t voip_stats_t; - -struct voip_crypto_functions_t{ - void (*rand_bytes)(uint8_t* buffer, size_t length); - void (*sha1)(uint8_t* msg, size_t length, uint8_t* output); - void (*sha256)(uint8_t* msg, size_t length, uint8_t* output); - void (*aes_ige_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv); - void (*aes_ige_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv); - void (*aes_ctr_encrypt)(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num); - void (*aes_cbc_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv); - void (*aes_cbc_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv); -}; -typedef struct voip_crypto_functions_t voip_crypto_functions_t; - -#define SEQ_MAX 0xFFFFFFFF - -inline bool seqgt(uint32_t s1, uint32_t s2){ - return ((s1>s2) && (s1-s2<=SEQ_MAX/2)) || ((s1SEQ_MAX/2)); -} - namespace tgvoip{ enum{ @@ -113,7 +61,8 @@ namespace tgvoip{ ERROR_UNKNOWN=0, ERROR_INCOMPATIBLE, ERROR_TIMEOUT, - ERROR_AUDIO_IO + ERROR_AUDIO_IO, + ERROR_PROXY }; enum{ @@ -137,6 +86,17 @@ namespace tgvoip{ DATA_SAVING_ALWAYS }; + struct CryptoFunctions{ + void (*rand_bytes)(uint8_t* buffer, size_t length); + void (*sha1)(uint8_t* msg, size_t length, uint8_t* output); + void (*sha256)(uint8_t* msg, size_t length, uint8_t* output); + void (*aes_ige_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv); + void (*aes_ige_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv); + void (*aes_ctr_encrypt)(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num); + void (*aes_cbc_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv); + void (*aes_cbc_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv); + }; + class Endpoint{ friend class VoIPController; friend class VoIPGroupController; @@ -151,6 +111,9 @@ namespace tgvoip{ Endpoint(int64_t id, uint16_t port, IPv4Address& address, IPv6Address& v6address, char type, unsigned char* peerTag); Endpoint(); + ~Endpoint(); + NetworkAddress& GetAddress(); + bool IsIPv6Only(); int64_t id; uint16_t port; IPv4Address address; @@ -181,9 +144,58 @@ namespace tgvoip{ }; + struct EncodedVideoFrame{ + unsigned char* data; + size_t size; + uint32_t flags; + + EncodedVideoFrame(size_t size){ + this->size=size; + data=(unsigned char*)malloc(size); + } + + ~EncodedVideoFrame(){ + free(data); + } + }; + class VoIPController{ friend class VoIPGroupController; public: + struct Config{ + Config(){ + } + + Config(double initTimeout, double recvTimeout, int dataSaving, bool enableAEC=false, bool enableNS=false, bool enableAGC=false){ + this->initTimeout=initTimeout; + this->recvTimeout=recvTimeout; + this->dataSaving=dataSaving; + this->enableAEC=enableAEC; + this->enableNS=enableNS; + this->enableAGC=enableAGC; + } + + double initTimeout; + double recvTimeout; + int dataSaving; + std::string logFilePath=""; + std::string statsDumpFilePath=""; + + bool enableAEC=false; + bool enableNS=false; + bool enableAGC=false; + + bool enableCallUpgrade=false; + }; + + struct TrafficStats{ + uint64_t bytesSentWifi; + uint64_t bytesRecvdWifi; + uint64_t bytesSentMobile; + uint64_t bytesRecvdMobile; + }; + + VoIPController(); virtual ~VoIPController(); @@ -208,10 +220,8 @@ namespace tgvoip{ Endpoint& GetRemoteEndpoint(); /** * Get the debug info string to be displayed in client UI - * @param buffer The buffer to put the string into - * @param len The length of the buffer */ - virtual void GetDebugString(char* buffer, size_t len); + virtual std::string GetDebugString(); /** * Notify the library of network type change * @param type The new network type @@ -242,14 +252,14 @@ namespace tgvoip{ * * @param cfg */ - void SetConfig(voip_config_t* cfg); + void SetConfig(Config& cfg); float GetOutputLevel(); void DebugCtl(int request, int param); /** * * @param stats */ - void GetStats(voip_stats_t* stats); + void GetStats(TrafficStats* stats); /** * * @return @@ -263,7 +273,7 @@ namespace tgvoip{ /** * */ - static voip_crypto_functions_t crypto; + static CryptoFunctions crypto; /** * * @return @@ -357,6 +367,10 @@ namespace tgvoip{ }; void SetCallbacks(Callbacks callbacks); + private: + struct Stream; + struct UnacknowledgedExtraData; + protected: struct RecentOutgoingPacket{ uint32_t seq; @@ -367,17 +381,34 @@ namespace tgvoip{ struct PendingOutgoingPacket{ uint32_t seq; unsigned char type; + //Buffer data; size_t len; unsigned char* data; - Endpoint* endpoint; + int64_t endpoint; }; - virtual void ProcessIncomingPacket(NetworkPacket& packet, Endpoint* srcEndpoint); + struct SegmentedPacket{ + unsigned char type; + + }; + struct QueuedPacket{ + Buffer data; + unsigned char type; + uint32_t seqs[16]; + double firstSentTime; + double lastSentTime; + double retryInterval; + double timeout; + }; + virtual void ProcessIncomingPacket(NetworkPacket& packet, std::shared_ptr srcEndpoint); + virtual void ProcessExtraData(Buffer& data); 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 SendPacket(unsigned char* data, size_t len, std::shared_ptr ep, PendingOutgoingPacket& srcPacket); virtual void SendInit(); - virtual void SendUdpPing(Endpoint* endpoint); + virtual void SendUdpPing(std::shared_ptr endpoint); virtual void SendRelayPings(); virtual void OnAudioOutputReady(); + virtual void SendExtra(Buffer& data, unsigned char type); + void SendStreamFlags(Stream& stream); private: struct Stream{ @@ -386,10 +417,18 @@ namespace tgvoip{ unsigned char type; uint32_t codec; bool enabled; + bool extraECEnabled; uint16_t frameDuration; - JitterBuffer* jitterBuffer; - OpusDecoder* decoder; - CallbackWrapper* callbackWrapper; + std::shared_ptr jitterBuffer; + std::shared_ptr decoder; + std::shared_ptr packetReassembler; + std::shared_ptr callbackWrapper; + std::vector codecSpecificData; + }; + struct UnacknowledgedExtraData{ + unsigned char type; + Buffer data; + uint32_t firstContainingSeq; }; enum{ UDP_UNKNOWN=0, @@ -402,7 +441,8 @@ namespace tgvoip{ void RunRecvThread(void* arg); void RunSendThread(void* arg); void RunTickThread(void* arg); - void HandleAudioInput(unsigned char* data, size_t len); + void HandleAudioInput(unsigned char* data, size_t len, unsigned char* secondaryData, size_t secondaryLen); + void HandleVideoInput(EncodedVideoFrame& frame); void UpdateAudioBitrate(); void SetState(int state); void UpdateAudioOutputState(); @@ -410,20 +450,23 @@ namespace tgvoip{ 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); + static void AudioInputCallback(unsigned char* data, size_t length, unsigned char* secondaryData, size_t secondaryLength, void* param); void SendPublicEndpointsRequest(); void SendPublicEndpointsRequest(Endpoint& relay); - Endpoint* GetEndpointByType(int type); + std::shared_ptr GetEndpointByType(int type); + std::shared_ptr GetEndpointByID(int64_t id); 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 ActuallySendPacket(NetworkPacket& pkt, std::shared_ptr ep); void StartAudio(); + void ProcessAcknowledgedOutgoingExtra(UnacknowledgedExtraData& extra); + void AddIPv6Relays(); int state; - std::vector endpoints; - Endpoint* currentEndpoint; - Endpoint* preferredRelay; - Endpoint* peerPreferredRelay; + std::vector> endpoints; + std::shared_ptr currentEndpoint; + std::shared_ptr preferredRelay; + std::shared_ptr peerPreferredRelay; bool runReceiver; uint32_t seq; uint32_t lastRemoteSeq; @@ -435,18 +478,19 @@ namespace tgvoip{ uint32_t audioTimestampIn; uint32_t audioTimestampOut; tgvoip::audio::AudioInput* audioInput; - tgvoip::audio::AudioOutput* audioOutput; + std::unique_ptr audioOutput; OpusEncoder* encoder; BlockingQueue* sendQueue; EchoCanceller* echoCanceller; Mutex sendBufferMutex; Mutex endpointsMutex; + Mutex socketSelectMutex; bool stopping; bool audioOutStarted; Thread* recvThread; Thread* sendThread; Thread* tickThread; - uint32_t packetsRecieved; + uint32_t packetsReceived; uint32_t recvLossCount; uint32_t prevSendLossCount; uint32_t firstSentPing; @@ -457,8 +501,8 @@ namespace tgvoip{ int lastError; bool micMuted; uint32_t maxBitrate; - std::vector outgoingStreams; - std::vector incomingStreams; + std::vector> outgoingStreams; + std::vector> incomingStreams; unsigned char encryptionKey[256]; unsigned char keyFingerprint[8]; unsigned char callID[16]; @@ -469,15 +513,15 @@ namespace tgvoip{ bool dataSavingRequestedByPeer; std::string activeNetItfName; double publicEndpointsReqTime; - std::vector queuedPackets; + std::vector queuedPackets; Mutex audioIOMutex; Mutex queuedPacketsMutex; double connectionInitTime; double lastRecvPacketTime; - voip_config_t config; + Config config; int32_t peerVersion; CongestionControl* conctl; - voip_stats_t stats; + TrafficStats stats; bool receivedInit; bool receivedInitAck; std::vector debugLogs; @@ -518,12 +562,23 @@ namespace tgvoip{ bool didReceiveGroupCallKeyAck; bool didSendGroupCallKey; bool didSendUpgradeRequest; - bool didInvokeUpdateCallback; + bool didInvokeUpgradeCallback; int32_t connectionMaxLayer; bool useMTProto2; bool setCurrentEndpointToTCP; + std::vector currentExtras; + std::unordered_map lastReceivedExtrasByType; + bool useIPv6; + bool peerIPv6Available; + IPv6Address myIPv6; + bool shittyInternetMode; + std::vector ecAudioPackets; + bool didAddIPv6Relays; + bool didSendIPv6Endpoint; + int publicEndpointsReqCount=0; + /*** server config values ***/ uint32_t maxAudioBitrate; uint32_t maxAudioBitrateEDGE; @@ -576,26 +631,26 @@ namespace tgvoip{ }; void SetCallbacks(Callbacks callbacks); - virtual void GetDebugString(char* buffer, size_t length); + virtual std::string GetDebugString(); virtual void SetNetworkType(int type); protected: - virtual void ProcessIncomingPacket(NetworkPacket& packet, Endpoint* srcEndpoint); + virtual void ProcessIncomingPacket(NetworkPacket& packet, std::shared_ptr srcEndpoint); virtual void SendInit(); - virtual void SendUdpPing(Endpoint* endpoint); + virtual void SendUdpPing(std::shared_ptr endpoint); virtual void SendRelayPings(); - virtual void SendPacket(unsigned char* data, size_t len, Endpoint* ep, PendingOutgoingPacket& srcPacket); + virtual void SendPacket(unsigned char* data, size_t len, std::shared_ptr 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 DeserializeStreams(BufferInputStream& in); + std::vector> 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 streams; + std::vector> streams; AudioLevelMeter* levelMeter; }; std::vector participants; @@ -603,7 +658,7 @@ namespace tgvoip{ unsigned char reflectorSelfSecret[16]; unsigned char reflectorSelfTagHash[32]; int32_t userSelfID; - Endpoint* groupReflector; + std::shared_ptr groupReflector; AudioMixer* audioMixer; AudioLevelMeter selfLevelMeter; Callbacks groupCallbacks; diff --git a/VoIPGroupController.cpp b/VoIPGroupController.cpp new file mode 100644 index 0000000000..5c2fc21d02 --- /dev/null +++ b/VoIPGroupController.cpp @@ -0,0 +1,813 @@ +// +// libtgvoip is free and unencumbered public domain software. +// For more information, see http://unlicense.org or the UNLICENSE file +// you should have received with this source code distribution. +// + +#include "VoIPController.h" +#include "logging.h" +#include "VoIPServerConfig.h" +#include "PrivateDefines.h" +#include +#include + +using namespace tgvoip; +using namespace std; + +VoIPGroupController::VoIPGroupController(int32_t timeDifference){ + audioMixer=new AudioMixer(); + memset(&callbacks, 0, sizeof(callbacks)); + userSelfID=0; + this->timeDifference=timeDifference; + LOGV("Created VoIPGroupController; timeDifference=%d", timeDifference); +} + +VoIPGroupController::~VoIPGroupController(){ + if(audioOutput){ + audioOutput->Stop(); + } + LOGD("before stop audio mixer"); + audioMixer->Stop(); + delete audioMixer; + + for(vector::iterator p=participants.begin();p!=participants.end();p++){ + if(p->levelMeter) + delete p->levelMeter; + } +} + +void VoIPGroupController::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){ + shared_ptr e=make_shared(); + e->address=reflectorAddress; + e->v6address=reflectorAddressV6; + e->port=reflectorPort; + memcpy(e->peerTag, reflectorGroupTag, 16); + e->type=Endpoint::TYPE_UDP_RELAY; + endpoints.push_back(e); + groupReflector=e; + currentEndpoint=e; + + memcpy(this->encryptionKey, encryptionKey, 256); + memcpy(this->reflectorSelfTag, reflectorSelfTag, 16); + memcpy(this->reflectorSelfSecret, reflectorSelfSecret, 16); + memcpy(this->reflectorSelfTagHash, reflectorSelfTagHash, 16); + uint8_t sha256[SHA256_LENGTH]; + crypto.sha256((uint8_t*) encryptionKey, 256, sha256); + memcpy(callID, sha256+(SHA256_LENGTH-16), 16); + memcpy(keyFingerprint, sha256+(SHA256_LENGTH-16), 8); + this->userSelfID=selfUserID; + + //LOGD("reflectorSelfTag = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", reflectorSelfTag[0], reflectorSelfTag[1], reflectorSelfTag[2], reflectorSelfTag[3], reflectorSelfTag[4], reflectorSelfTag[5], reflectorSelfTag[6], reflectorSelfTag[7], reflectorSelfTag[8], reflectorSelfTag[9], reflectorSelfTag[10], reflectorSelfTag[11], reflectorSelfTag[12], reflectorSelfTag[13], reflectorSelfTag[14], reflectorSelfTag[15]); + //LOGD("reflectorSelfSecret = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", reflectorSelfSecret[0], reflectorSelfSecret[1], reflectorSelfSecret[2], reflectorSelfSecret[3], reflectorSelfSecret[4], reflectorSelfSecret[5], reflectorSelfSecret[6], reflectorSelfSecret[7], reflectorSelfSecret[8], reflectorSelfSecret[9], reflectorSelfSecret[10], reflectorSelfSecret[11], reflectorSelfSecret[12], reflectorSelfSecret[13], reflectorSelfSecret[14], reflectorSelfSecret[15]); + //LOGD("reflectorSelfTagHash = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", reflectorSelfTagHash[0], reflectorSelfTagHash[1], reflectorSelfTagHash[2], reflectorSelfTagHash[3], reflectorSelfTagHash[4], reflectorSelfTagHash[5], reflectorSelfTagHash[6], reflectorSelfTagHash[7], reflectorSelfTagHash[8], reflectorSelfTagHash[9], reflectorSelfTagHash[10], reflectorSelfTagHash[11], reflectorSelfTagHash[12], reflectorSelfTagHash[13], reflectorSelfTagHash[14], reflectorSelfTagHash[15]); +} + +void VoIPGroupController::AddGroupCallParticipant(int32_t userID, unsigned char *memberTagHash, unsigned char* serializedStreams, size_t streamsLength){ + if(userID==userSelfID) + return; + if(userSelfID==0) + return; + //if(streamsLength==0) + // return; + MutexGuard m(participantsMutex); + LOGV("Adding group call user %d, streams length %u", userID, (unsigned int)streamsLength); + + for(vector::iterator p=participants.begin();p!=participants.end();++p){ + if(p->userID==userID){ + LOGE("user %d already added", userID); + abort(); + break; + } + } + + GroupCallParticipant p; + p.userID=userID; + memcpy(p.memberTagHash, memberTagHash, sizeof(p.memberTagHash)); + p.levelMeter=new AudioLevelMeter(); + + BufferInputStream ss(serializedStreams, streamsLength); + vector> streams=DeserializeStreams(ss); + + unsigned char audioStreamID=0; + + for(vector>::iterator _s=streams.begin();_s!=streams.end();++_s){ + shared_ptr& s=*_s; + s->userID=userID; + if(s->type==STREAM_TYPE_AUDIO && s->codec==CODEC_OPUS && !audioStreamID){ + audioStreamID=s->id; + s->jitterBuffer=make_shared(nullptr, s->frameDuration); + if(s->frameDuration>50) + s->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_60", 2)); + else if(s->frameDuration>30) + s->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_40", 4)); + else + s->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_20", 6)); + s->callbackWrapper=make_shared(); + s->decoder=make_shared(s->callbackWrapper, false, false); + s->decoder->SetJitterBuffer(s->jitterBuffer); + s->decoder->SetFrameDuration(s->frameDuration); + s->decoder->SetDTX(true); + s->decoder->SetLevelMeter(p.levelMeter); + audioMixer->AddInput(s->callbackWrapper); + } + incomingStreams.push_back(s); + } + + if(!audioStreamID){ + LOGW("User %d has no usable audio stream", userID); + } + + p.streams.insert(p.streams.end(), streams.begin(), streams.end()); + participants.push_back(p); + LOGI("Added group call participant %d", userID); +} + +void VoIPGroupController::RemoveGroupCallParticipant(int32_t userID){ + MutexGuard m(participantsMutex); + vector>::iterator stm=incomingStreams.begin(); + while(stm!=incomingStreams.end()){ + if((*stm)->userID==userID){ + LOGI("Removed stream %d belonging to user %d", (*stm)->id, userID); + audioMixer->RemoveInput((*stm)->callbackWrapper); + (*stm)->decoder->Stop(); + //delete (*stm)->decoder; + //delete (*stm)->jitterBuffer; + //delete (*stm)->callbackWrapper; + stm=incomingStreams.erase(stm); + continue; + } + ++stm; + } + for(vector::iterator p=participants.begin();p!=participants.end();++p){ + if(p->userID==userID){ + if(p->levelMeter) + delete p->levelMeter; + participants.erase(p); + LOGI("Removed group call participant %d", userID); + break; + } + } +} + +vector> VoIPGroupController::DeserializeStreams(BufferInputStream& in){ + vector> res; + try{ + unsigned char count=in.ReadByte(); + for(unsigned char i=0;i s=make_shared(); + s->id=inner.ReadByte(); + s->type=inner.ReadByte(); + s->codec=(uint32_t) inner.ReadInt32(); + uint32_t flags=(uint32_t) inner.ReadInt32(); + s->enabled=(flags & STREAM_FLAG_ENABLED)==STREAM_FLAG_ENABLED; + s->frameDuration=(uint16_t) inner.ReadInt16(); + res.push_back(s); + } + }catch(out_of_range& x){ + LOGW("Error deserializing streams: %s", x.what()); + } + return res; +} + +void VoIPGroupController::SetParticipantStreams(int32_t userID, unsigned char *serializedStreams, size_t length){ + LOGD("Set participant streams for %d", userID); + MutexGuard m(participantsMutex); + for(vector::iterator p=participants.begin();p!=participants.end();++p){ + if(p->userID==userID){ + BufferInputStream in(serializedStreams, length); + vector> streams=DeserializeStreams(in); + for(vector>::iterator ns=streams.begin();ns!=streams.end();++ns){ + bool found=false; + for(vector>::iterator s=p->streams.begin();s!=p->streams.end();++s){ + if((*s)->id==(*ns)->id){ + (*s)->enabled=(*ns)->enabled; + if(groupCallbacks.participantAudioStateChanged) + groupCallbacks.participantAudioStateChanged(this, userID, (*s)->enabled); + found=true; + break; + } + } + if(!found){ + LOGW("Tried to add stream %d for user %d but adding/removing streams is not supported", (*ns)->id, userID); + } + } + break; + } + } +} + +size_t VoIPGroupController::GetInitialStreams(unsigned char *buf, size_t size){ + BufferOutputStream s(buf, size); + s.WriteByte(1); // streams count + + s.WriteInt16(12); // this object length + s.WriteByte(1); // stream id + s.WriteByte(STREAM_TYPE_AUDIO); + s.WriteInt32(CODEC_OPUS); + s.WriteInt32(STREAM_FLAG_ENABLED | STREAM_FLAG_DTX); // flags + s.WriteInt16(60); // frame duration + + return s.GetLength(); +} + +void VoIPGroupController::SendInit(){ + SendRecentPacketsRequest(); +} + +void VoIPGroupController::ProcessIncomingPacket(NetworkPacket &packet, shared_ptr srcEndpoint){ + //LOGD("Received incoming packet from %s:%u, %u bytes", packet.address->ToString().c_str(), packet.port, packet.length); + if(packet.length<17 || packet.length>2000){ + LOGW("Received packet has wrong length %d", (int)packet.length); + return; + } + BufferOutputStream sigData(packet.length); + sigData.WriteBytes(packet.data, packet.length-16); + sigData.WriteBytes(reflectorSelfSecret, 16); + unsigned char sig[32]; + crypto.sha256(sigData.GetBuffer(), sigData.GetLength(), sig); + if(memcmp(sig, packet.data+(packet.length-16), 16)!=0){ + LOGW("Received packet has incorrect signature"); + return; + } + + // reflector special response + if(memcmp(packet.data, reflectorSelfTagHash, 16)==0 && packet.length>60){ + //LOGI("possible reflector special response"); + unsigned char firstBlock[16]; + unsigned char iv[16]; + memcpy(iv, packet.data+16, 16); + unsigned char key[32]; + crypto.sha256(reflectorSelfSecret, 16, key); + crypto.aes_cbc_decrypt(packet.data+32, firstBlock, 16, key, iv); + BufferInputStream in(firstBlock, 16); + in.Seek(8); + size_t len=(size_t) in.ReadInt32(); + int32_t tlid=in.ReadInt32(); + //LOGD("special response: len=%d, tlid=0x%08X", len, tlid); + if(len%4==0 && len+60<=packet.length && packet.length<=1500){ + lastRecvPacketTime=GetCurrentTime(); + memcpy(iv, packet.data+16, 16); + unsigned char buf[1500]; + crypto.aes_cbc_decrypt(packet.data+32, buf, len+16, key, iv); + try{ + if(tlid==TLID_UDP_REFLECTOR_LAST_PACKETS_INFO){ + MutexGuard m(sentPacketsMutex); + //LOGV("received udpReflector.lastPacketsInfo"); + in=BufferInputStream(buf, len+16); + in.Seek(16); + /*int32_t date=*/in.ReadInt32(); + /*int64_t queryID=*/in.ReadInt64(); + int32_t vectorMagic=in.ReadInt32(); + if(vectorMagic!=TLID_VECTOR){ + LOGW("last packets info: expected vector, got %08X", vectorMagic); + return; + } + int32_t recvCount=in.ReadInt32(); + //LOGV("%d received packets", recvCount); + for(int i=0;i::iterator pkt=recentSentPackets.begin();pkt!=recentSentPackets.end();++pkt){ + //LOGV("== sent id %04X", pkt->id); + if(pkt->id==id){ + if(!pkt->ackTime){ + pkt->ackTime=GetCurrentTime(); + conctl->PacketAcknowledged(pkt->seq); + //LOGV("relay acknowledged packet %u", pkt->seq); + if(seqgt(pkt->seq, lastRemoteAckSeq)) + lastRemoteAckSeq=pkt->seq; + } + break; + } + } + } + vectorMagic=in.ReadInt32(); + if(vectorMagic!=TLID_VECTOR){ + LOGW("last packets info: expected vector, got %08X", vectorMagic); + return; + } + int32_t sentCount=in.ReadInt32(); + //LOGV("%d sent packets", sentCount); + for(int i=0;iStart(); + } + } + } + }catch(out_of_range& x){ + LOGE("Error parsing special response: %s", x.what()); + } + return; + } + } + + if(packet.length<32) + return; + + // it's a packet relayed from another participant - find the sender + MutexGuard m(participantsMutex); + GroupCallParticipant* sender=NULL; + for(vector::iterator p=participants.begin();p!=participants.end();++p){ + if(memcmp(packet.data, p->memberTagHash, 16)==0){ + //LOGV("received data packet from user %d", p->userID); + sender=&*p; + break; + } + } + if(!sender){ + LOGV("Received data packet is from unknown user"); + return; + } + + if(memcmp(packet.data+16, keyFingerprint, 8)!=0){ + LOGW("received packet has wrong key fingerprint"); + return; + } + + BufferInputStream in(packet.data, packet.length-16); + in.Seek(16+8); // peer tag + key fingerprint + + unsigned char msgKey[16]; + in.ReadBytes(msgKey, 16); + + unsigned char decrypted[1500]; + unsigned char aesKey[32], aesIv[32]; + KDF2(msgKey, 0, aesKey, aesIv); + size_t decryptedLen=in.Remaining()-16; + if(decryptedLen>sizeof(decrypted)) + return; + //LOGV("-> MSG KEY: %08x %08x %08x %08x, hashed %u", *reinterpret_cast(msgKey), *reinterpret_cast(msgKey+4), *reinterpret_cast(msgKey+8), *reinterpret_cast(msgKey+12), decryptedLen-4); + uint8_t *decryptOffset = packet.data + in.GetOffset(); + if ((((intptr_t)decryptOffset) % sizeof(long)) != 0) { + LOGE("alignment2 packet.data+in.GetOffset()"); + } + if (decryptedLen % sizeof(long) != 0) { + LOGE("alignment2 decryptedLen"); + } + crypto.aes_ige_decrypt(packet.data+in.GetOffset(), decrypted, decryptedLen, aesKey, aesIv); + + in=BufferInputStream(decrypted, decryptedLen); + //LOGD("received packet length: %d", in.ReadInt32()); + + BufferOutputStream buf(decryptedLen+32); + size_t x=0; + buf.WriteBytes(encryptionKey+88+x, 32); + buf.WriteBytes(decrypted+4, decryptedLen-4); + unsigned char msgKeyLarge[32]; + crypto.sha256(buf.GetBuffer(), buf.GetLength(), msgKeyLarge); + + if(memcmp(msgKey, msgKeyLarge+8, 16)!=0){ + LOGW("Received packet from user %d has wrong hash", sender->userID); + return; + } + + uint32_t innerLen=(uint32_t) in.ReadInt32(); + if(innerLen>decryptedLen-4){ + LOGW("Received packet has wrong inner length (%d with total of %u)", (int)innerLen, (unsigned int)decryptedLen); + return; + } + if(decryptedLen-innerLen<12){ + LOGW("Received packet has too little padding (%u)", (unsigned int)(decryptedLen-innerLen)); + return; + } + in=BufferInputStream(decrypted+4, (size_t) innerLen); + + uint32_t tlid=(uint32_t) in.ReadInt32(); + if(tlid!=TLID_DECRYPTED_AUDIO_BLOCK){ + LOGW("Received packet has unknown TL ID 0x%08x", tlid); + return; + } + in.Seek(in.GetOffset()+16); // random bytes + int32_t flags=in.ReadInt32(); + if(!(flags & PFLAG_HAS_SEQ) || !(flags & PFLAG_HAS_SENDER_TAG_HASH)){ + LOGW("Received packet has wrong flags"); + return; + } + /*uint32_t seq=(uint32_t) */in.ReadInt32(); + unsigned char senderTagHash[16]; + in.ReadBytes(senderTagHash, 16); + if(memcmp(senderTagHash, sender->memberTagHash, 16)!=0){ + LOGW("Received packet has wrong inner sender tag hash"); + return; + } + + //int32_t oneMoreInnerLengthWhyDoWeEvenNeedThis; + if(flags & PFLAG_HAS_DATA){ + /*oneMoreInnerLengthWhyDoWeEvenNeedThis=*/in.ReadTlLength(); + } + unsigned char type=(unsigned char) ((flags >> 24) & 0xFF); + lastRecvPacketTime=GetCurrentTime(); + + if(type==PKT_STREAM_DATA || type==PKT_STREAM_DATA_X2 || type==PKT_STREAM_DATA_X3){ + if(state!=STATE_ESTABLISHED && receivedInitAck) + SetState(STATE_ESTABLISHED); + int count; + switch(type){ + case PKT_STREAM_DATA_X2: + count=2; + break; + case PKT_STREAM_DATA_X3: + count=3; + break; + case PKT_STREAM_DATA: + default: + count=1; + break; + } + int i; + //if(srcEndpoint->type==Endpoint::TYPE_UDP_RELAY && srcEndpoint!=peerPreferredRelay){ + // peerPreferredRelay=srcEndpoint; + //} + for(i=0;iStart(); + audioOutStarted=true; + }*/ + if(in.GetOffset()+sdlen>in.GetLength()){ + return; + } + for(vector>::iterator stm=sender->streams.begin();stm!=sender->streams.end();++stm){ + if((*stm)->id==streamID){ + if((*stm)->jitterBuffer){ + (*stm)->jitterBuffer->HandleInput(decrypted+4+in.GetOffset(), sdlen, pts, false); + } + break; + } + } + if(i endpoint){ + +} + +void VoIPGroupController::SetNetworkType(int type){ + networkType=type; + UpdateDataSavingState(); + UpdateAudioBitrate(); + string itfName=udpSocket->GetLocalInterfaceInfo(NULL, NULL); + if(itfName!=activeNetItfName){ + udpSocket->OnActiveInterfaceChanged(); + LOGI("Active network interface changed: %s -> %s", activeNetItfName.c_str(), itfName.c_str()); + bool isFirstChange=activeNetItfName.length()==0; + activeNetItfName=itfName; + if(isFirstChange) + return; + udpConnectivityState=UDP_UNKNOWN; + udpPingCount=0; + lastUdpPingTime=0; + if(proxyProtocol==PROXY_SOCKS5) + InitUDPProxy(); + selectCanceller->CancelSelect(); + } +} + +void VoIPGroupController::SendRecentPacketsRequest(){ + BufferOutputStream out(1024); + out.WriteInt32(TLID_UDP_REFLECTOR_REQUEST_PACKETS_INFO); // TL function + out.WriteInt32(GetCurrentUnixtime()); // date:int + out.WriteInt64(0); // query_id:long + out.WriteInt32(64); // recv_num:int + out.WriteInt32(0); // sent_num:int + SendSpecialReflectorRequest(out.GetBuffer(), out.GetLength()); +} + +void VoIPGroupController::SendSpecialReflectorRequest(unsigned char *data, size_t len){ + BufferOutputStream out(1024); + unsigned char buf[1500]; + crypto.rand_bytes(buf, 8); + out.WriteBytes(buf, 8); + out.WriteInt32((int32_t)len); + out.WriteBytes(data, len); + if(out.GetLength()%16!=0){ + size_t paddingLen=16-(out.GetLength()%16); + crypto.rand_bytes(buf, paddingLen); + out.WriteBytes(buf, paddingLen); + } + unsigned char iv[16]; + crypto.rand_bytes(iv, 16); + unsigned char key[32]; + crypto.sha256(reflectorSelfSecret, 16, key); + unsigned char _iv[16]; + memcpy(_iv, iv, 16); + size_t encryptedLen=out.GetLength(); + crypto.aes_cbc_encrypt(out.GetBuffer(), buf, encryptedLen, key, _iv); + out.Reset(); + out.WriteBytes(reflectorSelfTag, 16); + out.WriteBytes(iv, 16); + out.WriteBytes(buf, encryptedLen); + out.WriteBytes(reflectorSelfSecret, 16); + crypto.sha256(out.GetBuffer(), out.GetLength(), buf); + out.Rewind(16); + out.WriteBytes(buf, 16); + + NetworkPacket pkt={0}; + pkt.address=&groupReflector->address; + pkt.port=groupReflector->port; + pkt.protocol=PROTO_UDP; + pkt.data=out.GetBuffer(); + pkt.length=out.GetLength(); + ActuallySendPacket(pkt, groupReflector); +} + +void VoIPGroupController::SendRelayPings(){ + //LOGV("Send relay pings 2"); + double currentTime=GetCurrentTime(); + if(currentTime-groupReflector->lastPingTime>=0.25){ + SendRecentPacketsRequest(); + groupReflector->lastPingTime=currentTime; + } +} + +void VoIPGroupController::OnAudioOutputReady(){ + encoder->SetDTX(true); + audioMixer->SetOutput((unique_ptr&)audioOutput); + audioMixer->SetEchoCanceller(echoCanceller); + audioMixer->Start(); + audioOutput->Start(); + audioOutStarted=true; + encoder->SetLevelMeter(&selfLevelMeter); +} + +void VoIPGroupController::WritePacketHeader(uint32_t seq, BufferOutputStream *s, unsigned char type, uint32_t length){ + s->WriteInt32(TLID_DECRYPTED_AUDIO_BLOCK); + int64_t randomID; + crypto.rand_bytes((uint8_t *) &randomID, 8); + s->WriteInt64(randomID); + unsigned char randBytes[7]; + crypto.rand_bytes(randBytes, 7); + s->WriteByte(7); + s->WriteBytes(randBytes, 7); + uint32_t pflags=PFLAG_HAS_SEQ | PFLAG_HAS_SENDER_TAG_HASH; + if(length>0) + pflags|=PFLAG_HAS_DATA; + pflags|=((uint32_t) type) << 24; + s->WriteInt32(pflags); + + if(type==PKT_STREAM_DATA || type==PKT_STREAM_DATA_X2 || type==PKT_STREAM_DATA_X3){ + conctl->PacketSent(seq, length); + } + + /*if(pflags & PFLAG_HAS_CALL_ID){ + s->WriteBytes(callID, 16); + }*/ + //s->WriteInt32(lastRemoteSeq); + s->WriteInt32(seq); + s->WriteBytes(reflectorSelfTagHash, 16); + if(length>0){ + if(length<=253){ + s->WriteByte((unsigned char) length); + }else{ + s->WriteByte(254); + s->WriteByte((unsigned char) (length & 0xFF)); + s->WriteByte((unsigned char) ((length >> 8) & 0xFF)); + s->WriteByte((unsigned char) ((length >> 16) & 0xFF)); + } + } +} + +void VoIPGroupController::SendPacket(unsigned char *data, size_t len, shared_ptr ep, PendingOutgoingPacket& srcPacket){ + if(stopping) + return; + if(ep->type==Endpoint::TYPE_TCP_RELAY && !useTCP) + return; + BufferOutputStream out(len+128); + //LOGV("send group packet %u", len); + + out.WriteBytes(reflectorSelfTag, 16); + + if(len>0){ + BufferOutputStream inner(len+128); + inner.WriteInt32((uint32_t)len); + inner.WriteBytes(data, len); + size_t padLen=16-inner.GetLength()%16; + if(padLen<12) + padLen+=16; + unsigned char padding[28]; + crypto.rand_bytes((uint8_t *) padding, padLen); + inner.WriteBytes(padding, padLen); + assert(inner.GetLength()%16==0); + + unsigned char key[32], iv[32], msgKey[16]; + out.WriteBytes(keyFingerprint, 8); + BufferOutputStream buf(len+32); + size_t x=0; + buf.WriteBytes(encryptionKey+88+x, 32); + buf.WriteBytes(inner.GetBuffer()+4, inner.GetLength()-4); + unsigned char msgKeyLarge[32]; + crypto.sha256(buf.GetBuffer(), buf.GetLength(), msgKeyLarge); + memcpy(msgKey, msgKeyLarge+8, 16); + KDF2(msgKey, 0, key, iv); + out.WriteBytes(msgKey, 16); + //LOGV("<- MSG KEY: %08x %08x %08x %08x, hashed %u", *reinterpret_cast(msgKey), *reinterpret_cast(msgKey+4), *reinterpret_cast(msgKey+8), *reinterpret_cast(msgKey+12), inner.GetLength()-4); + + unsigned char aesOut[MSC_STACK_FALLBACK(inner.GetLength(), 1500)]; + crypto.aes_ige_encrypt(inner.GetBuffer(), aesOut, inner.GetLength(), key, iv); + out.WriteBytes(aesOut, inner.GetLength()); + } + + // relay signature + out.WriteBytes(reflectorSelfSecret, 16); + unsigned char sig[32]; + crypto.sha256(out.GetBuffer(), out.GetLength(), sig); + out.Rewind(16); + out.WriteBytes(sig, 16); + + if(srcPacket.type==PKT_STREAM_DATA || srcPacket.type==PKT_STREAM_DATA_X2 || srcPacket.type==PKT_STREAM_DATA_X3){ + PacketIdMapping mapping={srcPacket.seq, *reinterpret_cast(sig+14), 0}; + MutexGuard m(sentPacketsMutex); + recentSentPackets.push_back(mapping); + //LOGD("sent packet with id: %04X", mapping.id); + while(recentSentPackets.size()>64) + recentSentPackets.erase(recentSentPackets.begin()); + } + lastSentSeq=srcPacket.seq; + + if(IS_MOBILE_NETWORK(networkType)) + stats.bytesSentMobile+=(uint64_t)out.GetLength(); + else + stats.bytesSentWifi+=(uint64_t)out.GetLength(); + + NetworkPacket pkt={0}; + pkt.address=(NetworkAddress*)&ep->address; + pkt.port=ep->port; + pkt.length=out.GetLength(); + pkt.data=out.GetBuffer(); + pkt.protocol=ep->type==Endpoint::TYPE_TCP_RELAY ? PROTO_TCP : PROTO_UDP; + ActuallySendPacket(pkt, ep); +} + +void VoIPGroupController::SetCallbacks(VoIPGroupController::Callbacks callbacks){ + VoIPController::SetCallbacks(callbacks); + this->groupCallbacks=callbacks; +} + +int32_t VoIPGroupController::GetCurrentUnixtime(){ + return time(NULL)+timeDifference; +} + +float VoIPGroupController::GetParticipantAudioLevel(int32_t userID){ + if(userID==userSelfID) + return selfLevelMeter.GetLevel(); + MutexGuard m(participantsMutex); + for(vector::iterator p=participants.begin(); p!=participants.end(); ++p){ + if(p->userID==userID){ + return p->levelMeter->GetLevel(); + } + } + return 0; +} + +void VoIPGroupController::SetMicMute(bool mute){ + micMuted=mute; + if(audioInput){ + if(mute) + audioInput->Stop(); + else + audioInput->Start(); + if(!audioInput->IsInitialized()){ + lastError=ERROR_AUDIO_IO; + SetState(STATE_FAILED); + return; + } + } + outgoingStreams[0]->enabled=!mute; + SerializeAndUpdateOutgoingStreams(); +} + +void VoIPGroupController::SetParticipantVolume(int32_t userID, float volume){ + MutexGuard m(participantsMutex); + for(vector::iterator p=participants.begin();p!=participants.end();++p){ + if(p->userID==userID){ + for(vector>::iterator s=p->streams.begin();s!=p->streams.end();++s){ + if((*s)->type==STREAM_TYPE_AUDIO){ + if((*s)->decoder){ + float db; + if(volume==0.0f) + db=-INFINITY; + else if(volume<1.0f) + db=-50.0f*(1.0f-volume); + else if(volume>1.0f && volume<=2.0f) + db=10.0f*(volume-1.0f); + else + db=0.0f; + //LOGV("Setting user %u audio volume to %.2f dB", userID, db); + audioMixer->SetInputVolume((*s)->callbackWrapper, db); + } + break; + } + } + break; + } + } +} + +void VoIPGroupController::SerializeAndUpdateOutgoingStreams(){ + BufferOutputStream out(1024); + out.WriteByte((unsigned char) outgoingStreams.size()); + + for(vector>::iterator s=outgoingStreams.begin(); s!=outgoingStreams.end(); ++s){ + BufferOutputStream o(128); + o.WriteByte((*s)->id); + o.WriteByte((*s)->type); + o.WriteInt32((*s)->codec); + o.WriteInt32((unsigned char) (((*s)->enabled ? STREAM_FLAG_ENABLED : 0) | STREAM_FLAG_DTX)); + o.WriteInt16((*s)->frameDuration); + out.WriteInt16((int16_t) o.GetLength()); + out.WriteBytes(o.GetBuffer(), o.GetLength()); + } + if(groupCallbacks.updateStreams) + groupCallbacks.updateStreams(this, out.GetBuffer(), out.GetLength()); +} + +std::string VoIPGroupController::GetDebugString(){ + std::string r="Remote endpoints: \n"; + char buffer[2048]; + for(shared_ptr& endpoint:endpoints){ + const char* type; + switch(endpoint->type){ + case Endpoint::TYPE_UDP_P2P_INET: + type="UDP_P2P_INET"; + break; + case Endpoint::TYPE_UDP_P2P_LAN: + type="UDP_P2P_LAN"; + break; + case Endpoint::TYPE_UDP_RELAY: + type="UDP_RELAY"; + break; + case Endpoint::TYPE_TCP_RELAY: + type="TCP_RELAY"; + break; + default: + type="UNKNOWN"; + break; + } + snprintf(buffer, sizeof(buffer), "%s:%u %dms [%s%s]\n", endpoint->address.ToString().c_str(), endpoint->port, (int)(endpoint->averageRTT*1000), type, currentEndpoint==endpoint ? ", IN_USE" : ""); + r+=buffer; + } + double avgLate[3]; + shared_ptr jitterBuffer=incomingStreams.size()==1 ? incomingStreams[0]->jitterBuffer : NULL; + if(jitterBuffer) + jitterBuffer->GetAverageLateCount(avgLate); + else + memset(avgLate, 0, 3*sizeof(double)); + snprintf(buffer, sizeof(buffer), + "RTT avg/min: %d/%d\n" + "Congestion window: %d/%d bytes\n" + "Key fingerprint: %02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX\n" + "Last sent/ack'd seq: %u/%u\n" + "Send/recv losses: %u/%u (%d%%)\n" + "Audio bitrate: %d kbit\n" + "Bytes sent/recvd: %llu/%llu\n\n", + (int)(conctl->GetAverageRTT()*1000), (int)(conctl->GetMinimumRTT()*1000), + int(conctl->GetInflightDataSize()), int(conctl->GetCongestionWindow()), + keyFingerprint[0],keyFingerprint[1],keyFingerprint[2],keyFingerprint[3],keyFingerprint[4],keyFingerprint[5],keyFingerprint[6],keyFingerprint[7], + lastSentSeq, lastRemoteAckSeq, + conctl->GetSendLossCount(), recvLossCount, encoder ? encoder->GetPacketLoss() : 0, + encoder ? (encoder->GetBitrate()/1000) : 0, + (long long unsigned int)(stats.bytesSentMobile+stats.bytesSentWifi), + (long long unsigned int)(stats.bytesRecvdMobile+stats.bytesRecvdWifi)); + + MutexGuard m(participantsMutex); + for(vector::iterator p=participants.begin();p!=participants.end();++p){ + snprintf(buffer, sizeof(buffer), "Participant id: %d\n", p->userID); + r+=buffer; + for(vector>::iterator stm=p->streams.begin();stm!=p->streams.end();++stm){ + char* codec=reinterpret_cast(&(*stm)->codec); + snprintf(buffer, sizeof(buffer), "Stream %d (type %d, codec '%c%c%c%c', %sabled)\n", + (*stm)->id, (*stm)->type, codec[3], codec[2], codec[1], codec[0], (*stm)->enabled ? "en" : "dis"); + r+=buffer; + if((*stm)->enabled){ + if((*stm)->jitterBuffer){ + snprintf(buffer, sizeof(buffer), "Jitter buffer: %d/%.2f\n", + (*stm)->jitterBuffer->GetMinPacketCount(), (*stm)->jitterBuffer->GetAverageDelay()); + r+=buffer; + } + } + } + r+="\n"; + } + return r; +} diff --git a/audio/AudioOutput.cpp b/audio/AudioOutput.cpp index da964eca8a..109d24dbfe 100644 --- a/audio/AudioOutput.cpp +++ b/audio/AudioOutput.cpp @@ -34,36 +34,31 @@ using namespace tgvoip::audio; int32_t AudioOutput::estimatedDelay=60; -AudioOutput *AudioOutput::Create(std::string deviceID, void* platformSpecific){ +std::unique_ptr AudioOutput::Create(std::string deviceID, void* platformSpecific){ #if defined(__ANDROID__) - char sdkNum[PROP_VALUE_MAX]; - __system_property_get("ro.build.version.sdk", sdkNum); - int systemVersion=atoi(sdkNum); - //if(systemVersion<21) - return new AudioOutputAndroid(); - //return new AudioOutputOpenSLES(); + return std::unique_ptr(new AudioOutputAndroid()); #elif defined(__APPLE__) #if TARGET_OS_OSX if(kCFCoreFoundationVersionNumber(new AudioOutputAudioUnitLegacy(deviceID)); #endif - return new AudioOutputAudioUnit(deviceID, reinterpret_cast(platformSpecific)); + return std::unique_ptr(new AudioOutputAudioUnit(deviceID, reinterpret_cast(platformSpecific))); #elif defined(_WIN32) #ifdef TGVOIP_WINXP_COMPAT if(LOBYTE(LOWORD(GetVersion()))<6) - return new AudioOutputWave(deviceID); + return std::unique_ptr(new AudioOutputWave(deviceID)); #endif - return new AudioOutputWASAPI(deviceID); + return std::unique_ptr(new AudioOutputWASAPI(deviceID)); #elif defined(__linux__) if(AudioOutputPulse::IsAvailable()){ AudioOutputPulse* aop=new AudioOutputPulse(deviceID); if(!aop->IsInitialized()) delete aop; else - return aop; + return std::unique_ptr(aop); LOGW("out: PulseAudio available but not working; trying ALSA"); } - return new AudioOutputALSA(deviceID); + return std::unique_ptr(new AudioOutputALSA(deviceID)); #endif } diff --git a/audio/AudioOutput.h b/audio/AudioOutput.h index 1be31784c0..7acae42461 100644 --- a/audio/AudioOutput.h +++ b/audio/AudioOutput.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "../MediaStreamItf.h" namespace tgvoip{ @@ -29,7 +30,7 @@ public: static int32_t GetEstimatedDelay(); virtual std::string GetCurrentDevice(); virtual void SetCurrentDevice(std::string deviceID); - static AudioOutput* Create(std::string deviceID, void* platformSpecific); + static std::unique_ptr Create(std::string deviceID, void* platformSpecific); static void EnumerateDevices(std::vector& devs); bool IsInitialized(); diff --git a/client/android/tg_voip_jni.cpp b/client/android/tg_voip_jni.cpp index 67f73298c1..cb1475810f 100644 --- a/client/android/tg_voip_jni.cpp +++ b/client/android/tg_voip_jni.cpp @@ -341,9 +341,8 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_AudioTrackJNI_nativeC } extern "C" JNIEXPORT jstring Java_org_telegram_messenger_voip_VoIPController_nativeGetDebugString(JNIEnv* env, jobject thiz, jlong inst){ - char buf[10240]; - ((VoIPController*)(intptr_t)inst)->GetDebugString(buf, 10240); - return env->NewStringUTF(buf); + std::string str=((VoIPController*)(intptr_t)inst)->GetDebugString(); + return env->NewStringUTF(str.c_str()); } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetNetworkType(JNIEnv* env, jobject thiz, jlong inst, jint type){ @@ -355,31 +354,25 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_native } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetConfig(JNIEnv* env, jobject thiz, jlong inst, jdouble recvTimeout, jdouble initTimeout, jint dataSavingMode, jboolean enableAEC, jboolean enableNS, jboolean enableAGC, jstring logFilePath, jstring statsDumpPath){ - voip_config_t cfg; - cfg.init_timeout=initTimeout; - cfg.recv_timeout=recvTimeout; - cfg.data_saving=dataSavingMode; + VoIPController::Config cfg; + cfg.initTimeout=initTimeout; + cfg.recvTimeout=recvTimeout; + cfg.dataSaving=dataSavingMode; cfg.enableAEC=enableAEC; cfg.enableNS=enableNS; cfg.enableAGC=enableAGC; cfg.enableCallUpgrade=false; if(logFilePath){ char* path=(char *) env->GetStringUTFChars(logFilePath, NULL); - strncpy(cfg.logFilePath, path, sizeof(cfg.logFilePath)); - cfg.logFilePath[sizeof(cfg.logFilePath)-1]=0; + cfg.logFilePath=std::string(path); env->ReleaseStringUTFChars(logFilePath, path); - }else{ - memset(cfg.logFilePath, 0, sizeof(cfg.logFilePath)); } if(statsDumpPath){ char* path=(char *) env->GetStringUTFChars(statsDumpPath, NULL); - strncpy(cfg.statsDumpFilePath, path, sizeof(cfg.statsDumpFilePath)); - cfg.statsDumpFilePath[sizeof(cfg.logFilePath)-1]=0; + cfg.statsDumpFilePath=std::string(path); env->ReleaseStringUTFChars(logFilePath, path); - }else{ - memset(cfg.statsDumpFilePath, 0, sizeof(cfg.statsDumpFilePath)); } - ((VoIPController*)(intptr_t)inst)->SetConfig(&cfg); + ((VoIPController*)(intptr_t)inst)->SetConfig(cfg); } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeDebugCtl(JNIEnv* env, jobject thiz, jlong inst, jint request, jint param){ @@ -399,7 +392,7 @@ extern "C" JNIEXPORT jint Java_org_telegram_messenger_voip_VoIPController_native } extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeGetStats(JNIEnv* env, jclass clasz, jlong inst, jobject stats){ - voip_stats_t _stats; + VoIPController::TrafficStats _stats; ((VoIPController*)(intptr_t)inst)->GetStats(&_stats); jclass cls=env->GetObjectClass(stats); env->SetLongField(stats, env->GetFieldID(cls, "bytesSentWifi", "J"), _stats.bytesSentWifi); diff --git a/libtgvoip.gyp b/libtgvoip.gyp index 5ff19f6eca..f236987b10 100644 --- a/libtgvoip.gyp +++ b/libtgvoip.gyp @@ -28,12 +28,8 @@ 'sources': [ '<(tgvoip_src_loc)/BlockingQueue.cpp', '<(tgvoip_src_loc)/BlockingQueue.h', - '<(tgvoip_src_loc)/BufferInputStream.cpp', - '<(tgvoip_src_loc)/BufferInputStream.h', - '<(tgvoip_src_loc)/BufferOutputStream.cpp', - '<(tgvoip_src_loc)/BufferOutputStream.h', - '<(tgvoip_src_loc)/BufferPool.cpp', - '<(tgvoip_src_loc)/BufferPool.h', + '<(tgvoip_src_loc)/Buffers.cpp', + '<(tgvoip_src_loc)/Buffers.h', '<(tgvoip_src_loc)/CongestionControl.cpp', '<(tgvoip_src_loc)/CongestionControl.h', '<(tgvoip_src_loc)/EchoCanceller.cpp', @@ -50,7 +46,9 @@ '<(tgvoip_src_loc)/OpusEncoder.h', '<(tgvoip_src_loc)/threading.h', '<(tgvoip_src_loc)/VoIPController.cpp', + '<(tgvoip_src_loc)/VoIPGroupController.cpp', '<(tgvoip_src_loc)/VoIPController.h', + '<(tgvoip_src_loc)/PrivateDefines.h', '<(tgvoip_src_loc)/VoIPServerConfig.cpp', '<(tgvoip_src_loc)/VoIPServerConfig.h', '<(tgvoip_src_loc)/audio/AudioInput.cpp', @@ -61,6 +59,8 @@ '<(tgvoip_src_loc)/audio/Resampler.h', '<(tgvoip_src_loc)/NetworkSocket.cpp', '<(tgvoip_src_loc)/NetworkSocket.h', + '<(tgvoip_src_loc)/PacketReassembler.cpp', + '<(tgvoip_src_loc)/PacketReassembler.h', # Windows '<(tgvoip_src_loc)/os/windows/NetworkSocketWinsock.cpp', diff --git a/libtgvoip.xcodeproj/project.pbxproj b/libtgvoip.xcodeproj/project.pbxproj index 5f4bc88314..7e6da1c2b1 100644 --- a/libtgvoip.xcodeproj/project.pbxproj +++ b/libtgvoip.xcodeproj/project.pbxproj @@ -16,12 +16,6 @@ 692AB8CE1E6759DD00706ACC /* AudioOutput.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB88B1E6759DD00706ACC /* AudioOutput.h */; }; 692AB8CF1E6759DD00706ACC /* BlockingQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 692AB88C1E6759DD00706ACC /* BlockingQueue.cpp */; }; 692AB8D01E6759DD00706ACC /* BlockingQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB88D1E6759DD00706ACC /* BlockingQueue.h */; }; - 692AB8D11E6759DD00706ACC /* BufferInputStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 692AB88E1E6759DD00706ACC /* BufferInputStream.cpp */; }; - 692AB8D21E6759DD00706ACC /* BufferInputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB88F1E6759DD00706ACC /* BufferInputStream.h */; }; - 692AB8D31E6759DD00706ACC /* BufferOutputStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 692AB8901E6759DD00706ACC /* BufferOutputStream.cpp */; }; - 692AB8D41E6759DD00706ACC /* BufferOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB8911E6759DD00706ACC /* BufferOutputStream.h */; }; - 692AB8D51E6759DD00706ACC /* BufferPool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 692AB8921E6759DD00706ACC /* BufferPool.cpp */; }; - 692AB8D61E6759DD00706ACC /* BufferPool.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB8931E6759DD00706ACC /* BufferPool.h */; }; 692AB8D81E6759DD00706ACC /* CongestionControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 692AB8971E6759DD00706ACC /* CongestionControl.cpp */; }; 692AB8D91E6759DD00706ACC /* CongestionControl.h in Headers */ = {isa = PBXBuildFile; fileRef = 692AB8981E6759DD00706ACC /* CongestionControl.h */; }; 692AB8DA1E6759DD00706ACC /* EchoCanceller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 692AB8991E6759DD00706ACC /* EchoCanceller.cpp */; }; @@ -57,6 +51,10 @@ 69791A581EE8272A00BB85FB /* Resampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 69791A561EE8272A00BB85FB /* Resampler.h */; }; 69960A041EF85C2900F9D091 /* DarwinSpecific.h in Headers */ = {isa = PBXBuildFile; fileRef = 69960A021EF85C2900F9D091 /* DarwinSpecific.h */; }; 69960A051EF85C2900F9D091 /* DarwinSpecific.mm in Sources */ = {isa = PBXBuildFile; fileRef = 69960A031EF85C2900F9D091 /* DarwinSpecific.mm */; }; + 69986177209526D400B68BEC /* Buffers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 69986175209526D400B68BEC /* Buffers.cpp */; }; + 69986178209526D400B68BEC /* Buffers.h in Headers */ = {isa = PBXBuildFile; fileRef = 69986176209526D400B68BEC /* Buffers.h */; }; + 6998617B2095292A00B68BEC /* PacketReassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 699861792095292900B68BEC /* PacketReassembler.cpp */; }; + 6998617C2095292A00B68BEC /* PacketReassembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 6998617A2095292A00B68BEC /* PacketReassembler.h */; }; 69A6DD941E95EC7700000E69 /* array_view.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A6DD011E95EC7700000E69 /* array_view.h */; }; 69A6DD951E95EC7700000E69 /* atomicops.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A6DD021E95EC7700000E69 /* atomicops.h */; }; 69A6DD961E95EC7700000E69 /* basictypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A6DD031E95EC7700000E69 /* basictypes.h */; }; @@ -256,12 +254,6 @@ 692AB88B1E6759DD00706ACC /* AudioOutput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioOutput.h; sourceTree = ""; }; 692AB88C1E6759DD00706ACC /* BlockingQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlockingQueue.cpp; sourceTree = ""; }; 692AB88D1E6759DD00706ACC /* BlockingQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockingQueue.h; sourceTree = ""; }; - 692AB88E1E6759DD00706ACC /* BufferInputStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BufferInputStream.cpp; sourceTree = ""; }; - 692AB88F1E6759DD00706ACC /* BufferInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BufferInputStream.h; sourceTree = ""; }; - 692AB8901E6759DD00706ACC /* BufferOutputStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BufferOutputStream.cpp; sourceTree = ""; }; - 692AB8911E6759DD00706ACC /* BufferOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BufferOutputStream.h; sourceTree = ""; }; - 692AB8921E6759DD00706ACC /* BufferPool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BufferPool.cpp; sourceTree = ""; }; - 692AB8931E6759DD00706ACC /* BufferPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BufferPool.h; sourceTree = ""; }; 692AB8971E6759DD00706ACC /* CongestionControl.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = CongestionControl.cpp; sourceTree = ""; }; 692AB8981E6759DD00706ACC /* CongestionControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CongestionControl.h; sourceTree = ""; }; 692AB8991E6759DD00706ACC /* EchoCanceller.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EchoCanceller.cpp; sourceTree = ""; }; @@ -299,6 +291,10 @@ 69791A561EE8272A00BB85FB /* Resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Resampler.h; sourceTree = ""; }; 69960A021EF85C2900F9D091 /* DarwinSpecific.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DarwinSpecific.h; sourceTree = ""; }; 69960A031EF85C2900F9D091 /* DarwinSpecific.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DarwinSpecific.mm; sourceTree = ""; }; + 69986175209526D400B68BEC /* Buffers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Buffers.cpp; sourceTree = ""; }; + 69986176209526D400B68BEC /* Buffers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Buffers.h; sourceTree = ""; }; + 699861792095292900B68BEC /* PacketReassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PacketReassembler.cpp; sourceTree = ""; }; + 6998617A2095292A00B68BEC /* PacketReassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PacketReassembler.h; sourceTree = ""; }; 69A6DD011E95EC7700000E69 /* array_view.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = array_view.h; sourceTree = ""; }; 69A6DD021E95EC7700000E69 /* atomicops.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = atomicops.h; sourceTree = ""; }; 69A6DD031E95EC7700000E69 /* basictypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = basictypes.h; sourceTree = ""; }; @@ -467,12 +463,8 @@ 692AB8871E6759DD00706ACC /* audio */, 692AB88C1E6759DD00706ACC /* BlockingQueue.cpp */, 692AB88D1E6759DD00706ACC /* BlockingQueue.h */, - 692AB88E1E6759DD00706ACC /* BufferInputStream.cpp */, - 692AB88F1E6759DD00706ACC /* BufferInputStream.h */, - 692AB8901E6759DD00706ACC /* BufferOutputStream.cpp */, - 692AB8911E6759DD00706ACC /* BufferOutputStream.h */, - 692AB8921E6759DD00706ACC /* BufferPool.cpp */, - 692AB8931E6759DD00706ACC /* BufferPool.h */, + 69986175209526D400B68BEC /* Buffers.cpp */, + 69986176209526D400B68BEC /* Buffers.h */, 692AB8971E6759DD00706ACC /* CongestionControl.cpp */, 692AB8981E6759DD00706ACC /* CongestionControl.h */, 692AB8991E6759DD00706ACC /* EchoCanceller.cpp */, @@ -490,6 +482,8 @@ 692AB8AE1E6759DD00706ACC /* OpusDecoder.h */, 692AB8AF1E6759DD00706ACC /* OpusEncoder.cpp */, 692AB8B01E6759DD00706ACC /* OpusEncoder.h */, + 699861792095292900B68BEC /* PacketReassembler.cpp */, + 6998617A2095292A00B68BEC /* PacketReassembler.h */, 692AB8B11E6759DD00706ACC /* os */, 692AB8C61E6759DD00706ACC /* threading.h */, 692AB8C71E6759DD00706ACC /* VoIPController.cpp */, @@ -875,6 +869,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 69986178209526D400B68BEC /* Buffers.h in Headers */, 692AB9011E6759DD00706ACC /* threading.h in Headers */, 692AB8EA1E6759DD00706ACC /* MediaStreamItf.h in Headers */, 692AB8EE1E6759DD00706ACC /* OpusEncoder.h in Headers */, @@ -898,9 +893,9 @@ 69A6DD9C1E95EC7700000E69 /* safe_conversions_impl.h in Headers */, 69A6DDAE1E95EC7700000E69 /* complex_fft_tables.h in Headers */, 692AB8FF1E6759DD00706ACC /* TGLogWrapper.h in Headers */, - 692AB8D41E6759DD00706ACC /* BufferOutputStream.h in Headers */, 69791A4E1EE8262400BB85FB /* NetworkSocketPosix.h in Headers */, 692AB9051E6759DD00706ACC /* VoIPServerConfig.h in Headers */, + 6998617C2095292A00B68BEC /* PacketReassembler.h in Headers */, 69A6DDF31E95EC7700000E69 /* defines.h in Headers */, 69A6DD9D1E95EC7700000E69 /* sanitizer.h in Headers */, 692AB9031E6759DD00706ACC /* VoIPController.h in Headers */, @@ -952,11 +947,9 @@ 69791A581EE8272A00BB85FB /* Resampler.h in Headers */, 692AB8DB1E6759DD00706ACC /* EchoCanceller.h in Headers */, 69A6DE1C1E95ECF000000E69 /* wav_file.h in Headers */, - 692AB8D61E6759DD00706ACC /* BufferPool.h in Headers */, 69A6DDF51E95EC7700000E69 /* noise_suppression.h in Headers */, 692AB8E71E6759DD00706ACC /* JitterBuffer.h in Headers */, 69A6DE121E95EC7800000E69 /* compile_assert_c.h in Headers */, - 692AB8D21E6759DD00706ACC /* BufferInputStream.h in Headers */, 69A6DDF01E95EC7700000E69 /* gain_control.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1130,7 +1123,6 @@ 69A6DDE71E95EC7700000E69 /* aecm_core_c.cc in Sources */, 69A6DDC61E95EC7700000E69 /* min_max_operations_neon.c in Sources */, 69A6DDB01E95EC7700000E69 /* cross_correlation.c in Sources */, - 692AB8D11E6759DD00706ACC /* BufferInputStream.cpp in Sources */, 69791A571EE8272A00BB85FB /* Resampler.cpp in Sources */, 69A6DE0B1E95EC7800000E69 /* ooura_fft.cc in Sources */, 69A6DDB21E95EC7700000E69 /* division_operations.c in Sources */, @@ -1150,12 +1142,12 @@ 69A6DDB71E95EC7700000E69 /* filter_ar.c in Sources */, 69A6DE041E95EC7800000E69 /* block_mean_calculator.cc in Sources */, 69A6DD9E1E95EC7700000E69 /* stringutils.cc in Sources */, - 692AB8D31E6759DD00706ACC /* BufferOutputStream.cpp in Sources */, 69A6DE001E95EC7800000E69 /* splitting_filter.cc in Sources */, 69A6DDC81E95EC7700000E69 /* real_fft.c in Sources */, 69A6DDD11E95EC7700000E69 /* spl_init.c in Sources */, 69A6DE061E95EC7800000E69 /* delay_estimator.cc in Sources */, 69A6DDD41E95EC7700000E69 /* spl_sqrt_floor.c in Sources */, + 6998617B2095292A00B68BEC /* PacketReassembler.cpp in Sources */, 69A6DDB41E95EC7700000E69 /* downsample_fast.c in Sources */, 69A6DDEA1E95EC7700000E69 /* echo_control_mobile.cc in Sources */, 69A6DDF41E95EC7700000E69 /* noise_suppression.c in Sources */, @@ -1164,13 +1156,13 @@ 69A6DDF61E95EC7700000E69 /* noise_suppression_x.c in Sources */, 69A6DE1B1E95ECF000000E69 /* wav_file.cc in Sources */, 69A6DDCE1E95EC7700000E69 /* resample_by_2_internal.c in Sources */, - 692AB8D51E6759DD00706ACC /* BufferPool.cpp in Sources */, 692AB8CB1E6759DD00706ACC /* AudioInput.cpp in Sources */, 69A6DDCC1E95EC7700000E69 /* resample_48khz.c in Sources */, 69A6DDAC1E95EC7700000E69 /* complex_bit_reverse_arm.S in Sources */, 69A6DDD81E95EC7700000E69 /* vector_scaling_operations.c in Sources */, 69A6DE0D1E95EC7800000E69 /* ooura_fft_neon.cc in Sources */, 692AB8FD1E6759DD00706ACC /* AudioUnitIO.cpp in Sources */, + 69986177209526D400B68BEC /* Buffers.cpp in Sources */, 69A6DDB31E95EC7700000E69 /* dot_product_with_scale.c in Sources */, 69A6DDB91E95EC7700000E69 /* filter_ar_fast_q12_armv7.S in Sources */, 69A6DDAA1E95EC7700000E69 /* auto_correlation.c in Sources */, diff --git a/libtgvoip.xcodeproj/xcuserdata/grishka.xcuserdatad/xcschemes/xcschememanagement.plist b/libtgvoip.xcodeproj/xcuserdata/grishka.xcuserdatad/xcschemes/xcschememanagement.plist index 9e9e68e11c..253fba52b6 100644 --- a/libtgvoip.xcodeproj/xcuserdata/grishka.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/libtgvoip.xcodeproj/xcuserdata/grishka.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ libtgvoip.xcscheme orderHint - 1 + 0 SuppressBuildableAutocreation diff --git a/os/posix/NetworkSocketPosix.cpp b/os/posix/NetworkSocketPosix.cpp index 2bacfa44a3..05ddbb93f1 100644 --- a/os/posix/NetworkSocketPosix.cpp +++ b/os/posix/NetworkSocketPosix.cpp @@ -13,10 +13,10 @@ #include #include #include +#include #include "../../logging.h" #include "../../VoIPController.h" -#include "../../BufferInputStream.h" -#include "../../BufferOutputStream.h" +#include "../../Buffers.h" #ifdef __ANDROID__ #include @@ -126,6 +126,7 @@ void NetworkSocketPosix::Send(NetworkPacket *packet){ IPv6Address *v6addr=dynamic_cast(packet->address); assert(v6addr!=NULL); memcpy(addr.sin6_addr.s6_addr, v6addr->GetAddress(), 16); + addr.sin6_family=AF_INET6; } addr.sin6_port=htons(packet->port); res=sendto(fd, packet->data, packet->length, 0, (const sockaddr *) &addr, sizeof(addr)); @@ -306,96 +307,72 @@ void NetworkSocketPosix::OnActiveInterfaceChanged(){ } std::string NetworkSocketPosix::GetLocalInterfaceInfo(IPv4Address *v4addr, IPv6Address *v6addr){ + std::string name=""; + // Android doesn't support ifaddrs #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; - } + 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); + jmethodID getLocalNetworkAddressesAndInterfaceNameMethod=env->GetStaticMethodID(jniUtilitiesClass, "getLocalNetworkAddressesAndInterfaceName", "()[Ljava/lang/String;"); + jobjectArray jinfo=(jobjectArray) env->CallStaticObjectMethod(jniUtilitiesClass, getLocalNetworkAddressesAndInterfaceNameMethod); + if(jinfo){ + jstring jitfName=static_cast(env->GetObjectArrayElement(jinfo, 0)); + jstring jipv4=static_cast(env->GetObjectArrayElement(jinfo, 1)); + jstring jipv6=static_cast(env->GetObjectArrayElement(jinfo, 2)); + const char* itfchars=env->GetStringUTFChars(jitfName, NULL); + name=std::string(itfchars); + env->ReleaseStringUTFChars(jitfName, itfchars); - if(didAttach){ - sharedJVM->DetachCurrentThread(); + if(v4addr && jipv4){ + const char* ipchars=env->GetStringUTFChars(jipv4, NULL); + *v4addr=IPv4Address(ipchars); + env->ReleaseStringUTFChars(jipv4, ipchars); + } + if(v6addr && jipv6){ + const char* ipchars=env->GetStringUTFChars(jipv6, NULL); + *v6addr=IPv6Address(ipchars); + env->ReleaseStringUTFChars(jipv6, ipchars); } }else{ - memset(androidInterfaceName, 0, sizeof(androidInterfaceName)); + LOGW("Failed to get android network interface info"); + } + + if(didAttach){ + sharedJVM->DetachCurrentThread(); } -#endif - struct ifconf ifc; - struct ifreq* ifr; - char buf[16384]; - int sd; - std::string name=""; - sd=socket(PF_INET, SOCK_DGRAM, 0); - if(sd>=0){ - ifc.ifc_len=sizeof(buf); - ifc.ifc_ifcu.ifcu_buf=buf; - if(ioctl(sd, SIOCGIFCONF, &ifc)==0){ - ifr=ifc.ifc_req; - int len; - int i; - for(i=0;iifr_addr.sa_len; #else - len=sizeof(*ifr); -#endif - if(ifr->ifr_addr.sa_family==AF_INET){ -#ifdef __ANDROID__ - if(strlen(androidInterfaceName) && strcmp(androidInterfaceName, ifr->ifr_name)!=0){ - LOGI("Skipping interface %s as non-active [android-only]", ifr->ifr_name); - ifr=(struct ifreq*)((char*)ifr+len); - i+=len; + struct ifaddrs* interfaces; + if(!getifaddrs(&interfaces)){ + struct ifaddrs* interface; + for(interface=interfaces;interface;interface=interface->ifa_next){ + if(!(interface->ifa_flags & IFF_UP) || !(interface->ifa_flags & IFF_RUNNING) || (interface->ifa_flags & IFF_LOOPBACK)) + continue; + const struct sockaddr_in* addr=(const struct sockaddr_in*)interface->ifa_addr; + if(addr){ + if(addr->sin_family==AF_INET){ + if((ntohl(addr->sin_addr.s_addr) & 0xFFFF0000)==0xA9FE0000) continue; - } -#endif - if(ioctl(sd, SIOCGIFADDR, ifr)==0){ - struct sockaddr_in* addr=(struct sockaddr_in *)(&ifr->ifr_addr); - LOGI("Interface %s, address %s\n", ifr->ifr_name, inet_ntoa(addr->sin_addr)); - if(ioctl(sd, SIOCGIFFLAGS, ifr)==0){ - if(!(ifr->ifr_flags & IFF_LOOPBACK) && (ifr->ifr_flags & IFF_UP) && (ifr->ifr_flags & IFF_RUNNING)){ - //LOGV("flags = %08X", ifr->ifr_flags); - if((ntohl(addr->sin_addr.s_addr) & 0xFFFF0000)==0xA9FE0000){ - LOGV("skipping link-local"); - ifr=(struct ifreq*)((char*)ifr+len); - i+=len; - continue; - } - if(v4addr){ - *v4addr=IPv4Address(addr->sin_addr.s_addr); - } - name=ifr->ifr_name; - } - } - }else{ - LOGE("Error getting address for %s: %d\n", ifr->ifr_name, errno); - } + if(v4addr) + *v4addr=IPv4Address(addr->sin_addr.s_addr); + name=interface->ifa_name; + }else if(addr->sin_family==AF_INET6){ + const struct sockaddr_in6* addr6=(const struct sockaddr_in6*)addr; + if((addr6->sin6_addr.s6_addr[0] & 0xF0)==0xF0) + continue; + if(v6addr) + *v6addr=IPv6Address(addr6->sin6_addr.s6_addr); + name=interface->ifa_name; } - ifr=(struct ifreq*)((char*)ifr+len); - i+=len; } - }else{ - LOGE("Error getting LAN address: %d", errno); } - close(sd); + freeifaddrs(interfaces); } +#endif return name; } diff --git a/os/windows/AudioInputWASAPI.cpp b/os/windows/AudioInputWASAPI.cpp index 25829cf909..25289e5a8f 100644 --- a/os/windows/AudioInputWASAPI.cpp +++ b/os/windows/AudioInputWASAPI.cpp @@ -107,7 +107,7 @@ void AudioInputWASAPI::Configure(uint32_t sampleRate, uint32_t bitsPerSample, ui void AudioInputWASAPI::Start(){ isRecording=true; if(!thread){ - thread=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AudioInputWASAPI::StartThread, this, 0, NULL); + thread=CreateThread(NULL, 0, AudioInputWASAPI::StartThread, this, 0, NULL); } if(audioClient && !started){ @@ -319,7 +319,7 @@ void AudioInputWASAPI::ActuallySetCurrentDevice(std::string deviceID){ LOGV("set current input device done"); } -DWORD AudioInputWASAPI::StartThread(void* arg) { +DWORD WINAPI AudioInputWASAPI::StartThread(void* arg) { LOGV("WASAPI capture thread starting"); ((AudioInputWASAPI*)arg)->RunThread(); return 0; diff --git a/os/windows/AudioInputWASAPI.h b/os/windows/AudioInputWASAPI.h index d19d10ad26..b6d64da306 100644 --- a/os/windows/AudioInputWASAPI.h +++ b/os/windows/AudioInputWASAPI.h @@ -57,7 +57,7 @@ public: private: void ActuallySetCurrentDevice(std::string deviceID); - static DWORD StartThread(void* arg); + static DWORD WINAPI StartThread(void* arg); void RunThread(); WAVEFORMATEX format; bool isRecording; diff --git a/os/windows/AudioOutputWASAPI.cpp b/os/windows/AudioOutputWASAPI.cpp index 9536785958..a823253516 100644 --- a/os/windows/AudioOutputWASAPI.cpp +++ b/os/windows/AudioOutputWASAPI.cpp @@ -108,7 +108,7 @@ void AudioOutputWASAPI::Configure(uint32_t sampleRate, uint32_t bitsPerSample, u void AudioOutputWASAPI::Start(){ isPlaying=true; if(!thread){ - thread=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AudioOutputWASAPI::StartThread, this, 0, NULL); + thread=CreateThread(NULL, 0, AudioOutputWASAPI::StartThread, this, 0, NULL); } if(audioClient) @@ -326,7 +326,7 @@ void AudioOutputWASAPI::ActuallySetCurrentDevice(std::string deviceID){ LOGV("set current output device done"); } -DWORD AudioOutputWASAPI::StartThread(void* arg) { +DWORD WINAPI AudioOutputWASAPI::StartThread(void* arg) { ((AudioOutputWASAPI*)arg)->RunThread(); return 0; } diff --git a/os/windows/AudioOutputWASAPI.h b/os/windows/AudioOutputWASAPI.h index 6fd22c2695..17891edcc4 100644 --- a/os/windows/AudioOutputWASAPI.h +++ b/os/windows/AudioOutputWASAPI.h @@ -56,7 +56,7 @@ public: private: void ActuallySetCurrentDevice(std::string deviceID); - static DWORD StartThread(void* arg); + static DWORD WINAPI StartThread(void* arg); void RunThread(); WAVEFORMATEX format; bool isPlaying; diff --git a/os/windows/CXWrapper.cpp b/os/windows/CXWrapper.cpp index 08fda34d9b..2738fba2fc 100755 --- a/os/windows/CXWrapper.cpp +++ b/os/windows/CXWrapper.cpp @@ -145,10 +145,10 @@ void VoIPControllerWrapper::OnSignalBarsChangedInternal(int count){ } void VoIPControllerWrapper::SetConfig(double initTimeout, double recvTimeout, DataSavingMode dataSavingMode, bool enableAEC, bool enableNS, bool enableAGC, Platform::String^ logFilePath, Platform::String^ statsDumpFilePath){ - voip_config_t config{0}; - config.init_timeout=initTimeout; - config.recv_timeout=recvTimeout; - config.data_saving=(int)dataSavingMode; + VoIPController::Config config{0}; + config.initTimeout=initTimeout; + config.recvTimeout=recvTimeout; + config.dataSaving=(int)dataSavingMode; config.enableAEC=enableAEC; config.enableAGC=enableAGC; config.enableNS=enableNS;