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/pacing/packet_router.h"
12 
13 #include <algorithm>
14 #include <limits>
15 
16 #include "modules/rtp_rtcp/include/rtp_rtcp.h"
17 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
18 #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
19 #include "rtc_base/atomicops.h"
20 #include "rtc_base/checks.h"
21 #include "rtc_base/timeutils.h"
22 
23 namespace webrtc {
24 namespace {
25 
26 constexpr int kRembSendIntervalMs = 200;
27 
28 }  // namespace
29 
PacketRouter()30 PacketRouter::PacketRouter()
31     : last_remb_time_ms_(rtc::TimeMillis()),
32       last_send_bitrate_bps_(0),
33       bitrate_bps_(0),
34       max_bitrate_bps_(std::numeric_limits<decltype(max_bitrate_bps_)>::max()),
35       active_remb_module_(nullptr),
36       transport_seq_(0) {}
37 
~PacketRouter()38 PacketRouter::~PacketRouter() {
39   RTC_DCHECK(rtp_send_modules_.empty());
40   RTC_DCHECK(rtp_receive_modules_.empty());
41   RTC_DCHECK(sender_remb_candidates_.empty());
42   RTC_DCHECK(receiver_remb_candidates_.empty());
43   RTC_DCHECK(active_remb_module_ == nullptr);
44 }
45 
AddSendRtpModule(RtpRtcp * rtp_module,bool remb_candidate)46 void PacketRouter::AddSendRtpModule(RtpRtcp* rtp_module, bool remb_candidate) {
47   rtc::CritScope cs(&modules_crit_);
48   RTC_DCHECK(std::find(rtp_send_modules_.begin(), rtp_send_modules_.end(),
49                        rtp_module) == rtp_send_modules_.end());
50   // Put modules which can use regular payload packets (over rtx) instead of
51   // padding first as it's less of a waste
52   if ((rtp_module->RtxSendStatus() & kRtxRedundantPayloads) > 0) {
53     rtp_send_modules_.push_front(rtp_module);
54   } else {
55     rtp_send_modules_.push_back(rtp_module);
56   }
57 
58   if (remb_candidate) {
59     AddRembModuleCandidate(rtp_module, true);
60   }
61 }
62 
RemoveSendRtpModule(RtpRtcp * rtp_module)63 void PacketRouter::RemoveSendRtpModule(RtpRtcp* rtp_module) {
64   rtc::CritScope cs(&modules_crit_);
65   MaybeRemoveRembModuleCandidate(rtp_module, /* sender = */ true);
66   auto it =
67       std::find(rtp_send_modules_.begin(), rtp_send_modules_.end(), rtp_module);
68   RTC_DCHECK(it != rtp_send_modules_.end());
69   rtp_send_modules_.erase(it);
70 }
71 
AddReceiveRtpModule(RtpRtcp * rtp_module,bool remb_candidate)72 void PacketRouter::AddReceiveRtpModule(RtpRtcp* rtp_module,
73                                        bool remb_candidate) {
74   rtc::CritScope cs(&modules_crit_);
75   RTC_DCHECK(std::find(rtp_receive_modules_.begin(), rtp_receive_modules_.end(),
76                        rtp_module) == rtp_receive_modules_.end());
77 
78   rtp_receive_modules_.push_back(rtp_module);
79 
80   if (remb_candidate) {
81     AddRembModuleCandidate(rtp_module, false);
82   }
83 }
84 
RemoveReceiveRtpModule(RtpRtcp * rtp_module)85 void PacketRouter::RemoveReceiveRtpModule(RtpRtcp* rtp_module) {
86   rtc::CritScope cs(&modules_crit_);
87   MaybeRemoveRembModuleCandidate(rtp_module, /* sender = */ false);
88   const auto& it = std::find(rtp_receive_modules_.begin(),
89                              rtp_receive_modules_.end(), rtp_module);
90   RTC_DCHECK(it != rtp_receive_modules_.end());
91   rtp_receive_modules_.erase(it);
92 }
93 
TimeToSendPacket(uint32_t ssrc,uint16_t sequence_number,int64_t capture_timestamp,bool retransmission,const PacedPacketInfo & pacing_info)94 bool PacketRouter::TimeToSendPacket(uint32_t ssrc,
95                                     uint16_t sequence_number,
96                                     int64_t capture_timestamp,
97                                     bool retransmission,
98                                     const PacedPacketInfo& pacing_info) {
99   RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
100   rtc::CritScope cs(&modules_crit_);
101   for (auto* rtp_module : rtp_send_modules_) {
102     if (!rtp_module->SendingMedia())
103       continue;
104     if (ssrc == rtp_module->SSRC() || ssrc == rtp_module->FlexfecSsrc()) {
105       return rtp_module->TimeToSendPacket(ssrc, sequence_number,
106                                           capture_timestamp, retransmission,
107                                           pacing_info);
108     }
109   }
110   return true;
111 }
112 
TimeToSendPadding(size_t bytes_to_send,const PacedPacketInfo & pacing_info)113 size_t PacketRouter::TimeToSendPadding(size_t bytes_to_send,
114                                        const PacedPacketInfo& pacing_info) {
115   RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
116   size_t total_bytes_sent = 0;
117   rtc::CritScope cs(&modules_crit_);
118   // Rtp modules are ordered by which stream can most benefit from padding.
119   for (RtpRtcp* module : rtp_send_modules_) {
120     if (module->SendingMedia() && module->HasBweExtensions()) {
121       size_t bytes_sent = module->TimeToSendPadding(
122           bytes_to_send - total_bytes_sent, pacing_info);
123       total_bytes_sent += bytes_sent;
124       if (total_bytes_sent >= bytes_to_send)
125         break;
126     }
127   }
128   return total_bytes_sent;
129 }
130 
SetTransportWideSequenceNumber(uint16_t sequence_number)131 void PacketRouter::SetTransportWideSequenceNumber(uint16_t sequence_number) {
132   rtc::AtomicOps::ReleaseStore(&transport_seq_, sequence_number);
133 }
134 
AllocateSequenceNumber()135 uint16_t PacketRouter::AllocateSequenceNumber() {
136   int prev_seq = rtc::AtomicOps::AcquireLoad(&transport_seq_);
137   int desired_prev_seq;
138   int new_seq;
139   do {
140     desired_prev_seq = prev_seq;
141     new_seq = (desired_prev_seq + 1) & 0xFFFF;
142     // Note: CompareAndSwap returns the actual value of transport_seq at the
143     // time the CAS operation was executed. Thus, if prev_seq is returned, the
144     // operation was successful - otherwise we need to retry. Saving the
145     // return value saves us a load on retry.
146     prev_seq = rtc::AtomicOps::CompareAndSwap(&transport_seq_, desired_prev_seq,
147                                               new_seq);
148   } while (prev_seq != desired_prev_seq);
149 
150   return new_seq;
151 }
152 
OnReceiveBitrateChanged(const std::vector<uint32_t> & ssrcs,uint32_t bitrate_bps)153 void PacketRouter::OnReceiveBitrateChanged(const std::vector<uint32_t>& ssrcs,
154                                            uint32_t bitrate_bps) {
155   // % threshold for if we should send a new REMB asap.
156   const uint32_t kSendThresholdPercent = 97;
157 
158   int64_t now_ms = rtc::TimeMillis();
159   {
160     rtc::CritScope lock(&remb_crit_);
161 
162     // If we already have an estimate, check if the new total estimate is below
163     // kSendThresholdPercent of the previous estimate.
164     if (last_send_bitrate_bps_ > 0) {
165       uint32_t new_remb_bitrate_bps =
166           last_send_bitrate_bps_ - bitrate_bps_ + bitrate_bps;
167 
168       if (new_remb_bitrate_bps <
169           kSendThresholdPercent * last_send_bitrate_bps_ / 100) {
170         // The new bitrate estimate is less than kSendThresholdPercent % of the
171         // last report. Send a REMB asap.
172         last_remb_time_ms_ = now_ms - kRembSendIntervalMs;
173       }
174     }
175     bitrate_bps_ = bitrate_bps;
176 
177     if (now_ms - last_remb_time_ms_ < kRembSendIntervalMs) {
178       return;
179     }
180     // NOTE: Updated if we intend to send the data; we might not have
181     // a module to actually send it.
182     last_remb_time_ms_ = now_ms;
183     last_send_bitrate_bps_ = bitrate_bps;
184     // Cap the value to send in remb with configured value.
185     bitrate_bps = std::min(bitrate_bps, max_bitrate_bps_);
186   }
187   SendRemb(bitrate_bps, ssrcs);
188 }
189 
SetMaxDesiredReceiveBitrate(uint32_t bitrate_bps)190 void PacketRouter::SetMaxDesiredReceiveBitrate(uint32_t bitrate_bps) {
191   {
192     rtc::CritScope lock(&remb_crit_);
193     max_bitrate_bps_ = bitrate_bps;
194     if (rtc::TimeMillis() - last_remb_time_ms_ < kRembSendIntervalMs &&
195         last_send_bitrate_bps_ > 0 &&
196         last_send_bitrate_bps_ <= max_bitrate_bps_) {
197       // Recent measured bitrate is already below the cap.
198       return;
199     }
200   }
201   SendRemb(bitrate_bps, /*ssrcs=*/{});
202 }
203 
SendRemb(uint32_t bitrate_bps,const std::vector<uint32_t> & ssrcs)204 bool PacketRouter::SendRemb(uint32_t bitrate_bps,
205                             const std::vector<uint32_t>& ssrcs) {
206   rtc::CritScope lock(&modules_crit_);
207 
208   if (!active_remb_module_) {
209     return false;
210   }
211 
212   // The Add* and Remove* methods above ensure that REMB is disabled on all
213   // other modules, because otherwise, they will send REMB with stale info.
214   active_remb_module_->SetRemb(bitrate_bps, ssrcs);
215 
216   return true;
217 }
218 
SendTransportFeedback(rtcp::TransportFeedback * packet)219 bool PacketRouter::SendTransportFeedback(rtcp::TransportFeedback* packet) {
220   RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
221   rtc::CritScope cs(&modules_crit_);
222   // Prefer send modules.
223   for (auto* rtp_module : rtp_send_modules_) {
224     packet->SetSenderSsrc(rtp_module->SSRC());
225     if (rtp_module->SendFeedbackPacket(*packet))
226       return true;
227   }
228   for (auto* rtp_module : rtp_receive_modules_) {
229     packet->SetSenderSsrc(rtp_module->SSRC());
230     if (rtp_module->SendFeedbackPacket(*packet))
231       return true;
232   }
233   return false;
234 }
235 
AddRembModuleCandidate(RtpRtcp * candidate_module,bool sender)236 void PacketRouter::AddRembModuleCandidate(RtpRtcp* candidate_module,
237                                           bool sender) {
238   RTC_DCHECK(candidate_module);
239   std::vector<RtpRtcp*>& candidates =
240       sender ? sender_remb_candidates_ : receiver_remb_candidates_;
241   RTC_DCHECK(std::find(candidates.cbegin(), candidates.cend(),
242                        candidate_module) == candidates.cend());
243   candidates.push_back(candidate_module);
244   DetermineActiveRembModule();
245 }
246 
MaybeRemoveRembModuleCandidate(RtpRtcp * candidate_module,bool sender)247 void PacketRouter::MaybeRemoveRembModuleCandidate(RtpRtcp* candidate_module,
248                                                   bool sender) {
249   RTC_DCHECK(candidate_module);
250   std::vector<RtpRtcp*>& candidates =
251       sender ? sender_remb_candidates_ : receiver_remb_candidates_;
252   auto it = std::find(candidates.begin(), candidates.end(), candidate_module);
253 
254   if (it == candidates.end()) {
255     return;  // Function called due to removal of non-REMB-candidate module.
256   }
257 
258   if (*it == active_remb_module_) {
259     UnsetActiveRembModule();
260   }
261   candidates.erase(it);
262   DetermineActiveRembModule();
263 }
264 
UnsetActiveRembModule()265 void PacketRouter::UnsetActiveRembModule() {
266   RTC_CHECK(active_remb_module_);
267   active_remb_module_->UnsetRemb();
268   active_remb_module_ = nullptr;
269 }
270 
DetermineActiveRembModule()271 void PacketRouter::DetermineActiveRembModule() {
272   // Sender modules take precedence over receiver modules, because SRs (sender
273   // reports) are sent more frequently than RR (receiver reports).
274   // When adding the first sender module, we should change the active REMB
275   // module to be that. Otherwise, we remain with the current active module.
276 
277   RtpRtcp* new_active_remb_module;
278 
279   if (!sender_remb_candidates_.empty()) {
280     new_active_remb_module = sender_remb_candidates_.front();
281   } else if (!receiver_remb_candidates_.empty()) {
282     new_active_remb_module = receiver_remb_candidates_.front();
283   } else {
284     new_active_remb_module = nullptr;
285   }
286 
287   if (new_active_remb_module != active_remb_module_ && active_remb_module_) {
288     UnsetActiveRembModule();
289   }
290 
291   active_remb_module_ = new_active_remb_module;
292 }
293 
294 }  // namespace webrtc
295