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/remote_bitrate_estimator/remote_estimator_proxy.h"
12
13 #include <algorithm>
14 #include <limits>
15 #include <memory>
16 #include <utility>
17
18 #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/logging.h"
21 #include "rtc_base/numerics/safe_minmax.h"
22 #include "system_wrappers/include/clock.h"
23
24 namespace webrtc {
25
26 // Impossible to request feedback older than what can be represented by 15 bits.
27 const int RemoteEstimatorProxy::kMaxNumberOfPackets = (1 << 15);
28
29 // The maximum allowed value for a timestamp in milliseconds. This is lower
30 // than the numerical limit since we often convert to microseconds.
31 static constexpr int64_t kMaxTimeMs =
32 std::numeric_limits<int64_t>::max() / 1000;
33
RemoteEstimatorProxy(Clock * clock,TransportFeedbackSenderInterface * feedback_sender,const WebRtcKeyValueConfig * key_value_config,NetworkStateEstimator * network_state_estimator)34 RemoteEstimatorProxy::RemoteEstimatorProxy(
35 Clock* clock,
36 TransportFeedbackSenderInterface* feedback_sender,
37 const WebRtcKeyValueConfig* key_value_config,
38 NetworkStateEstimator* network_state_estimator)
39 : clock_(clock),
40 feedback_sender_(feedback_sender),
41 send_config_(key_value_config),
42 last_process_time_ms_(-1),
43 network_state_estimator_(network_state_estimator),
44 media_ssrc_(0),
45 feedback_packet_count_(0),
46 send_interval_ms_(send_config_.default_interval->ms()),
47 send_periodic_feedback_(true),
48 previous_abs_send_time_(0),
49 abs_send_timestamp_(clock->CurrentTime()) {
50 RTC_LOG(LS_INFO)
51 << "Maximum interval between transport feedback RTCP messages (ms): "
52 << send_config_.max_interval->ms();
53 }
54
~RemoteEstimatorProxy()55 RemoteEstimatorProxy::~RemoteEstimatorProxy() {}
56
IncomingPacket(int64_t arrival_time_ms,size_t payload_size,const RTPHeader & header)57 void RemoteEstimatorProxy::IncomingPacket(int64_t arrival_time_ms,
58 size_t payload_size,
59 const RTPHeader& header) {
60 if (arrival_time_ms < 0 || arrival_time_ms > kMaxTimeMs) {
61 RTC_LOG(LS_WARNING) << "Arrival time out of bounds: " << arrival_time_ms;
62 return;
63 }
64 MutexLock lock(&lock_);
65 media_ssrc_ = header.ssrc;
66 int64_t seq = 0;
67
68 if (header.extension.hasTransportSequenceNumber) {
69 seq = unwrapper_.Unwrap(header.extension.transportSequenceNumber);
70
71 if (send_periodic_feedback_) {
72 if (periodic_window_start_seq_ &&
73 packet_arrival_times_.lower_bound(*periodic_window_start_seq_) ==
74 packet_arrival_times_.end()) {
75 // Start new feedback packet, cull old packets.
76 for (auto it = packet_arrival_times_.begin();
77 it != packet_arrival_times_.end() && it->first < seq &&
78 arrival_time_ms - it->second >= send_config_.back_window->ms();) {
79 it = packet_arrival_times_.erase(it);
80 }
81 }
82 if (!periodic_window_start_seq_ || seq < *periodic_window_start_seq_) {
83 periodic_window_start_seq_ = seq;
84 }
85 }
86
87 // We are only interested in the first time a packet is received.
88 if (packet_arrival_times_.find(seq) != packet_arrival_times_.end())
89 return;
90
91 packet_arrival_times_[seq] = arrival_time_ms;
92
93 // Limit the range of sequence numbers to send feedback for.
94 auto first_arrival_time_to_keep = packet_arrival_times_.lower_bound(
95 packet_arrival_times_.rbegin()->first - kMaxNumberOfPackets);
96 if (first_arrival_time_to_keep != packet_arrival_times_.begin()) {
97 packet_arrival_times_.erase(packet_arrival_times_.begin(),
98 first_arrival_time_to_keep);
99 if (send_periodic_feedback_) {
100 // |packet_arrival_times_| cannot be empty since we just added one
101 // element and the last element is not deleted.
102 RTC_DCHECK(!packet_arrival_times_.empty());
103 periodic_window_start_seq_ = packet_arrival_times_.begin()->first;
104 }
105 }
106
107 if (header.extension.feedback_request) {
108 // Send feedback packet immediately.
109 SendFeedbackOnRequest(seq, header.extension.feedback_request.value());
110 }
111 }
112
113 if (network_state_estimator_ && header.extension.hasAbsoluteSendTime) {
114 PacketResult packet_result;
115 packet_result.receive_time = Timestamp::Millis(arrival_time_ms);
116 // Ignore reordering of packets and assume they have approximately the same
117 // send time.
118 abs_send_timestamp_ += std::max(
119 header.extension.GetAbsoluteSendTimeDelta(previous_abs_send_time_),
120 TimeDelta::Millis(0));
121 previous_abs_send_time_ = header.extension.absoluteSendTime;
122 packet_result.sent_packet.send_time = abs_send_timestamp_;
123 // TODO(webrtc:10742): Take IP header and transport overhead into account.
124 packet_result.sent_packet.size =
125 DataSize::Bytes(header.headerLength + payload_size);
126 packet_result.sent_packet.sequence_number = seq;
127 network_state_estimator_->OnReceivedPacket(packet_result);
128 }
129 }
130
LatestEstimate(std::vector<unsigned int> * ssrcs,unsigned int * bitrate_bps) const131 bool RemoteEstimatorProxy::LatestEstimate(std::vector<unsigned int>* ssrcs,
132 unsigned int* bitrate_bps) const {
133 return false;
134 }
135
TimeUntilNextProcess()136 int64_t RemoteEstimatorProxy::TimeUntilNextProcess() {
137 MutexLock lock(&lock_);
138 if (!send_periodic_feedback_) {
139 // Wait a day until next process.
140 return 24 * 60 * 60 * 1000;
141 } else if (last_process_time_ms_ != -1) {
142 int64_t now = clock_->TimeInMilliseconds();
143 if (now - last_process_time_ms_ < send_interval_ms_)
144 return last_process_time_ms_ + send_interval_ms_ - now;
145 }
146 return 0;
147 }
148
Process()149 void RemoteEstimatorProxy::Process() {
150 MutexLock lock(&lock_);
151 if (!send_periodic_feedback_) {
152 return;
153 }
154 last_process_time_ms_ = clock_->TimeInMilliseconds();
155
156 SendPeriodicFeedbacks();
157 }
158
OnBitrateChanged(int bitrate_bps)159 void RemoteEstimatorProxy::OnBitrateChanged(int bitrate_bps) {
160 // TwccReportSize = Ipv4(20B) + UDP(8B) + SRTP(10B) +
161 // AverageTwccReport(30B)
162 // TwccReport size at 50ms interval is 24 byte.
163 // TwccReport size at 250ms interval is 36 byte.
164 // AverageTwccReport = (TwccReport(50ms) + TwccReport(250ms)) / 2
165 constexpr int kTwccReportSize = 20 + 8 + 10 + 30;
166 const double kMinTwccRate =
167 kTwccReportSize * 8.0 * 1000.0 / send_config_.max_interval->ms();
168 const double kMaxTwccRate =
169 kTwccReportSize * 8.0 * 1000.0 / send_config_.min_interval->ms();
170
171 // Let TWCC reports occupy 5% of total bandwidth.
172 MutexLock lock(&lock_);
173 send_interval_ms_ = static_cast<int>(
174 0.5 + kTwccReportSize * 8.0 * 1000.0 /
175 rtc::SafeClamp(send_config_.bandwidth_fraction * bitrate_bps,
176 kMinTwccRate, kMaxTwccRate));
177 }
178
SetSendPeriodicFeedback(bool send_periodic_feedback)179 void RemoteEstimatorProxy::SetSendPeriodicFeedback(
180 bool send_periodic_feedback) {
181 MutexLock lock(&lock_);
182 send_periodic_feedback_ = send_periodic_feedback;
183 }
184
SendPeriodicFeedbacks()185 void RemoteEstimatorProxy::SendPeriodicFeedbacks() {
186 // |periodic_window_start_seq_| is the first sequence number to include in the
187 // current feedback packet. Some older may still be in the map, in case a
188 // reordering happens and we need to retransmit them.
189 if (!periodic_window_start_seq_)
190 return;
191
192 std::unique_ptr<rtcp::RemoteEstimate> remote_estimate;
193 if (network_state_estimator_) {
194 absl::optional<NetworkStateEstimate> state_estimate =
195 network_state_estimator_->GetCurrentEstimate();
196 if (state_estimate) {
197 remote_estimate = std::make_unique<rtcp::RemoteEstimate>();
198 remote_estimate->SetEstimate(state_estimate.value());
199 }
200 }
201
202 for (auto begin_iterator =
203 packet_arrival_times_.lower_bound(*periodic_window_start_seq_);
204 begin_iterator != packet_arrival_times_.cend();
205 begin_iterator =
206 packet_arrival_times_.lower_bound(*periodic_window_start_seq_)) {
207 auto feedback_packet = std::make_unique<rtcp::TransportFeedback>();
208 periodic_window_start_seq_ = BuildFeedbackPacket(
209 feedback_packet_count_++, media_ssrc_, *periodic_window_start_seq_,
210 begin_iterator, packet_arrival_times_.cend(), feedback_packet.get());
211
212 RTC_DCHECK(feedback_sender_ != nullptr);
213
214 std::vector<std::unique_ptr<rtcp::RtcpPacket>> packets;
215 if (remote_estimate) {
216 packets.push_back(std::move(remote_estimate));
217 }
218 packets.push_back(std::move(feedback_packet));
219
220 feedback_sender_->SendCombinedRtcpPacket(std::move(packets));
221 // Note: Don't erase items from packet_arrival_times_ after sending, in case
222 // they need to be re-sent after a reordering. Removal will be handled
223 // by OnPacketArrival once packets are too old.
224 }
225 }
226
SendFeedbackOnRequest(int64_t sequence_number,const FeedbackRequest & feedback_request)227 void RemoteEstimatorProxy::SendFeedbackOnRequest(
228 int64_t sequence_number,
229 const FeedbackRequest& feedback_request) {
230 if (feedback_request.sequence_count == 0) {
231 return;
232 }
233
234 auto feedback_packet = std::make_unique<rtcp::TransportFeedback>(
235 feedback_request.include_timestamps);
236
237 int64_t first_sequence_number =
238 sequence_number - feedback_request.sequence_count + 1;
239 auto begin_iterator =
240 packet_arrival_times_.lower_bound(first_sequence_number);
241 auto end_iterator = packet_arrival_times_.upper_bound(sequence_number);
242
243 BuildFeedbackPacket(feedback_packet_count_++, media_ssrc_,
244 first_sequence_number, begin_iterator, end_iterator,
245 feedback_packet.get());
246
247 // Clear up to the first packet that is included in this feedback packet.
248 packet_arrival_times_.erase(packet_arrival_times_.begin(), begin_iterator);
249
250 RTC_DCHECK(feedback_sender_ != nullptr);
251 std::vector<std::unique_ptr<rtcp::RtcpPacket>> packets;
252 packets.push_back(std::move(feedback_packet));
253 feedback_sender_->SendCombinedRtcpPacket(std::move(packets));
254 }
255
BuildFeedbackPacket(uint8_t feedback_packet_count,uint32_t media_ssrc,int64_t base_sequence_number,std::map<int64_t,int64_t>::const_iterator begin_iterator,std::map<int64_t,int64_t>::const_iterator end_iterator,rtcp::TransportFeedback * feedback_packet)256 int64_t RemoteEstimatorProxy::BuildFeedbackPacket(
257 uint8_t feedback_packet_count,
258 uint32_t media_ssrc,
259 int64_t base_sequence_number,
260 std::map<int64_t, int64_t>::const_iterator begin_iterator,
261 std::map<int64_t, int64_t>::const_iterator end_iterator,
262 rtcp::TransportFeedback* feedback_packet) {
263 RTC_DCHECK(begin_iterator != end_iterator);
264
265 // TODO(sprang): Measure receive times in microseconds and remove the
266 // conversions below.
267 feedback_packet->SetMediaSsrc(media_ssrc);
268 // Base sequence number is the expected first sequence number. This is known,
269 // but we might not have actually received it, so the base time shall be the
270 // time of the first received packet in the feedback.
271 feedback_packet->SetBase(static_cast<uint16_t>(base_sequence_number & 0xFFFF),
272 begin_iterator->second * 1000);
273 feedback_packet->SetFeedbackSequenceNumber(feedback_packet_count);
274 int64_t next_sequence_number = base_sequence_number;
275 for (auto it = begin_iterator; it != end_iterator; ++it) {
276 if (!feedback_packet->AddReceivedPacket(
277 static_cast<uint16_t>(it->first & 0xFFFF), it->second * 1000)) {
278 // If we can't even add the first seq to the feedback packet, we won't be
279 // able to build it at all.
280 RTC_CHECK(begin_iterator != it);
281
282 // Could not add timestamp, feedback packet might be full. Return and
283 // try again with a fresh packet.
284 break;
285 }
286 next_sequence_number = it->first + 1;
287 }
288 return next_sequence_number;
289 }
290
291 } // namespace webrtc
292