aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport/src/protocols/rtc/rtc_data_path.cc
blob: a545225cbbfdf528bacd520d4d8caf9edd566eed (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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
 * 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/rtc_data_path.h>
#include <stdlib.h>

#include <algorithm>
#include <cfloat>
#include <chrono>

#define MAX_ROUNDS_WITHOUT_PKTS 10  // 2sec

namespace transport {

namespace protocol {

namespace rtc {

RTCDataPath::RTCDataPath(uint32_t path_id)
    : path_id_(path_id),
      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(DBL_MAX),
      queuing_delay(DBL_MAX),
      jitter_(0.0),
      last_owd_(0),
      largest_recv_seq_(0),
      largest_recv_seq_time_(0),
      avg_inter_arrival_(DBL_MAX),
      received_nacks_(false),
      received_packets_(false),
      rounds_without_packets_(0),
      last_received_data_packet_(0),
      RTT_history_(HISTORY_LEN),
      OWD_history_(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;
  last_received_data_packet_ =
      std::chrono::duration_cast<std::chrono::milliseconds>(
          std::chrono::steady_clock::now().time_since_epoch())
          .count();
}

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 = (double)owd;
  }

  int64_t queueVal = owd - std::min(getMinOwd(), min_owd);

  if (queuing_delay != DBL_MAX)
    queuing_delay = (queuing_delay * (1 - ALPHA_RTC)) + (queueVal * ALPHA_RTC);
  else {
    queuing_delay = (double)queueVal;
  }

  // keep track of the jitter computed as for RTP (RFC 3550)
  int64_t diff = std::abs(owd - last_owd_);
  last_owd_ = owd;
  jitter_ += (1.0 / 16.0) * ((double)diff - jitter_);

  // 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 segment_number) {
  // got packet in sequence, compute gap
  if (largest_recv_seq_ == (segment_number - 1)) {
    uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
                       std::chrono::steady_clock::now().time_since_epoch())
                       .count();
    uint64_t delta = now - largest_recv_seq_time_;
    largest_recv_seq_ = segment_number;
    largest_recv_seq_time_ = now;
    if (avg_inter_arrival_ == DBL_MAX)
      avg_inter_arrival_ = (double)delta;
    else
      avg_inter_arrival_ =
          (avg_inter_arrival_ * (1 - ALPHA_RTC)) + (delta * ALPHA_RTC);
    return;
  }

  // ooo packet, update the stasts if needed
  if (largest_recv_seq_ <= segment_number) {
    largest_recv_seq_ = segment_number;
    largest_recv_seq_time_ =
        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;
}

bool RTCDataPath::pathToProducer() {
  if (received_nacks_) 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;

  RTT_history_.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) {
    OWD_history_.pushBack(min_owd);
    min_owd = INT_MAX;
  }

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

uint32_t RTCDataPath::getPathId() { return path_id_; }

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

uint64_t RTCDataPath::getMinRtt() {
  if (RTT_history_.size() != 0) return RTT_history_.begin();
  return 0;
}

int64_t RTCDataPath::getMinOwd() {
  if (OWD_history_.size() != 0) return OWD_history_.begin();
  return 0;
}

double RTCDataPath::getJitter() { return jitter_; }

uint64_t RTCDataPath::getLastPacketTS() { return last_received_data_packet_; }

void RTCDataPath::clearRtt() { RTT_history_.clear(); }

}  // end namespace rtc

}  // end namespace protocol

}  // end namespace transport