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