blob: 7f76c6626a67858eabff66d67fdd80d331eb30cd [file] [log] [blame]
Stefan Holmere5904162015-03-26 11:11:06 +01001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/pacing/packet_router.h"
Stefan Holmere5904162015-03-26 11:11:06 +010012
danilchap47085372017-08-10 06:03:57 -070013#include <algorithm>
14#include <limits>
15
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#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"
Stefan Holmere5904162015-03-26 11:11:06 +010022
23namespace webrtc {
danilchap47085372017-08-10 06:03:57 -070024namespace {
25
26constexpr int kRembSendIntervalMs = 200;
27
28} // namespace
Stefan Holmere5904162015-03-26 11:11:06 +010029
nisse05843312017-04-18 23:38:35 -070030PacketRouter::PacketRouter()
31 : last_remb_time_ms_(rtc::TimeMillis()),
32 last_send_bitrate_bps_(0),
danilchap47085372017-08-10 06:03:57 -070033 bitrate_bps_(0),
34 max_bitrate_bps_(std::numeric_limits<decltype(max_bitrate_bps_)>::max()),
eladalon822ff2b2017-08-01 06:30:28 -070035 active_remb_module_(nullptr),
erikvargabf5a2fc2017-06-16 05:02:05 -070036 transport_seq_(0) {}
Stefan Holmere5904162015-03-26 11:11:06 +010037
38PacketRouter::~PacketRouter() {
nissefdbfdc92017-03-31 05:44:52 -070039 RTC_DCHECK(rtp_send_modules_.empty());
40 RTC_DCHECK(rtp_receive_modules_.empty());
eladalon822ff2b2017-08-01 06:30:28 -070041 RTC_DCHECK(sender_remb_candidates_.empty());
42 RTC_DCHECK(receiver_remb_candidates_.empty());
43 RTC_DCHECK(active_remb_module_ == nullptr);
Stefan Holmere5904162015-03-26 11:11:06 +010044}
45
eladalon822ff2b2017-08-01 06:30:28 -070046void PacketRouter::AddSendRtpModule(RtpRtcp* rtp_module, bool remb_candidate) {
stefanbba9dec2016-02-01 04:39:55 -080047 rtc::CritScope cs(&modules_crit_);
nissefdbfdc92017-03-31 05:44:52 -070048 RTC_DCHECK(std::find(rtp_send_modules_.begin(), rtp_send_modules_.end(),
49 rtp_module) == rtp_send_modules_.end());
stefan16b02212017-01-27 07:12:16 -080050 // 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) {
nissefdbfdc92017-03-31 05:44:52 -070053 rtp_send_modules_.push_front(rtp_module);
stefan16b02212017-01-27 07:12:16 -080054 } else {
nissefdbfdc92017-03-31 05:44:52 -070055 rtp_send_modules_.push_back(rtp_module);
stefan16b02212017-01-27 07:12:16 -080056 }
eladalon822ff2b2017-08-01 06:30:28 -070057
58 if (remb_candidate) {
59 AddRembModuleCandidate(rtp_module, true);
60 }
Stefan Holmere5904162015-03-26 11:11:06 +010061}
62
nissefdbfdc92017-03-31 05:44:52 -070063void PacketRouter::RemoveSendRtpModule(RtpRtcp* rtp_module) {
stefanbba9dec2016-02-01 04:39:55 -080064 rtc::CritScope cs(&modules_crit_);
eladalon822ff2b2017-08-01 06:30:28 -070065 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);
nissefdbfdc92017-03-31 05:44:52 -070070}
71
eladalon822ff2b2017-08-01 06:30:28 -070072void PacketRouter::AddReceiveRtpModule(RtpRtcp* rtp_module,
73 bool remb_candidate) {
nissefdbfdc92017-03-31 05:44:52 -070074 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());
eladalon822ff2b2017-08-01 06:30:28 -070077
nissefdbfdc92017-03-31 05:44:52 -070078 rtp_receive_modules_.push_back(rtp_module);
eladalon822ff2b2017-08-01 06:30:28 -070079
80 if (remb_candidate) {
81 AddRembModuleCandidate(rtp_module, false);
82 }
nissefdbfdc92017-03-31 05:44:52 -070083}
84
85void PacketRouter::RemoveReceiveRtpModule(RtpRtcp* rtp_module) {
86 rtc::CritScope cs(&modules_crit_);
eladalon822ff2b2017-08-01 06:30:28 -070087 MaybeRemoveRembModuleCandidate(rtp_module, /* sender = */ false);
nissefdbfdc92017-03-31 05:44:52 -070088 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);
Stefan Holmere5904162015-03-26 11:11:06 +010092}
93
94bool PacketRouter::TimeToSendPacket(uint32_t ssrc,
95 uint16_t sequence_number,
96 int64_t capture_timestamp,
philipel29dca2c2016-05-13 11:13:05 +020097 bool retransmission,
philipelc7bf32a2017-02-17 03:59:43 -080098 const PacedPacketInfo& pacing_info) {
erikvargabf5a2fc2017-06-16 05:02:05 -070099 RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
stefanbba9dec2016-02-01 04:39:55 -0800100 rtc::CritScope cs(&modules_crit_);
nissefdbfdc92017-03-31 05:44:52 -0700101 for (auto* rtp_module : rtp_send_modules_) {
brandtr9dfff292016-11-14 05:14:50 -0800102 if (!rtp_module->SendingMedia())
103 continue;
104 if (ssrc == rtp_module->SSRC() || ssrc == rtp_module->FlexfecSsrc()) {
Stefan Holmere5904162015-03-26 11:11:06 +0100105 return rtp_module->TimeToSendPacket(ssrc, sequence_number,
philipela1ed0b32016-06-01 06:31:17 -0700106 capture_timestamp, retransmission,
philipelc7bf32a2017-02-17 03:59:43 -0800107 pacing_info);
Stefan Holmere5904162015-03-26 11:11:06 +0100108 }
109 }
110 return true;
111}
112
philipela1ed0b32016-06-01 06:31:17 -0700113size_t PacketRouter::TimeToSendPadding(size_t bytes_to_send,
philipelc7bf32a2017-02-17 03:59:43 -0800114 const PacedPacketInfo& pacing_info) {
erikvargabf5a2fc2017-06-16 05:02:05 -0700115 RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
sprang867fb522015-08-03 04:38:41 -0700116 size_t total_bytes_sent = 0;
stefanbba9dec2016-02-01 04:39:55 -0800117 rtc::CritScope cs(&modules_crit_);
stefan16b02212017-01-27 07:12:16 -0800118 // Rtp modules are ordered by which stream can most benefit from padding.
nissefdbfdc92017-03-31 05:44:52 -0700119 for (RtpRtcp* module : rtp_send_modules_) {
stefan53b6cc32017-02-03 08:13:57 -0800120 if (module->SendingMedia() && module->HasBweExtensions()) {
philipela1ed0b32016-06-01 06:31:17 -0700121 size_t bytes_sent = module->TimeToSendPadding(
philipelc7bf32a2017-02-17 03:59:43 -0800122 bytes_to_send - total_bytes_sent, pacing_info);
sprang867fb522015-08-03 04:38:41 -0700123 total_bytes_sent += bytes_sent;
124 if (total_bytes_sent >= bytes_to_send)
125 break;
126 }
Stefan Holmere5904162015-03-26 11:11:06 +0100127 }
sprang867fb522015-08-03 04:38:41 -0700128 return total_bytes_sent;
Stefan Holmere5904162015-03-26 11:11:06 +0100129}
sprang867fb522015-08-03 04:38:41 -0700130
131void PacketRouter::SetTransportWideSequenceNumber(uint16_t sequence_number) {
pbos46ad5422015-12-07 14:29:14 -0800132 rtc::AtomicOps::ReleaseStore(&transport_seq_, sequence_number);
sprang867fb522015-08-03 04:38:41 -0700133}
134
135uint16_t PacketRouter::AllocateSequenceNumber() {
pbos46ad5422015-12-07 14:29:14 -0800136 int prev_seq = rtc::AtomicOps::AcquireLoad(&transport_seq_);
sprang867fb522015-08-03 04:38:41 -0700137 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.
pbos46ad5422015-12-07 14:29:14 -0800146 prev_seq = rtc::AtomicOps::CompareAndSwap(&transport_seq_, desired_prev_seq,
sprang867fb522015-08-03 04:38:41 -0700147 new_seq);
148 } while (prev_seq != desired_prev_seq);
149
150 return new_seq;
151}
152
nisse05843312017-04-18 23:38:35 -0700153void PacketRouter::OnReceiveBitrateChanged(const std::vector<uint32_t>& ssrcs,
154 uint32_t bitrate_bps) {
nisse05843312017-04-18 23:38:35 -0700155 // % 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;
danilchap47085372017-08-10 06:03:57 -0700184 // Cap the value to send in remb with configured value.
185 bitrate_bps = std::min(bitrate_bps, max_bitrate_bps_);
nisse05843312017-04-18 23:38:35 -0700186 }
187 SendRemb(bitrate_bps, ssrcs);
188}
189
danilchap47085372017-08-10 06:03:57 -0700190void 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
nisse05843312017-04-18 23:38:35 -0700204bool PacketRouter::SendRemb(uint32_t bitrate_bps,
205 const std::vector<uint32_t>& ssrcs) {
206 rtc::CritScope lock(&modules_crit_);
eladalon822ff2b2017-08-01 06:30:28 -0700207
208 if (!active_remb_module_) {
nisse05843312017-04-18 23:38:35 -0700209 return false;
eladalon822ff2b2017-08-01 06:30:28 -0700210 }
211
nisse05843312017-04-18 23:38:35 -0700212 // The Add* and Remove* methods above ensure that this (and only this) module
213 // has REMB enabled. REMB should be disabled on all other modules, because
214 // otherwise, they will send REMB with stale info.
eladalon822ff2b2017-08-01 06:30:28 -0700215 RTC_DCHECK(active_remb_module_->REMB());
216 active_remb_module_->SetREMBData(bitrate_bps, ssrcs);
217
nisse05843312017-04-18 23:38:35 -0700218 return true;
219}
220
221bool PacketRouter::SendTransportFeedback(rtcp::TransportFeedback* packet) {
erikvargabf5a2fc2017-06-16 05:02:05 -0700222 RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
stefanbba9dec2016-02-01 04:39:55 -0800223 rtc::CritScope cs(&modules_crit_);
nissefdbfdc92017-03-31 05:44:52 -0700224 // Prefer send modules.
225 for (auto* rtp_module : rtp_send_modules_) {
226 packet->SetSenderSsrc(rtp_module->SSRC());
227 if (rtp_module->SendFeedbackPacket(*packet))
228 return true;
229 }
230 for (auto* rtp_module : rtp_receive_modules_) {
danilchap822a16f2016-09-27 09:27:47 -0700231 packet->SetSenderSsrc(rtp_module->SSRC());
Peter Boström3dd5d1d2016-02-25 16:56:48 +0100232 if (rtp_module->SendFeedbackPacket(*packet))
233 return true;
234 }
sprang233bd872015-09-08 13:25:16 -0700235 return false;
236}
237
eladalon822ff2b2017-08-01 06:30:28 -0700238void PacketRouter::AddRembModuleCandidate(RtpRtcp* candidate_module,
239 bool sender) {
240 RTC_DCHECK(candidate_module);
241 std::vector<RtpRtcp*>& candidates =
242 sender ? sender_remb_candidates_ : receiver_remb_candidates_;
243 RTC_DCHECK(std::find(candidates.cbegin(), candidates.cend(),
244 candidate_module) == candidates.cend());
245 candidates.push_back(candidate_module);
246 DetermineActiveRembModule();
247}
248
249void PacketRouter::MaybeRemoveRembModuleCandidate(RtpRtcp* candidate_module,
250 bool sender) {
251 RTC_DCHECK(candidate_module);
252 std::vector<RtpRtcp*>& candidates =
253 sender ? sender_remb_candidates_ : receiver_remb_candidates_;
254 auto it = std::find(candidates.begin(), candidates.end(), candidate_module);
255
256 if (it == candidates.end()) {
257 return; // Function called due to removal of non-REMB-candidate module.
258 }
259
260 if (*it == active_remb_module_) {
261 UnsetActiveRembModule();
262 }
263 candidates.erase(it);
264 DetermineActiveRembModule();
265}
266
267void PacketRouter::UnsetActiveRembModule() {
268 RTC_CHECK(active_remb_module_);
269 RTC_DCHECK(active_remb_module_->REMB());
270 active_remb_module_->SetREMBStatus(false);
271 active_remb_module_ = nullptr;
272}
273
274void PacketRouter::DetermineActiveRembModule() {
275 // Sender modules take precedence over receiver modules, because SRs (sender
276 // reports) are sent more frequently than RR (receiver reports).
277 // When adding the first sender module, we should change the active REMB
278 // module to be that. Otherwise, we remain with the current active module.
279
280 RtpRtcp* new_active_remb_module_;
281
282 if (!sender_remb_candidates_.empty()) {
283 new_active_remb_module_ = sender_remb_candidates_.front();
284 } else if (!receiver_remb_candidates_.empty()) {
285 new_active_remb_module_ = receiver_remb_candidates_.front();
286 } else {
287 new_active_remb_module_ = nullptr;
288 }
289
290 if (new_active_remb_module_ != active_remb_module_) {
291 if (active_remb_module_) {
292 UnsetActiveRembModule();
293 }
294 if (new_active_remb_module_) {
295 RTC_DCHECK(!new_active_remb_module_->REMB());
296 new_active_remb_module_->SetREMBStatus(true);
297 }
298 }
299
300 active_remb_module_ = new_active_remb_module_;
301}
302
Stefan Holmere5904162015-03-26 11:11:06 +0100303} // namespace webrtc