blob: a7c2b939c1b08dc41e64b627c19c67b9f2bbad7a [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>
Yves Gerey988cc082018-10-23 12:03:01 +020014#include <cstdint>
danilchap47085372017-08-10 06:03:57 -070015#include <limits>
16
Yves Gerey988cc082018-10-23 12:03:01 +020017#include "absl/types/optional.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "modules/rtp_rtcp/include/rtp_rtcp.h"
19#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
20#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "rtc_base/atomic_ops.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "rtc_base/time_utils.h"
Stefan Holmere5904162015-03-26 11:11:06 +010024
25namespace webrtc {
danilchap47085372017-08-10 06:03:57 -070026namespace {
27
28constexpr int kRembSendIntervalMs = 200;
29
30} // namespace
Stefan Holmere5904162015-03-26 11:11:06 +010031
nisse05843312017-04-18 23:38:35 -070032PacketRouter::PacketRouter()
Erik Språng8b7ca4a2018-05-17 13:43:35 +020033 : last_send_module_(nullptr),
34 last_remb_time_ms_(rtc::TimeMillis()),
nisse05843312017-04-18 23:38:35 -070035 last_send_bitrate_bps_(0),
danilchap47085372017-08-10 06:03:57 -070036 bitrate_bps_(0),
37 max_bitrate_bps_(std::numeric_limits<decltype(max_bitrate_bps_)>::max()),
eladalon822ff2b2017-08-01 06:30:28 -070038 active_remb_module_(nullptr),
erikvargabf5a2fc2017-06-16 05:02:05 -070039 transport_seq_(0) {}
Stefan Holmere5904162015-03-26 11:11:06 +010040
41PacketRouter::~PacketRouter() {
nissefdbfdc92017-03-31 05:44:52 -070042 RTC_DCHECK(rtp_send_modules_.empty());
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010043 RTC_DCHECK(rtcp_feedback_senders_.empty());
eladalon822ff2b2017-08-01 06:30:28 -070044 RTC_DCHECK(sender_remb_candidates_.empty());
45 RTC_DCHECK(receiver_remb_candidates_.empty());
46 RTC_DCHECK(active_remb_module_ == nullptr);
Stefan Holmere5904162015-03-26 11:11:06 +010047}
48
eladalon822ff2b2017-08-01 06:30:28 -070049void PacketRouter::AddSendRtpModule(RtpRtcp* rtp_module, bool remb_candidate) {
stefanbba9dec2016-02-01 04:39:55 -080050 rtc::CritScope cs(&modules_crit_);
nissefdbfdc92017-03-31 05:44:52 -070051 RTC_DCHECK(std::find(rtp_send_modules_.begin(), rtp_send_modules_.end(),
52 rtp_module) == rtp_send_modules_.end());
stefan16b02212017-01-27 07:12:16 -080053 // Put modules which can use regular payload packets (over rtx) instead of
54 // padding first as it's less of a waste
55 if ((rtp_module->RtxSendStatus() & kRtxRedundantPayloads) > 0) {
nissefdbfdc92017-03-31 05:44:52 -070056 rtp_send_modules_.push_front(rtp_module);
stefan16b02212017-01-27 07:12:16 -080057 } else {
nissefdbfdc92017-03-31 05:44:52 -070058 rtp_send_modules_.push_back(rtp_module);
stefan16b02212017-01-27 07:12:16 -080059 }
eladalon822ff2b2017-08-01 06:30:28 -070060
61 if (remb_candidate) {
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010062 AddRembModuleCandidate(rtp_module, /* media_sender = */ true);
eladalon822ff2b2017-08-01 06:30:28 -070063 }
Stefan Holmere5904162015-03-26 11:11:06 +010064}
65
nissefdbfdc92017-03-31 05:44:52 -070066void PacketRouter::RemoveSendRtpModule(RtpRtcp* rtp_module) {
stefanbba9dec2016-02-01 04:39:55 -080067 rtc::CritScope cs(&modules_crit_);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010068 MaybeRemoveRembModuleCandidate(rtp_module, /* media_sender = */ true);
eladalon822ff2b2017-08-01 06:30:28 -070069 auto it =
70 std::find(rtp_send_modules_.begin(), rtp_send_modules_.end(), rtp_module);
71 RTC_DCHECK(it != rtp_send_modules_.end());
72 rtp_send_modules_.erase(it);
Erik Språng8b7ca4a2018-05-17 13:43:35 +020073 if (last_send_module_ == rtp_module) {
74 last_send_module_ = nullptr;
75 }
nissefdbfdc92017-03-31 05:44:52 -070076}
77
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010078void PacketRouter::AddReceiveRtpModule(RtcpFeedbackSenderInterface* rtcp_sender,
eladalon822ff2b2017-08-01 06:30:28 -070079 bool remb_candidate) {
nissefdbfdc92017-03-31 05:44:52 -070080 rtc::CritScope cs(&modules_crit_);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010081 RTC_DCHECK(std::find(rtcp_feedback_senders_.begin(),
82 rtcp_feedback_senders_.end(),
83 rtcp_sender) == rtcp_feedback_senders_.end());
eladalon822ff2b2017-08-01 06:30:28 -070084
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010085 rtcp_feedback_senders_.push_back(rtcp_sender);
eladalon822ff2b2017-08-01 06:30:28 -070086
87 if (remb_candidate) {
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010088 AddRembModuleCandidate(rtcp_sender, /* media_sender = */ false);
eladalon822ff2b2017-08-01 06:30:28 -070089 }
nissefdbfdc92017-03-31 05:44:52 -070090}
91
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010092void PacketRouter::RemoveReceiveRtpModule(
93 RtcpFeedbackSenderInterface* rtcp_sender) {
nissefdbfdc92017-03-31 05:44:52 -070094 rtc::CritScope cs(&modules_crit_);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010095 MaybeRemoveRembModuleCandidate(rtcp_sender, /* media_sender = */ false);
96 auto it = std::find(rtcp_feedback_senders_.begin(),
97 rtcp_feedback_senders_.end(), rtcp_sender);
98 RTC_DCHECK(it != rtcp_feedback_senders_.end());
99 rtcp_feedback_senders_.erase(it);
Stefan Holmere5904162015-03-26 11:11:06 +0100100}
101
Erik Språngd2879622019-05-10 08:29:01 -0700102RtpPacketSendResult PacketRouter::TimeToSendPacket(
103 uint32_t ssrc,
104 uint16_t sequence_number,
105 int64_t capture_timestamp,
106 bool retransmission,
107 const PacedPacketInfo& pacing_info) {
stefanbba9dec2016-02-01 04:39:55 -0800108 rtc::CritScope cs(&modules_crit_);
nissefdbfdc92017-03-31 05:44:52 -0700109 for (auto* rtp_module : rtp_send_modules_) {
Erik Språng8b7ca4a2018-05-17 13:43:35 +0200110 if (!rtp_module->SendingMedia()) {
brandtr9dfff292016-11-14 05:14:50 -0800111 continue;
Erik Språng8b7ca4a2018-05-17 13:43:35 +0200112 }
brandtr9dfff292016-11-14 05:14:50 -0800113 if (ssrc == rtp_module->SSRC() || ssrc == rtp_module->FlexfecSsrc()) {
Erik Språng8b7ca4a2018-05-17 13:43:35 +0200114 if ((rtp_module->RtxSendStatus() & kRtxRedundantPayloads) &&
115 rtp_module->HasBweExtensions()) {
116 // This is now the last module to send media, and has the desired
117 // properties needed for payload based padding. Cache it for later use.
118 last_send_module_ = rtp_module;
119 }
Stefan Holmere5904162015-03-26 11:11:06 +0100120 return rtp_module->TimeToSendPacket(ssrc, sequence_number,
philipela1ed0b32016-06-01 06:31:17 -0700121 capture_timestamp, retransmission,
philipelc7bf32a2017-02-17 03:59:43 -0800122 pacing_info);
Stefan Holmere5904162015-03-26 11:11:06 +0100123 }
124 }
Erik Språngd2879622019-05-10 08:29:01 -0700125 return RtpPacketSendResult::kPacketNotFound;
Stefan Holmere5904162015-03-26 11:11:06 +0100126}
127
philipela1ed0b32016-06-01 06:31:17 -0700128size_t PacketRouter::TimeToSendPadding(size_t bytes_to_send,
philipelc7bf32a2017-02-17 03:59:43 -0800129 const PacedPacketInfo& pacing_info) {
sprang867fb522015-08-03 04:38:41 -0700130 size_t total_bytes_sent = 0;
stefanbba9dec2016-02-01 04:39:55 -0800131 rtc::CritScope cs(&modules_crit_);
Erik Språng8b7ca4a2018-05-17 13:43:35 +0200132 // First try on the last rtp module to have sent media. This increases the
133 // the chance that any payload based padding will be useful as it will be
134 // somewhat distributed over modules according the packet rate, even if it
135 // will be more skewed towards the highest bitrate stream. At the very least
136 // this prevents sending payload padding on a disabled stream where it's
137 // guaranteed not to be useful.
138 if (last_send_module_ != nullptr) {
139 RTC_DCHECK(std::find(rtp_send_modules_.begin(), rtp_send_modules_.end(),
140 last_send_module_) != rtp_send_modules_.end());
141 RTC_DCHECK(last_send_module_->HasBweExtensions());
142 total_bytes_sent += last_send_module_->TimeToSendPadding(
143 bytes_to_send - total_bytes_sent, pacing_info);
144 if (total_bytes_sent >= bytes_to_send) {
145 return total_bytes_sent;
146 }
147 }
148
stefan16b02212017-01-27 07:12:16 -0800149 // Rtp modules are ordered by which stream can most benefit from padding.
nissefdbfdc92017-03-31 05:44:52 -0700150 for (RtpRtcp* module : rtp_send_modules_) {
stefan53b6cc32017-02-03 08:13:57 -0800151 if (module->SendingMedia() && module->HasBweExtensions()) {
philipela1ed0b32016-06-01 06:31:17 -0700152 size_t bytes_sent = module->TimeToSendPadding(
philipelc7bf32a2017-02-17 03:59:43 -0800153 bytes_to_send - total_bytes_sent, pacing_info);
sprang867fb522015-08-03 04:38:41 -0700154 total_bytes_sent += bytes_sent;
155 if (total_bytes_sent >= bytes_to_send)
156 break;
157 }
Stefan Holmere5904162015-03-26 11:11:06 +0100158 }
sprang867fb522015-08-03 04:38:41 -0700159 return total_bytes_sent;
Stefan Holmere5904162015-03-26 11:11:06 +0100160}
sprang867fb522015-08-03 04:38:41 -0700161
162void PacketRouter::SetTransportWideSequenceNumber(uint16_t sequence_number) {
pbos46ad5422015-12-07 14:29:14 -0800163 rtc::AtomicOps::ReleaseStore(&transport_seq_, sequence_number);
sprang867fb522015-08-03 04:38:41 -0700164}
165
166uint16_t PacketRouter::AllocateSequenceNumber() {
pbos46ad5422015-12-07 14:29:14 -0800167 int prev_seq = rtc::AtomicOps::AcquireLoad(&transport_seq_);
sprang867fb522015-08-03 04:38:41 -0700168 int desired_prev_seq;
169 int new_seq;
170 do {
171 desired_prev_seq = prev_seq;
172 new_seq = (desired_prev_seq + 1) & 0xFFFF;
173 // Note: CompareAndSwap returns the actual value of transport_seq at the
174 // time the CAS operation was executed. Thus, if prev_seq is returned, the
175 // operation was successful - otherwise we need to retry. Saving the
176 // return value saves us a load on retry.
pbos46ad5422015-12-07 14:29:14 -0800177 prev_seq = rtc::AtomicOps::CompareAndSwap(&transport_seq_, desired_prev_seq,
sprang867fb522015-08-03 04:38:41 -0700178 new_seq);
179 } while (prev_seq != desired_prev_seq);
180
181 return new_seq;
182}
183
nisse05843312017-04-18 23:38:35 -0700184void PacketRouter::OnReceiveBitrateChanged(const std::vector<uint32_t>& ssrcs,
185 uint32_t bitrate_bps) {
nisse05843312017-04-18 23:38:35 -0700186 // % threshold for if we should send a new REMB asap.
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100187 const int64_t kSendThresholdPercent = 97;
188 // TODO(danilchap): Remove receive_bitrate_bps variable and the cast
189 // when OnReceiveBitrateChanged takes bitrate as int64_t.
190 int64_t receive_bitrate_bps = static_cast<int64_t>(bitrate_bps);
nisse05843312017-04-18 23:38:35 -0700191
192 int64_t now_ms = rtc::TimeMillis();
193 {
194 rtc::CritScope lock(&remb_crit_);
195
196 // If we already have an estimate, check if the new total estimate is below
197 // kSendThresholdPercent of the previous estimate.
198 if (last_send_bitrate_bps_ > 0) {
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100199 int64_t new_remb_bitrate_bps =
200 last_send_bitrate_bps_ - bitrate_bps_ + receive_bitrate_bps;
nisse05843312017-04-18 23:38:35 -0700201
202 if (new_remb_bitrate_bps <
203 kSendThresholdPercent * last_send_bitrate_bps_ / 100) {
204 // The new bitrate estimate is less than kSendThresholdPercent % of the
205 // last report. Send a REMB asap.
206 last_remb_time_ms_ = now_ms - kRembSendIntervalMs;
207 }
208 }
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100209 bitrate_bps_ = receive_bitrate_bps;
nisse05843312017-04-18 23:38:35 -0700210
211 if (now_ms - last_remb_time_ms_ < kRembSendIntervalMs) {
212 return;
213 }
214 // NOTE: Updated if we intend to send the data; we might not have
215 // a module to actually send it.
216 last_remb_time_ms_ = now_ms;
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100217 last_send_bitrate_bps_ = receive_bitrate_bps;
danilchap47085372017-08-10 06:03:57 -0700218 // Cap the value to send in remb with configured value.
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100219 receive_bitrate_bps = std::min(receive_bitrate_bps, max_bitrate_bps_);
nisse05843312017-04-18 23:38:35 -0700220 }
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100221 SendRemb(receive_bitrate_bps, ssrcs);
nisse05843312017-04-18 23:38:35 -0700222}
223
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100224void PacketRouter::SetMaxDesiredReceiveBitrate(int64_t bitrate_bps) {
225 RTC_DCHECK_GE(bitrate_bps, 0);
danilchap47085372017-08-10 06:03:57 -0700226 {
227 rtc::CritScope lock(&remb_crit_);
228 max_bitrate_bps_ = bitrate_bps;
229 if (rtc::TimeMillis() - last_remb_time_ms_ < kRembSendIntervalMs &&
230 last_send_bitrate_bps_ > 0 &&
231 last_send_bitrate_bps_ <= max_bitrate_bps_) {
232 // Recent measured bitrate is already below the cap.
233 return;
234 }
235 }
236 SendRemb(bitrate_bps, /*ssrcs=*/{});
237}
238
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100239bool PacketRouter::SendRemb(int64_t bitrate_bps,
nisse05843312017-04-18 23:38:35 -0700240 const std::vector<uint32_t>& ssrcs) {
241 rtc::CritScope lock(&modules_crit_);
eladalon822ff2b2017-08-01 06:30:28 -0700242
243 if (!active_remb_module_) {
nisse05843312017-04-18 23:38:35 -0700244 return false;
eladalon822ff2b2017-08-01 06:30:28 -0700245 }
246
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200247 // The Add* and Remove* methods above ensure that REMB is disabled on all
248 // other modules, because otherwise, they will send REMB with stale info.
249 active_remb_module_->SetRemb(bitrate_bps, ssrcs);
eladalon822ff2b2017-08-01 06:30:28 -0700250
nisse05843312017-04-18 23:38:35 -0700251 return true;
252}
253
254bool PacketRouter::SendTransportFeedback(rtcp::TransportFeedback* packet) {
stefanbba9dec2016-02-01 04:39:55 -0800255 rtc::CritScope cs(&modules_crit_);
nissefdbfdc92017-03-31 05:44:52 -0700256 // Prefer send modules.
257 for (auto* rtp_module : rtp_send_modules_) {
258 packet->SetSenderSsrc(rtp_module->SSRC());
Erik Språng8b7ca4a2018-05-17 13:43:35 +0200259 if (rtp_module->SendFeedbackPacket(*packet)) {
nissefdbfdc92017-03-31 05:44:52 -0700260 return true;
Erik Språng8b7ca4a2018-05-17 13:43:35 +0200261 }
nissefdbfdc92017-03-31 05:44:52 -0700262 }
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100263 for (auto* rtcp_sender : rtcp_feedback_senders_) {
264 packet->SetSenderSsrc(rtcp_sender->SSRC());
Erik Språng8b7ca4a2018-05-17 13:43:35 +0200265 if (rtcp_sender->SendFeedbackPacket(*packet)) {
Peter Boström3dd5d1d2016-02-25 16:56:48 +0100266 return true;
Erik Språng8b7ca4a2018-05-17 13:43:35 +0200267 }
Peter Boström3dd5d1d2016-02-25 16:56:48 +0100268 }
sprang233bd872015-09-08 13:25:16 -0700269 return false;
270}
271
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100272void PacketRouter::AddRembModuleCandidate(
273 RtcpFeedbackSenderInterface* candidate_module,
274 bool media_sender) {
eladalon822ff2b2017-08-01 06:30:28 -0700275 RTC_DCHECK(candidate_module);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100276 std::vector<RtcpFeedbackSenderInterface*>& candidates =
277 media_sender ? sender_remb_candidates_ : receiver_remb_candidates_;
eladalon822ff2b2017-08-01 06:30:28 -0700278 RTC_DCHECK(std::find(candidates.cbegin(), candidates.cend(),
279 candidate_module) == candidates.cend());
280 candidates.push_back(candidate_module);
281 DetermineActiveRembModule();
282}
283
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100284void PacketRouter::MaybeRemoveRembModuleCandidate(
285 RtcpFeedbackSenderInterface* candidate_module,
286 bool media_sender) {
eladalon822ff2b2017-08-01 06:30:28 -0700287 RTC_DCHECK(candidate_module);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100288 std::vector<RtcpFeedbackSenderInterface*>& candidates =
289 media_sender ? sender_remb_candidates_ : receiver_remb_candidates_;
eladalon822ff2b2017-08-01 06:30:28 -0700290 auto it = std::find(candidates.begin(), candidates.end(), candidate_module);
291
292 if (it == candidates.end()) {
293 return; // Function called due to removal of non-REMB-candidate module.
294 }
295
296 if (*it == active_remb_module_) {
297 UnsetActiveRembModule();
298 }
299 candidates.erase(it);
300 DetermineActiveRembModule();
301}
302
303void PacketRouter::UnsetActiveRembModule() {
304 RTC_CHECK(active_remb_module_);
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200305 active_remb_module_->UnsetRemb();
eladalon822ff2b2017-08-01 06:30:28 -0700306 active_remb_module_ = nullptr;
307}
308
309void PacketRouter::DetermineActiveRembModule() {
310 // Sender modules take precedence over receiver modules, because SRs (sender
311 // reports) are sent more frequently than RR (receiver reports).
312 // When adding the first sender module, we should change the active REMB
313 // module to be that. Otherwise, we remain with the current active module.
314
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100315 RtcpFeedbackSenderInterface* new_active_remb_module;
eladalon822ff2b2017-08-01 06:30:28 -0700316
317 if (!sender_remb_candidates_.empty()) {
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200318 new_active_remb_module = sender_remb_candidates_.front();
eladalon822ff2b2017-08-01 06:30:28 -0700319 } else if (!receiver_remb_candidates_.empty()) {
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200320 new_active_remb_module = receiver_remb_candidates_.front();
eladalon822ff2b2017-08-01 06:30:28 -0700321 } else {
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200322 new_active_remb_module = nullptr;
eladalon822ff2b2017-08-01 06:30:28 -0700323 }
324
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200325 if (new_active_remb_module != active_remb_module_ && active_remb_module_) {
326 UnsetActiveRembModule();
eladalon822ff2b2017-08-01 06:30:28 -0700327 }
328
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200329 active_remb_module_ = new_active_remb_module;
eladalon822ff2b2017-08-01 06:30:28 -0700330}
331
Stefan Holmere5904162015-03-26 11:11:06 +0100332} // namespace webrtc