// // 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. // #ifndef _WIN32 #include #include #endif #include #include #include #include "VoIPController.h" #include "logging.h" #include "threading.h" #include "BufferOutputStream.h" #include "BufferInputStream.h" #include "OpusEncoder.h" #include "OpusDecoder.h" #include "VoIPServerConfig.h" #include #include #include #include #include #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 double VoIPController::machTimebase=0; uint64_t VoIPController::machTimestart=0; #endif #ifdef _WIN32 int64_t VoIPController::win32TimeScale = 0; bool VoIPController::didInitWin32TimeScale = false; #endif #define SHA1_LENGTH 20 #define SHA256_LENGTH 32 #ifndef TGVOIP_USE_CUSTOM_CRYPTO extern "C" { #include #include #include #include } void tgvoip_openssl_aes_ige_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){ AES_KEY akey; AES_set_encrypt_key(key, 32*8, &akey); AES_ige_encrypt(in, out, length, &akey, iv, AES_ENCRYPT); } void tgvoip_openssl_aes_ige_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){ AES_KEY akey; AES_set_decrypt_key(key, 32*8, &akey); AES_ige_encrypt(in, out, length, &akey, iv, AES_DECRYPT); } void tgvoip_openssl_rand_bytes(uint8_t* buffer, size_t len){ RAND_bytes(buffer, len); } void tgvoip_openssl_sha1(uint8_t* msg, size_t len, uint8_t* output){ SHA1(msg, len, output); } void tgvoip_openssl_sha256(uint8_t* msg, size_t len, uint8_t* output){ SHA256(msg, len, output); } void tgvoip_openssl_aes_ctr_encrypt(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num){ AES_KEY akey; AES_set_encrypt_key(key, 32*8, &akey); CRYPTO_ctr128_encrypt(inout, inout, length, &akey, iv, ecount, num, (block128_f) AES_encrypt); } void tgvoip_openssl_aes_cbc_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){ AES_KEY akey; AES_set_encrypt_key(key, 256, &akey); AES_cbc_encrypt(in, out, length, &akey, iv, AES_ENCRYPT); } void tgvoip_openssl_aes_cbc_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){ AES_KEY akey; AES_set_decrypt_key(key, 256, &akey); AES_cbc_encrypt(in, out, length, &akey, iv, AES_DECRYPT); } voip_crypto_functions_t VoIPController::crypto={ tgvoip_openssl_rand_bytes, tgvoip_openssl_sha1, tgvoip_openssl_sha256, tgvoip_openssl_aes_ige_encrypt, tgvoip_openssl_aes_ige_decrypt, tgvoip_openssl_aes_ctr_encrypt, tgvoip_openssl_aes_cbc_encrypt, tgvoip_openssl_aes_cbc_decrypt }; #else voip_crypto_functions_t 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; VoIPController::VoIPController() : activeNetItfName(""), currentAudioInput("default"), currentAudioOutput("default"), outgoingPacketsBufferPool(1024, 20), proxyAddress(""), proxyUsername(""), proxyPassword("") { seq=1; lastRemoteSeq=0; state=STATE_WAIT_INIT; audioInput=NULL; audioOutput=NULL; encoder=NULL; audioOutStarted=false; audioTimestampIn=0; audioTimestampOut=0; stopping=false; sendQueue=new BlockingQueue(21); 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)); lastRemoteAckSeq=0; lastSentSeq=0; recvLossCount=0; packetsRecieved=0; waitingForAcks=false; networkType=NET_TYPE_UNKNOWN; echoCanceller=NULL; dontSendPackets=0; micMuted=false; currentEndpoint=NULL; waitingForRelayPeerInfo=false; allowP2p=true; dataSavingMode=false; publicEndpointsReqTime=0; connectionInitTime=0; lastRecvPacketTime=0; dataSavingRequestedByPeer=false; peerVersion=0; conctl=new CongestionControl(); prevSendLossCount=0; receivedInit=false; receivedInitAck=false; peerPreferredRelay=NULL; statsDump=NULL; useTCP=false; useUDP=true; didAddTcpRelays=false; setEstablishedAt=0; udpPingCount=0; lastUdpPingTime=0; openingTcpSocket=NULL; proxyProtocol=PROXY_NONE; proxyPort=0; resolvedProxyAddress=NULL; signalBarCount=0; selectCanceller=SocketSelectCanceller::Create(); udpSocket=NetworkSocket::Create(PROTO_UDP); realUdpSocket=udpSocket; udpConnectivityState=UDP_UNKNOWN; echoCancellationStrength=1; outputAGC=NULL; outputAGCEnabled=false; peerCapabilities=0; callbacks={0}; didReceiveGroupCallKey=false; didReceiveGroupCallKeyAck=false; didSendGroupCallKey=false; didSendUpgradeRequest=false; didInvokeUpdateCallback=false; connectionMaxLayer=0; useMTProto2=false; setCurrentEndpointToTCP=false; sendThread=NULL; recvThread=NULL; tickThread=NULL; maxAudioBitrate=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate", 20000); maxAudioBitrateGPRS=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate_gprs", 8000); maxAudioBitrateEDGE=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate_edge", 16000); maxAudioBitrateSaving=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate_saving", 8000); initAudioBitrate=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate", 16000); initAudioBitrateGPRS=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate_gprs", 8000); initAudioBitrateEDGE=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate_edge", 8000); initAudioBitrateSaving=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate_saving", 8000); audioBitrateStepIncr=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_bitrate_step_incr", 1000); audioBitrateStepDecr=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_bitrate_step_decr", 1000); minAudioBitrate=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_min_bitrate", 8000); relaySwitchThreshold=ServerConfig::GetSharedInstance()->GetDouble("relay_switch_threshold", 0.8); p2pToRelaySwitchThreshold=ServerConfig::GetSharedInstance()->GetDouble("p2p_to_relay_switch_threshold", 0.6); relayToP2pSwitchThreshold=ServerConfig::GetSharedInstance()->GetDouble("relay_to_p2p_switch_threshold", 0.8); reconnectingTimeout=ServerConfig::GetSharedInstance()->GetDouble("reconnecting_state_timeout", 2.0); #ifdef __APPLE__ machTimestart=0; #if TARGET_OS_OSX if(kCFCoreFoundationVersionNumber>=kCFCoreFoundationVersionNumber10_7){ #endif appleAudioIO=new audio::AudioUnitIO(); #if TARGET_OS_OSX }else{ appleAudioIO=NULL; } #endif #endif Stream stm; stm.id=1; stm.type=STREAM_TYPE_AUDIO; stm.codec=CODEC_OPUS; stm.enabled=1; stm.frameDuration=60; outgoingStreams.push_back(stm); 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){ LOGE("!!!!!!!!!!!!!!!!!!!! CALL controller->Stop() BEFORE DELETING THE CONTROLLER OBJECT !!!!!!!!!!!!!!!!!!!!!!!1"); abort(); } LOGD("before close socket"); if(udpSocket) 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){ delete stm->jitterBuffer; } LOGD("before stop decoder"); if(stm->decoder){ stm->decoder->Stop(); } } LOGD("before delete audio input"); if(audioInput){ delete audioInput; } LOGD("before delete encoder"); if(encoder){ encoder->Stop(); delete encoder; } 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){ LOGD("before delete 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){ if((*itr)->socket){ (*itr)->socket->Close(); delete (*itr)->socket; } delete *itr; } if(tgvoipLogFile){ FILE* log=tgvoipLogFile; tgvoipLogFile=NULL; fclose(log); } if(statsDump) fclose(statsDump); if(resolvedProxyAddress) delete resolvedProxyAddress; delete selectCanceller; if(outputAGC) delete outputAGC; LOGD("Left VoIPController::~VoIPController"); } void VoIPController::Stop(){ LOGD("Entered VoIPController::Stop"); stopping=true; runReceiver=false; LOGD("before shutdown socket"); if(udpSocket) udpSocket->Close(); if(realUdpSocket!=udpSocket) realUdpSocket->Close(); selectCanceller->CancelSelect(); sendQueue->Put(PendingOutgoingPacket{0}); if(openingTcpSocket) openingTcpSocket->Close(); LOGD("before join sendThread"); if(sendThread){ sendThread->Join(); delete sendThread; } LOGD("before join recvThread"); if(recvThread){ recvThread->Join(); delete recvThread; } LOGD("before join tickThread"); if(tickThread){ tickThread->Join(); delete tickThread; } { LOGD("Before stop audio I/O"); MutexGuard m(audioIOMutex); if(audioInput) audioInput->Stop(); if(audioOutput) audioOutput->Stop(); } LOGD("Left VoIPController::Stop"); } void VoIPController::SetRemoteEndpoints(std::vector endpoints, bool allowP2p, int32_t connectionMaxLayer){ LOGW("Set remote endpoints, allowP2P=%d, connectionMaxLayer=%u", allowP2p ? 1 : 0, connectionMaxLayer); preferredRelay=NULL; { MutexGuard m(endpointsMutex); 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)); if(itrtr->type==Endpoint::TYPE_TCP_RELAY) didAddTcpRelays=true; if(itrtr->type==Endpoint::TYPE_UDP_RELAY) useTCP=false; LOGV("Adding endpoint: %s:%d, %s", itrtr->address.ToString().c_str(), itrtr->port, itrtr->type==Endpoint::TYPE_UDP_RELAY ? "UDP" : "TCP"); } } currentEndpoint=this->endpoints[0]; preferredRelay=currentEndpoint; this->allowP2p=allowP2p; this->connectionMaxLayer=connectionMaxLayer; if(connectionMaxLayer>=74){ useMTProto2=true; } } void VoIPController::Start(){ LOGW("Starting voip controller"); udpSocket->Open(); if(udpSocket->IsFailed()){ SetState(STATE_FAILED); return; } //SendPacket(NULL, 0, currentEndpoint); runReceiver=true; recvThread=new Thread(new MethodPointer(&VoIPController::RunRecvThread, this), NULL); recvThread->SetName("VoipRecv"); recvThread->Start(); sendThread=new Thread(new MethodPointer(&VoIPController::RunSendThread, this), NULL); sendThread->SetName("VoipSend"); sendThread->Start(); tickThread=new Thread(new MethodPointer(&VoIPController::RunTickThread, this), NULL); tickThread->SetName("VoipTick"); tickThread->Start(); } size_t VoIPController::AudioInputCallback(unsigned char* data, size_t length, void* param){ ((VoIPController*)param)->HandleAudioInput(data, length); return 0; } void VoIPController::HandleAudioInput(unsigned char *data, size_t len){ if(stopping) return; if(waitingForAcks || dontSendPackets>0){ LOGV("waiting for RLC, dropping outgoing audio packet"); return; } unsigned char* buf=outgoingPacketsBufferPool.Get(); if(buf){ BufferOutputStream pkt(buf, outgoingPacketsBufferPool.GetSingleBufferSize()); unsigned char flags=(unsigned char) (len>255 ? STREAM_DATA_FLAG_LEN16 : 0); pkt.WriteByte((unsigned char) (1 | flags)); // streamID + flags if(len>255) pkt.WriteInt16((int16_t) len); else pkt.WriteByte((unsigned char) len); pkt.WriteInt32(audioTimestampOut); pkt.WriteBytes(data, len); PendingOutgoingPacket p{ /*.seq=*/GenerateOutSeq(), /*.type=*/PKT_STREAM_DATA, /*.len=*/pkt.GetLength(), /*.data=*/buf, /*.endpoint=*/NULL, }; sendQueue->Put(p); } audioTimestampOut+=outgoingStreams[0].frameDuration; } void VoIPController::Connect(){ assert(state!=STATE_WAIT_INIT_ACK); if(proxyProtocol==PROXY_SOCKS5){ resolvedProxyAddress=NetworkSocket::ResolveDomainName(proxyAddress); if(!resolvedProxyAddress){ LOGW("Error resolving proxy address %s", proxyAddress.c_str()); SetState(STATE_FAILED); return; } InitUDPProxy(); } connectionInitTime=GetCurrentTime(); SendInit(); } void VoIPController::SetEncryptionKey(char *key, bool isOutgoing){ memcpy(encryptionKey, key, 256); uint8_t sha1[SHA1_LENGTH]; crypto.sha1((uint8_t*) encryptionKey, 256, sha1); memcpy(keyFingerprint, sha1+(SHA1_LENGTH-8), 8); uint8_t sha256[SHA256_LENGTH]; crypto.sha256((uint8_t*) encryptionKey, 256, sha256); memcpy(callID, sha256+(SHA256_LENGTH-16), 16); 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++; } void VoIPController::WritePacketHeader(uint32_t pseq, BufferOutputStream *s, unsigned char type, uint32_t length){ uint32_t acks=0; int i; for(i=0;i<32;i++){ if(recvPacketTimes[i]>0) acks|=1; if(i<31) acks<<=1; } if(state==STATE_WAIT_INIT || state==STATE_WAIT_INIT_ACK){ 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_RECENT_RECV | PFLAG_HAS_SEQ; if(length>0) pflags|=PFLAG_HAS_DATA; if(state==STATE_WAIT_INIT || state==STATE_WAIT_INIT_ACK){ pflags|=PFLAG_HAS_CALL_ID | PFLAG_HAS_PROTO; } pflags|=((uint32_t) type) << 24; s->WriteInt32(pflags); if(pflags & PFLAG_HAS_CALL_ID){ s->WriteBytes(callID, 16); } s->WriteInt32(lastRemoteSeq); s->WriteInt32(pseq); s->WriteInt32(acks); if(pflags & PFLAG_HAS_PROTO){ s->WriteInt32(PROTOCOL_NAME); } 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)); } } }else{ s->WriteInt32(TLID_SIMPLE_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 lenWithHeader=length+13; if(lenWithHeader>0){ if(lenWithHeader<=253){ s->WriteByte((unsigned char) lenWithHeader); }else{ s->WriteByte(254); s->WriteByte((unsigned char) (lenWithHeader & 0xFF)); s->WriteByte((unsigned char) ((lenWithHeader >> 8) & 0xFF)); s->WriteByte((unsigned char) ((lenWithHeader >> 16) & 0xFF)); } } s->WriteByte(type); s->WriteInt32(lastRemoteSeq); s->WriteInt32(pseq); s->WriteInt32(acks); } if(type==PKT_STREAM_DATA || type==PKT_STREAM_DATA_X2 || type==PKT_STREAM_DATA_X3) conctl->PacketSent(pseq, length); MutexGuard m(queuedPacketsMutex); recentOutgoingPackets.push_back(RecentOutgoingPacket{ pseq, 0, GetCurrentTime(), 0 }); while(recentOutgoingPackets.size()>MAX_RECENT_PACKETS) recentOutgoingPackets.erase(recentOutgoingPackets.begin()); lastSentSeq=pseq; //LOGI("packet header size %d", s->GetLength()); } void VoIPController::UpdateAudioBitrate(){ if(encoder){ if(dataSavingMode || dataSavingRequestedByPeer){ maxBitrate=maxAudioBitrateSaving; encoder->SetBitrate(initAudioBitrateSaving); }else if(networkType==NET_TYPE_GPRS){ maxBitrate=maxAudioBitrateGPRS; encoder->SetBitrate(initAudioBitrateGPRS); }else if(networkType==NET_TYPE_EDGE){ maxBitrate=maxAudioBitrateEDGE; encoder->SetBitrate(initAudioBitrateEDGE); }else{ maxBitrate=maxAudioBitrate; encoder->SetBitrate(initAudioBitrate); } } } 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) continue; unsigned char *pkt=outgoingPacketsBufferPool.Get(); if(!pkt){ LOGW("can't send init, queue overflow"); continue; } BufferOutputStream out(pkt, outgoingPacketsBufferPool.GetSingleBufferSize()); out.WriteInt32(PROTOCOL_VERSION); out.WriteInt32(MIN_PROTOCOL_VERSION); uint32_t flags=0; if(config.enableCallUpgrade) flags|=INIT_FLAG_GROUP_CALLS_SUPPORTED; if(dataSavingMode) flags|=INIT_FLAG_DATA_SAVING_ENABLED; out.WriteInt32(flags); if(connectionMaxLayer<74){ out.WriteByte(2); // audio codecs count out.WriteByte(CODEC_OPUS_OLD); out.WriteByte(0); out.WriteByte(0); out.WriteByte(0); out.WriteInt32(CODEC_OPUS); out.WriteByte(0); // video codecs count }else{ out.WriteByte(1); out.WriteInt32(CODEC_OPUS); out.WriteByte(0); } sendQueue->Put(PendingOutgoingPacket{ /*.seq=*/initSeq, /*.type=*/PKT_INIT, /*.len=*/out.GetLength(), /*.data=*/pkt, /*.endpoint=*/*itr }); } } SetState(STATE_WAIT_INIT_ACK); } void VoIPGroupController::SendInit(){ SendRecentPacketsRequest(); } void VoIPController::InitUDPProxy(){ if(realUdpSocket!=udpSocket){ udpSocket->Close(); delete udpSocket; udpSocket=realUdpSocket; } NetworkSocket* tcp=NetworkSocket::Create(PROTO_TCP); tcp->Connect(resolvedProxyAddress, proxyPort); if(tcp->IsFailed()){ SetState(STATE_FAILED); tcp->Close(); delete tcp; return; } NetworkSocketSOCKS5Proxy* udpProxy=new NetworkSocketSOCKS5Proxy(tcp, udpSocket, proxyUsername, proxyPassword); udpProxy->InitConnection(); udpProxy->Open(); if(udpProxy->IsFailed()){ udpProxy->Close(); delete udpProxy; useTCP=true; useUDP=false; udpConnectivityState=UDP_NOT_AVAILABLE; }else{ udpSocket=udpProxy; } } void VoIPController::RunRecvThread(void* arg){ LOGI("Receive thread starting"); unsigned char *buffer = (unsigned char *)malloc(1500); NetworkPacket packet={0}; while(runReceiver){ packet.data=buffer; packet.length=1500; std::vector readSockets; std::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); } } } //} 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()){ LOGW("UDP socket failed"); SetState(STATE_FAILED); return; } } NetworkSocket* socket=NULL; if(std::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); break; } } } continue; } socket->Receive(&packet); if(!packet.address){ LOGE("Packet has null address. This shouldn't happen."); continue; } size_t len=packet.length; if(!len){ LOGE("Packet has zero length."); continue; } //LOGV("Received %d bytes from %s:%d at %.5lf", len, packet.address->ToString().c_str(), packet.port, GetCurrentTime()); Endpoint* srcEndpoint=NULL; 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; break; } } } } if(!srcEndpoint){ LOGW("Received a packet from unknown source %s:%u", packet.address->ToString().c_str(), packet.port); continue; } if(len<=0){ //LOGW("error receiving: %d / %s", errno, strerror(errno)); continue; } if(IS_MOBILE_NETWORK(networkType)) stats.bytesRecvdMobile+=(uint64_t)len; else stats.bytesRecvdWifi+=(uint64_t)len; try{ ProcessIncomingPacket(packet, srcEndpoint); }catch(std::out_of_range x){ LOGW("Error parsing packet: %s", x.what()); } } free(buffer); LOGI("=== recv thread exiting ==="); } void VoIPController::RunSendThread(void* arg){ unsigned char buf[1500]; while(runReceiver){ PendingOutgoingPacket pkt=sendQueue->GetBlocking(); if(pkt.data){ MutexGuard m(endpointsMutex); Endpoint *endpoint=pkt.endpoint ? pkt.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); p.WriteBytes(pkt.data, pkt.len); SendPacket(p.GetBuffer(), p.GetLength(), endpoint, pkt); } outgoingPacketsBufferPool.Reuse(pkt.data); }else{ LOGE("tried to send null packet"); } } LOGI("=== send thread exiting ==="); } void VoIPController::ProcessIncomingPacket(NetworkPacket &packet, Endpoint* srcEndpoint){ unsigned char* buffer=packet.data; size_t len=packet.length; BufferInputStream in(buffer, (size_t)len); if(memcmp(buffer, srcEndpoint->type==Endpoint::TYPE_UDP_RELAY || srcEndpoint->type==Endpoint::TYPE_TCP_RELAY ? (void*)srcEndpoint->peerTag : (void*)callID, 16)!=0){ LOGW("Received packet has wrong peerTag"); return; } in.Seek(16); if(in.Remaining()>=16 && (srcEndpoint->type==Endpoint::TYPE_UDP_RELAY || srcEndpoint->type==Endpoint::TYPE_TCP_RELAY) && *reinterpret_cast(buffer+16)==0xFFFFFFFFFFFFFFFFLL && *reinterpret_cast(buffer+24)==0xFFFFFFFF){ // relay special request response in.Seek(16+12); uint32_t tlid=(uint32_t) in.ReadInt32(); 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(); unsigned char myIP[16]; in.ReadBytes(myIP, 16); /*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); srcEndpoint->udpPongCount++; } }else if(tlid==TLID_UDP_REFLECTOR_PEER_INFO){ if(waitingForRelayPeerInfo && in.Remaining()>=16){ MutexGuard _m(endpointsMutex); uint32_t myAddr=(uint32_t) in.ReadInt32(); 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){ 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; 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"); unsigned char peerTag[16]; endpoints.push_back(new Endpoint(0, (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"); IPv4Address lanAddr(0); udpSocket->GetLocalInterfaceInfo(&lanAddr, NULL); BufferOutputStream pkt(8); pkt.WriteInt32(lanAddr.GetAddress()); pkt.WriteInt32(udpSocket->GetLocalPort()); SendPacketReliably(PKT_LAN_ENDPOINT, pkt.GetBuffer(), pkt.GetLength(), 0.5, 10); } waitingForRelayPeerInfo=false; } }else{ LOGV("Received relay response with unknown tl id: 0x%08X", tlid); } return; } if(in.Remaining()<40){ LOGV("Received packet is too small"); return; } bool retryWith2=false; if(!useMTProto2){ unsigned char fingerprint[8], msgHash[16]; in.ReadBytes(fingerprint, 8); in.ReadBytes(msgHash, 16); if(memcmp(fingerprint, keyFingerprint, 8)!=0){ LOGW("Received packet has wrong key fingerprint"); return; } unsigned char key[32], iv[32]; KDF(msgHash, isOutgoing ? 8 : 0, key, iv); unsigned char aesOut[MSC_STACK_FALLBACK(in.Remaining(), 1500)]; if(in.Remaining()>sizeof(aesOut)) return; crypto.aes_ige_decrypt((unsigned char *) buffer+in.GetOffset(), aesOut, in.Remaining(), key, iv); BufferInputStream _in(aesOut, in.Remaining()); unsigned char sha[SHA1_LENGTH]; uint32_t _len=(uint32_t) _in.ReadInt32(); if(_len>_in.Remaining()) _len=_in.Remaining(); crypto.sha1((uint8_t *) (aesOut), (size_t) (_len+4), sha); if(memcmp(msgHash, sha+(SHA1_LENGTH-16), 16)!=0){ LOGW("Received packet has wrong hash after decryption"); if(state==STATE_WAIT_INIT || state==STATE_WAIT_INIT_ACK) retryWith2=true; else return; }else{ memcpy(buffer+in.GetOffset(), aesOut, in.Remaining()); in.ReadInt32(); } } if(useMTProto2 || retryWith2){ in.Seek(16); // peer tag unsigned char fingerprint[8], msgKey[16]; in.ReadBytes(fingerprint, 8); if(memcmp(fingerprint, keyFingerprint, 8)!=0){ LOGW("Received packet has wrong key fingerprint"); return; } in.ReadBytes(msgKey, 16); unsigned char decrypted[1500]; unsigned char aesKey[32], aesIv[32]; KDF2(msgKey, isOutgoing ? 8 : 0, aesKey, aesIv); size_t decryptedLen=in.Remaining(); 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=isOutgoing ? 8 : 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 has wrong hash"); 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; } memcpy(buffer, decrypted+4, innerLen); in=BufferInputStream(buffer, (size_t) innerLen); if(retryWith2){ LOGD("Successfully decrypted packet in MTProto2.0 fallback, upgrading"); useMTProto2=true; } } lastRecvPacketTime=GetCurrentTime(); /*decryptedAudioBlock random_id:long random_bytes:string 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 = DecryptedAudioBlock simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedAudioBlock; */ uint32_t ackId, pseq, acks; unsigned char type; uint32_t tlid=(uint32_t) in.ReadInt32(); uint32_t packetInnerLen=0; if(tlid==TLID_DECRYPTED_AUDIO_BLOCK){ in.ReadInt64(); // random id uint32_t randLen=(uint32_t) in.ReadTlLength(); in.Seek(in.GetOffset()+randLen+pad4(randLen)); uint32_t flags=(uint32_t) in.ReadInt32(); type=(unsigned char) ((flags >> 24) & 0xFF); if(!(flags & PFLAG_HAS_SEQ && flags & PFLAG_HAS_RECENT_RECV)){ LOGW("Received packet doesn't have PFLAG_HAS_SEQ, PFLAG_HAS_RECENT_RECV, or both"); return; } if(flags & PFLAG_HAS_CALL_ID){ unsigned char pktCallID[16]; in.ReadBytes(pktCallID, 16); if(memcmp(pktCallID, callID, 16)!=0){ LOGW("Received packet has wrong call id"); lastError=ERROR_UNKNOWN; SetState(STATE_FAILED); return; } } ackId=(uint32_t) in.ReadInt32(); pseq=(uint32_t) in.ReadInt32(); acks=(uint32_t) in.ReadInt32(); if(flags & PFLAG_HAS_PROTO){ uint32_t proto=(uint32_t) in.ReadInt32(); if(proto!=PROTOCOL_NAME){ LOGW("Received packet uses wrong protocol"); lastError=ERROR_INCOMPATIBLE; SetState(STATE_FAILED); return; } } if(flags & PFLAG_HAS_EXTRA){ uint32_t extraLen=(uint32_t) in.ReadTlLength(); in.Seek(in.GetOffset()+extraLen+pad4(extraLen)); } if(flags & PFLAG_HAS_DATA){ packetInnerLen=in.ReadTlLength(); } }else if(tlid==TLID_SIMPLE_AUDIO_BLOCK){ in.ReadInt64(); // random id uint32_t randLen=(uint32_t) in.ReadTlLength(); in.Seek(in.GetOffset()+randLen+pad4(randLen)); packetInnerLen=in.ReadTlLength(); type=in.ReadByte(); ackId=(uint32_t) in.ReadInt32(); pseq=(uint32_t) in.ReadInt32(); acks=(uint32_t) in.ReadInt32(); }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++; if(seqgt(pseq, lastRemoteSeq)){ uint32_t diff=pseq-lastRemoteSeq; if(diff>31){ memset(recvPacketTimes, 0, 32*sizeof(double)); }else{ memmove(&recvPacketTimes[diff], recvPacketTimes, (32-diff)*sizeof(double)); if(diff>1){ memset(recvPacketTimes, 0, diff*sizeof(double)); } recvPacketTimes[0]=GetCurrentTime(); } lastRemoteSeq=pseq; }else if(!seqgt(pseq, lastRemoteSeq) && lastRemoteSeq-pseq<32){ if(recvPacketTimes[lastRemoteSeq-pseq]!=0){ LOGW("Received duplicated packet for seq %u", pseq); return; } recvPacketTimes[lastRemoteSeq-pseq]=GetCurrentTime(); }else if(lastRemoteSeq-pseq>=32){ LOGW("Packet %u is out of order and too late", pseq); return; } if(seqgt(ackId, lastRemoteAckSeq)){ //uint32_t diff=ackId-lastRemoteAckSeq; /*if(diff>31){ memset(remoteAcks, 0, 32*sizeof(double)); }else{ memmove(&remoteAcks[diff], remoteAcks, (32-diff)*sizeof(double)); if(diff>1){ memset(remoteAcks, 0, diff*sizeof(double)); } remoteAcks[0]=GetCurrentTime(); }*/ MutexGuard _m(queuedPacketsMutex); if(waitingForAcks && lastRemoteAckSeq>=firstSentPing){ memset(rttHistory, 0, 32*sizeof(double)); waitingForAcks=false; dontSendPackets=10; LOGI("resuming sending"); } lastRemoteAckSeq=ackId; conctl->PacketAcknowledged(ackId); unsigned int i; for(i=0;i<31;i++){ for(std::vector::iterator itr=recentOutgoingPackets.begin();itr!=recentOutgoingPackets.end();++itr){ if(itr->ackTime!=0) continue; if(((acks >> (31-i)) & 1) && itr->seq==ackId-(i+1)){ itr->ackTime=GetCurrentTime(); conctl->PacketAcknowledged(itr->seq); } } /*if(remoteAcks[i+1]==0){ if((acks >> (31-i)) & 1){ remoteAcks[i+1]=GetCurrentTime(); conctl->PacketAcknowledged(ackId-(i+1)); } }*/ } for(i=0;iseqs[j]); if(qp->seqs[j]==0) break; 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]); didAck=true; break; } } if(didAck) break; } } 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; } } } 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)){ if(seqgt(lastSentSeq-32, lastRemoteAckSeq)){ currentEndpoint=srcEndpoint; LOGI("Peer network address probably changed, switching to relay"); if(allowP2p) SendPublicEndpointsRequest(); } } //LOGV("acks: %u -> %.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()); //LOGV("Packet %u type is %d", pseq, type); if(type==PKT_INIT){ LOGD("Received init"); if(!receivedInit){ receivedInit=true; if((srcEndpoint->type==Endpoint::TYPE_UDP_RELAY && udpConnectivityState!=UDP_BAD && udpConnectivityState!=UDP_NOT_AVAILABLE) || srcEndpoint->type==Endpoint::TYPE_TCP_RELAY){ currentEndpoint=srcEndpoint; if(srcEndpoint->type==Endpoint::TYPE_UDP_RELAY || (useTCP && srcEndpoint->type==Endpoint::TYPE_TCP_RELAY)) preferredRelay=srcEndpoint; } LogDebugInfo(); } peerVersion=(uint32_t) in.ReadInt32(); LOGI("Peer version is %d", peerVersion); uint32_t minVer=(uint32_t) in.ReadInt32(); if(minVer>PROTOCOL_VERSION || peerVersion=2 ? 10 : 2)+(peerVersion>=2 ? 6 : 4)*outgoingStreams.size()); out.WriteInt32(PROTOCOL_VERSION); out.WriteInt32(MIN_PROTOCOL_VERSION); out.WriteByte((unsigned char) outgoingStreams.size()); for(i=0; iPut(PendingOutgoingPacket{ /*.seq=*/GenerateOutSeq(), /*.type=*/PKT_INIT_ACK, /*.len=*/out.GetLength(), /*.data=*/buf, /*.endpoint=*/NULL }); } } if(type==PKT_INIT_ACK){ LOGD("Received init ack"); if(!receivedInitAck){ receivedInitAck=true; if(packetInnerLen>10){ peerVersion=in.ReadInt32(); uint32_t minVer=(uint32_t) in.ReadInt32(); if(minVer>PROTOCOL_VERSION || peerVersion50) 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(!incomingAudioStream) return; if(peerVersion>=5 && !useMTProto2){ useMTProto2=true; LOGD("MTProto2 wasn't initially enabled for whatever reason but peer supports it; upgrading"); } { MutexGuard m(audioIOMutex); if(!audioInput){ StartAudio(); } } setEstablishedAt=GetCurrentTime()+ServerConfig::GetSharedInstance()->GetDouble("established_delay_if_no_stream_data", 1.5); if(allowP2p) SendPublicEndpointsRequest(); } } 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>len){ return; } if(incomingStreams.size()>0 && incomingStreams[0].jitterBuffer) incomingStreams[0].jitterBuffer->HandleInput((unsigned char*) (buffer+in.GetOffset()), sdlen, pts); if(iToString().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; } unsigned char* buf=outgoingPacketsBufferPool.Get(); if(!buf){ LOGW("Dropping pong packet, queue overflow"); return; } BufferOutputStream pkt(buf, outgoingPacketsBufferPool.GetSingleBufferSize()); pkt.WriteInt32(pseq); sendQueue->Put(PendingOutgoingPacket{ /*.seq=*/GenerateOutSeq(), /*.type=*/PKT_PONG, /*.len=*/pkt.GetLength(), /*.data=*/buf, /*.endpoint=*/srcEndpoint, }); } if(type==PKT_PONG){ if(packetInnerLen>=4){ uint32_t pingSeq=(uint32_t) in.ReadInt32(); if(pingSeq==srcEndpoint->lastPingSeq){ memmove(&srcEndpoint->rtts[1], srcEndpoint->rtts, sizeof(double)*5); srcEndpoint->rtts[0]=GetCurrentTime()-srcEndpoint->lastPingTime; int i; srcEndpoint->averageRTT=0; for(i=0;i<6;i++){ if(srcEndpoint->rtts[i]==0) break; srcEndpoint->averageRTT+=srcEndpoint->rtts[i]; } srcEndpoint->averageRTT/=i; LOGD("Current RTT via %s: %.3f, average: %.3f", packet.address->ToString().c_str(), srcEndpoint->rtts[0], srcEndpoint->averageRTT); } } } if(type==PKT_STREAM_STATE){ unsigned char id=in.ReadByte(); unsigned char enabled=in.ReadByte(); unsigned int i; for(i=0;i::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){ if((*itrtr)->type==Endpoint::TYPE_UDP_P2P_LAN){ if(currentEndpoint==*itrtr) currentEndpoint=preferredRelay; found=true; (*itrtr)->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)); } } if(type==PKT_NETWORK_CHANGED && 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(); } } 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; } } 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); 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(std::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(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; 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(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(i0){ LOGI("rtt diff: %.3lf", rttHistory[0]-rttHistory[16]); }*/ int i; double v=0; for(i=1;i<32;i++){ v+=rttHistory[i-1]-rttHistory[i]; } v=v/32; if(rttHistory[0]>10.0 && rttHistory[8]>10.0 && (networkType==NET_TYPE_EDGE || networkType==NET_TYPE_GPRS)){ waitingForAcks=true; signalBarCount=1; }else{ 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(); if(lostCount>0 || (lostCount<0 && recvLossCount>((uint32_t) -lostCount))) recvLossCount+=lostCount; } } } if(dontSendPackets>0) dontSendPackets--; unsigned int i; 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) continue; Endpoint *tcpRelay=new Endpoint(**itr); 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; if(setCurrentEndpointToTCP && currentEndpoint->type!=Endpoint::TYPE_TCP_RELAY){ setCurrentEndpointToTCP=false; currentEndpoint=tcpRelay; preferredRelay=tcpRelay; } relays.push_back(tcpRelay); } endpoints.insert(endpoints.end(), relays.begin(), relays.end()); didAddTcpRelays=true; } if(state==STATE_ESTABLISHED && encoder && conctl){ if((audioInput && !audioInput->IsInitialized()) || (audioOutput && !audioOutput->IsInitialized())){ LOGE("Audio I/O failed"); lastError=ERROR_AUDIO_IO; SetState(STATE_FAILED); } int act=conctl->GetBandwidthControlAction(); if(act==TGVOIP_CONCTL_ACT_DECREASE){ uint32_t bitrate=encoder->GetBitrate(); if(bitrate>8000) encoder->SetBitrate(bitrate<(minAudioBitrate+audioBitrateStepDecr) ? minAudioBitrate : (bitrate-audioBitrateStepDecr)); }else if(act==TGVOIP_CONCTL_ACT_INCREASE){ uint32_t bitrate=encoder->GetBitrate(); if(bitrateSetBitrate(bitrate+audioBitrateStepIncr); } if(tickCount%10==0 && encoder){ uint32_t sendLossCount=conctl->GetSendLossCount(); memmove(sendLossCountHistory+1, sendLossCountHistory, 31*sizeof(uint32_t)); sendLossCountHistory[0]=sendLossCount-prevSendLossCount; prevSendLossCount=sendLossCount; double avgSendLossCount=0; for(i=0;i<10;i++){ avgSendLossCount+=sendLossCountHistory[i]; } double packetsPerSec=1000/(double)outgoingStreams[0].frameDuration; avgSendLossCount=avgSendLossCount/10/packetsPerSec; //LOGV("avg send loss: %.1f%%", avgSendLossCount*100); if(avgSendLossCount>0.1){ encoder->SetPacketLoss(40); signalBarCount=1; }else if(avgSendLossCount>0.075){ encoder->SetPacketLoss(35); signalBarCount=MIN(signalBarCount, 2); }else if(avgSendLossCount>0.0625){ encoder->SetPacketLoss(30); signalBarCount=MIN(signalBarCount, 2); }else if(avgSendLossCount>0.05){ encoder->SetPacketLoss(25); signalBarCount=MIN(signalBarCount, 3); }else if(avgSendLossCount>0.025){ encoder->SetPacketLoss(20); signalBarCount=MIN(signalBarCount, 3); }else if(avgSendLossCount>0.01){ encoder->SetPacketLoss(17); }else{ encoder->SetPacketLoss(15); } } } if(currentEndpoint->type==Endpoint::TYPE_TCP_RELAY){ signalBarCount=MIN(signalBarCount, 3); } bool areThereAnyEnabledStreams=false; for(i=0;iPut(PendingOutgoingPacket{ /*.seq=*/(firstSentPing=GenerateOutSeq()), /*.type=*/PKT_NOP, /*.len=*/0, /*.data=*/buf, /*.endpoint=*/NULL }); } } if(state==STATE_WAIT_INIT_ACK && GetCurrentTime()-stateChangeTime>.5){ SendInit(); } if(waitingForRelayPeerInfo && GetCurrentTime()-publicEndpointsReqTime>5){ LOGD("Resending peer relay info request"); SendPublicEndpointsRequest(); } { MutexGuard m(queuedPacketsMutex); for(i=0; itimeout>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){ 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); sendQueue->Put(PendingOutgoingPacket{ /*.seq=*/seq, /*.type=*/qp->type, /*.len=*/qp->length, /*.data=*/buf, /*.endpoint=*/NULL }); } } } } for(std::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); /*if(avgDelay>=5) signalBarCount=1; else if(avgDelay>=4) signalBarCount=MIN(signalBarCount, 2); else if(avgDelay>=3) signalBarCount=MIN(signalBarCount, 3);*/ if(avgLateCount[2]>=0.2) signalBarCount=1; else if(avgLateCount[2]>=0.1) signalBarCount=MIN(signalBarCount, 2); } } { 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); } } udpConnectivityState=UDP_PING_SENT; lastUdpPingTime=time; udpPingCount=1; }else if(udpConnectivityState==UDP_PING_SENT || udpConnectivityState==UDP_BAD){ 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); } } udpPingCount++; lastUdpPingTime=time; }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; count++; } } } if(count>0) avgPongs/=(double)count; else avgPongs=0.0; LOGI("UDP ping reply count: %.2f", avgPongs); bool configUseTCP=ServerConfig::GetSharedInstance()->GetBoolean("use_tcp", true); if(configUseTCP){ if(avgPongs==0.0 || (udpConnectivityState==UDP_BAD && avgPongs<7.0)){ udpConnectivityState=UDP_NOT_AVAILABLE; useTCP=true; useUDP=false; waitingForRelayPeerInfo=false; if(currentEndpoint->type!=Endpoint::TYPE_TCP_RELAY) setCurrentEndpointToTCP=true; }else if(avgPongs<3.0){ udpConnectivityState=UDP_BAD; useTCP=true; setCurrentEndpointToTCP=true; }else{ udpConnectivityState=UDP_AVAILABLE; } }else{ udpConnectivityState=UDP_NOT_AVAILABLE; } //LOGW("No UDP ping replies received; assuming no connectivity and trying TCP") //udpConnectivityState=UDP_NOT_AVAILABLE; //useTCP=true; } } } } if(state==STATE_ESTABLISHED || state==STATE_RECONNECTING){ if(time-lastRecvPacketTime>=config.recv_timeout){ 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; 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)); } } if(allowP2p){ SendPublicEndpointsRequest(); } UpdateDataSavingState(); UpdateAudioBitrate(); BufferOutputStream s(4); s.WriteInt32(dataSavingMode ? INIT_FLAG_DATA_SAVING_ENABLED : 0); SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20); lastRecvPacketTime=time; }else{ LOGW("Packet receive timeout, disconnecting"); lastError=ERROR_TIMEOUT; SetState(STATE_FAILED); } } }else if(state==STATE_WAIT_INIT || state==STATE_WAIT_INIT_ACK){ if(GetCurrentTime()-connectionInitTime>=config.init_timeout){ LOGW("Init timeout, disconnecting"); lastError=ERROR_TIMEOUT; SetState(STATE_FAILED); } } if(state==STATE_ESTABLISHED && time-lastRecvPacketTime>=reconnectingTimeout){ SetState(STATE_RECONNECTING); } if(state!=STATE_ESTABLISHED && setEstablishedAt>0 && time>=setEstablishedAt){ SetState(STATE_ESTABLISHED); setEstablishedAt=0; } if(tickCount%10==0){ signalBarsHistory[(tickCount/10)%sizeof(signalBarsHistory)]=(unsigned char) signalBarCount; //LOGV("Signal bar count history %08X", *reinterpret_cast(&signalBarsHistory)); int _signalBarCount=GetSignalBarsCount(); if(_signalBarCount!=prevSignalBarCount){ LOGD("SIGNAL BAR COUNT CHANGED: %d", _signalBarCount); if(callbacks.signalBarCountChanged) callbacks.signalBarCountChanged(this, _signalBarCount); } } if(statsDump && incomingStreams.size()==1){ JitterBuffer* 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, currentEndpoint->rtts[0], lastRemoteSeq, seq, lastRemoteAckSeq, recvLossCount, conctl ? conctl->GetSendLossCount() : 0, conctl ? (int)conctl->GetInflightDataSize() : 0, encoder ? encoder->GetBitrate() : 0, encoder ? encoder->GetPacketLoss() : 0, jitterBuffer ? jitterBuffer->GetLastMeasuredJitter() : 0, jitterBuffer ? jitterBuffer->GetLastMeasuredDelay()*0.06 : 0, jitterBuffer ? jitterBuffer->GetAverageDelay()*0.06 : 0); } } LOGI("=== tick thread exiting ==="); } Endpoint& VoIPController::GetRemoteEndpoint(){ return *currentEndpoint; } void VoIPController::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); if(ep->type==Endpoint::TYPE_UDP_RELAY || ep->type==Endpoint::TYPE_TCP_RELAY) out.WriteBytes((unsigned char*)ep->peerTag, 16); else out.WriteBytes(callID, 16); if(len>0){ if(useMTProto2){ 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=isOutgoing ? 0 : 8; 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, isOutgoing ? 0 : 8, 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()); }else{ BufferOutputStream inner(len+128); inner.WriteInt32(len); inner.WriteBytes(data, len); if(inner.GetLength()%16!=0){ size_t padLen=16-inner.GetLength()%16; unsigned char padding[16]; crypto.rand_bytes((uint8_t *) padding, padLen); inner.WriteBytes(padding, padLen); } assert(inner.GetLength()%16==0); unsigned char key[32], iv[32], msgHash[SHA1_LENGTH]; crypto.sha1((uint8_t *) inner.GetBuffer(), len+4, msgHash); out.WriteBytes(keyFingerprint, 8); out.WriteBytes((msgHash+(SHA1_LENGTH-16)), 16); KDF(msgHash+(SHA1_LENGTH-16), isOutgoing ? 0 : 8, key, iv); 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()); } } //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.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 VoIPController::ActuallySendPacket(NetworkPacket &pkt, Endpoint* ep){ //LOGI("Sending packet of %d bytes", pkt.length); if(IS_MOBILE_NETWORK(networkType)) stats.bytesSentMobile+=(uint64_t)pkt.length; else stats.bytesSentWifi+=(uint64_t)pkt.length; if(ep->type==Endpoint::TYPE_TCP_RELAY){ if(ep->socket && !ep->socket->IsFailed()){ ep->socket->Send(&pkt); }else{ if(ep->socket){ LOGD("closing failed TCP socket: %s:%u", ep->address.ToString().c_str(), ep->port); ep->socket->Close(); delete ep->socket; ep->socket=NULL; } LOGI("connecting to tcp: %s:%u", ep->address.ToString().c_str(), ep->port); NetworkSocket* s; if(proxyProtocol==PROXY_NONE){ s=NetworkSocket::Create(PROTO_TCP); }else if(proxyProtocol==PROXY_SOCKS5){ NetworkSocket* rawTcp=NetworkSocket::Create(PROTO_TCP); openingTcpSocket=rawTcp; rawTcp->Connect(resolvedProxyAddress, proxyPort); if(rawTcp->IsFailed()){ openingTcpSocket=NULL; rawTcp->Close(); delete rawTcp; LOGW("Error connecting to SOCKS5 proxy"); return; } NetworkSocketSOCKS5Proxy* proxy=new NetworkSocketSOCKS5Proxy(rawTcp, NULL, proxyUsername, proxyPassword); openingTcpSocket=proxy; proxy->InitConnection(); if(proxy->IsFailed()){ openingTcpSocket=NULL; LOGW("Proxy initialization failed"); proxy->Close(); delete proxy; return; } s=proxy; }/*else if(proxyProtocol==PROXY_HTTP){ s=NetworkSocket::Create(PROTO_TCP); }*/else{ LOGE("Unsupported proxy protocol %d", proxyProtocol); SetState(STATE_FAILED); return; } s->Connect(&ep->address, ep->port); if(s->IsFailed()){ openingTcpSocket=NULL; s->Close(); delete s; LOGW("Error connecting to %s:%u", ep->address.ToString().c_str(), ep->port); }else{ NetworkSocketTCPObfuscated* tcpWrapper=new NetworkSocketTCPObfuscated(s); openingTcpSocket=tcpWrapper; tcpWrapper->InitConnection(); openingTcpSocket=NULL; if(tcpWrapper->IsFailed()){ tcpWrapper->Close(); delete tcpWrapper; LOGW("Error initializing connection to %s:%u", ep->address.ToString().c_str(), ep->port); }else{ tcpWrapper->Send(&pkt); ep->socket=tcpWrapper; selectCanceller->CancelSelect(); } } } }else{ udpSocket->Send(&pkt); } } void VoIPController::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; if(currentEndpoint && currentEndpoint->type!=Endpoint::TYPE_UDP_RELAY){ 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; if(endpoint->type==Endpoint::TYPE_UDP_RELAY && useTCP){ useTCP=false; if(preferredRelay->type==Endpoint::TYPE_TCP_RELAY){ preferredRelay=endpoint; currentEndpoint=endpoint; } }else if(endpoint->type==Endpoint::TYPE_TCP_RELAY && endpoint->socket){ endpoint->socket->Close(); } //if(endpoint->type==Endpoint::TYPE_UDP_P2P_INET){ endpoint->averageRTT=0; memset(endpoint->rtts, 0, sizeof(endpoint->rtts)); //} if(endpoint->type==Endpoint::TYPE_UDP_P2P_LAN){ delete endpoint; itr=endpoints.erase(itr); }else{ ++itr; } } } udpConnectivityState=UDP_UNKNOWN; udpPingCount=0; lastUdpPingTime=0; if(proxyProtocol==PROXY_SOCKS5) InitUDPProxy(); if(allowP2p && currentEndpoint){ SendPublicEndpointsRequest(); } BufferOutputStream s(4); s.WriteInt32(dataSavingMode ? INIT_FLAG_DATA_SAVING_ENABLED : 0); SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20); selectCanceller->CancelSelect(); } 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(); } } double VoIPController::GetAverageRTT(){ if(lastSentSeq>=lastRemoteAckSeq){ uint32_t diff=lastSentSeq-lastRemoteAckSeq; //LOGV("rtt diff=%u", diff); if(diff<32){ double res=0; int count=0; /*for(i=diff;i<32;i++){ if(remoteAcks[i-diff]>0){ res+=(remoteAcks[i-diff]-sentPacketTimes[i]); count++; } }*/ MutexGuard m(queuedPacketsMutex); for(std::vector::iterator itr=recentOutgoingPackets.begin();itr!=recentOutgoingPackets.end();++itr){ if(itr->ackTime>0){ res+=(itr->ackTime-itr->sendTime); count++; } } if(count>0) res/=count; return res; } } return 999; } #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(); } #endif double VoIPController::GetCurrentTime(){ #if defined(__linux__) struct timespec ts; 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); return (mach_absolute_time() - machTimestart) * machTimebase / 1000000000.0f; #elif defined(_WIN32) if(!didInitWin32TimeScale){ LARGE_INTEGER scale; QueryPerformanceFrequency(&scale); win32TimeScale=scale.QuadPart; didInitWin32TimeScale=true; } LARGE_INTEGER t; QueryPerformanceCounter(&t); return (double)t.QuadPart/(double)win32TimeScale; #endif } void VoIPController::SetState(int state){ this->state=state; LOGV("Call state changed to %d", state); stateChangeTime=GetCurrentTime(); if(callbacks.connectionStateChanged){ callbacks.connectionStateChanged(this, state); } if(state==STATE_ESTABLISHED) SetMicMute(micMuted); } void VoIPController::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; } } if(echoCanceller) echoCanceller->Enable(!mute); if(state==STATE_ESTABLISHED){ unsigned int i; for(i=0; iReset(); } if(decoder){ decoder->ResetQueue(); }*/ if(audioOutput){ if(audioOutput->IsPlaying()!=areAnyAudioStreamsEnabled){ if(areAnyAudioStreamsEnabled) audioOutput->Start(); else audioOutput->Stop(); } } } 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); buf.WriteBytes(msgKey, 16); buf.WriteBytes(encryptionKey+x, 32); crypto.sha1(buf.GetBuffer(), buf.GetLength(), sA); buf.Reset(); buf.WriteBytes(encryptionKey+32+x, 16); buf.WriteBytes(msgKey, 16); buf.WriteBytes(encryptionKey+48+x, 16); crypto.sha1(buf.GetBuffer(), buf.GetLength(), sB); buf.Reset(); buf.WriteBytes(encryptionKey+64+x, 32); buf.WriteBytes(msgKey, 16); crypto.sha1(buf.GetBuffer(), buf.GetLength(), sC); buf.Reset(); buf.WriteBytes(msgKey, 16); buf.WriteBytes(encryptionKey+96+x, 32); crypto.sha1(buf.GetBuffer(), buf.GetLength(), sD); buf.Reset(); buf.WriteBytes(sA, 8); buf.WriteBytes(sB+8, 12); buf.WriteBytes(sC+4, 12); assert(buf.GetLength()==32); memcpy(aesKey, buf.GetBuffer(), 32); buf.Reset(); buf.WriteBytes(sA+8, 12); buf.WriteBytes(sB, 8); buf.WriteBytes(sC+16, 4); buf.WriteBytes(sD, 8); assert(buf.GetLength()==32); memcpy(aesIv, buf.GetBuffer(), 32); } void VoIPController::KDF2(unsigned char* msgKey, size_t x, unsigned char *aesKey, unsigned char *aesIv){ uint8_t sA[32], sB[32]; BufferOutputStream buf(128); buf.WriteBytes(msgKey, 16); buf.WriteBytes(encryptionKey+x, 36); crypto.sha256(buf.GetBuffer(), buf.GetLength(), sA); buf.Reset(); buf.WriteBytes(encryptionKey+40+x, 36); buf.WriteBytes(msgKey, 16); crypto.sha256(buf.GetBuffer(), buf.GetLength(), sB); buf.Reset(); buf.WriteBytes(sA, 8); buf.WriteBytes(sB+8, 16); buf.WriteBytes(sA+24, 8); memcpy(aesKey, buf.GetBuffer(), 32); buf.Reset(); buf.WriteBytes(sB, 8); buf.WriteBytes(sA+8, 16); buf.WriteBytes(sB+24, 8); 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){ 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 %d [%s%s]\n", endpoint->address.ToString().c_str(), endpoint->port, (int)(endpoint->averageRTT*1000), endpoint->udpPongCount, 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" "Jitter buffer: %d/%.2f | %.1f, %.1f, %.1f\n" "RTT avg/min: %d/%d\n" "Congestion window: %d/%d bytes\n" "Key fingerprint: %02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%s\n" "Last sent/ack'd seq: %u/%u\n" "Last recvd seq: %u\n" "Send/recv losses: %u/%u (%d%%)\n" "Audio bitrate: %d kbit\n" // "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), int(conctl->GetInflightDataSize()), int(conctl->GetCongestionWindow()), keyFingerprint[0],keyFingerprint[1],keyFingerprint[2],keyFingerprint[3],keyFingerprint[4],keyFingerprint[5],keyFingerprint[6],keyFingerprint[7], useMTProto2 ? " (MTProto2.0)" : "", lastSentSeq, lastRemoteAckSeq, lastRemoteSeq, conctl->GetSendLossCount(), recvLossCount, encoder ? encoder->GetPacketLoss() : 0, encoder ? (encoder->GetBitrate()/1000) : 0, // audioPacketGrouping, 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)); } void VoIPController::SendPublicEndpointsRequest(){ LOGI("Sending public endpoints request"); if(preferredRelay){ SendPublicEndpointsRequest(*preferredRelay); } if(peerPreferredRelay && peerPreferredRelay!=preferredRelay){ SendPublicEndpointsRequest(*peerPreferredRelay); } } void VoIPController::SendPublicEndpointsRequest(Endpoint& relay){ if(!useUDP) return; LOGD("Sending public endpoints request to %s:%d", relay.address.ToString().c_str(), relay.port); publicEndpointsReqTime=GetCurrentTime(); waitingForRelayPeerInfo=true; unsigned char buf[32]; memcpy(buf, relay.peerTag, 16); memset(buf+16, 0xFF, 16); NetworkPacket pkt={0}; pkt.data=buf; pkt.length=32; pkt.address=(NetworkAddress*)&relay.address; pkt.port=relay.port; pkt.protocol=PROTO_UDP; udpSocket->Send(&pkt); } Endpoint* 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; } return NULL; } float VoIPController::GetOutputLevel(){ 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; if(data){ pkt->data=(unsigned char *) malloc(len); memcpy(pkt->data, data, len); pkt->length=len; } pkt->retryInterval=retryInterval; pkt->timeout=timeout; pkt->firstSentTime=0; pkt->lastSentTime=0; MutexGuard m(queuedPacketsMutex); queuedPackets.push_back(pkt); } void VoIPController::SetConfig(voip_config_t *cfg){ memcpy(&config, cfg, sizeof(voip_config_t)); if(tgvoipLogFile){ fclose(tgvoipLogFile); tgvoipLogFile=NULL; } if(strlen(cfg->logFilePath)){ tgvoipLogFile=fopen(cfg->logFilePath, "a"); tgvoip_log_file_write_header(tgvoipLogFile); }else{ tgvoipLogFile=NULL; } if(statsDump){ fclose(statsDump); statsDump=NULL; } if(strlen(cfg->statsDumpFilePath)){ statsDump=fopen(cfg->statsDumpFilePath, "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); }else{ statsDump=NULL; } UpdateDataSavingState(); UpdateAudioBitrate(); } void VoIPController::UpdateDataSavingState(){ if(config.data_saving==DATA_SAVING_ALWAYS){ dataSavingMode=true; }else if(config.data_saving==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); } void VoIPController::DebugCtl(int request, int param){ if(request==1){ // set bitrate maxBitrate=param; if(encoder){ encoder->SetBitrate(maxBitrate); } }else if(request==2){ // set packet loss if(encoder){ encoder->SetPacketLoss(param); } }else if(request==3){ // force enable/disable p2p allowP2p=param==1; if(!allowP2p && currentEndpoint && currentEndpoint->type!=Endpoint::TYPE_UDP_RELAY){ currentEndpoint=preferredRelay; }else if(allowP2p){ SendPublicEndpointsRequest(); } BufferOutputStream s(4); s.WriteInt32(dataSavingMode ? INIT_FLAG_DATA_SAVING_ENABLED : 0); SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20); }else if(request==4){ if(echoCanceller) echoCanceller->Enable(param==1); } } const char* VoIPController::GetVersion(){ return LIBTGVOIP_VERSION; } int64_t VoIPController::GetPreferredRelayID(){ if(preferredRelay) return preferredRelay->id; return 0; } int VoIPController::GetLastError(){ return lastError; } void VoIPController::GetStats(voip_stats_t *stats){ memcpy(stats, &this->stats, sizeof(voip_stats_t)); } #ifdef TGVOIP_USE_AUDIO_SESSION void VoIPController::SetAcquireAudioSession(void (^completion)(void (^)())) { this->acquireAudioSession = [completion copy]; } void VoIPController::ReleaseAudioSession(void (^completion)()) { completion(); } #endif void VoIPController::LogDebugInfo(){ std::string json="{\"endpoints\":["; for(std::vector::iterator itr=endpoints.begin();itr!=endpoints.end();++itr){ Endpoint* e=*itr; char buffer[1024]; const char* typeStr="unknown"; switch(e->type){ case Endpoint::TYPE_UDP_RELAY: typeStr="udp_relay"; break; case Endpoint::TYPE_UDP_P2P_INET: typeStr="udp_p2p_inet"; break; case Endpoint::TYPE_UDP_P2P_LAN: typeStr="udp_p2p_lan"; break; case Endpoint::TYPE_TCP_RELAY: 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" : ""); json+=buffer; if(itr!=endpoints.end()-1) json+=","; } json+="],"; char buffer[1024]; const char* netTypeStr; switch(networkType){ case NET_TYPE_WIFI: netTypeStr="wifi"; break; case NET_TYPE_GPRS: netTypeStr="gprs"; break; case NET_TYPE_EDGE: netTypeStr="edge"; break; case NET_TYPE_3G: netTypeStr="3g"; break; case NET_TYPE_HSPA: netTypeStr="hspa"; break; case NET_TYPE_LTE: netTypeStr="lte"; break; case NET_TYPE_ETHERNET: netTypeStr="ethernet"; break; case NET_TYPE_OTHER_HIGH_SPEED: netTypeStr="other_high_speed"; break; case NET_TYPE_OTHER_LOW_SPEED: netTypeStr="other_low_speed"; break; case NET_TYPE_DIALUP: netTypeStr="dialup"; break; case NET_TYPE_OTHER_MOBILE: netTypeStr="other_mobile"; break; default: netTypeStr="unknown"; break; } snprintf(buffer, 1024, "\"time\":%u,\"network_type\":\"%s\"}", (unsigned int)time(NULL), netTypeStr); json+=buffer; debugLogs.push_back(json); } std::string VoIPController::GetDebugLog(){ std::string log="{\"events\":["; for(std::vector::iterator itr=debugLogs.begin();itr!=debugLogs.end();++itr){ log+=(*itr); if((itr+1)!=debugLogs.end()) log+=","; } log+="],\"libtgvoip_version\":\"" LIBTGVOIP_VERSION "\"}"; return log; } void VoIPController::GetDebugLog(char *buffer){ strcpy(buffer, GetDebugLog().c_str()); } size_t VoIPController::GetDebugLogLength(){ size_t len=128; for(std::vector::iterator itr=debugLogs.begin();itr!=debugLogs.end();++itr){ len+=(*itr).length()+1; } return len; } std::vector VoIPController::EnumerateAudioInputs(){ vector devs; audio::AudioInput::EnumerateDevices(devs); return devs; } std::vector VoIPController::EnumerateAudioOutputs(){ vector devs; audio::AudioOutput::EnumerateDevices(devs); return devs; } void VoIPController::SetCurrentAudioInput(std::string id){ currentAudioInput=id; if(audioInput) audioInput->SetCurrentDevice(id); } void VoIPController::SetCurrentAudioOutput(std::string id){ currentAudioOutput=id; if(audioOutput) audioOutput->SetCurrentDevice(id); } std::string VoIPController::GetCurrentAudioInputID(){ return currentAudioInput; } std::string VoIPController::GetCurrentAudioOutputID(){ return currentAudioOutput; } void VoIPController::SetProxy(int protocol, std::string address, uint16_t port, std::string username, std::string password){ proxyProtocol=protocol; proxyAddress=address; proxyPort=port; proxyUsername=username; proxyPassword=password; } void VoIPController::SendUdpPing(Endpoint *endpoint){ if(endpoint->type!=Endpoint::TYPE_UDP_RELAY) return; LOGV("Sending UDP ping to %s:%d", endpoint->address.ToString().c_str(), endpoint->port); BufferOutputStream p(1024); p.WriteBytes(endpoint->peerTag, 16); p.WriteInt32(-1); p.WriteInt32(-1); p.WriteInt32(-1); p.WriteInt32(-2); p.WriteInt64(12345); NetworkPacket pkt={0}; pkt.address=&endpoint->address; pkt.port=endpoint->port; pkt.protocol=PROTO_UDP; pkt.data=p.GetBuffer(); pkt.length=p.GetLength(); 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; 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; if(endpoint->type==Endpoint::TYPE_TCP_RELAY && !useTCP) continue; if(GetCurrentTime()-endpoint->lastPingTime>=10){ LOGV("Sending ping to %s", endpoint->address.ToString().c_str()); unsigned char* buf=outgoingPacketsBufferPool.Get(); if(buf){ sendQueue->Put(PendingOutgoingPacket{ /*.seq=*/(endpoint->lastPingSeq=GenerateOutSeq()), /*.type=*/PKT_PING, /*.len=*/0, /*.data=*/buf, /*.endpoint=*/endpoint }); } endpoint->lastPingTime=GetCurrentTime(); } if(endpoint->type==Endpoint::TYPE_UDP_RELAY || (useTCP && endpoint->type==Endpoint::TYPE_TCP_RELAY)){ double k=endpoint->type==Endpoint::TYPE_UDP_RELAY ? 1 : 2; if(endpoint->averageRTT>0 && endpoint->averageRTT*kaverageRTT*k; minPingRelay=endpoint; } } } if(minPingRelay!=preferredRelay){ preferredRelay=minPingRelay; LOGV("set preferred relay to %s", preferredRelay->address.ToString().c_str()); 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); if(p2p){ Endpoint* lan=GetEndpointByType(Endpoint::TYPE_UDP_P2P_LAN); if(lan && lan->averageRTT>0 && lan->averageRTTaverageRTT>0 && p2p->averageRTT0 && minPingaverageRTT*p2pToRelaySwitchThreshold){ LOGI("Switching to relay"); currentEndpoint=preferredRelay; LogDebugInfo(); } } } } void VoIPGroupController::SendRelayPings(){ //LOGV("Send relay pings 2"); double currentTime=GetCurrentTime(); if(currentTime-groupReflector->lastPingTime>=0.25){ SendRecentPacketsRequest(); groupReflector->lastPingTime=currentTime; } } void VoIPController::StartAudio(){ Stream& outgoingAudioStream=outgoingStreams[0]; LOGI("before create audio io"); void* platformSpecific=NULL; #ifdef __APPLE__ platformSpecific=appleAudioIO; #endif audioInput=tgvoip::audio::AudioInput::Create(currentAudioInput, platformSpecific); audioInput->Configure(48000, 16, 1); audioOutput=tgvoip::audio::AudioOutput::Create(currentAudioOutput, platformSpecific); audioOutput->Configure(48000, 16, 1); echoCanceller=new EchoCanceller(config.enableAEC, config.enableNS, config.enableAGC); encoder=new OpusEncoder(audioInput); encoder->SetCallback(AudioInputCallback, this); encoder->SetOutputFrameDuration(outgoingAudioStream.frameDuration); encoder->SetEchoCanceller(echoCanceller); encoder->Start(); if(!micMuted){ audioInput->Start(); if(!audioInput->IsInitialized()){ LOGE("Erorr initializing audio capture"); lastError=ERROR_AUDIO_IO; SetState(STATE_FAILED); return; } } if(!audioOutput->IsInitialized()){ LOGE("Erorr initializing audio playback"); lastError=ERROR_AUDIO_IO; SetState(STATE_FAILED); return; } UpdateAudioBitrate(); /*voip_stream_t* incomingAudioStream=incomingStreams[0]; jitterBuffer=new JitterBuffer(NULL, incomingAudioStream->frameDuration); decoder=new OpusDecoder(audioOutput); decoder->SetEchoCanceller(echoCanceller); decoder->SetJitterBuffer(jitterBuffer); decoder->SetFrameDuration(incomingAudioStream->frameDuration); decoder->Start(); if(incomingAudioStream->frameDuration>50) jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_60", 3)); else if(incomingAudioStream->frameDuration>30) jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_40", 4)); else jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_20", 6));*/ //audioOutput->Start(); OnAudioOutputReady(); } void VoIPController::OnAudioOutputReady(){ Stream& 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); } int VoIPController::GetSignalBarsCount(){ unsigned char avg=0; for(unsigned int i=0;i> 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) callbacks.connectionStateChanged(this, state); } void VoIPController::SetAudioOutputGainControlEnabled(bool enabled){ LOGD("New output AGC state: %d", enabled); outputAGCEnabled=enabled; if(outputAGC) outputAGC->SetPassThrough(!enabled); } uint32_t VoIPController::GetPeerCapabilities(){ return peerCapabilities; } void VoIPController::SendGroupCallKey(unsigned char *key){ if(!(peerCapabilities & TGVOIP_PEER_CAP_GROUP_CALLS)){ LOGE("Tried to send group call key but peer isn't capable of them"); return; } if(didSendGroupCallKey){ LOGE("Tried to send a group call key repeatedly"); return; } if(!isOutgoing){ LOGE("You aren't supposed to send group call key in an incoming call, use VoIPController::RequestCallUpgrade() instead"); return; } didSendGroupCallKey=true; SendPacketReliably(PKT_GROUP_CALL_KEY, key, 256, 0.5, 20); } void VoIPController::RequestCallUpgrade(){ if(!(peerCapabilities & TGVOIP_PEER_CAP_GROUP_CALLS)){ LOGE("Tried to send group call key but peer isn't capable of them"); return; } if(didSendUpgradeRequest){ LOGE("Tried to send upgrade request repeatedly"); return; } if(isOutgoing){ LOGE("You aren't supposed to send an upgrade request in an outgoing call, generate an encryption key and use VoIPController::SendGroupCallKey instead"); 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; } void VoIPController::SetEchoCancellationStrength(int strength){ echoCancellationStrength=strength; if(echoCanceller) echoCanceller->SetAECStrength(strength); } Endpoint::Endpoint(int64_t id, uint16_t port, IPv4Address& _address, IPv6Address& _v6address, char type, unsigned char peerTag[16]) : address(_address), v6address(_v6address){ this->id=id; this->port=port; this->type=type; memcpy(this->peerTag, peerTag, 16); if(type==TYPE_UDP_RELAY && ServerConfig::GetSharedInstance()->GetBoolean("force_tcp", false)) this->type=TYPE_TCP_RELAY; lastPingSeq=0; lastPingTime=0; averageRTT=0; memset(rtts, 0, sizeof(rtts)); socket=NULL; udpPongCount=0; } Endpoint::Endpoint() : address(0), v6address("::0") { lastPingSeq=0; lastPingTime=0; averageRTT=0; memset(rtts, 0, sizeof(rtts)); socket=NULL; udpPongCount=0; }