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 "webrtc/modules/congestion_controller/transport_feedback_adapter.h"
12
13 #include <algorithm>
14 #include <limits>
15
16 #include "webrtc/base/checks.h"
17 #include "webrtc/base/logging.h"
18 #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
19 #include "webrtc/modules/congestion_controller/delay_based_bwe.h"
20 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
21 #include "webrtc/modules/utility/include/process_thread.h"
22 #include "webrtc/system_wrappers/include/field_trial.h"
23
24 namespace webrtc {
25
26 const int64_t kNoTimestamp = -1;
27 const int64_t kSendTimeHistoryWindowMs = 10000;
28 const int64_t kBaseTimestampScaleFactor =
29 rtcp::TransportFeedback::kDeltaScaleFactor * (1 << 8);
30 const int64_t kBaseTimestampRangeSizeUs = kBaseTimestampScaleFactor * (1 << 24);
31
32 class PacketInfoComparator {
33 public:
operator ()(const PacketInfo & lhs,const PacketInfo & rhs)34 inline bool operator()(const PacketInfo& lhs, const PacketInfo& rhs) {
35 if (lhs.arrival_time_ms != rhs.arrival_time_ms)
36 return lhs.arrival_time_ms < rhs.arrival_time_ms;
37 if (lhs.send_time_ms != rhs.send_time_ms)
38 return lhs.send_time_ms < rhs.send_time_ms;
39 return lhs.sequence_number < rhs.sequence_number;
40 }
41 };
42
TransportFeedbackAdapter(Clock * clock,BitrateController * bitrate_controller)43 TransportFeedbackAdapter::TransportFeedbackAdapter(
44 Clock* clock,
45 BitrateController* bitrate_controller)
46 : transport_overhead_bytes_per_packet_(0),
47 send_time_history_(clock, kSendTimeHistoryWindowMs),
48 clock_(clock),
49 current_offset_ms_(kNoTimestamp),
50 last_timestamp_us_(kNoTimestamp),
51 bitrate_controller_(bitrate_controller) {}
52
~TransportFeedbackAdapter()53 TransportFeedbackAdapter::~TransportFeedbackAdapter() {}
54
InitBwe()55 void TransportFeedbackAdapter::InitBwe() {
56 rtc::CritScope cs(&bwe_lock_);
57 delay_based_bwe_.reset(new DelayBasedBwe(clock_));
58 }
59
AddPacket(uint16_t sequence_number,size_t length,int probe_cluster_id)60 void TransportFeedbackAdapter::AddPacket(uint16_t sequence_number,
61 size_t length,
62 int probe_cluster_id) {
63 rtc::CritScope cs(&lock_);
64 if (webrtc::field_trial::FindFullName("WebRTC-SendSideBwe-WithOverhead") ==
65 "Enabled") {
66 length += transport_overhead_bytes_per_packet_;
67 }
68 send_time_history_.AddAndRemoveOld(sequence_number, length, probe_cluster_id);
69 }
70
OnSentPacket(uint16_t sequence_number,int64_t send_time_ms)71 void TransportFeedbackAdapter::OnSentPacket(uint16_t sequence_number,
72 int64_t send_time_ms) {
73 rtc::CritScope cs(&lock_);
74 send_time_history_.OnSentPacket(sequence_number, send_time_ms);
75 }
76
SetMinBitrate(int min_bitrate_bps)77 void TransportFeedbackAdapter::SetMinBitrate(int min_bitrate_bps) {
78 rtc::CritScope cs(&bwe_lock_);
79 delay_based_bwe_->SetMinBitrate(min_bitrate_bps);
80 }
81
SetTransportOverhead(int transport_overhead_bytes_per_packet)82 void TransportFeedbackAdapter::SetTransportOverhead(
83 int transport_overhead_bytes_per_packet) {
84 rtc::CritScope cs(&lock_);
85 transport_overhead_bytes_per_packet_ = transport_overhead_bytes_per_packet;
86 }
87
GetProbingIntervalMs() const88 int64_t TransportFeedbackAdapter::GetProbingIntervalMs() const {
89 rtc::CritScope cs(&bwe_lock_);
90 return delay_based_bwe_->GetProbingIntervalMs();
91 }
92
GetPacketFeedbackVector(const rtcp::TransportFeedback & feedback)93 std::vector<PacketInfo> TransportFeedbackAdapter::GetPacketFeedbackVector(
94 const rtcp::TransportFeedback& feedback) {
95 int64_t timestamp_us = feedback.GetBaseTimeUs();
96 // Add timestamp deltas to a local time base selected on first packet arrival.
97 // This won't be the true time base, but makes it easier to manually inspect
98 // time stamps.
99 if (last_timestamp_us_ == kNoTimestamp) {
100 current_offset_ms_ = clock_->TimeInMilliseconds();
101 } else {
102 int64_t delta = timestamp_us - last_timestamp_us_;
103
104 // Detect and compensate for wrap-arounds in base time.
105 if (std::abs(delta - kBaseTimestampRangeSizeUs) < std::abs(delta)) {
106 delta -= kBaseTimestampRangeSizeUs; // Wrap backwards.
107 } else if (std::abs(delta + kBaseTimestampRangeSizeUs) < std::abs(delta)) {
108 delta += kBaseTimestampRangeSizeUs; // Wrap forwards.
109 }
110
111 current_offset_ms_ += delta / 1000;
112 }
113 last_timestamp_us_ = timestamp_us;
114
115 uint16_t sequence_number = feedback.GetBaseSequence();
116 std::vector<int64_t> delta_vec = feedback.GetReceiveDeltasUs();
117 auto delta_it = delta_vec.begin();
118 std::vector<PacketInfo> packet_feedback_vector;
119 packet_feedback_vector.reserve(delta_vec.size());
120
121 {
122 rtc::CritScope cs(&lock_);
123 size_t failed_lookups = 0;
124 int64_t offset_us = 0;
125 for (auto symbol : feedback.GetStatusVector()) {
126 if (symbol != rtcp::TransportFeedback::StatusSymbol::kNotReceived) {
127 RTC_DCHECK(delta_it != delta_vec.end());
128 offset_us += *(delta_it++);
129 int64_t timestamp_ms = current_offset_ms_ + (offset_us / 1000);
130 PacketInfo info(timestamp_ms, sequence_number);
131 if (send_time_history_.GetInfo(&info, true) && info.send_time_ms >= 0) {
132 packet_feedback_vector.push_back(info);
133 } else {
134 ++failed_lookups;
135 }
136 }
137 ++sequence_number;
138 }
139 std::sort(packet_feedback_vector.begin(), packet_feedback_vector.end(),
140 PacketInfoComparator());
141 RTC_DCHECK(delta_it == delta_vec.end());
142 if (failed_lookups > 0) {
143 LOG(LS_WARNING) << "Failed to lookup send time for " << failed_lookups
144 << " packet" << (failed_lookups > 1 ? "s" : "")
145 << ". Send time history too small?";
146 }
147 }
148 return packet_feedback_vector;
149 }
150
OnTransportFeedback(const rtcp::TransportFeedback & feedback)151 void TransportFeedbackAdapter::OnTransportFeedback(
152 const rtcp::TransportFeedback& feedback) {
153 last_packet_feedback_vector_ = GetPacketFeedbackVector(feedback);
154 DelayBasedBwe::Result result;
155 {
156 rtc::CritScope cs(&bwe_lock_);
157 result = delay_based_bwe_->IncomingPacketFeedbackVector(
158 last_packet_feedback_vector_);
159 }
160 if (result.updated)
161 bitrate_controller_->OnDelayBasedBweResult(result);
162 }
163
GetTransportFeedbackVector() const164 std::vector<PacketInfo> TransportFeedbackAdapter::GetTransportFeedbackVector()
165 const {
166 return last_packet_feedback_vector_;
167 }
168
OnRttUpdate(int64_t avg_rtt_ms,int64_t max_rtt_ms)169 void TransportFeedbackAdapter::OnRttUpdate(int64_t avg_rtt_ms,
170 int64_t max_rtt_ms) {
171 rtc::CritScope cs(&bwe_lock_);
172 delay_based_bwe_->OnRttUpdate(avg_rtt_ms, max_rtt_ms);
173 }
174
175 } // namespace webrtc
176