2018-06-04 21:37:43 +02:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
|
2020-01-23 16:45:53 +01:00
|
|
|
#include "VoIPGroupController.h"
|
2020-01-22 12:43:51 +01:00
|
|
|
#include "tools/logging.h"
|
2018-06-04 21:37:43 +02:00
|
|
|
#include "VoIPServerConfig.h"
|
2020-01-22 12:43:51 +01:00
|
|
|
#include "controller/PrivateDefines.h"
|
2018-06-04 21:37:43 +02:00
|
|
|
#include <assert.h>
|
|
|
|
#include <math.h>
|
2018-06-04 21:59:58 +02:00
|
|
|
#include <time.h>
|
2018-06-04 21:37:43 +02:00
|
|
|
|
|
|
|
using namespace tgvoip;
|
|
|
|
using namespace std;
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
VoIPGroupController::VoIPGroupController(int32_t timeDifference)
|
|
|
|
{
|
|
|
|
audioMixer = new AudioMixer();
|
2018-06-04 21:37:43 +02:00
|
|
|
memset(&callbacks, 0, sizeof(callbacks));
|
2020-01-22 12:43:51 +01:00
|
|
|
userSelfID = 0;
|
|
|
|
this->timeDifference = timeDifference;
|
2018-06-04 21:37:43 +02:00
|
|
|
LOGV("Created VoIPGroupController; timeDifference=%d", timeDifference);
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
VoIPGroupController::~VoIPGroupController()
|
|
|
|
{
|
|
|
|
if (audioOutput)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
audioOutput->Stop();
|
|
|
|
}
|
|
|
|
LOGD("before stop audio mixer");
|
|
|
|
audioMixer->Stop();
|
|
|
|
delete audioMixer;
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
for (vector<GroupCallParticipant>::iterator p = participants.begin(); p != participants.end(); p++)
|
|
|
|
{
|
|
|
|
if (p->levelMeter)
|
2018-06-04 21:37:43 +02:00
|
|
|
delete p->levelMeter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::SetGroupCallInfo(unsigned char *encryptionKey, unsigned char *reflectorGroupTag, unsigned char *reflectorSelfTag, unsigned char *reflectorSelfSecret, unsigned char *reflectorSelfTagHash, int32_t selfUserID, NetworkAddress reflectorAddress, NetworkAddress reflectorAddressV6, uint16_t reflectorPort)
|
|
|
|
{
|
2018-11-09 16:44:01 +01:00
|
|
|
Endpoint e;
|
2020-01-22 12:43:51 +01:00
|
|
|
e.address = reflectorAddress;
|
|
|
|
e.v6address = reflectorAddressV6;
|
|
|
|
e.port = reflectorPort;
|
2018-11-09 16:44:01 +01:00
|
|
|
memcpy(e.peerTag, reflectorGroupTag, 16);
|
2020-01-22 12:43:51 +01:00
|
|
|
e.type = Endpoint::Type::UDP_RELAY;
|
|
|
|
e.id = FOURCC('G', 'R', 'P', 'R');
|
|
|
|
endpoints[e.id] = e;
|
|
|
|
groupReflector = e;
|
|
|
|
currentEndpoint = e.id;
|
2018-06-04 21:37:43 +02:00
|
|
|
|
|
|
|
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];
|
2020-01-22 12:43:51 +01:00
|
|
|
crypto.sha256((uint8_t *)encryptionKey, 256, sha256);
|
|
|
|
memcpy(callID, sha256 + (SHA256_LENGTH - 16), 16);
|
|
|
|
memcpy(keyFingerprint, sha256 + (SHA256_LENGTH - 16), 8);
|
|
|
|
this->userSelfID = selfUserID;
|
2018-06-04 21:37:43 +02:00
|
|
|
|
|
|
|
//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]);
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::AddGroupCallParticipant(int32_t userID, unsigned char *memberTagHash, unsigned char *serializedStreams, size_t streamsLength)
|
|
|
|
{
|
|
|
|
if (userID == userSelfID)
|
2018-06-04 21:37:43 +02:00
|
|
|
return;
|
2020-01-22 12:43:51 +01:00
|
|
|
if (userSelfID == 0)
|
2018-06-04 21:37:43 +02:00
|
|
|
return;
|
|
|
|
//if(streamsLength==0)
|
|
|
|
// return;
|
|
|
|
MutexGuard m(participantsMutex);
|
|
|
|
LOGV("Adding group call user %d, streams length %u", userID, (unsigned int)streamsLength);
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
for (vector<GroupCallParticipant>::iterator p = participants.begin(); p != participants.end(); ++p)
|
|
|
|
{
|
|
|
|
if (p->userID == userID)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
LOGE("user %d already added", userID);
|
|
|
|
abort();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GroupCallParticipant p;
|
2020-01-22 12:43:51 +01:00
|
|
|
p.userID = userID;
|
2018-06-04 21:37:43 +02:00
|
|
|
memcpy(p.memberTagHash, memberTagHash, sizeof(p.memberTagHash));
|
2020-01-22 12:43:51 +01:00
|
|
|
p.levelMeter = new AudioLevelMeter();
|
2018-06-04 21:37:43 +02:00
|
|
|
|
|
|
|
BufferInputStream ss(serializedStreams, streamsLength);
|
2020-01-22 12:43:51 +01:00
|
|
|
vector<shared_ptr<Stream>> streams = DeserializeStreams(ss);
|
|
|
|
|
|
|
|
unsigned char audioStreamID = 0;
|
|
|
|
|
|
|
|
for (vector<shared_ptr<Stream>>::iterator _s = streams.begin(); _s != streams.end(); ++_s)
|
|
|
|
{
|
|
|
|
shared_ptr<Stream> &s = *_s;
|
|
|
|
s->userID = userID;
|
|
|
|
if (s->type == STREAM_TYPE_AUDIO && s->codec == CODEC_OPUS && !audioStreamID)
|
|
|
|
{
|
|
|
|
audioStreamID = s->id;
|
|
|
|
s->jitterBuffer = make_shared<JitterBuffer>(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));
|
2018-06-04 21:37:43 +02:00
|
|
|
else
|
2020-01-22 12:43:51 +01:00
|
|
|
s->jitterBuffer->SetMinPacketCount((uint32_t)ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_20", 6));
|
|
|
|
s->callbackWrapper = make_shared<CallbackWrapper>();
|
|
|
|
s->decoder = make_shared<OpusDecoder>(s->callbackWrapper, false, false);
|
2018-06-04 21:37:43 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
if (!audioStreamID)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::RemoveGroupCallParticipant(int32_t userID)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
MutexGuard m(participantsMutex);
|
2020-01-22 12:43:51 +01:00
|
|
|
vector<shared_ptr<Stream>>::iterator stm = incomingStreams.begin();
|
|
|
|
while (stm != incomingStreams.end())
|
|
|
|
{
|
|
|
|
if ((*stm)->userID == userID)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
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;
|
2020-01-22 12:43:51 +01:00
|
|
|
stm = incomingStreams.erase(stm);
|
2018-06-04 21:37:43 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
++stm;
|
|
|
|
}
|
2020-01-22 12:43:51 +01:00
|
|
|
for (vector<GroupCallParticipant>::iterator p = participants.begin(); p != participants.end(); ++p)
|
|
|
|
{
|
|
|
|
if (p->userID == userID)
|
|
|
|
{
|
|
|
|
if (p->levelMeter)
|
2018-06-04 21:37:43 +02:00
|
|
|
delete p->levelMeter;
|
|
|
|
participants.erase(p);
|
|
|
|
LOGI("Removed group call participant %d", userID);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
vector<shared_ptr<VoIPController::Stream>> VoIPGroupController::DeserializeStreams(BufferInputStream &in)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
vector<shared_ptr<Stream>> res;
|
2020-01-22 12:43:51 +01:00
|
|
|
try
|
|
|
|
{
|
|
|
|
unsigned char count = in.ReadByte();
|
|
|
|
for (unsigned char i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
uint16_t len = (uint16_t)in.ReadInt16();
|
|
|
|
BufferInputStream inner = in.GetPartBuffer(len, true);
|
|
|
|
shared_ptr<Stream> s = make_shared<Stream>();
|
|
|
|
s->id = inner.ReadByte();
|
|
|
|
s->type = inner.ReadByte();
|
|
|
|
s->codec = (uint32_t)inner.ReadInt32();
|
|
|
|
uint32_t flags = (uint32_t)inner.ReadInt32();
|
|
|
|
s->enabled = (flags & STREAM_FLAG_ENABLED) == STREAM_FLAG_ENABLED;
|
|
|
|
s->frameDuration = (uint16_t)inner.ReadInt16();
|
2018-06-04 21:37:43 +02:00
|
|
|
res.push_back(s);
|
|
|
|
}
|
2020-01-22 12:43:51 +01:00
|
|
|
}
|
|
|
|
catch (out_of_range &x)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
LOGW("Error deserializing streams: %s", x.what());
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::SetParticipantStreams(int32_t userID, unsigned char *serializedStreams, size_t length)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
LOGD("Set participant streams for %d", userID);
|
|
|
|
MutexGuard m(participantsMutex);
|
2020-01-22 12:43:51 +01:00
|
|
|
for (vector<GroupCallParticipant>::iterator p = participants.begin(); p != participants.end(); ++p)
|
|
|
|
{
|
|
|
|
if (p->userID == userID)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
BufferInputStream in(serializedStreams, length);
|
2020-01-22 12:43:51 +01:00
|
|
|
vector<shared_ptr<Stream>> streams = DeserializeStreams(in);
|
|
|
|
for (vector<shared_ptr<Stream>>::iterator ns = streams.begin(); ns != streams.end(); ++ns)
|
|
|
|
{
|
|
|
|
bool found = false;
|
|
|
|
for (vector<shared_ptr<Stream>>::iterator s = p->streams.begin(); s != p->streams.end(); ++s)
|
|
|
|
{
|
|
|
|
if ((*s)->id == (*ns)->id)
|
|
|
|
{
|
|
|
|
(*s)->enabled = (*ns)->enabled;
|
|
|
|
if (groupCallbacks.participantAudioStateChanged)
|
2018-06-04 21:37:43 +02:00
|
|
|
groupCallbacks.participantAudioStateChanged(this, userID, (*s)->enabled);
|
2020-01-22 12:43:51 +01:00
|
|
|
found = true;
|
2018-06-04 21:37:43 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-01-22 12:43:51 +01:00
|
|
|
if (!found)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
LOGW("Tried to add stream %d for user %d but adding/removing streams is not supported", (*ns)->id, userID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
size_t VoIPGroupController::GetInitialStreams(unsigned char *buf, size_t size)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
BufferOutputStream s(buf, size);
|
|
|
|
s.WriteByte(1); // streams count
|
|
|
|
|
|
|
|
s.WriteInt16(12); // this object length
|
2020-01-22 12:43:51 +01:00
|
|
|
s.WriteByte(1); // stream id
|
2018-06-04 21:37:43 +02:00
|
|
|
s.WriteByte(STREAM_TYPE_AUDIO);
|
|
|
|
s.WriteInt32(CODEC_OPUS);
|
|
|
|
s.WriteInt32(STREAM_FLAG_ENABLED | STREAM_FLAG_DTX); // flags
|
2020-01-22 12:43:51 +01:00
|
|
|
s.WriteInt16(60); // frame duration
|
2018-06-04 21:37:43 +02:00
|
|
|
|
|
|
|
return s.GetLength();
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::SendInit()
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
SendRecentPacketsRequest();
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::ProcessIncomingPacket(NetworkPacket &packet, Endpoint &srcEndpoint)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
//LOGD("Received incoming packet from %s:%u, %u bytes", packet.address->ToString().c_str(), packet.port, packet.length);
|
2019-04-15 01:43:10 +02:00
|
|
|
/*if(packet.length<17 || packet.length>2000){
|
2018-06-04 21:37:43 +02:00
|
|
|
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);
|
2019-04-15 01:43:10 +02:00
|
|
|
/*int32_t date=* /in.ReadInt32();
|
|
|
|
/*int64_t queryID=* /in.ReadInt64();
|
2018-06-04 21:37:43 +02:00
|
|
|
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<recvCount;i++){
|
|
|
|
uint32_t p=(uint32_t) in.ReadInt32();
|
|
|
|
//LOGV("Relay received packet: %08X", p);
|
|
|
|
uint16_t id=(uint16_t) (p & 0xFFFF);
|
|
|
|
//LOGV("ack id %04X", id);
|
|
|
|
for(vector<PacketIdMapping>::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;i<sentCount;i++){
|
2019-04-15 01:43:10 +02:00
|
|
|
/*int32_t p=* /in.ReadInt32();
|
2018-06-04 21:37:43 +02:00
|
|
|
//LOGV("Sent packet: %08X", p);
|
|
|
|
}
|
|
|
|
if(udpConnectivityState!=UDP_AVAILABLE)
|
|
|
|
udpConnectivityState=UDP_AVAILABLE;
|
|
|
|
if(state!=STATE_ESTABLISHED)
|
|
|
|
SetState(STATE_ESTABLISHED);
|
|
|
|
if(!audioInput){
|
2018-11-09 16:44:01 +01:00
|
|
|
InitializeAudio();
|
2018-06-04 21:37:43 +02:00
|
|
|
if(state!=STATE_FAILED){
|
|
|
|
// audioOutput->Start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}catch(out_of_range& x){
|
|
|
|
LOGE("Error parsing special response: %s", x.what());
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet.length<32)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// it's a packet relayed from another participant - find the sender
|
|
|
|
MutexGuard m(participantsMutex);
|
|
|
|
GroupCallParticipant* sender=NULL;
|
|
|
|
for(vector<GroupCallParticipant>::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<int32_t*>(msgKey), *reinterpret_cast<int32_t*>(msgKey+4), *reinterpret_cast<int32_t*>(msgKey+8), *reinterpret_cast<int32_t*>(msgKey+12), decryptedLen-4);
|
|
|
|
uint8_t *decryptOffset = packet.data + in.GetOffset();
|
|
|
|
if ((((intptr_t)decryptOffset) % sizeof(long)) != 0) {
|
|
|
|
LOGE("alignment2 packet.data+in.GetOffset()");
|
|
|
|
}
|
|
|
|
if (decryptedLen % sizeof(long) != 0) {
|
|
|
|
LOGE("alignment2 decryptedLen");
|
|
|
|
}
|
|
|
|
crypto.aes_ige_decrypt(packet.data+in.GetOffset(), decrypted, decryptedLen, aesKey, aesIv);
|
|
|
|
|
|
|
|
in=BufferInputStream(decrypted, decryptedLen);
|
|
|
|
//LOGD("received packet length: %d", in.ReadInt32());
|
|
|
|
|
|
|
|
BufferOutputStream buf(decryptedLen+32);
|
|
|
|
size_t x=0;
|
|
|
|
buf.WriteBytes(encryptionKey+88+x, 32);
|
|
|
|
buf.WriteBytes(decrypted+4, decryptedLen-4);
|
|
|
|
unsigned char msgKeyLarge[32];
|
|
|
|
crypto.sha256(buf.GetBuffer(), buf.GetLength(), msgKeyLarge);
|
|
|
|
|
|
|
|
if(memcmp(msgKey, msgKeyLarge+8, 16)!=0){
|
|
|
|
LOGW("Received packet from user %d has wrong hash", sender->userID);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t innerLen=(uint32_t) in.ReadInt32();
|
|
|
|
if(innerLen>decryptedLen-4){
|
|
|
|
LOGW("Received packet has wrong inner length (%d with total of %u)", (int)innerLen, (unsigned int)decryptedLen);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(decryptedLen-innerLen<12){
|
|
|
|
LOGW("Received packet has too little padding (%u)", (unsigned int)(decryptedLen-innerLen));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
in=BufferInputStream(decrypted+4, (size_t) innerLen);
|
|
|
|
|
|
|
|
uint32_t tlid=(uint32_t) in.ReadInt32();
|
|
|
|
if(tlid!=TLID_DECRYPTED_AUDIO_BLOCK){
|
|
|
|
LOGW("Received packet has unknown TL ID 0x%08x", tlid);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
in.Seek(in.GetOffset()+16); // random bytes
|
|
|
|
int32_t flags=in.ReadInt32();
|
|
|
|
if(!(flags & PFLAG_HAS_SEQ) || !(flags & PFLAG_HAS_SENDER_TAG_HASH)){
|
|
|
|
LOGW("Received packet has wrong flags");
|
|
|
|
return;
|
|
|
|
}
|
2019-04-15 01:43:10 +02:00
|
|
|
/*uint32_t seq=(uint32_t) * /in.ReadInt32();
|
2018-06-04 21:37:43 +02:00
|
|
|
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){
|
2019-04-15 01:43:10 +02:00
|
|
|
/*oneMoreInnerLengthWhyDoWeEvenNeedThis=* /in.ReadTlLength();
|
2018-06-04 21:37:43 +02:00
|
|
|
}
|
|
|
|
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;
|
2018-11-09 16:44:01 +01:00
|
|
|
//if(srcEndpoint->type==Endpoint::Type::UDP_RELAY && srcEndpoint!=peerPreferredRelay){
|
2018-06-04 21:37:43 +02:00
|
|
|
// peerPreferredRelay=srcEndpoint;
|
|
|
|
//}
|
|
|
|
for(i=0;i<count;i++){
|
|
|
|
unsigned char streamID=in.ReadByte();
|
|
|
|
unsigned char sflags=(unsigned char) (streamID & 0xC0);
|
|
|
|
uint16_t sdlen=(uint16_t) (sflags & STREAM_DATA_FLAG_LEN16 ? in.ReadInt16() : in.ReadByte());
|
|
|
|
uint32_t pts=(uint32_t) in.ReadInt32();
|
|
|
|
//LOGD("stream data, pts=%d, len=%d, rem=%d", pts, sdlen, in.Remaining());
|
|
|
|
audioTimestampIn=pts;
|
|
|
|
/*if(!audioOutStarted && audioOutput){
|
|
|
|
audioOutput->Start();
|
|
|
|
audioOutStarted=true;
|
2019-04-15 01:43:10 +02:00
|
|
|
}* /
|
2018-06-04 21:37:43 +02:00
|
|
|
if(in.GetOffset()+sdlen>in.GetLength()){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for(vector<shared_ptr<Stream>>::iterator stm=sender->streams.begin();stm!=sender->streams.end();++stm){
|
|
|
|
if((*stm)->id==streamID){
|
|
|
|
if((*stm)->jitterBuffer){
|
|
|
|
(*stm)->jitterBuffer->HandleInput(decrypted+4+in.GetOffset(), sdlen, pts, false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(i<count-1)
|
|
|
|
in.Seek(in.GetOffset()+sdlen);
|
|
|
|
}
|
2019-04-15 01:43:10 +02:00
|
|
|
}*/
|
2018-06-04 21:37:43 +02:00
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::SendUdpPing(Endpoint &endpoint)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::SetNetworkType(int type)
|
|
|
|
{
|
|
|
|
networkType = type;
|
2018-06-04 21:37:43 +02:00
|
|
|
UpdateDataSavingState();
|
2018-07-17 18:48:21 +02:00
|
|
|
UpdateAudioBitrateLimit();
|
2020-01-22 12:43:51 +01:00
|
|
|
string itfName = udpSocket->GetLocalInterfaceInfo(NULL, NULL);
|
|
|
|
if (itfName != activeNetItfName)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
udpSocket->OnActiveInterfaceChanged();
|
|
|
|
LOGI("Active network interface changed: %s -> %s", activeNetItfName.c_str(), itfName.c_str());
|
2020-01-22 12:43:51 +01:00
|
|
|
bool isFirstChange = activeNetItfName.length() == 0;
|
|
|
|
activeNetItfName = itfName;
|
|
|
|
if (isFirstChange)
|
2018-06-04 21:37:43 +02:00
|
|
|
return;
|
2020-01-22 12:43:51 +01:00
|
|
|
udpConnectivityState = UDP_UNKNOWN;
|
|
|
|
udpPingCount = 0;
|
|
|
|
lastUdpPingTime = 0;
|
|
|
|
if (proxyProtocol == PROXY_SOCKS5)
|
2018-06-04 21:37:43 +02:00
|
|
|
InitUDPProxy();
|
|
|
|
selectCanceller->CancelSelect();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::SendRecentPacketsRequest()
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
BufferOutputStream out(1024);
|
|
|
|
out.WriteInt32(TLID_UDP_REFLECTOR_REQUEST_PACKETS_INFO); // TL function
|
2020-01-22 12:43:51 +01:00
|
|
|
out.WriteInt32(GetCurrentUnixtime()); // date:int
|
|
|
|
out.WriteInt64(0); // query_id:long
|
|
|
|
out.WriteInt32(64); // recv_num:int
|
|
|
|
out.WriteInt32(0); // sent_num:int
|
2018-06-04 21:37:43 +02:00
|
|
|
SendSpecialReflectorRequest(out.GetBuffer(), out.GetLength());
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::SendSpecialReflectorRequest(unsigned char *data, size_t len)
|
|
|
|
{
|
2019-04-15 01:43:10 +02:00
|
|
|
/*BufferOutputStream out(1024);
|
2018-06-04 21:37:43 +02:00
|
|
|
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};
|
2018-11-09 16:44:01 +01:00
|
|
|
pkt.address=&groupReflector.address;
|
|
|
|
pkt.port=groupReflector.port;
|
2018-06-04 21:37:43 +02:00
|
|
|
pkt.protocol=PROTO_UDP;
|
|
|
|
pkt.data=out.GetBuffer();
|
|
|
|
pkt.length=out.GetLength();
|
2019-04-15 01:43:10 +02:00
|
|
|
ActuallySendPacket(pkt, groupReflector);*/
|
2018-06-04 21:37:43 +02:00
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::SendRelayPings()
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
//LOGV("Send relay pings 2");
|
2020-01-22 12:43:51 +01:00
|
|
|
double currentTime = GetCurrentTime();
|
|
|
|
if (currentTime - groupReflector.lastPingTime >= 0.25)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
SendRecentPacketsRequest();
|
2020-01-22 12:43:51 +01:00
|
|
|
groupReflector.lastPingTime = currentTime;
|
2018-06-04 21:37:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::OnAudioOutputReady()
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
encoder->SetDTX(true);
|
2018-07-17 18:48:21 +02:00
|
|
|
audioMixer->SetOutput(audioOutput);
|
2018-06-04 21:37:43 +02:00
|
|
|
audioMixer->SetEchoCanceller(echoCanceller);
|
|
|
|
audioMixer->Start();
|
|
|
|
audioOutput->Start();
|
2020-01-22 12:43:51 +01:00
|
|
|
audioOutStarted = true;
|
2018-06-04 21:37:43 +02:00
|
|
|
encoder->SetLevelMeter(&selfLevelMeter);
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::WritePacketHeader(uint32_t seq, BufferOutputStream *s, unsigned char type, uint32_t length, PacketSender *source)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
s->WriteInt32(TLID_DECRYPTED_AUDIO_BLOCK);
|
|
|
|
int64_t randomID;
|
2020-01-22 12:43:51 +01:00
|
|
|
crypto.rand_bytes((uint8_t *)&randomID, 8);
|
2018-06-04 21:37:43 +02:00
|
|
|
s->WriteInt64(randomID);
|
|
|
|
unsigned char randBytes[7];
|
|
|
|
crypto.rand_bytes(randBytes, 7);
|
|
|
|
s->WriteByte(7);
|
|
|
|
s->WriteBytes(randBytes, 7);
|
2020-01-22 12:43:51 +01:00
|
|
|
uint32_t pflags = PFLAG_HAS_SEQ | PFLAG_HAS_SENDER_TAG_HASH;
|
|
|
|
if (length > 0)
|
|
|
|
pflags |= PFLAG_HAS_DATA;
|
|
|
|
pflags |= ((uint32_t)type) << 24;
|
2018-06-04 21:37:43 +02:00
|
|
|
s->WriteInt32(pflags);
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
if (type == PKT_STREAM_DATA || type == PKT_STREAM_DATA_X2 || type == PKT_STREAM_DATA_X3)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
conctl->PacketSent(seq, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*if(pflags & PFLAG_HAS_CALL_ID){
|
|
|
|
s->WriteBytes(callID, 16);
|
|
|
|
}*/
|
|
|
|
//s->WriteInt32(lastRemoteSeq);
|
|
|
|
s->WriteInt32(seq);
|
|
|
|
s->WriteBytes(reflectorSelfTagHash, 16);
|
2020-01-22 12:43:51 +01:00
|
|
|
if (length > 0)
|
|
|
|
{
|
|
|
|
if (length <= 253)
|
|
|
|
{
|
|
|
|
s->WriteByte((unsigned char)length);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
s->WriteByte(254);
|
2020-01-22 12:43:51 +01:00
|
|
|
s->WriteByte((unsigned char)(length & 0xFF));
|
|
|
|
s->WriteByte((unsigned char)((length >> 8) & 0xFF));
|
|
|
|
s->WriteByte((unsigned char)((length >> 16) & 0xFF));
|
2018-06-04 21:37:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::SendPacket(unsigned char *data, size_t len, Endpoint &ep, PendingOutgoingPacket &srcPacket)
|
|
|
|
{
|
|
|
|
if (stopping)
|
2018-06-04 21:37:43 +02:00
|
|
|
return;
|
2020-01-22 12:43:51 +01:00
|
|
|
if (ep.type == Endpoint::Type::TCP_RELAY && !useTCP)
|
2018-06-04 21:37:43 +02:00
|
|
|
return;
|
2020-01-22 12:43:51 +01:00
|
|
|
BufferOutputStream out(len + 128);
|
2018-06-04 21:37:43 +02:00
|
|
|
//LOGV("send group packet %u", len);
|
|
|
|
|
|
|
|
out.WriteBytes(reflectorSelfTag, 16);
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
if (len > 0)
|
|
|
|
{
|
|
|
|
BufferOutputStream inner(len + 128);
|
2018-06-04 21:37:43 +02:00
|
|
|
inner.WriteInt32((uint32_t)len);
|
|
|
|
inner.WriteBytes(data, len);
|
2020-01-22 12:43:51 +01:00
|
|
|
size_t padLen = 16 - inner.GetLength() % 16;
|
|
|
|
if (padLen < 12)
|
|
|
|
padLen += 16;
|
2018-06-04 21:37:43 +02:00
|
|
|
unsigned char padding[28];
|
2020-01-22 12:43:51 +01:00
|
|
|
crypto.rand_bytes((uint8_t *)padding, padLen);
|
2018-06-04 21:37:43 +02:00
|
|
|
inner.WriteBytes(padding, padLen);
|
2020-01-22 12:43:51 +01:00
|
|
|
assert(inner.GetLength() % 16 == 0);
|
2018-06-04 21:37:43 +02:00
|
|
|
|
|
|
|
unsigned char key[32], iv[32], msgKey[16];
|
|
|
|
out.WriteBytes(keyFingerprint, 8);
|
2020-01-22 12:43:51 +01:00
|
|
|
BufferOutputStream buf(len + 32);
|
|
|
|
size_t x = 0;
|
|
|
|
buf.WriteBytes(encryptionKey + 88 + x, 32);
|
|
|
|
buf.WriteBytes(inner.GetBuffer() + 4, inner.GetLength() - 4);
|
2018-06-04 21:37:43 +02:00
|
|
|
unsigned char msgKeyLarge[32];
|
|
|
|
crypto.sha256(buf.GetBuffer(), buf.GetLength(), msgKeyLarge);
|
2020-01-22 12:43:51 +01:00
|
|
|
memcpy(msgKey, msgKeyLarge + 8, 16);
|
2018-06-04 21:37:43 +02:00
|
|
|
KDF2(msgKey, 0, key, iv);
|
|
|
|
out.WriteBytes(msgKey, 16);
|
|
|
|
//LOGV("<- MSG KEY: %08x %08x %08x %08x, hashed %u", *reinterpret_cast<int32_t*>(msgKey), *reinterpret_cast<int32_t*>(msgKey+4), *reinterpret_cast<int32_t*>(msgKey+8), *reinterpret_cast<int32_t*>(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);
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
if (srcPacket.type == PKT_STREAM_DATA || srcPacket.type == PKT_STREAM_DATA_X2 || srcPacket.type == PKT_STREAM_DATA_X3)
|
|
|
|
{
|
|
|
|
PacketIdMapping mapping = {srcPacket.seq, *reinterpret_cast<uint16_t *>(sig + 14), 0};
|
2018-06-04 21:37:43 +02:00
|
|
|
MutexGuard m(sentPacketsMutex);
|
|
|
|
recentSentPackets.push_back(mapping);
|
|
|
|
//LOGD("sent packet with id: %04X", mapping.id);
|
2020-01-22 12:43:51 +01:00
|
|
|
while (recentSentPackets.size() > 64)
|
2018-06-04 21:37:43 +02:00
|
|
|
recentSentPackets.erase(recentSentPackets.begin());
|
|
|
|
}
|
2020-01-22 12:43:51 +01:00
|
|
|
lastSentSeq = srcPacket.seq;
|
2018-06-04 21:37:43 +02:00
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
if (IS_MOBILE_NETWORK(networkType))
|
|
|
|
stats.bytesSentMobile += (uint64_t)out.GetLength();
|
2018-06-04 21:37:43 +02:00
|
|
|
else
|
2020-01-22 12:43:51 +01:00
|
|
|
stats.bytesSentWifi += (uint64_t)out.GetLength();
|
2018-06-04 21:37:43 +02:00
|
|
|
|
2019-04-15 01:43:10 +02:00
|
|
|
/*NetworkPacket pkt={0};
|
2018-11-09 16:44:01 +01:00
|
|
|
pkt.address=(NetworkAddress*)&ep.address;
|
|
|
|
pkt.port=ep.port;
|
2018-06-04 21:37:43 +02:00
|
|
|
pkt.length=out.GetLength();
|
|
|
|
pkt.data=out.GetBuffer();
|
2018-11-09 16:44:01 +01:00
|
|
|
pkt.protocol=ep.type==Endpoint::Type::TCP_RELAY ? PROTO_TCP : PROTO_UDP;
|
2019-04-15 01:43:10 +02:00
|
|
|
ActuallySendPacket(pkt, ep);*/
|
2018-06-04 21:37:43 +02:00
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::SetCallbacks(VoIPGroupController::Callbacks callbacks)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
VoIPController::SetCallbacks(callbacks);
|
2020-01-22 12:43:51 +01:00
|
|
|
this->groupCallbacks = callbacks;
|
2018-06-04 21:37:43 +02:00
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
int32_t VoIPGroupController::GetCurrentUnixtime()
|
|
|
|
{
|
|
|
|
return time(NULL) + timeDifference;
|
2018-06-04 21:37:43 +02:00
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
float VoIPGroupController::GetParticipantAudioLevel(int32_t userID)
|
|
|
|
{
|
|
|
|
if (userID == userSelfID)
|
2018-06-04 21:37:43 +02:00
|
|
|
return selfLevelMeter.GetLevel();
|
|
|
|
MutexGuard m(participantsMutex);
|
2020-01-22 12:43:51 +01:00
|
|
|
for (vector<GroupCallParticipant>::iterator p = participants.begin(); p != participants.end(); ++p)
|
|
|
|
{
|
|
|
|
if (p->userID == userID)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
return p->levelMeter->GetLevel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::SetMicMute(bool mute)
|
|
|
|
{
|
|
|
|
micMuted = mute;
|
|
|
|
if (audioInput)
|
|
|
|
{
|
|
|
|
if (mute)
|
2018-06-04 21:37:43 +02:00
|
|
|
audioInput->Stop();
|
|
|
|
else
|
|
|
|
audioInput->Start();
|
2020-01-22 12:43:51 +01:00
|
|
|
if (!audioInput->IsInitialized())
|
|
|
|
{
|
|
|
|
lastError = ERROR_AUDIO_IO;
|
2018-06-04 21:37:43 +02:00
|
|
|
SetState(STATE_FAILED);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2020-01-22 12:43:51 +01:00
|
|
|
outgoingStreams[0]->enabled = !mute;
|
2018-06-04 21:37:43 +02:00
|
|
|
SerializeAndUpdateOutgoingStreams();
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::SetParticipantVolume(int32_t userID, float volume)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
MutexGuard m(participantsMutex);
|
2020-01-22 12:43:51 +01:00
|
|
|
for (vector<GroupCallParticipant>::iterator p = participants.begin(); p != participants.end(); ++p)
|
|
|
|
{
|
|
|
|
if (p->userID == userID)
|
|
|
|
{
|
|
|
|
for (vector<shared_ptr<Stream>>::iterator s = p->streams.begin(); s != p->streams.end(); ++s)
|
|
|
|
{
|
|
|
|
if ((*s)->type == STREAM_TYPE_AUDIO)
|
|
|
|
{
|
|
|
|
if ((*s)->decoder)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
float db;
|
2020-01-22 12:43:51 +01:00
|
|
|
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);
|
2018-06-04 21:37:43 +02:00
|
|
|
else
|
2020-01-22 12:43:51 +01:00
|
|
|
db = 0.0f;
|
2018-06-04 21:37:43 +02:00
|
|
|
//LOGV("Setting user %u audio volume to %.2f dB", userID, db);
|
|
|
|
audioMixer->SetInputVolume((*s)->callbackWrapper, db);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
void VoIPGroupController::SerializeAndUpdateOutgoingStreams()
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
BufferOutputStream out(1024);
|
2020-01-22 12:43:51 +01:00
|
|
|
out.WriteByte((unsigned char)outgoingStreams.size());
|
2018-06-04 21:37:43 +02:00
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
for (vector<shared_ptr<Stream>>::iterator s = outgoingStreams.begin(); s != outgoingStreams.end(); ++s)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
BufferOutputStream o(128);
|
|
|
|
o.WriteByte((*s)->id);
|
|
|
|
o.WriteByte((*s)->type);
|
|
|
|
o.WriteInt32((*s)->codec);
|
2020-01-22 12:43:51 +01:00
|
|
|
o.WriteInt32((unsigned char)(((*s)->enabled ? STREAM_FLAG_ENABLED : 0) | STREAM_FLAG_DTX));
|
2018-06-04 21:37:43 +02:00
|
|
|
o.WriteInt16((*s)->frameDuration);
|
2020-01-22 12:43:51 +01:00
|
|
|
out.WriteInt16((int16_t)o.GetLength());
|
2018-06-04 21:37:43 +02:00
|
|
|
out.WriteBytes(o.GetBuffer(), o.GetLength());
|
|
|
|
}
|
2020-01-22 12:43:51 +01:00
|
|
|
if (groupCallbacks.updateStreams)
|
2018-06-04 21:37:43 +02:00
|
|
|
groupCallbacks.updateStreams(this, out.GetBuffer(), out.GetLength());
|
|
|
|
}
|
|
|
|
|
2020-01-22 12:43:51 +01:00
|
|
|
std::string VoIPGroupController::GetDebugString()
|
|
|
|
{
|
|
|
|
std::string r = "Remote endpoints: \n";
|
2018-06-04 21:37:43 +02:00
|
|
|
char buffer[2048];
|
2020-01-22 12:43:51 +01:00
|
|
|
for (pair<const int64_t, Endpoint> &_endpoint : endpoints)
|
|
|
|
{
|
|
|
|
Endpoint &endpoint = _endpoint.second;
|
|
|
|
const char *type;
|
|
|
|
switch (endpoint.type)
|
|
|
|
{
|
|
|
|
case Endpoint::Type::UDP_P2P_INET:
|
|
|
|
type = "UDP_P2P_INET";
|
|
|
|
break;
|
|
|
|
case Endpoint::Type::UDP_P2P_LAN:
|
|
|
|
type = "UDP_P2P_LAN";
|
|
|
|
break;
|
|
|
|
case Endpoint::Type::UDP_RELAY:
|
|
|
|
type = "UDP_RELAY";
|
|
|
|
break;
|
|
|
|
case Endpoint::Type::TCP_RELAY:
|
|
|
|
type = "TCP_RELAY";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
type = "UNKNOWN";
|
|
|
|
break;
|
2018-06-04 21:37:43 +02:00
|
|
|
}
|
2020-01-22 12:43:51 +01:00
|
|
|
snprintf(buffer, sizeof(buffer), "%s:%u %dms [%s%s]\n", endpoint.address.ToString().c_str(), endpoint.port, (int)(endpoint.averageRTT * 1000), type, currentEndpoint == endpoint.id ? ", IN_USE" : "");
|
|
|
|
r += buffer;
|
2018-06-04 21:37:43 +02:00
|
|
|
}
|
|
|
|
double avgLate[3];
|
2020-01-22 12:43:51 +01:00
|
|
|
shared_ptr<JitterBuffer> jitterBuffer = incomingStreams.size() == 1 ? incomingStreams[0]->jitterBuffer : NULL;
|
|
|
|
if (jitterBuffer)
|
2018-06-04 21:37:43 +02:00
|
|
|
jitterBuffer->GetAverageLateCount(avgLate);
|
|
|
|
else
|
2020-01-22 12:43:51 +01:00
|
|
|
memset(avgLate, 0, 3 * sizeof(double));
|
2018-06-04 21:37:43 +02:00
|
|
|
snprintf(buffer, sizeof(buffer),
|
2020-01-22 12:43:51 +01:00
|
|
|
"RTT avg/min: %d/%d\n"
|
|
|
|
"Congestion window: %d/%d bytes\n"
|
|
|
|
"Key fingerprint: %02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX\n"
|
|
|
|
"Last sent/ack'd seq: %u/%u\n"
|
|
|
|
"Send/recv losses: %u/%u (%d%%)\n"
|
|
|
|
"Audio bitrate: %d kbit\n"
|
|
|
|
"Bytes sent/recvd: %llu/%llu\n\n",
|
|
|
|
(int)(conctl->GetAverageRTT() * 1000), (int)(conctl->GetMinimumRTT() * 1000),
|
2018-06-04 21:37:43 +02:00
|
|
|
int(conctl->GetInflightDataSize()), int(conctl->GetCongestionWindow()),
|
2020-01-22 12:43:51 +01:00
|
|
|
keyFingerprint[0], keyFingerprint[1], keyFingerprint[2], keyFingerprint[3], keyFingerprint[4], keyFingerprint[5], keyFingerprint[6], keyFingerprint[7],
|
2018-06-04 21:37:43 +02:00
|
|
|
lastSentSeq, lastRemoteAckSeq,
|
|
|
|
conctl->GetSendLossCount(), recvLossCount, encoder ? encoder->GetPacketLoss() : 0,
|
2020-01-22 12:43:51 +01:00
|
|
|
encoder ? (encoder->GetBitrate() / 1000) : 0,
|
|
|
|
(long long unsigned int)(stats.bytesSentMobile + stats.bytesSentWifi),
|
|
|
|
(long long unsigned int)(stats.bytesRecvdMobile + stats.bytesRecvdWifi));
|
2018-06-04 21:37:43 +02:00
|
|
|
|
|
|
|
MutexGuard m(participantsMutex);
|
2020-01-22 12:43:51 +01:00
|
|
|
for (vector<GroupCallParticipant>::iterator p = participants.begin(); p != participants.end(); ++p)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
snprintf(buffer, sizeof(buffer), "Participant id: %d\n", p->userID);
|
2020-01-22 12:43:51 +01:00
|
|
|
r += buffer;
|
|
|
|
for (vector<shared_ptr<Stream>>::iterator stm = p->streams.begin(); stm != p->streams.end(); ++stm)
|
|
|
|
{
|
|
|
|
char *codec = reinterpret_cast<char *>(&(*stm)->codec);
|
2018-06-04 21:37:43 +02:00
|
|
|
snprintf(buffer, sizeof(buffer), "Stream %d (type %d, codec '%c%c%c%c', %sabled)\n",
|
|
|
|
(*stm)->id, (*stm)->type, codec[3], codec[2], codec[1], codec[0], (*stm)->enabled ? "en" : "dis");
|
2020-01-22 12:43:51 +01:00
|
|
|
r += buffer;
|
|
|
|
if ((*stm)->enabled)
|
|
|
|
{
|
|
|
|
if ((*stm)->jitterBuffer)
|
|
|
|
{
|
2018-06-04 21:37:43 +02:00
|
|
|
snprintf(buffer, sizeof(buffer), "Jitter buffer: %d/%.2f\n",
|
|
|
|
(*stm)->jitterBuffer->GetMinPacketCount(), (*stm)->jitterBuffer->GetAverageDelay());
|
2020-01-22 12:43:51 +01:00
|
|
|
r += buffer;
|
2018-06-04 21:37:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-22 12:43:51 +01:00
|
|
|
r += "\n";
|
2018-06-04 21:37:43 +02:00
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|