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/transport_feedback_adapter.h"
12 
13 #include <algorithm>
14 
15 #include "modules/congestion_controller/delay_based_bwe.h"
16 #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
17 #include "rtc_base/checks.h"
18 #include "rtc_base/logging.h"
19 #include "rtc_base/numerics/mod_ops.h"
20 #include "system_wrappers/include/field_trial.h"
21 
22 namespace webrtc {
23 
24 const int64_t kNoTimestamp = -1;
25 const int64_t kSendTimeHistoryWindowMs = 60000;
26 const int64_t kBaseTimestampScaleFactor =
27     rtcp::TransportFeedback::kDeltaScaleFactor * (1 << 8);
28 const int64_t kBaseTimestampRangeSizeUs = kBaseTimestampScaleFactor * (1 << 24);
29 
TransportFeedbackAdapter(const Clock * clock)30 TransportFeedbackAdapter::TransportFeedbackAdapter(const Clock* clock)
31     : send_side_bwe_with_overhead_(
32           webrtc::field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")),
33       transport_overhead_bytes_per_packet_(0),
34       send_time_history_(clock, kSendTimeHistoryWindowMs),
35       clock_(clock),
36       current_offset_ms_(kNoTimestamp),
37       last_timestamp_us_(kNoTimestamp),
38       local_net_id_(0),
39       remote_net_id_(0) {}
40 
~TransportFeedbackAdapter()41 TransportFeedbackAdapter::~TransportFeedbackAdapter() {
42   RTC_DCHECK(observers_.empty());
43 }
44 
RegisterPacketFeedbackObserver(PacketFeedbackObserver * observer)45 void TransportFeedbackAdapter::RegisterPacketFeedbackObserver(
46     PacketFeedbackObserver* observer) {
47   rtc::CritScope cs(&observers_lock_);
48   RTC_DCHECK(observer);
49   RTC_DCHECK(std::find(observers_.begin(), observers_.end(), observer) ==
50              observers_.end());
51   observers_.push_back(observer);
52 }
53 
DeRegisterPacketFeedbackObserver(PacketFeedbackObserver * observer)54 void TransportFeedbackAdapter::DeRegisterPacketFeedbackObserver(
55     PacketFeedbackObserver* observer) {
56   rtc::CritScope cs(&observers_lock_);
57   RTC_DCHECK(observer);
58   const auto it = std::find(observers_.begin(), observers_.end(), observer);
59   RTC_DCHECK(it != observers_.end());
60   observers_.erase(it);
61 }
62 
AddPacket(uint32_t ssrc,uint16_t sequence_number,size_t length,const PacedPacketInfo & pacing_info)63 void TransportFeedbackAdapter::AddPacket(uint32_t ssrc,
64                                          uint16_t sequence_number,
65                                          size_t length,
66                                          const PacedPacketInfo& pacing_info) {
67   {
68     rtc::CritScope cs(&lock_);
69     if (send_side_bwe_with_overhead_) {
70       length += transport_overhead_bytes_per_packet_;
71     }
72     const int64_t creation_time_ms = clock_->TimeInMilliseconds();
73     send_time_history_.AddAndRemoveOld(
74         PacketFeedback(creation_time_ms, sequence_number, length, local_net_id_,
75                        remote_net_id_, pacing_info));
76   }
77 
78   {
79     rtc::CritScope cs(&observers_lock_);
80     for (auto observer : observers_) {
81       observer->OnPacketAdded(ssrc, sequence_number);
82     }
83   }
84 }
85 
OnSentPacket(uint16_t sequence_number,int64_t send_time_ms)86 void TransportFeedbackAdapter::OnSentPacket(uint16_t sequence_number,
87                                             int64_t send_time_ms) {
88   rtc::CritScope cs(&lock_);
89   send_time_history_.OnSentPacket(sequence_number, send_time_ms);
90 }
91 
SetTransportOverhead(int transport_overhead_bytes_per_packet)92 void TransportFeedbackAdapter::SetTransportOverhead(
93     int transport_overhead_bytes_per_packet) {
94   rtc::CritScope cs(&lock_);
95   transport_overhead_bytes_per_packet_ = transport_overhead_bytes_per_packet;
96 }
97 
SetNetworkIds(uint16_t local_id,uint16_t remote_id)98 void TransportFeedbackAdapter::SetNetworkIds(uint16_t local_id,
99                                              uint16_t remote_id) {
100   rtc::CritScope cs(&lock_);
101   local_net_id_ = local_id;
102   remote_net_id_ = remote_id;
103 }
104 
GetPacketFeedbackVector(const rtcp::TransportFeedback & feedback)105 std::vector<PacketFeedback> TransportFeedbackAdapter::GetPacketFeedbackVector(
106     const rtcp::TransportFeedback& feedback) {
107   int64_t timestamp_us = feedback.GetBaseTimeUs();
108   int64_t now_ms = clock_->TimeInMilliseconds();
109   // Add timestamp deltas to a local time base selected on first packet arrival.
110   // This won't be the true time base, but makes it easier to manually inspect
111   // time stamps.
112   if (last_timestamp_us_ == kNoTimestamp) {
113     current_offset_ms_ = now_ms;
114   } else {
115     int64_t delta = timestamp_us - last_timestamp_us_;
116 
117     // Detect and compensate for wrap-arounds in base time.
118     if (std::abs(delta - kBaseTimestampRangeSizeUs) < std::abs(delta)) {
119       delta -= kBaseTimestampRangeSizeUs;  // Wrap backwards.
120     } else if (std::abs(delta + kBaseTimestampRangeSizeUs) < std::abs(delta)) {
121       delta += kBaseTimestampRangeSizeUs;  // Wrap forwards.
122     }
123 
124     current_offset_ms_ += delta / 1000;
125   }
126   last_timestamp_us_ = timestamp_us;
127 
128   std::vector<PacketFeedback> packet_feedback_vector;
129   if (feedback.GetPacketStatusCount() == 0) {
130     RTC_LOG(LS_INFO) << "Empty transport feedback packet received.";
131     return packet_feedback_vector;
132   }
133   packet_feedback_vector.reserve(feedback.GetPacketStatusCount());
134   int64_t feedback_rtt = -1;
135   {
136     rtc::CritScope cs(&lock_);
137     size_t failed_lookups = 0;
138     int64_t offset_us = 0;
139     int64_t timestamp_ms = 0;
140     uint16_t seq_num = feedback.GetBaseSequence();
141     for (const auto& packet : feedback.GetReceivedPackets()) {
142       // Insert into the vector those unreceived packets which precede this
143       // iteration's received packet.
144       for (; seq_num != packet.sequence_number(); ++seq_num) {
145         PacketFeedback packet_feedback(PacketFeedback::kNotReceived, seq_num);
146         // Note: Element not removed from history because it might be reported
147         // as received by another feedback.
148         if (!send_time_history_.GetFeedback(&packet_feedback, false))
149           ++failed_lookups;
150         if (packet_feedback.local_net_id == local_net_id_ &&
151             packet_feedback.remote_net_id == remote_net_id_) {
152           packet_feedback_vector.push_back(packet_feedback);
153         }
154       }
155 
156       // Handle this iteration's received packet.
157       offset_us += packet.delta_us();
158       timestamp_ms = current_offset_ms_ + (offset_us / 1000);
159       PacketFeedback packet_feedback(timestamp_ms, packet.sequence_number());
160       if (!send_time_history_.GetFeedback(&packet_feedback, true))
161         ++failed_lookups;
162       if (packet_feedback.local_net_id == local_net_id_ &&
163           packet_feedback.remote_net_id == remote_net_id_) {
164         if (packet_feedback.send_time_ms >= 0) {
165           int64_t rtt = now_ms - packet_feedback.send_time_ms;
166           // max() is used to account for feedback being delayed by the
167           // receiver.
168           feedback_rtt = std::max(rtt, feedback_rtt);
169         }
170         packet_feedback_vector.push_back(packet_feedback);
171       }
172 
173       ++seq_num;
174     }
175 
176     if (failed_lookups > 0) {
177       RTC_LOG(LS_WARNING) << "Failed to lookup send time for " << failed_lookups
178                           << " packet" << (failed_lookups > 1 ? "s" : "")
179                           << ". Send time history too small?";
180     }
181     if (feedback_rtt > -1) {
182       feedback_rtts_.push_back(feedback_rtt);
183       const size_t kFeedbackRttWindow = 32;
184       if (feedback_rtts_.size() > kFeedbackRttWindow)
185         feedback_rtts_.pop_front();
186       min_feedback_rtt_.emplace(
187           *std::min_element(feedback_rtts_.begin(), feedback_rtts_.end()));
188     }
189   }
190   return packet_feedback_vector;
191 }
192 
OnTransportFeedback(const rtcp::TransportFeedback & feedback)193 void TransportFeedbackAdapter::OnTransportFeedback(
194     const rtcp::TransportFeedback& feedback) {
195   last_packet_feedback_vector_ = GetPacketFeedbackVector(feedback);
196   {
197     rtc::CritScope cs(&observers_lock_);
198     for (auto observer : observers_) {
199       observer->OnPacketFeedbackVector(last_packet_feedback_vector_);
200     }
201   }
202 }
203 
204 std::vector<PacketFeedback>
GetTransportFeedbackVector() const205 TransportFeedbackAdapter::GetTransportFeedbackVector() const {
206   return last_packet_feedback_vector_;
207 }
208 
GetMinFeedbackLoopRtt() const209 rtc::Optional<int64_t> TransportFeedbackAdapter::GetMinFeedbackLoopRtt() const {
210   rtc::CritScope cs(&lock_);
211   return min_feedback_rtt_;
212 }
213 
GetOutstandingBytes() const214 size_t TransportFeedbackAdapter::GetOutstandingBytes() const {
215   rtc::CritScope cs(&lock_);
216   return send_time_history_.GetOutstandingBytes(local_net_id_, remote_net_id_);
217 }
218 }  // namespace webrtc
219