• Home
  • 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/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