blob: c280299950a8ec1d18c3982b7c0b4c210c9b484c [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ång13a8e162019-10-21 19:39:57 +0200136 packet->SetExtension<TransportSequenceNumber>((++transport_seq_) & 0xFFFF);
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
Erik Språng5f01bf62019-10-16 17:06:34 +0200193uint16_t PacketRouter::CurrentTransportSequenceNumber() const {
194 rtc::CritScope lock(&modules_crit_);
Erik Språng13a8e162019-10-21 19:39:57 +0200195 return transport_seq_ & 0xFFFF;
sprang867fb522015-08-03 04:38:41 -0700196}
197
nisse05843312017-04-18 23:38:35 -0700198void PacketRouter::OnReceiveBitrateChanged(const std::vector<uint32_t>& ssrcs,
199 uint32_t bitrate_bps) {
nisse05843312017-04-18 23:38:35 -0700200 // % threshold for if we should send a new REMB asap.
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100201 const int64_t kSendThresholdPercent = 97;
202 // TODO(danilchap): Remove receive_bitrate_bps variable and the cast
203 // when OnReceiveBitrateChanged takes bitrate as int64_t.
204 int64_t receive_bitrate_bps = static_cast<int64_t>(bitrate_bps);
nisse05843312017-04-18 23:38:35 -0700205
206 int64_t now_ms = rtc::TimeMillis();
207 {
208 rtc::CritScope lock(&remb_crit_);
209
210 // If we already have an estimate, check if the new total estimate is below
211 // kSendThresholdPercent of the previous estimate.
212 if (last_send_bitrate_bps_ > 0) {
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100213 int64_t new_remb_bitrate_bps =
214 last_send_bitrate_bps_ - bitrate_bps_ + receive_bitrate_bps;
nisse05843312017-04-18 23:38:35 -0700215
216 if (new_remb_bitrate_bps <
217 kSendThresholdPercent * last_send_bitrate_bps_ / 100) {
218 // The new bitrate estimate is less than kSendThresholdPercent % of the
219 // last report. Send a REMB asap.
220 last_remb_time_ms_ = now_ms - kRembSendIntervalMs;
221 }
222 }
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100223 bitrate_bps_ = receive_bitrate_bps;
nisse05843312017-04-18 23:38:35 -0700224
225 if (now_ms - last_remb_time_ms_ < kRembSendIntervalMs) {
226 return;
227 }
228 // NOTE: Updated if we intend to send the data; we might not have
229 // a module to actually send it.
230 last_remb_time_ms_ = now_ms;
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100231 last_send_bitrate_bps_ = receive_bitrate_bps;
danilchap47085372017-08-10 06:03:57 -0700232 // Cap the value to send in remb with configured value.
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100233 receive_bitrate_bps = std::min(receive_bitrate_bps, max_bitrate_bps_);
nisse05843312017-04-18 23:38:35 -0700234 }
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100235 SendRemb(receive_bitrate_bps, ssrcs);
nisse05843312017-04-18 23:38:35 -0700236}
237
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100238void PacketRouter::SetMaxDesiredReceiveBitrate(int64_t bitrate_bps) {
239 RTC_DCHECK_GE(bitrate_bps, 0);
danilchap47085372017-08-10 06:03:57 -0700240 {
241 rtc::CritScope lock(&remb_crit_);
242 max_bitrate_bps_ = bitrate_bps;
243 if (rtc::TimeMillis() - last_remb_time_ms_ < kRembSendIntervalMs &&
244 last_send_bitrate_bps_ > 0 &&
245 last_send_bitrate_bps_ <= max_bitrate_bps_) {
246 // Recent measured bitrate is already below the cap.
247 return;
248 }
249 }
250 SendRemb(bitrate_bps, /*ssrcs=*/{});
251}
252
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100253bool PacketRouter::SendRemb(int64_t bitrate_bps,
nisse05843312017-04-18 23:38:35 -0700254 const std::vector<uint32_t>& ssrcs) {
255 rtc::CritScope lock(&modules_crit_);
eladalon822ff2b2017-08-01 06:30:28 -0700256
257 if (!active_remb_module_) {
nisse05843312017-04-18 23:38:35 -0700258 return false;
eladalon822ff2b2017-08-01 06:30:28 -0700259 }
260
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200261 // The Add* and Remove* methods above ensure that REMB is disabled on all
262 // other modules, because otherwise, they will send REMB with stale info.
263 active_remb_module_->SetRemb(bitrate_bps, ssrcs);
eladalon822ff2b2017-08-01 06:30:28 -0700264
nisse05843312017-04-18 23:38:35 -0700265 return true;
266}
267
Per Kjellanderee153c92019-10-10 16:43:46 +0200268bool PacketRouter::SendCombinedRtcpPacket(
269 std::vector<std::unique_ptr<rtcp::RtcpPacket>> packets) {
stefanbba9dec2016-02-01 04:39:55 -0800270 rtc::CritScope cs(&modules_crit_);
Per Kjellanderee153c92019-10-10 16:43:46 +0200271
nissefdbfdc92017-03-31 05:44:52 -0700272 // Prefer send modules.
Erik Språngc06aef22019-10-17 13:02:27 +0200273 for (RtpRtcp* rtp_module : send_modules_list_) {
Per Kjellanderee153c92019-10-10 16:43:46 +0200274 if (rtp_module->RTCP() == RtcpMode::kOff) {
275 continue;
Erik Språng8b7ca4a2018-05-17 13:43:35 +0200276 }
Per Kjellanderee153c92019-10-10 16:43:46 +0200277 rtp_module->SendCombinedRtcpPacket(std::move(packets));
278 return true;
nissefdbfdc92017-03-31 05:44:52 -0700279 }
sprang233bd872015-09-08 13:25:16 -0700280
Per Kjellanderee153c92019-10-10 16:43:46 +0200281 if (rtcp_feedback_senders_.empty()) {
282 return false;
Per Kjellander52f7ae72019-09-10 19:28:06 +0200283 }
Per Kjellanderee153c92019-10-10 16:43:46 +0200284 auto* rtcp_sender = rtcp_feedback_senders_[0];
285 rtcp_sender->SendCombinedRtcpPacket(std::move(packets));
286 return true;
Per Kjellander52f7ae72019-09-10 19:28:06 +0200287}
288
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100289void PacketRouter::AddRembModuleCandidate(
290 RtcpFeedbackSenderInterface* candidate_module,
291 bool media_sender) {
eladalon822ff2b2017-08-01 06:30:28 -0700292 RTC_DCHECK(candidate_module);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100293 std::vector<RtcpFeedbackSenderInterface*>& candidates =
294 media_sender ? sender_remb_candidates_ : receiver_remb_candidates_;
eladalon822ff2b2017-08-01 06:30:28 -0700295 RTC_DCHECK(std::find(candidates.cbegin(), candidates.cend(),
296 candidate_module) == candidates.cend());
297 candidates.push_back(candidate_module);
298 DetermineActiveRembModule();
299}
300
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100301void PacketRouter::MaybeRemoveRembModuleCandidate(
302 RtcpFeedbackSenderInterface* candidate_module,
303 bool media_sender) {
eladalon822ff2b2017-08-01 06:30:28 -0700304 RTC_DCHECK(candidate_module);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100305 std::vector<RtcpFeedbackSenderInterface*>& candidates =
306 media_sender ? sender_remb_candidates_ : receiver_remb_candidates_;
eladalon822ff2b2017-08-01 06:30:28 -0700307 auto it = std::find(candidates.begin(), candidates.end(), candidate_module);
308
309 if (it == candidates.end()) {
310 return; // Function called due to removal of non-REMB-candidate module.
311 }
312
313 if (*it == active_remb_module_) {
314 UnsetActiveRembModule();
315 }
316 candidates.erase(it);
317 DetermineActiveRembModule();
318}
319
320void PacketRouter::UnsetActiveRembModule() {
321 RTC_CHECK(active_remb_module_);
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200322 active_remb_module_->UnsetRemb();
eladalon822ff2b2017-08-01 06:30:28 -0700323 active_remb_module_ = nullptr;
324}
325
326void PacketRouter::DetermineActiveRembModule() {
327 // Sender modules take precedence over receiver modules, because SRs (sender
328 // reports) are sent more frequently than RR (receiver reports).
329 // When adding the first sender module, we should change the active REMB
330 // module to be that. Otherwise, we remain with the current active module.
331
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100332 RtcpFeedbackSenderInterface* new_active_remb_module;
eladalon822ff2b2017-08-01 06:30:28 -0700333
334 if (!sender_remb_candidates_.empty()) {
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200335 new_active_remb_module = sender_remb_candidates_.front();
eladalon822ff2b2017-08-01 06:30:28 -0700336 } else if (!receiver_remb_candidates_.empty()) {
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200337 new_active_remb_module = receiver_remb_candidates_.front();
eladalon822ff2b2017-08-01 06:30:28 -0700338 } else {
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200339 new_active_remb_module = nullptr;
eladalon822ff2b2017-08-01 06:30:28 -0700340 }
341
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200342 if (new_active_remb_module != active_remb_module_ && active_remb_module_) {
343 UnsetActiveRembModule();
eladalon822ff2b2017-08-01 06:30:28 -0700344 }
345
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200346 active_remb_module_ = new_active_remb_module;
eladalon822ff2b2017-08-01 06:30:28 -0700347}
348
Stefan Holmere5904162015-03-26 11:11:06 +0100349} // namespace webrtc