blob: e3d935e65c892c5d1b09ea2c2ff4554926a7e9fb [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());
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010040 RTC_DCHECK(rtcp_feedback_senders_.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) {
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010059 AddRembModuleCandidate(rtp_module, /* media_sender = */ true);
eladalon822ff2b2017-08-01 06:30:28 -070060 }
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_);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010065 MaybeRemoveRembModuleCandidate(rtp_module, /* media_sender = */ true);
eladalon822ff2b2017-08-01 06:30:28 -070066 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
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010072void PacketRouter::AddReceiveRtpModule(RtcpFeedbackSenderInterface* rtcp_sender,
eladalon822ff2b2017-08-01 06:30:28 -070073 bool remb_candidate) {
nissefdbfdc92017-03-31 05:44:52 -070074 rtc::CritScope cs(&modules_crit_);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010075 RTC_DCHECK(std::find(rtcp_feedback_senders_.begin(),
76 rtcp_feedback_senders_.end(),
77 rtcp_sender) == rtcp_feedback_senders_.end());
eladalon822ff2b2017-08-01 06:30:28 -070078
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010079 rtcp_feedback_senders_.push_back(rtcp_sender);
eladalon822ff2b2017-08-01 06:30:28 -070080
81 if (remb_candidate) {
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010082 AddRembModuleCandidate(rtcp_sender, /* media_sender = */ false);
eladalon822ff2b2017-08-01 06:30:28 -070083 }
nissefdbfdc92017-03-31 05:44:52 -070084}
85
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010086void PacketRouter::RemoveReceiveRtpModule(
87 RtcpFeedbackSenderInterface* rtcp_sender) {
nissefdbfdc92017-03-31 05:44:52 -070088 rtc::CritScope cs(&modules_crit_);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010089 MaybeRemoveRembModuleCandidate(rtcp_sender, /* media_sender = */ false);
90 auto it = std::find(rtcp_feedback_senders_.begin(),
91 rtcp_feedback_senders_.end(), rtcp_sender);
92 RTC_DCHECK(it != rtcp_feedback_senders_.end());
93 rtcp_feedback_senders_.erase(it);
Stefan Holmere5904162015-03-26 11:11:06 +010094}
95
96bool PacketRouter::TimeToSendPacket(uint32_t ssrc,
97 uint16_t sequence_number,
98 int64_t capture_timestamp,
philipel29dca2c2016-05-13 11:13:05 +020099 bool retransmission,
philipelc7bf32a2017-02-17 03:59:43 -0800100 const PacedPacketInfo& pacing_info) {
erikvargabf5a2fc2017-06-16 05:02:05 -0700101 RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
stefanbba9dec2016-02-01 04:39:55 -0800102 rtc::CritScope cs(&modules_crit_);
nissefdbfdc92017-03-31 05:44:52 -0700103 for (auto* rtp_module : rtp_send_modules_) {
brandtr9dfff292016-11-14 05:14:50 -0800104 if (!rtp_module->SendingMedia())
105 continue;
106 if (ssrc == rtp_module->SSRC() || ssrc == rtp_module->FlexfecSsrc()) {
Stefan Holmere5904162015-03-26 11:11:06 +0100107 return rtp_module->TimeToSendPacket(ssrc, sequence_number,
philipela1ed0b32016-06-01 06:31:17 -0700108 capture_timestamp, retransmission,
philipelc7bf32a2017-02-17 03:59:43 -0800109 pacing_info);
Stefan Holmere5904162015-03-26 11:11:06 +0100110 }
111 }
112 return true;
113}
114
philipela1ed0b32016-06-01 06:31:17 -0700115size_t PacketRouter::TimeToSendPadding(size_t bytes_to_send,
philipelc7bf32a2017-02-17 03:59:43 -0800116 const PacedPacketInfo& pacing_info) {
erikvargabf5a2fc2017-06-16 05:02:05 -0700117 RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
sprang867fb522015-08-03 04:38:41 -0700118 size_t total_bytes_sent = 0;
stefanbba9dec2016-02-01 04:39:55 -0800119 rtc::CritScope cs(&modules_crit_);
stefan16b02212017-01-27 07:12:16 -0800120 // Rtp modules are ordered by which stream can most benefit from padding.
nissefdbfdc92017-03-31 05:44:52 -0700121 for (RtpRtcp* module : rtp_send_modules_) {
stefan53b6cc32017-02-03 08:13:57 -0800122 if (module->SendingMedia() && module->HasBweExtensions()) {
philipela1ed0b32016-06-01 06:31:17 -0700123 size_t bytes_sent = module->TimeToSendPadding(
philipelc7bf32a2017-02-17 03:59:43 -0800124 bytes_to_send - total_bytes_sent, pacing_info);
sprang867fb522015-08-03 04:38:41 -0700125 total_bytes_sent += bytes_sent;
126 if (total_bytes_sent >= bytes_to_send)
127 break;
128 }
Stefan Holmere5904162015-03-26 11:11:06 +0100129 }
sprang867fb522015-08-03 04:38:41 -0700130 return total_bytes_sent;
Stefan Holmere5904162015-03-26 11:11:06 +0100131}
sprang867fb522015-08-03 04:38:41 -0700132
133void PacketRouter::SetTransportWideSequenceNumber(uint16_t sequence_number) {
pbos46ad5422015-12-07 14:29:14 -0800134 rtc::AtomicOps::ReleaseStore(&transport_seq_, sequence_number);
sprang867fb522015-08-03 04:38:41 -0700135}
136
137uint16_t PacketRouter::AllocateSequenceNumber() {
pbos46ad5422015-12-07 14:29:14 -0800138 int prev_seq = rtc::AtomicOps::AcquireLoad(&transport_seq_);
sprang867fb522015-08-03 04:38:41 -0700139 int desired_prev_seq;
140 int new_seq;
141 do {
142 desired_prev_seq = prev_seq;
143 new_seq = (desired_prev_seq + 1) & 0xFFFF;
144 // Note: CompareAndSwap returns the actual value of transport_seq at the
145 // time the CAS operation was executed. Thus, if prev_seq is returned, the
146 // operation was successful - otherwise we need to retry. Saving the
147 // return value saves us a load on retry.
pbos46ad5422015-12-07 14:29:14 -0800148 prev_seq = rtc::AtomicOps::CompareAndSwap(&transport_seq_, desired_prev_seq,
sprang867fb522015-08-03 04:38:41 -0700149 new_seq);
150 } while (prev_seq != desired_prev_seq);
151
152 return new_seq;
153}
154
nisse05843312017-04-18 23:38:35 -0700155void PacketRouter::OnReceiveBitrateChanged(const std::vector<uint32_t>& ssrcs,
156 uint32_t bitrate_bps) {
nisse05843312017-04-18 23:38:35 -0700157 // % threshold for if we should send a new REMB asap.
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100158 const int64_t kSendThresholdPercent = 97;
159 // TODO(danilchap): Remove receive_bitrate_bps variable and the cast
160 // when OnReceiveBitrateChanged takes bitrate as int64_t.
161 int64_t receive_bitrate_bps = static_cast<int64_t>(bitrate_bps);
nisse05843312017-04-18 23:38:35 -0700162
163 int64_t now_ms = rtc::TimeMillis();
164 {
165 rtc::CritScope lock(&remb_crit_);
166
167 // If we already have an estimate, check if the new total estimate is below
168 // kSendThresholdPercent of the previous estimate.
169 if (last_send_bitrate_bps_ > 0) {
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100170 int64_t new_remb_bitrate_bps =
171 last_send_bitrate_bps_ - bitrate_bps_ + receive_bitrate_bps;
nisse05843312017-04-18 23:38:35 -0700172
173 if (new_remb_bitrate_bps <
174 kSendThresholdPercent * last_send_bitrate_bps_ / 100) {
175 // The new bitrate estimate is less than kSendThresholdPercent % of the
176 // last report. Send a REMB asap.
177 last_remb_time_ms_ = now_ms - kRembSendIntervalMs;
178 }
179 }
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100180 bitrate_bps_ = receive_bitrate_bps;
nisse05843312017-04-18 23:38:35 -0700181
182 if (now_ms - last_remb_time_ms_ < kRembSendIntervalMs) {
183 return;
184 }
185 // NOTE: Updated if we intend to send the data; we might not have
186 // a module to actually send it.
187 last_remb_time_ms_ = now_ms;
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100188 last_send_bitrate_bps_ = receive_bitrate_bps;
danilchap47085372017-08-10 06:03:57 -0700189 // Cap the value to send in remb with configured value.
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100190 receive_bitrate_bps = std::min(receive_bitrate_bps, max_bitrate_bps_);
nisse05843312017-04-18 23:38:35 -0700191 }
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100192 SendRemb(receive_bitrate_bps, ssrcs);
nisse05843312017-04-18 23:38:35 -0700193}
194
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100195void PacketRouter::SetMaxDesiredReceiveBitrate(int64_t bitrate_bps) {
196 RTC_DCHECK_GE(bitrate_bps, 0);
danilchap47085372017-08-10 06:03:57 -0700197 {
198 rtc::CritScope lock(&remb_crit_);
199 max_bitrate_bps_ = bitrate_bps;
200 if (rtc::TimeMillis() - last_remb_time_ms_ < kRembSendIntervalMs &&
201 last_send_bitrate_bps_ > 0 &&
202 last_send_bitrate_bps_ <= max_bitrate_bps_) {
203 // Recent measured bitrate is already below the cap.
204 return;
205 }
206 }
207 SendRemb(bitrate_bps, /*ssrcs=*/{});
208}
209
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100210bool PacketRouter::SendRemb(int64_t bitrate_bps,
nisse05843312017-04-18 23:38:35 -0700211 const std::vector<uint32_t>& ssrcs) {
212 rtc::CritScope lock(&modules_crit_);
eladalon822ff2b2017-08-01 06:30:28 -0700213
214 if (!active_remb_module_) {
nisse05843312017-04-18 23:38:35 -0700215 return false;
eladalon822ff2b2017-08-01 06:30:28 -0700216 }
217
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200218 // The Add* and Remove* methods above ensure that REMB is disabled on all
219 // other modules, because otherwise, they will send REMB with stale info.
220 active_remb_module_->SetRemb(bitrate_bps, ssrcs);
eladalon822ff2b2017-08-01 06:30:28 -0700221
nisse05843312017-04-18 23:38:35 -0700222 return true;
223}
224
225bool PacketRouter::SendTransportFeedback(rtcp::TransportFeedback* packet) {
erikvargabf5a2fc2017-06-16 05:02:05 -0700226 RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
stefanbba9dec2016-02-01 04:39:55 -0800227 rtc::CritScope cs(&modules_crit_);
nissefdbfdc92017-03-31 05:44:52 -0700228 // Prefer send modules.
229 for (auto* rtp_module : rtp_send_modules_) {
230 packet->SetSenderSsrc(rtp_module->SSRC());
231 if (rtp_module->SendFeedbackPacket(*packet))
232 return true;
233 }
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100234 for (auto* rtcp_sender : rtcp_feedback_senders_) {
235 packet->SetSenderSsrc(rtcp_sender->SSRC());
236 if (rtcp_sender->SendFeedbackPacket(*packet))
Peter Boström3dd5d1d2016-02-25 16:56:48 +0100237 return true;
238 }
sprang233bd872015-09-08 13:25:16 -0700239 return false;
240}
241
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100242void PacketRouter::AddRembModuleCandidate(
243 RtcpFeedbackSenderInterface* candidate_module,
244 bool media_sender) {
eladalon822ff2b2017-08-01 06:30:28 -0700245 RTC_DCHECK(candidate_module);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100246 std::vector<RtcpFeedbackSenderInterface*>& candidates =
247 media_sender ? sender_remb_candidates_ : receiver_remb_candidates_;
eladalon822ff2b2017-08-01 06:30:28 -0700248 RTC_DCHECK(std::find(candidates.cbegin(), candidates.cend(),
249 candidate_module) == candidates.cend());
250 candidates.push_back(candidate_module);
251 DetermineActiveRembModule();
252}
253
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100254void PacketRouter::MaybeRemoveRembModuleCandidate(
255 RtcpFeedbackSenderInterface* candidate_module,
256 bool media_sender) {
eladalon822ff2b2017-08-01 06:30:28 -0700257 RTC_DCHECK(candidate_module);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100258 std::vector<RtcpFeedbackSenderInterface*>& candidates =
259 media_sender ? sender_remb_candidates_ : receiver_remb_candidates_;
eladalon822ff2b2017-08-01 06:30:28 -0700260 auto it = std::find(candidates.begin(), candidates.end(), candidate_module);
261
262 if (it == candidates.end()) {
263 return; // Function called due to removal of non-REMB-candidate module.
264 }
265
266 if (*it == active_remb_module_) {
267 UnsetActiveRembModule();
268 }
269 candidates.erase(it);
270 DetermineActiveRembModule();
271}
272
273void PacketRouter::UnsetActiveRembModule() {
274 RTC_CHECK(active_remb_module_);
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200275 active_remb_module_->UnsetRemb();
eladalon822ff2b2017-08-01 06:30:28 -0700276 active_remb_module_ = nullptr;
277}
278
279void PacketRouter::DetermineActiveRembModule() {
280 // Sender modules take precedence over receiver modules, because SRs (sender
281 // reports) are sent more frequently than RR (receiver reports).
282 // When adding the first sender module, we should change the active REMB
283 // module to be that. Otherwise, we remain with the current active module.
284
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100285 RtcpFeedbackSenderInterface* new_active_remb_module;
eladalon822ff2b2017-08-01 06:30:28 -0700286
287 if (!sender_remb_candidates_.empty()) {
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200288 new_active_remb_module = sender_remb_candidates_.front();
eladalon822ff2b2017-08-01 06:30:28 -0700289 } else if (!receiver_remb_candidates_.empty()) {
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200290 new_active_remb_module = receiver_remb_candidates_.front();
eladalon822ff2b2017-08-01 06:30:28 -0700291 } else {
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200292 new_active_remb_module = nullptr;
eladalon822ff2b2017-08-01 06:30:28 -0700293 }
294
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200295 if (new_active_remb_module != active_remb_module_ && active_remb_module_) {
296 UnsetActiveRembModule();
eladalon822ff2b2017-08-01 06:30:28 -0700297 }
298
Danil Chapovalov51e21aa2017-10-10 17:46:26 +0200299 active_remb_module_ = new_active_remb_module;
eladalon822ff2b2017-08-01 06:30:28 -0700300}
301
Stefan Holmere5904162015-03-26 11:11:06 +0100302} // namespace webrtc