• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3   *
4   *  Use of this source code is governed by a BSD-style license
5   *  that can be found in the LICENSE file in the root of the source
6   *  tree. An additional intellectual property rights grant can be found
7   *  in the file PATENTS.  All contributing project authors may
8   *  be found in the AUTHORS file in the root of the source tree.
9   */
10  
11  #include "modules/congestion_controller/rtp/transport_feedback_adapter.h"
12  
13  #include <stdlib.h>
14  
15  #include <algorithm>
16  #include <cmath>
17  #include <utility>
18  
19  #include "absl/algorithm/container.h"
20  #include "api/units/timestamp.h"
21  #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
22  #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
23  #include "rtc_base/checks.h"
24  #include "rtc_base/logging.h"
25  #include "system_wrappers/include/field_trial.h"
26  
27  namespace webrtc {
28  
29  constexpr TimeDelta kSendTimeHistoryWindow = TimeDelta::Seconds(60);
30  
AddInFlightPacketBytes(const PacketFeedback & packet)31  void InFlightBytesTracker::AddInFlightPacketBytes(
32      const PacketFeedback& packet) {
33    RTC_DCHECK(packet.sent.send_time.IsFinite());
34    auto it = in_flight_data_.find(packet.network_route);
35    if (it != in_flight_data_.end()) {
36      it->second += packet.sent.size;
37    } else {
38      in_flight_data_.insert({packet.network_route, packet.sent.size});
39    }
40  }
41  
RemoveInFlightPacketBytes(const PacketFeedback & packet)42  void InFlightBytesTracker::RemoveInFlightPacketBytes(
43      const PacketFeedback& packet) {
44    if (packet.sent.send_time.IsInfinite())
45      return;
46    auto it = in_flight_data_.find(packet.network_route);
47    if (it != in_flight_data_.end()) {
48      RTC_DCHECK_GE(it->second, packet.sent.size);
49      it->second -= packet.sent.size;
50      if (it->second.IsZero())
51        in_flight_data_.erase(it);
52    }
53  }
54  
GetOutstandingData(const rtc::NetworkRoute & network_route) const55  DataSize InFlightBytesTracker::GetOutstandingData(
56      const rtc::NetworkRoute& network_route) const {
57    auto it = in_flight_data_.find(network_route);
58    if (it != in_flight_data_.end()) {
59      return it->second;
60    } else {
61      return DataSize::Zero();
62    }
63  }
64  
65  // Comparator for consistent map with NetworkRoute as key.
operator ()(const rtc::NetworkRoute & a,const rtc::NetworkRoute & b) const66  bool InFlightBytesTracker::NetworkRouteComparator::operator()(
67      const rtc::NetworkRoute& a,
68      const rtc::NetworkRoute& b) const {
69    if (a.local.network_id() != b.local.network_id())
70      return a.local.network_id() < b.local.network_id();
71    if (a.remote.network_id() != b.remote.network_id())
72      return a.remote.network_id() < b.remote.network_id();
73  
74    if (a.local.adapter_id() != b.local.adapter_id())
75      return a.local.adapter_id() < b.local.adapter_id();
76    if (a.remote.adapter_id() != b.remote.adapter_id())
77      return a.remote.adapter_id() < b.remote.adapter_id();
78  
79    if (a.local.uses_turn() != b.local.uses_turn())
80      return a.local.uses_turn() < b.local.uses_turn();
81    if (a.remote.uses_turn() != b.remote.uses_turn())
82      return a.remote.uses_turn() < b.remote.uses_turn();
83  
84    return a.connected < b.connected;
85  }
86  
87  TransportFeedbackAdapter::TransportFeedbackAdapter() = default;
88  
89  
AddPacket(const RtpPacketSendInfo & packet_info,size_t overhead_bytes,Timestamp creation_time)90  void TransportFeedbackAdapter::AddPacket(const RtpPacketSendInfo& packet_info,
91                                           size_t overhead_bytes,
92                                           Timestamp creation_time) {
93    PacketFeedback packet;
94    packet.creation_time = creation_time;
95    packet.sent.sequence_number =
96        seq_num_unwrapper_.Unwrap(packet_info.transport_sequence_number);
97    packet.sent.size = DataSize::Bytes(packet_info.length + overhead_bytes);
98    packet.sent.audio = packet_info.packet_type == RtpPacketMediaType::kAudio;
99    packet.network_route = network_route_;
100    packet.sent.pacing_info = packet_info.pacing_info;
101  
102    while (!history_.empty() &&
103           creation_time - history_.begin()->second.creation_time >
104               kSendTimeHistoryWindow) {
105      // TODO(sprang): Warn if erasing (too many) old items?
106      if (history_.begin()->second.sent.sequence_number > last_ack_seq_num_)
107        in_flight_.RemoveInFlightPacketBytes(history_.begin()->second);
108      history_.erase(history_.begin());
109    }
110    history_.insert(std::make_pair(packet.sent.sequence_number, packet));
111  }
112  
ProcessSentPacket(const rtc::SentPacket & sent_packet)113  absl::optional<SentPacket> TransportFeedbackAdapter::ProcessSentPacket(
114      const rtc::SentPacket& sent_packet) {
115    auto send_time = Timestamp::Millis(sent_packet.send_time_ms);
116    // TODO(srte): Only use one way to indicate that packet feedback is used.
117    if (sent_packet.info.included_in_feedback || sent_packet.packet_id != -1) {
118      int64_t unwrapped_seq_num =
119          seq_num_unwrapper_.Unwrap(sent_packet.packet_id);
120      auto it = history_.find(unwrapped_seq_num);
121      if (it != history_.end()) {
122        bool packet_retransmit = it->second.sent.send_time.IsFinite();
123        it->second.sent.send_time = send_time;
124        last_send_time_ = std::max(last_send_time_, send_time);
125        // TODO(srte): Don't do this on retransmit.
126        if (!pending_untracked_size_.IsZero()) {
127          if (send_time < last_untracked_send_time_)
128            RTC_LOG(LS_WARNING)
129                << "appending acknowledged data for out of order packet. (Diff: "
130                << ToString(last_untracked_send_time_ - send_time) << " ms.)";
131          it->second.sent.prior_unacked_data += pending_untracked_size_;
132          pending_untracked_size_ = DataSize::Zero();
133        }
134        if (!packet_retransmit) {
135          if (it->second.sent.sequence_number > last_ack_seq_num_)
136            in_flight_.AddInFlightPacketBytes(it->second);
137          it->second.sent.data_in_flight = GetOutstandingData();
138          return it->second.sent;
139        }
140      }
141    } else if (sent_packet.info.included_in_allocation) {
142      if (send_time < last_send_time_) {
143        RTC_LOG(LS_WARNING) << "ignoring untracked data for out of order packet.";
144      }
145      pending_untracked_size_ +=
146          DataSize::Bytes(sent_packet.info.packet_size_bytes);
147      last_untracked_send_time_ = std::max(last_untracked_send_time_, send_time);
148    }
149    return absl::nullopt;
150  }
151  
152  absl::optional<TransportPacketsFeedback>
ProcessTransportFeedback(const rtcp::TransportFeedback & feedback,Timestamp feedback_receive_time)153  TransportFeedbackAdapter::ProcessTransportFeedback(
154      const rtcp::TransportFeedback& feedback,
155      Timestamp feedback_receive_time) {
156    if (feedback.GetPacketStatusCount() == 0) {
157      RTC_LOG(LS_INFO) << "Empty transport feedback packet received.";
158      return absl::nullopt;
159    }
160  
161    TransportPacketsFeedback msg;
162    msg.feedback_time = feedback_receive_time;
163  
164    msg.prior_in_flight = in_flight_.GetOutstandingData(network_route_);
165    msg.packet_feedbacks =
166        ProcessTransportFeedbackInner(feedback, feedback_receive_time);
167    if (msg.packet_feedbacks.empty())
168      return absl::nullopt;
169  
170    auto it = history_.find(last_ack_seq_num_);
171    if (it != history_.end()) {
172      msg.first_unacked_send_time = it->second.sent.send_time;
173    }
174    msg.data_in_flight = in_flight_.GetOutstandingData(network_route_);
175  
176    return msg;
177  }
178  
SetNetworkRoute(const rtc::NetworkRoute & network_route)179  void TransportFeedbackAdapter::SetNetworkRoute(
180      const rtc::NetworkRoute& network_route) {
181    network_route_ = network_route;
182  }
183  
GetOutstandingData() const184  DataSize TransportFeedbackAdapter::GetOutstandingData() const {
185    return in_flight_.GetOutstandingData(network_route_);
186  }
187  
188  std::vector<PacketResult>
ProcessTransportFeedbackInner(const rtcp::TransportFeedback & feedback,Timestamp feedback_receive_time)189  TransportFeedbackAdapter::ProcessTransportFeedbackInner(
190      const rtcp::TransportFeedback& feedback,
191      Timestamp feedback_receive_time) {
192    // Add timestamp deltas to a local time base selected on first packet arrival.
193    // This won't be the true time base, but makes it easier to manually inspect
194    // time stamps.
195    if (last_timestamp_.IsInfinite()) {
196      current_offset_ = feedback_receive_time;
197    } else {
198      // TODO(srte): We shouldn't need to do rounding here.
199      const TimeDelta delta = feedback.GetBaseDelta(last_timestamp_)
200                                  .RoundDownTo(TimeDelta::Millis(1));
201      // Protect against assigning current_offset_ negative value.
202      if (delta < Timestamp::Zero() - current_offset_) {
203        RTC_LOG(LS_WARNING) << "Unexpected feedback timestamp received.";
204        current_offset_ = feedback_receive_time;
205      } else {
206        current_offset_ += delta;
207      }
208    }
209    last_timestamp_ = feedback.GetBaseTime();
210  
211    std::vector<PacketResult> packet_result_vector;
212    packet_result_vector.reserve(feedback.GetPacketStatusCount());
213  
214    size_t failed_lookups = 0;
215    size_t ignored = 0;
216    TimeDelta packet_offset = TimeDelta::Zero();
217    for (const auto& packet : feedback.GetAllPackets()) {
218      int64_t seq_num = seq_num_unwrapper_.Unwrap(packet.sequence_number());
219  
220      if (seq_num > last_ack_seq_num_) {
221        // Starts at history_.begin() if last_ack_seq_num_ < 0, since any valid
222        // sequence number is >= 0.
223        for (auto it = history_.upper_bound(last_ack_seq_num_);
224             it != history_.upper_bound(seq_num); ++it) {
225          in_flight_.RemoveInFlightPacketBytes(it->second);
226        }
227        last_ack_seq_num_ = seq_num;
228      }
229  
230      auto it = history_.find(seq_num);
231      if (it == history_.end()) {
232        ++failed_lookups;
233        continue;
234      }
235  
236      if (it->second.sent.send_time.IsInfinite()) {
237        // TODO(srte): Fix the tests that makes this happen and make this a
238        // DCHECK.
239        RTC_DLOG(LS_ERROR)
240            << "Received feedback before packet was indicated as sent";
241        continue;
242      }
243  
244      PacketFeedback packet_feedback = it->second;
245      if (packet.received()) {
246        packet_offset += packet.delta();
247        packet_feedback.receive_time =
248            current_offset_ + packet_offset.RoundDownTo(TimeDelta::Millis(1));
249        // Note: Lost packets are not removed from history because they might be
250        // reported as received by a later feedback.
251        history_.erase(it);
252      }
253      if (packet_feedback.network_route == network_route_) {
254        PacketResult result;
255        result.sent_packet = packet_feedback.sent;
256        result.receive_time = packet_feedback.receive_time;
257        packet_result_vector.push_back(result);
258      } else {
259        ++ignored;
260      }
261    }
262  
263    if (failed_lookups > 0) {
264      RTC_LOG(LS_WARNING) << "Failed to lookup send time for " << failed_lookups
265                          << " packet" << (failed_lookups > 1 ? "s" : "")
266                          << ". Send time history too small?";
267    }
268    if (ignored > 0) {
269      RTC_LOG(LS_INFO) << "Ignoring " << ignored
270                       << " packets because they were sent on a different route.";
271    }
272  
273    return packet_result_vector;
274  }
275  
276  }  // namespace webrtc
277