aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport/src/protocols/rtc_data_path.cc
blob: 30644e939180b68101af900642bf34fe919ad168 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
 * Copyright (c) 2017-2019 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <protocols/rtc_data_path.h>

#include <cfloat>
#include <chrono>

#define MAX_ROUNDS_WITHOUT_PKTS 10  // 2sec

namespace transport {

namespace protocol {

RTCDataPath::RTCDataPath()
    : min_rtt(UINT_MAX),
      prev_min_rtt(UINT_MAX),
      min_owd(INT_MAX),  // this is computed like in LEDBAT, so it is not the
                         // real OWD, but the measured one, that depends on the
                         // clock of sender and receiver. the only meaningful
                         // value is is the queueing delay. for this reason we
                         // keep both RTT (for the windowd calculation) and OWD
                         // (for congestion/quality control)
      prev_min_owd(INT_MAX),
      avg_owd(0.0),
      queuing_delay(DBL_MAX),
      lastRecvSeq_(0),
      lastRecvTime_(0),
      avg_inter_arrival_(DBL_MAX),
      received_nacks_(false),
      received_packets_(false),
      rounds_without_packets_(0),
      RTThistory_(HISTORY_LEN),
      OWDhistory_(HISTORY_LEN){};

void RTCDataPath::insertRttSample(uint64_t rtt) {
  // for the rtt we only keep track of the min one
  if (rtt < min_rtt) min_rtt = rtt;
}

void RTCDataPath::insertOwdSample(int64_t owd) {
  // for owd we use both min and avg
  if (owd < min_owd) min_owd = owd;

  if (avg_owd != DBL_MAX)
    avg_owd = (avg_owd * (1 - ALPHA_RTC)) + (owd * ALPHA_RTC);
  else {
    avg_owd = owd;
  }

  // owd is computed only for valid data packets so we count only
  // this for decide if we recevie traffic or not
  received_packets_ = true;
}

void RTCDataPath::computeInterArrivalGap(uint32_t segmentNumber) {
  // got packet in sequence, compute gap
  if (lastRecvSeq_ == (segmentNumber - 1)) {
    uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
                       std::chrono::steady_clock::now().time_since_epoch())
                       .count();
    uint64_t delta = now - lastRecvTime_;
    lastRecvSeq_ = segmentNumber;
    lastRecvTime_ = now;
    if (avg_inter_arrival_ == DBL_MAX)
      avg_inter_arrival_ = delta;
    else
      avg_inter_arrival_ =
          (avg_inter_arrival_ * (1 - ALPHA_RTC)) + (delta * ALPHA_RTC);
    return;
  }

  // ooo packet, update the stasts if needed
  if (lastRecvSeq_ <= segmentNumber) {
    lastRecvSeq_ = segmentNumber;
    lastRecvTime_ = std::chrono::duration_cast<std::chrono::milliseconds>(
                        std::chrono::steady_clock::now().time_since_epoch())
                        .count();
  }
}

void RTCDataPath::receivedNack() { received_nacks_ = true; }

double RTCDataPath::getInterArrivalGap() {
  if (avg_inter_arrival_ == DBL_MAX) return 0;
  return avg_inter_arrival_;
}

bool RTCDataPath::isActive() {
  if (received_nacks_ && rounds_without_packets_ < MAX_ROUNDS_WITHOUT_PKTS)
    return true;
  return false;
}

void RTCDataPath::roundEnd() {
  // reset min_rtt and add it to the history
  if (min_rtt != UINT_MAX) {
    prev_min_rtt = min_rtt;
  } else {
    // this may happen if we do not receive any packet
    // from this path in the last round. in this case
    // we use the measure from the previuos round
    min_rtt = prev_min_rtt;
  }

  if (min_rtt == 0) min_rtt = 1;

  RTThistory_.pushBack(min_rtt);
  min_rtt = UINT_MAX;

  // do the same for min owd
  if (min_owd != INT_MAX) {
    prev_min_owd = min_owd;
  } else {
    min_owd = prev_min_owd;
  }

  if (min_owd != INT_MAX) {
    OWDhistory_.pushBack(min_owd);
    min_owd = INT_MAX;

    // compute queuing delay
    queuing_delay = avg_owd - getMinOwd();

  } else {
    queuing_delay = 0.0;
  }

  if (!received_packets_)
    rounds_without_packets_++;
  else
    rounds_without_packets_ = 0;
  received_packets_ = false;
}

double RTCDataPath::getQueuingDealy() { return queuing_delay; }

uint64_t RTCDataPath::getMinRtt() { return RTThistory_.begin(); }

int64_t RTCDataPath::getMinOwd() { return OWDhistory_.begin(); }

}  // end namespace protocol

}  // end namespace transport