blob: 8edfd1fe282e112a0c299b51c65f1404587b7df4 [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>
Per Kjellanderee153c92019-10-10 16:43:46 +020016#include <memory>
Erik Språng58ee1872019-06-18 16:20:11 +020017#include <utility>
danilchap47085372017-08-10 06:03:57 -070018
Yves Gerey988cc082018-10-23 12:03:01 +020019#include "absl/types/optional.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "modules/rtp_rtcp/include/rtp_rtcp.h"
21#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
Per Kjellanderee153c92019-10-10 16:43:46 +020022#include "modules/rtp_rtcp/source/rtcp_packet.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "rtc_base/checks.h"
Erik Språng58ee1872019-06-18 16:20:11 +020025#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "rtc_base/time_utils.h"
Stefan Holmere5904162015-03-26 11:11:06 +010027
28namespace webrtc {
danilchap47085372017-08-10 06:03:57 -070029namespace {
30
31constexpr int kRembSendIntervalMs = 200;
32
33} // namespace
Stefan Holmere5904162015-03-26 11:11:06 +010034
Erik Språng5f01bf62019-10-16 17:06:34 +020035PacketRouter::PacketRouter() : PacketRouter(0) {}
36
37PacketRouter::PacketRouter(uint16_t start_transport_seq)
Erik Språng8b7ca4a2018-05-17 13:43:35 +020038 : last_send_module_(nullptr),
39 last_remb_time_ms_(rtc::TimeMillis()),
nisse05843312017-04-18 23:38:35 -070040 last_send_bitrate_bps_(0),
danilchap47085372017-08-10 06:03:57 -070041 bitrate_bps_(0),
42 max_bitrate_bps_(std::numeric_limits<decltype(max_bitrate_bps_)>::max()),
eladalon822ff2b2017-08-01 06:30:28 -070043 active_remb_module_(nullptr),
Erik Språng5f01bf62019-10-16 17:06:34 +020044 transport_seq_(start_transport_seq) {}
Stefan Holmere5904162015-03-26 11:11:06 +010045
46PacketRouter::~PacketRouter() {
Erik Språngc06aef22019-10-17 13:02:27 +020047 RTC_DCHECK(send_modules_map_.empty());
48 RTC_DCHECK(send_modules_list_.empty());
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010049 RTC_DCHECK(rtcp_feedback_senders_.empty());
eladalon822ff2b2017-08-01 06:30:28 -070050 RTC_DCHECK(sender_remb_candidates_.empty());
51 RTC_DCHECK(receiver_remb_candidates_.empty());
52 RTC_DCHECK(active_remb_module_ == nullptr);
Stefan Holmere5904162015-03-26 11:11:06 +010053}
54
eladalon822ff2b2017-08-01 06:30:28 -070055void PacketRouter::AddSendRtpModule(RtpRtcp* rtp_module, bool remb_candidate) {
stefanbba9dec2016-02-01 04:39:55 -080056 rtc::CritScope cs(&modules_crit_);
Erik Språngc06aef22019-10-17 13:02:27 +020057
58 AddSendRtpModuleToMap(rtp_module, rtp_module->SSRC());
59 if (absl::optional<uint32_t> rtx_ssrc = rtp_module->RtxSsrc()) {
60 AddSendRtpModuleToMap(rtp_module, *rtx_ssrc);
61 }
62 if (absl::optional<uint32_t> flexfec_ssrc = rtp_module->FlexfecSsrc()) {
63 AddSendRtpModuleToMap(rtp_module, *flexfec_ssrc);
64 }
65
Erik Språng4208a132019-08-26 08:58:45 +020066 if (rtp_module->SupportsRtxPayloadPadding()) {
Erik Språngc06aef22019-10-17 13:02:27 +020067 last_send_module_ = rtp_module;
stefan16b02212017-01-27 07:12:16 -080068 }
eladalon822ff2b2017-08-01 06:30:28 -070069
70 if (remb_candidate) {
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010071 AddRembModuleCandidate(rtp_module, /* media_sender = */ true);
eladalon822ff2b2017-08-01 06:30:28 -070072 }
Stefan Holmere5904162015-03-26 11:11:06 +010073}
74
Erik Språngc06aef22019-10-17 13:02:27 +020075void PacketRouter::AddSendRtpModuleToMap(RtpRtcp* rtp_module, uint32_t ssrc) {
76 RTC_DCHECK(send_modules_map_.find(ssrc) == send_modules_map_.end());
77 send_modules_list_.push_front(rtp_module);
78 send_modules_map_[ssrc] = std::pair<RtpRtcp*, std::list<RtpRtcp*>::iterator>(
79 rtp_module, send_modules_list_.begin());
80}
81
82void PacketRouter::RemoveSendRtpModuleFromMap(uint32_t ssrc) {
83 auto kv = send_modules_map_.find(ssrc);
84 RTC_DCHECK(kv != send_modules_map_.end());
85 send_modules_list_.erase(kv->second.second);
86 send_modules_map_.erase(kv);
87}
88
nissefdbfdc92017-03-31 05:44:52 -070089void PacketRouter::RemoveSendRtpModule(RtpRtcp* rtp_module) {
stefanbba9dec2016-02-01 04:39:55 -080090 rtc::CritScope cs(&modules_crit_);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010091 MaybeRemoveRembModuleCandidate(rtp_module, /* media_sender = */ true);
Erik Språngc06aef22019-10-17 13:02:27 +020092
93 RemoveSendRtpModuleFromMap(rtp_module->SSRC());
94 if (absl::optional<uint32_t> rtx_ssrc = rtp_module->RtxSsrc()) {
95 RemoveSendRtpModuleFromMap(*rtx_ssrc);
96 }
97 if (absl::optional<uint32_t> flexfec_ssrc = rtp_module->FlexfecSsrc()) {
98 RemoveSendRtpModuleFromMap(*flexfec_ssrc);
99 }
100
Erik Språng8b7ca4a2018-05-17 13:43:35 +0200101 if (last_send_module_ == rtp_module) {
102 last_send_module_ = nullptr;
103 }
nissefdbfdc92017-03-31 05:44:52 -0700104}
105
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100106void PacketRouter::AddReceiveRtpModule(RtcpFeedbackSenderInterface* rtcp_sender,
eladalon822ff2b2017-08-01 06:30:28 -0700107 bool remb_candidate) {
nissefdbfdc92017-03-31 05:44:52 -0700108 rtc::CritScope cs(&modules_crit_);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100109 RTC_DCHECK(std::find(rtcp_feedback_senders_.begin(),
110 rtcp_feedback_senders_.end(),
111 rtcp_sender) == rtcp_feedback_senders_.end());
eladalon822ff2b2017-08-01 06:30:28 -0700112
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100113 rtcp_feedback_senders_.push_back(rtcp_sender);
eladalon822ff2b2017-08-01 06:30:28 -0700114
115 if (remb_candidate) {
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100116 AddRembModuleCandidate(rtcp_sender, /* media_sender = */ false);
eladalon822ff2b2017-08-01 06:30:28 -0700117 }
nissefdbfdc92017-03-31 05:44:52 -0700118}
119
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100120void PacketRouter::RemoveReceiveRtpModule(
121 RtcpFeedbackSenderInterface* rtcp_sender) {
nissefdbfdc92017-03-31 05:44:52 -0700122 rtc::CritScope cs(&modules_crit_);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100123 MaybeRemoveRembModuleCandidate(rtcp_sender, /* media_sender = */ false);
124 auto it = std::find(rtcp_feedback_senders_.begin(),
125 rtcp_feedback_senders_.end(), rtcp_sender);
126 RTC_DCHECK(it != rtcp_feedback_senders_.end());
127 rtcp_feedback_senders_.erase(it);
Stefan Holmere5904162015-03-26 11:11:06 +0100128}
129
Erik Språng58ee1872019-06-18 16:20:11 +0200130void PacketRouter::SendPacket(std::unique_ptr<RtpPacketToSend> packet,
131 const PacedPacketInfo& cluster_info) {
132 rtc::CritScope cs(&modules_crit_);
Erik Språngf6468d22019-07-05 16:53:43 +0200133 // With the new pacer code path, transport sequence numbers are only set here,
134 // on the pacer thread. Therefore we don't need atomics/synchronization.
Erik Språng6cdab462019-07-15 19:40:13 +0200135 if (packet->IsExtensionReserved<TransportSequenceNumber>()) {
Erik Språng4208a132019-08-26 08:58:45 +0200136 packet->SetExtension<TransportSequenceNumber>(AllocateSequenceNumber());
Erik Språngf6468d22019-07-05 16:53:43 +0200137 }
Mirko Bonadei999a72a2019-07-12 17:33:46 +0000138
Erik Språngc06aef22019-10-17 13:02:27 +0200139 uint32_t ssrc = packet->Ssrc();
140 auto kv = send_modules_map_.find(ssrc);
141 if (kv == send_modules_map_.end()) {
142 RTC_LOG(LS_WARNING)
143 << "Failed to send packet, matching RTP module not found "
144 "or transport error. SSRC = "
145 << packet->Ssrc() << ", sequence number " << packet->SequenceNumber();
146 return;
Mirko Bonadei999a72a2019-07-12 17:33:46 +0000147 }
148
Erik Språngc06aef22019-10-17 13:02:27 +0200149 RtpRtcp* rtp_module = kv->second.first;
150 if (!rtp_module->TrySendPacket(packet.get(), cluster_info)) {
151 RTC_LOG(LS_WARNING) << "Failed to send packet, rejected by RTP module.";
152 return;
Erik Språng58ee1872019-06-18 16:20:11 +0200153 }
154
Erik Språngc06aef22019-10-17 13:02:27 +0200155 if (rtp_module->SupportsRtxPayloadPadding()) {
156 // This is now the last module to send media, and has the desired
157 // properties needed for payload based padding. Cache it for later use.
158 last_send_module_ = rtp_module;
159 }
Erik Språng58ee1872019-06-18 16:20:11 +0200160}
161
Erik Språngf6468d22019-07-05 16:53:43 +0200162std::vector<std::unique_ptr<RtpPacketToSend>> PacketRouter::GeneratePadding(
163 size_t target_size_bytes) {
Erik Språng478cb462019-06-26 15:49:27 +0200164 rtc::CritScope cs(&modules_crit_);
165 // First try on the last rtp module to have sent media. This increases the
166 // the chance that any payload based padding will be useful as it will be
167 // somewhat distributed over modules according the packet rate, even if it
168 // will be more skewed towards the highest bitrate stream. At the very least
169 // this prevents sending payload padding on a disabled stream where it's
170 // guaranteed not to be useful.
Erik Språngc06aef22019-10-17 13:02:27 +0200171 std::vector<std::unique_ptr<RtpPacketToSend>> padding_packets;
Mirko Bonadei999a72a2019-07-12 17:33:46 +0000172 if (last_send_module_ != nullptr &&
173 last_send_module_->SupportsRtxPayloadPadding()) {
Erik Språngc06aef22019-10-17 13:02:27 +0200174 padding_packets = last_send_module_->GeneratePadding(target_size_bytes);
175 if (!padding_packets.empty()) {
Mirko Bonadei999a72a2019-07-12 17:33:46 +0000176 return padding_packets;
Erik Språng478cb462019-06-26 15:49:27 +0200177 }
178 }
Erik Språngf6468d22019-07-05 16:53:43 +0200179
Erik Språngc06aef22019-10-17 13:02:27 +0200180 for (RtpRtcp* rtp_module : send_modules_list_) {
181 if (rtp_module->SupportsPadding()) {
182 padding_packets = rtp_module->GeneratePadding(target_size_bytes);
183 if (!padding_packets.empty()) {
184 last_send_module_ = rtp_module;
185 break;
186 }
187 }
188 }
189
190 return padding_packets;
Erik Språng478cb462019-06-26 15:49:27 +0200191}
192
sprang867fb522015-08-03 04:38:41 -0700193void PacketRouter::SetTransportWideSequenceNumber(uint16_t sequence_number) {
Erik Språng5f01bf62019-10-16 17:06:34 +0200194 rtc::CritScope lock(&modules_crit_);
195 transport_seq_ = sequence_number;
sprang867fb522015-08-03 04:38:41 -0700196}
197
198uint16_t PacketRouter::AllocateSequenceNumber() {
Erik Språng5f01bf62019-10-16 17:06:34 +0200199 rtc::CritScope lock(&modules_crit_);
200 transport_seq_ = (transport_seq_ + 1) & 0xFFFF;
201 return transport_seq_;
202}
sprang867fb522015-08-03 04:38:41 -0700203
Erik Språng5f01bf62019-10-16 17:06:34 +0200204uint16_t PacketRouter::CurrentTransportSequenceNumber() const {
205 rtc::CritScope lock(&modules_crit_);
206 return transport_seq_;
sprang867fb522015-08-03 04:38:41 -0700207}
208
nisse05843312017-04-18 23:38:35 -0700209void PacketRouter::OnReceiveBitrateChanged(const std::vector<uint32_t>& ssrcs,
210 uint32_t bitrate_bps) {
nisse05843312017-04-18 23:38:35 -0700211 // % threshold for if we should send a new REMB asap.
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100212 const int64_t kSendThresholdPercent = 97;
213 // TODO(danilchap): Remove receive_bitrate_bps variable and the cast
214 // when OnReceiveBitrateChanged takes bitrate as int64_t.
215 int64_t receive_bitrate_bps = static_cast<int64_t>(bitrate_bps);
nisse05843312017-04-18 23:38:35 -0700216
217 int64_t now_ms = rtc::TimeMillis();
218 {
219 rtc::CritScope lock(&remb_crit_);
220
221 // If we already have an estimate, check if the new total estimate is below
222 // kSendThresholdPercent of the previous estimate.
223 if (last_send_bitrate_bps_ > 0) {
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100224 int64_t new_remb_bitrate_bps =
225 last_send_bitrate_bps_ - bitrate_bps_ + receive_bitrate_bps;
nisse05843312017-04-18 23:38:35 -0700226
227 if (new_remb_bitrate_bps <
228 kSendThresholdPercent * last_send_bitrate_bps_ / 100) {
229 // The new bitrate estimate is less than kSendThresholdPercent % of the
230 // last report. Send a REMB asap.
231 last_remb_time_ms_ = now_ms - kRembSendIntervalMs;
232 }
233 }
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100234 bitrate_bps_ = receive_bitrate_bps;
nisse05843312017-04-18 23:38:35 -0700235
236 if (now_ms - last_remb_time_ms_ < kRembSendIntervalMs) {
237 return;
238 }
239 // NOTE: Updated if we intend to send the data; we might not have
240 // a module to actually send it.
241 last_remb_time_ms_ = now_ms;
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100242 last_send_bitrate_bps_ = receive_bitrate_bps;
danilchap47085372017-08-10 06:03:57 -0700243 // Cap the value to send in remb with configured value.
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100244 receive_bitrate_bps = std::min(receive_bitrate_bps, max_bitrate_bps_);
nisse05843312017-04-18 23:38:35 -0700245 }
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100246 SendRemb(receive_bitrate_bps, ssrcs);
nisse05843312017-04-18 23:38:35 -0700247}
248
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100249void PacketRouter::SetMaxDesiredReceiveBitrate(int64_t bitrate_bps) {
250 RTC_DCHECK_GE(bitrate_bps, 0);
danilchap47085372017-08-10 06:03:57 -0700251 {
252 rtc::CritScope lock(&remb_crit_);
253 max_bitrate_bps_ = bitrate_bps;
254 if (rtc::TimeMillis() - last_remb_time_ms_ < kRembSendIntervalMs &&
255 last_send_bitrate_bps_ > 0 &&
256 last_send_bitrate_bps_ <= max_bitrate_bps_) {
257 // Recent measured bitrate is already below the cap.
258 return;
259 }
260 }
261 SendRemb(bitrate_bps, /*ssrcs=*/{});
262}
263
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100264bool PacketRouter::SendRemb(int64_t bitrate_bps,
nisse05843312017-04-18 23:38:35 -0700265 const std::vector<uint32_t>& ssrcs) {
266 rtc::CritScope lock(&modules_crit_);
eladalon822ff2b2017-08-01 06:30:28 -0700267
268 if (!active_remb_module_) {
nisse05843312017-04-18 23:38:35 -0700269 return false;
eladalon822ff2b2017-08-01 06:30:28 -0700270 }
271
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200272 // The Add* and Remove* methods above ensure that REMB is disabled on all
273 // other modules, because otherwise, they will send REMB with stale info.
274 active_remb_module_->SetRemb(bitrate_bps, ssrcs);
eladalon822ff2b2017-08-01 06:30:28 -0700275
nisse05843312017-04-18 23:38:35 -0700276 return true;
277}
278
Per Kjellanderee153c92019-10-10 16:43:46 +0200279bool PacketRouter::SendCombinedRtcpPacket(
280 std::vector<std::unique_ptr<rtcp::RtcpPacket>> packets) {
stefanbba9dec2016-02-01 04:39:55 -0800281 rtc::CritScope cs(&modules_crit_);
Per Kjellanderee153c92019-10-10 16:43:46 +0200282
nissefdbfdc92017-03-31 05:44:52 -0700283 // Prefer send modules.
Erik Språngc06aef22019-10-17 13:02:27 +0200284 for (RtpRtcp* rtp_module : send_modules_list_) {
Per Kjellanderee153c92019-10-10 16:43:46 +0200285 if (rtp_module->RTCP() == RtcpMode::kOff) {
286 continue;
Erik Språng8b7ca4a2018-05-17 13:43:35 +0200287 }
Per Kjellanderee153c92019-10-10 16:43:46 +0200288 rtp_module->SendCombinedRtcpPacket(std::move(packets));
289 return true;
nissefdbfdc92017-03-31 05:44:52 -0700290 }
sprang233bd872015-09-08 13:25:16 -0700291
Per Kjellanderee153c92019-10-10 16:43:46 +0200292 if (rtcp_feedback_senders_.empty()) {
293 return false;
Per Kjellander52f7ae72019-09-10 19:28:06 +0200294 }
Per Kjellanderee153c92019-10-10 16:43:46 +0200295 auto* rtcp_sender = rtcp_feedback_senders_[0];
296 rtcp_sender->SendCombinedRtcpPacket(std::move(packets));
297 return true;
Per Kjellander52f7ae72019-09-10 19:28:06 +0200298}
299
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100300void PacketRouter::AddRembModuleCandidate(
301 RtcpFeedbackSenderInterface* candidate_module,
302 bool media_sender) {
eladalon822ff2b2017-08-01 06:30:28 -0700303 RTC_DCHECK(candidate_module);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100304 std::vector<RtcpFeedbackSenderInterface*>& candidates =
305 media_sender ? sender_remb_candidates_ : receiver_remb_candidates_;
eladalon822ff2b2017-08-01 06:30:28 -0700306 RTC_DCHECK(std::find(candidates.cbegin(), candidates.cend(),
307 candidate_module) == candidates.cend());
308 candidates.push_back(candidate_module);
309 DetermineActiveRembModule();
310}
311
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100312void PacketRouter::MaybeRemoveRembModuleCandidate(
313 RtcpFeedbackSenderInterface* candidate_module,
314 bool media_sender) {
eladalon822ff2b2017-08-01 06:30:28 -0700315 RTC_DCHECK(candidate_module);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100316 std::vector<RtcpFeedbackSenderInterface*>& candidates =
317 media_sender ? sender_remb_candidates_ : receiver_remb_candidates_;
eladalon822ff2b2017-08-01 06:30:28 -0700318 auto it = std::find(candidates.begin(), candidates.end(), candidate_module);
319
320 if (it == candidates.end()) {
321 return; // Function called due to removal of non-REMB-candidate module.
322 }
323
324 if (*it == active_remb_module_) {
325 UnsetActiveRembModule();
326 }
327 candidates.erase(it);
328 DetermineActiveRembModule();
329}
330
331void PacketRouter::UnsetActiveRembModule() {
332 RTC_CHECK(active_remb_module_);
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200333 active_remb_module_->UnsetRemb();
eladalon822ff2b2017-08-01 06:30:28 -0700334 active_remb_module_ = nullptr;
335}
336
337void PacketRouter::DetermineActiveRembModule() {
338 // Sender modules take precedence over receiver modules, because SRs (sender
339 // reports) are sent more frequently than RR (receiver reports).
340 // When adding the first sender module, we should change the active REMB
341 // module to be that. Otherwise, we remain with the current active module.
342
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100343 RtcpFeedbackSenderInterface* new_active_remb_module;
eladalon822ff2b2017-08-01 06:30:28 -0700344
345 if (!sender_remb_candidates_.empty()) {
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200346 new_active_remb_module = sender_remb_candidates_.front();
eladalon822ff2b2017-08-01 06:30:28 -0700347 } else if (!receiver_remb_candidates_.empty()) {
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200348 new_active_remb_module = receiver_remb_candidates_.front();
eladalon822ff2b2017-08-01 06:30:28 -0700349 } else {
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200350 new_active_remb_module = nullptr;
eladalon822ff2b2017-08-01 06:30:28 -0700351 }
352
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200353 if (new_active_remb_module != active_remb_module_ && active_remb_module_) {
354 UnsetActiveRembModule();
eladalon822ff2b2017-08-01 06:30:28 -0700355 }
356
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200357 active_remb_module_ = new_active_remb_module;
eladalon822ff2b2017-08-01 06:30:28 -0700358}
359
Stefan Holmere5904162015-03-26 11:11:06 +0100360} // namespace webrtc