2020-01-22 12:43:51 +01: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 "CongestionControl.h"
|
2020-03-25 15:49:13 +01:00
|
|
|
#include "../../VoIPController.h"
|
2020-03-24 12:15:04 +01:00
|
|
|
#include "../protocol/packets/PacketStructs.h"
|
2020-01-22 12:43:51 +01:00
|
|
|
#include "VoIPController.h"
|
|
|
|
#include "VoIPServerConfig.h"
|
2020-03-22 21:25:02 +01:00
|
|
|
#include "tools/logging.h"
|
2020-01-22 12:43:51 +01:00
|
|
|
#include <assert.h>
|
2020-03-22 21:25:02 +01:00
|
|
|
#include <math.h>
|
2020-01-22 12:43:51 +01:00
|
|
|
|
|
|
|
using namespace tgvoip;
|
|
|
|
|
2020-03-24 12:15:04 +01:00
|
|
|
CongestionControlPacket::CongestionControlPacket(uint32_t _seq, uint8_t _streamId) : seq(_seq), streamId(_streamId){};
|
|
|
|
CongestionControlPacket::CongestionControlPacket(const Packet &pkt) : seq(pkt.seq), streamId(pkt.streamId){};
|
|
|
|
|
2020-03-30 19:10:20 +02:00
|
|
|
CongestionControl::CongestionControl() : cwnd(static_cast<size_t>(ServerConfig::GetSharedInstance()->GetInt("audio_congestion_window", 1024)))
|
2020-01-22 12:43:51 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CongestionControl::~CongestionControl()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t CongestionControl::GetAcknowledgedDataSize()
|
|
|
|
{
|
2020-03-22 21:25:02 +01:00
|
|
|
return 0;
|
2020-01-22 12:43:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
double CongestionControl::GetAverageRTT()
|
|
|
|
{
|
2020-03-22 21:25:02 +01:00
|
|
|
return rttHistory.NonZeroAverage();
|
2020-01-22 12:43:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t CongestionControl::GetInflightDataSize()
|
|
|
|
{
|
2020-03-22 21:25:02 +01:00
|
|
|
return inflightHistory.Average();
|
2020-01-22 12:43:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t CongestionControl::GetCongestionWindow()
|
|
|
|
{
|
2020-03-22 21:25:02 +01:00
|
|
|
return cwnd;
|
2020-01-22 12:43:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
double CongestionControl::GetMinimumRTT()
|
|
|
|
{
|
2020-03-22 21:25:02 +01:00
|
|
|
return rttHistory.Min();
|
2020-01-22 12:43:51 +01:00
|
|
|
}
|
|
|
|
|
2020-03-24 12:15:04 +01:00
|
|
|
void CongestionControl::PacketSent(const CongestionControlPacket &pkt, size_t size)
|
2020-01-22 12:43:51 +01:00
|
|
|
{
|
2020-03-24 12:15:04 +01:00
|
|
|
if (lastSentSeq.find(pkt.streamId) == lastSentSeq.end())
|
2020-03-22 21:25:02 +01:00
|
|
|
{
|
2020-03-24 12:15:04 +01:00
|
|
|
lastSentSeq[pkt.streamId] = 0;
|
2020-03-22 21:25:02 +01:00
|
|
|
}
|
2020-03-24 12:15:04 +01:00
|
|
|
if (!seqgt(pkt.seq, lastSentSeq[pkt.streamId]) || pkt.seq == lastSentSeq[pkt.streamId])
|
2020-03-22 21:25:02 +01:00
|
|
|
{
|
2020-03-25 21:38:07 +01:00
|
|
|
//LOGW("Duplicate outgoing seq %u", pkt.seq);
|
2020-03-22 21:25:02 +01:00
|
|
|
return;
|
|
|
|
}
|
2020-03-24 12:15:04 +01:00
|
|
|
lastSentSeq[pkt.streamId] = pkt.seq;
|
2020-03-22 21:25:02 +01:00
|
|
|
double smallestSendTime = INFINITY;
|
|
|
|
tgvoip_congestionctl_packet_t *slot = NULL;
|
|
|
|
for (auto &packet : inflightPackets)
|
|
|
|
{
|
|
|
|
if (packet.sendTime == 0)
|
|
|
|
{
|
|
|
|
slot = &packet;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (smallestSendTime > packet.sendTime)
|
|
|
|
{
|
|
|
|
slot = &packet;
|
|
|
|
smallestSendTime = slot->sendTime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(slot != NULL);
|
|
|
|
if (slot->sendTime > 0)
|
|
|
|
{
|
|
|
|
inflightDataSize -= slot->size;
|
|
|
|
lossCount++;
|
|
|
|
LOGD("Packet with seq %u, streamId=%hhu was not acknowledged", slot->seq, slot->streamId);
|
|
|
|
}
|
2020-03-24 12:15:04 +01:00
|
|
|
slot->seq = pkt.seq;
|
2020-03-22 21:25:02 +01:00
|
|
|
slot->size = size;
|
2020-03-24 12:15:04 +01:00
|
|
|
slot->streamId = pkt.streamId;
|
2020-03-22 21:25:02 +01:00
|
|
|
slot->sendTime = VoIPController::GetCurrentTime();
|
|
|
|
inflightDataSize += size;
|
2020-01-22 12:43:51 +01:00
|
|
|
}
|
|
|
|
|
2020-03-24 12:15:04 +01:00
|
|
|
void CongestionControl::PacketAcknowledged(const CongestionControlPacket &pkt)
|
2020-03-13 21:12:58 +01:00
|
|
|
{
|
2020-03-22 21:25:02 +01:00
|
|
|
for (auto &packet : inflightPackets)
|
|
|
|
{
|
2020-03-24 12:15:04 +01:00
|
|
|
if (packet.seq == pkt.seq && packet.streamId == pkt.streamId && packet.sendTime > 0)
|
2020-03-22 21:25:02 +01:00
|
|
|
{
|
|
|
|
tmpRtt += (VoIPController::GetCurrentTime() - packet.sendTime);
|
|
|
|
tmpRttCount++;
|
|
|
|
packet.sendTime = 0;
|
|
|
|
inflightDataSize -= packet.size;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-03-13 21:12:58 +01:00
|
|
|
}
|
|
|
|
|
2020-03-24 12:15:04 +01:00
|
|
|
void CongestionControl::PacketLost(const CongestionControlPacket &pkt)
|
2020-01-22 12:43:51 +01:00
|
|
|
{
|
2020-03-22 21:25:02 +01:00
|
|
|
for (auto &packet : inflightPackets)
|
|
|
|
{
|
2020-03-24 12:15:04 +01:00
|
|
|
if (packet.seq == pkt.seq && packet.streamId == pkt.streamId && packet.sendTime > 0)
|
2020-03-22 21:25:02 +01:00
|
|
|
{
|
|
|
|
packet.sendTime = 0;
|
|
|
|
inflightDataSize -= packet.size;
|
|
|
|
lossCount++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-01-22 12:43:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CongestionControl::Tick()
|
|
|
|
{
|
2020-03-22 21:25:02 +01:00
|
|
|
tickCount++;
|
|
|
|
if (tmpRttCount > 0)
|
|
|
|
{
|
|
|
|
rttHistory.Add(tmpRtt / tmpRttCount);
|
|
|
|
tmpRtt = 0;
|
|
|
|
tmpRttCount = 0;
|
|
|
|
}
|
|
|
|
for (auto &packet : inflightPackets)
|
|
|
|
{
|
|
|
|
if (packet.sendTime && VoIPController::GetCurrentTime() - packet.sendTime > TGVOIP_CONCTL_LOST_AFTER)
|
|
|
|
{
|
|
|
|
packet.sendTime = 0;
|
|
|
|
inflightDataSize -= packet.size;
|
|
|
|
lossCount++;
|
|
|
|
LOGD("Packet with seq %u was not acknowledged", packet.seq);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
inflightHistory.Add(inflightDataSize);
|
2020-01-22 12:43:51 +01:00
|
|
|
}
|
|
|
|
|
2020-03-30 19:10:20 +02:00
|
|
|
CongestionControl::Action CongestionControl::GetBandwidthControlAction(int netMode, double multiply)
|
2020-01-22 12:43:51 +01:00
|
|
|
{
|
2020-03-22 21:25:02 +01:00
|
|
|
if (VoIPController::GetCurrentTime() - lastActionTime < 1)
|
2020-03-30 19:10:20 +02:00
|
|
|
return None;
|
2020-03-22 21:25:02 +01:00
|
|
|
|
2020-03-30 19:10:20 +02:00
|
|
|
Action action;
|
2020-03-22 21:25:02 +01:00
|
|
|
size_t inflightAvg = GetInflightDataSize();
|
2020-03-30 19:10:20 +02:00
|
|
|
size_t max = (cwnd * multiply) * 1.1;
|
|
|
|
size_t min = (cwnd * multiply) * 0.9;
|
|
|
|
LOGW("inflightAvg=%lu, max=%lu, min=%lu", inflightAvg, max, min);
|
2020-03-22 21:25:02 +01:00
|
|
|
if (inflightAvg < min)
|
|
|
|
{
|
2020-03-30 19:10:20 +02:00
|
|
|
action = Increase;
|
2020-03-22 21:25:02 +01:00
|
|
|
}
|
2020-03-30 19:10:20 +02:00
|
|
|
else if (inflightAvg > max)
|
2020-03-22 21:25:02 +01:00
|
|
|
{
|
2020-03-30 19:10:20 +02:00
|
|
|
action = Decrease;
|
2020-03-22 21:25:02 +01:00
|
|
|
}
|
2020-03-30 19:10:20 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
action = None;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t actAfter = 3;
|
|
|
|
if (netMode < NET_TYPE_LTE)
|
|
|
|
{
|
|
|
|
actAfter--;
|
|
|
|
}
|
|
|
|
if (netMode <= NET_TYPE_GPRS)
|
|
|
|
{
|
|
|
|
actAfter--;
|
|
|
|
}
|
|
|
|
if (netMode <= NET_TYPE_EDGE)
|
|
|
|
{
|
|
|
|
actAfter--;
|
|
|
|
}
|
|
|
|
if (action == lastAction)
|
|
|
|
{
|
|
|
|
LOGE("Would act on %hhu, current tries %hhu, act after %hhu", action, lastActionCount, actAfter);
|
|
|
|
if (lastActionCount++ == actAfter)
|
|
|
|
{
|
|
|
|
lastActionTime = VoIPController::GetCurrentTime();
|
|
|
|
lastActionCount = 0;
|
|
|
|
return action;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lastActionCount = 0;
|
|
|
|
LOGE("Would act on %hhu, current tries %hhu, act after %hhu", action, lastActionCount, actAfter);
|
|
|
|
}
|
|
|
|
lastAction = action;
|
|
|
|
return None;
|
2020-01-22 12:43:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t CongestionControl::GetSendLossCount()
|
|
|
|
{
|
2020-03-22 21:25:02 +01:00
|
|
|
return lossCount;
|
2020-01-22 12:43:51 +01:00
|
|
|
}
|