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