diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index bb3e8723ac..0097c0fd1d 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -23,6 +23,9 @@ const int MAX_DATAGRAM_SIZE = MAX_PACKET_SIZE; const int DEFAULT_MAX_PACKET_SIZE = 3000; +// the default slow-start threshold, which will be lowered quickly when we first encounter packet loss +const float DEFAULT_SLOW_START_THRESHOLD = 1000.0f; + DatagramSequencer::DatagramSequencer(const QByteArray& datagramHeader, QObject* parent) : QObject(parent), _outgoingPacketStream(&_outgoingPacketData, QIODevice::WriteOnly), @@ -37,7 +40,12 @@ DatagramSequencer::DatagramSequencer(const QByteArray& datagramHeader, QObject* _incomingPacketStream(&_incomingPacketData, QIODevice::ReadOnly), _inputStream(_incomingPacketStream), _receivedHighPriorityMessages(0), - _maxPacketSize(DEFAULT_MAX_PACKET_SIZE) { + _maxPacketSize(DEFAULT_MAX_PACKET_SIZE), + _packetsPerGroup(1.0f), + _packetsToWrite(0.0f), + _slowStartThreshold(DEFAULT_SLOW_START_THRESHOLD), + _packetRateIncreasePacketNumber(0), + _packetRateDecreasePacketNumber(0) { _outgoingPacketStream.setByteOrder(QDataStream::LittleEndian); _incomingDatagramStream.setByteOrder(QDataStream::LittleEndian); @@ -71,6 +79,14 @@ ReliableChannel* DatagramSequencer::getReliableInputChannel(int index) { return channel; } +int DatagramSequencer::startPacketGroup() { + // increment our packet counter and subtract/return the integer portion + _packetsToWrite += _packetsPerGroup; + int wholePackets = (int)_packetsToWrite; + _packetsToWrite -= wholePackets; + return wholePackets; +} + Bitstream& DatagramSequencer::startPacket() { // start with the list of acknowledgements _outgoingPacketStream << (quint32)_receiveRecords.size(); @@ -256,6 +272,14 @@ void DatagramSequencer::sendRecordAcknowledged(const SendRecord& record) { foreach (const ChannelSpan& span, record.spans) { getReliableOutputChannel(span.channel)->spanAcknowledged(span); } + + // increase the packet rate with every ack until we pass the slow start threshold; then, every round trip + if (record.packetNumber >= _packetRateIncreasePacketNumber) { + if (_packetsPerGroup >= _slowStartThreshold) { + _packetRateIncreasePacketNumber = _outgoingPacketNumber + 1; + } + _packetsPerGroup += 1.0f; + } } void DatagramSequencer::sendRecordLost(const SendRecord& record) { @@ -263,6 +287,13 @@ void DatagramSequencer::sendRecordLost(const SendRecord& record) { foreach (const ChannelSpan& span, record.spans) { getReliableOutputChannel(span.channel)->spanLost(record.packetNumber, _outgoingPacketNumber + 1); } + + // halve the rate and remember as threshold + if (record.packetNumber >= _packetRateDecreasePacketNumber) { + _packetsPerGroup = qMax(_packetsPerGroup * 0.5f, 1.0f); + _slowStartThreshold = _packetsPerGroup; + _packetRateDecreasePacketNumber = _outgoingPacketNumber + 1; + } } void DatagramSequencer::appendReliableData(int bytes, QVector& spans) { diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index 4ab9f7667b..e2ea9d00af 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -99,6 +99,10 @@ public: /// Returns the intput channel at the specified index, creating it if necessary. ReliableChannel* getReliableInputChannel(int index = 0); + /// Starts a packet group. + /// \return the number of packets to write in the group + int startPacketGroup(); + /// Starts a new packet for transmission. /// \return a reference to the Bitstream to use for writing to the packet Bitstream& startPacket(); @@ -203,6 +207,12 @@ private: int _maxPacketSize; + float _packetsPerGroup; + float _packetsToWrite; + float _slowStartThreshold; + int _packetRateIncreasePacketNumber; + int _packetRateDecreasePacketNumber; + QHash _reliableOutputChannels; QHash _reliableInputChannels; }; diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 688749f39b..9cb21faf06 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -652,7 +652,7 @@ Endpoint::Endpoint(const QByteArray& datagramHeader, Mode mode) : output->setMessagesEnabled(false); QByteArray bytes; if (mode == CONGESTION_MODE) { - const int HUGE_STREAM_BYTES = 50 * 1024 * 1024; + const int HUGE_STREAM_BYTES = 60 * 1024 * 1024; bytes = createRandomBytes(HUGE_STREAM_BYTES, HUGE_STREAM_BYTES); // initialize the pipeline @@ -820,14 +820,23 @@ bool Endpoint::simulate(int iterationNumber) { bytesReceived += datagram.size(); _remainingPipelineCapacity += datagram.size(); } - - Bitstream& out = _sequencer->startPacket(); - out << QVariant(); - _sequencer->endPacket(); - - // record the send - SendRecord record = { _sequencer->getOutgoingPacketNumber() }; - _sendRecords.append(record); + int packetCount = _sequencer->startPacketGroup(); + for (int i = 0; i < packetCount; i++) { + oldDatagramsSent = datagramsSent; + oldBytesSent = bytesSent; + + Bitstream& out = _sequencer->startPacket(); + out << QVariant(); + _sequencer->endPacket(); + + maxDatagramsPerPacket = qMax(maxDatagramsPerPacket, datagramsSent - oldDatagramsSent); + maxBytesPerPacket = qMax(maxBytesPerPacket, bytesSent - oldBytesSent); + + // record the send + SendRecord record = { _sequencer->getOutgoingPacketNumber() }; + _sendRecords.append(record); + } + return false; } else if (_mode == METAVOXEL_CLIENT_MODE) { Bitstream& out = _sequencer->startPacket();