// // PacketTimeWindow.cpp // libraries/networking/src/udt // // Created by Stephen Birarda on 2015-07-28. // Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "PacketTimeWindow.h" #include #include using namespace udt; using namespace std::chrono; static const int DEFAULT_PACKET_INTERVAL_MICROSECONDS = 1000000; static const int DEFAULT_PROBE_INTERVAL_MICROSECONDS = 1000; PacketTimeWindow::PacketTimeWindow(int numPacketIntervals, int numProbeIntervals) : _numPacketIntervals(numPacketIntervals), _numProbeIntervals(numProbeIntervals), _packetIntervals(_numPacketIntervals, DEFAULT_PACKET_INTERVAL_MICROSECONDS), _probeIntervals(_numProbeIntervals, DEFAULT_PROBE_INTERVAL_MICROSECONDS) { } int32_t meanOfMedianFilteredValues(std::vector intervals, int numValues, int valuesRequired = 0) { // sort the intervals from smallest to largest std::sort(intervals.begin(), intervals.end()); int median = 0; if (numValues % 2 == 0) { median = intervals[numValues / 2]; } else { median = (intervals[(numValues / 2) - 1] + intervals[numValues / 2]) / 2; } int count = 0; int sum = 0; static const int MEDIAN_FILTERING_BOUND_MULTIPLIER = 8; int upperBound = median * MEDIAN_FILTERING_BOUND_MULTIPLIER; int lowerBound = median / MEDIAN_FILTERING_BOUND_MULTIPLIER; for (auto& interval : intervals) { if ((interval < upperBound) && (interval > lowerBound)) { ++count; sum += interval; } } if (count >= valuesRequired) { static const double USECS_PER_SEC = 1000000; return (int32_t) ceil(USECS_PER_SEC / ((double) sum) / ((double) count)); } else { return 0; } } int32_t PacketTimeWindow::getPacketReceiveSpeed() const { // return the mean value of median filtered values (per second) - or zero if there are too few filtered values return meanOfMedianFilteredValues(_packetIntervals, _numPacketIntervals, _numPacketIntervals / 2); } int32_t PacketTimeWindow::getEstimatedBandwidth() const { // return mean value of median filtered values (per second) return meanOfMedianFilteredValues(_probeIntervals, _numProbeIntervals); } void PacketTimeWindow::onPacketArrival() { // take the current time auto now = high_resolution_clock::now(); // record the interval between this packet and the last one _packetIntervals[_currentPacketInterval++] = duration_cast(now - _lastPacketTime).count(); // reset the currentPacketInterval index when it wraps if (_currentPacketInterval == _numPacketIntervals) { _currentPacketInterval = 0; } // remember this as the last packet arrival time _lastPacketTime = now; } void PacketTimeWindow::onProbePair1Arrival() { // take the current time as the first probe time _firstProbeTime = high_resolution_clock::now(); } void PacketTimeWindow::onProbePair2Arrival() { // store the interval between the two probes auto now = high_resolution_clock::now(); _probeIntervals[_currentProbeInterval++] = duration_cast(now - _firstProbeTime).count(); // reset the currentProbeInterval index when it wraps if (_currentProbeInterval == _numProbeIntervals) { _currentProbeInterval = 0; } }