blob: 64e1aeacc1cde5277be14adf30b2bf1e8d855ad0 [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
Henrik Kjellander0b9e29c2015-11-16 11:12:24 +010011#include "webrtc/modules/pacing/packet_router.h"
Stefan Holmere5904162015-03-26 11:11:06 +010012
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010013#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
14#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
sprang233bd872015-09-08 13:25:16 -070015#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020016#include "webrtc/rtc_base/atomicops.h"
17#include "webrtc/rtc_base/checks.h"
18#include "webrtc/rtc_base/timeutils.h"
Stefan Holmere5904162015-03-26 11:11:06 +010019
20namespace webrtc {
21
nisse05843312017-04-18 23:38:35 -070022PacketRouter::PacketRouter()
23 : last_remb_time_ms_(rtc::TimeMillis()),
24 last_send_bitrate_bps_(0),
eladalon822ff2b2017-08-01 06:30:28 -070025 active_remb_module_(nullptr),
erikvargabf5a2fc2017-06-16 05:02:05 -070026 transport_seq_(0) {}
Stefan Holmere5904162015-03-26 11:11:06 +010027
28PacketRouter::~PacketRouter() {
nissefdbfdc92017-03-31 05:44:52 -070029 RTC_DCHECK(rtp_send_modules_.empty());
30 RTC_DCHECK(rtp_receive_modules_.empty());
eladalon822ff2b2017-08-01 06:30:28 -070031 RTC_DCHECK(sender_remb_candidates_.empty());
32 RTC_DCHECK(receiver_remb_candidates_.empty());
33 RTC_DCHECK(active_remb_module_ == nullptr);
Stefan Holmere5904162015-03-26 11:11:06 +010034}
35
eladalon822ff2b2017-08-01 06:30:28 -070036void PacketRouter::AddSendRtpModule(RtpRtcp* rtp_module, bool remb_candidate) {
stefanbba9dec2016-02-01 04:39:55 -080037 rtc::CritScope cs(&modules_crit_);
nissefdbfdc92017-03-31 05:44:52 -070038 RTC_DCHECK(std::find(rtp_send_modules_.begin(), rtp_send_modules_.end(),
39 rtp_module) == rtp_send_modules_.end());
stefan16b02212017-01-27 07:12:16 -080040 // Put modules which can use regular payload packets (over rtx) instead of
41 // padding first as it's less of a waste
42 if ((rtp_module->RtxSendStatus() & kRtxRedundantPayloads) > 0) {
nissefdbfdc92017-03-31 05:44:52 -070043 rtp_send_modules_.push_front(rtp_module);
stefan16b02212017-01-27 07:12:16 -080044 } else {
nissefdbfdc92017-03-31 05:44:52 -070045 rtp_send_modules_.push_back(rtp_module);
stefan16b02212017-01-27 07:12:16 -080046 }
eladalon822ff2b2017-08-01 06:30:28 -070047
48 if (remb_candidate) {
49 AddRembModuleCandidate(rtp_module, true);
50 }
Stefan Holmere5904162015-03-26 11:11:06 +010051}
52
nissefdbfdc92017-03-31 05:44:52 -070053void PacketRouter::RemoveSendRtpModule(RtpRtcp* rtp_module) {
stefanbba9dec2016-02-01 04:39:55 -080054 rtc::CritScope cs(&modules_crit_);
eladalon822ff2b2017-08-01 06:30:28 -070055 MaybeRemoveRembModuleCandidate(rtp_module, /* sender = */ true);
56 auto it =
57 std::find(rtp_send_modules_.begin(), rtp_send_modules_.end(), rtp_module);
58 RTC_DCHECK(it != rtp_send_modules_.end());
59 rtp_send_modules_.erase(it);
nissefdbfdc92017-03-31 05:44:52 -070060}
61
eladalon822ff2b2017-08-01 06:30:28 -070062void PacketRouter::AddReceiveRtpModule(RtpRtcp* rtp_module,
63 bool remb_candidate) {
nissefdbfdc92017-03-31 05:44:52 -070064 rtc::CritScope cs(&modules_crit_);
65 RTC_DCHECK(std::find(rtp_receive_modules_.begin(), rtp_receive_modules_.end(),
66 rtp_module) == rtp_receive_modules_.end());
eladalon822ff2b2017-08-01 06:30:28 -070067
nissefdbfdc92017-03-31 05:44:52 -070068 rtp_receive_modules_.push_back(rtp_module);
eladalon822ff2b2017-08-01 06:30:28 -070069
70 if (remb_candidate) {
71 AddRembModuleCandidate(rtp_module, false);
72 }
nissefdbfdc92017-03-31 05:44:52 -070073}
74
75void PacketRouter::RemoveReceiveRtpModule(RtpRtcp* rtp_module) {
76 rtc::CritScope cs(&modules_crit_);
eladalon822ff2b2017-08-01 06:30:28 -070077 MaybeRemoveRembModuleCandidate(rtp_module, /* sender = */ false);
nissefdbfdc92017-03-31 05:44:52 -070078 const auto& it = std::find(rtp_receive_modules_.begin(),
79 rtp_receive_modules_.end(), rtp_module);
80 RTC_DCHECK(it != rtp_receive_modules_.end());
81 rtp_receive_modules_.erase(it);
Stefan Holmere5904162015-03-26 11:11:06 +010082}
83
84bool PacketRouter::TimeToSendPacket(uint32_t ssrc,
85 uint16_t sequence_number,
86 int64_t capture_timestamp,
philipel29dca2c2016-05-13 11:13:05 +020087 bool retransmission,
philipelc7bf32a2017-02-17 03:59:43 -080088 const PacedPacketInfo& pacing_info) {
erikvargabf5a2fc2017-06-16 05:02:05 -070089 RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
stefanbba9dec2016-02-01 04:39:55 -080090 rtc::CritScope cs(&modules_crit_);
nissefdbfdc92017-03-31 05:44:52 -070091 for (auto* rtp_module : rtp_send_modules_) {
brandtr9dfff292016-11-14 05:14:50 -080092 if (!rtp_module->SendingMedia())
93 continue;
94 if (ssrc == rtp_module->SSRC() || ssrc == rtp_module->FlexfecSsrc()) {
Stefan Holmere5904162015-03-26 11:11:06 +010095 return rtp_module->TimeToSendPacket(ssrc, sequence_number,
philipela1ed0b32016-06-01 06:31:17 -070096 capture_timestamp, retransmission,
philipelc7bf32a2017-02-17 03:59:43 -080097 pacing_info);
Stefan Holmere5904162015-03-26 11:11:06 +010098 }
99 }
100 return true;
101}
102
philipela1ed0b32016-06-01 06:31:17 -0700103size_t PacketRouter::TimeToSendPadding(size_t bytes_to_send,
philipelc7bf32a2017-02-17 03:59:43 -0800104 const PacedPacketInfo& pacing_info) {
erikvargabf5a2fc2017-06-16 05:02:05 -0700105 RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
sprang867fb522015-08-03 04:38:41 -0700106 size_t total_bytes_sent = 0;
stefanbba9dec2016-02-01 04:39:55 -0800107 rtc::CritScope cs(&modules_crit_);
stefan16b02212017-01-27 07:12:16 -0800108 // Rtp modules are ordered by which stream can most benefit from padding.
nissefdbfdc92017-03-31 05:44:52 -0700109 for (RtpRtcp* module : rtp_send_modules_) {
stefan53b6cc32017-02-03 08:13:57 -0800110 if (module->SendingMedia() && module->HasBweExtensions()) {
philipela1ed0b32016-06-01 06:31:17 -0700111 size_t bytes_sent = module->TimeToSendPadding(
philipelc7bf32a2017-02-17 03:59:43 -0800112 bytes_to_send - total_bytes_sent, pacing_info);
sprang867fb522015-08-03 04:38:41 -0700113 total_bytes_sent += bytes_sent;
114 if (total_bytes_sent >= bytes_to_send)
115 break;
116 }
Stefan Holmere5904162015-03-26 11:11:06 +0100117 }
sprang867fb522015-08-03 04:38:41 -0700118 return total_bytes_sent;
Stefan Holmere5904162015-03-26 11:11:06 +0100119}
sprang867fb522015-08-03 04:38:41 -0700120
121void PacketRouter::SetTransportWideSequenceNumber(uint16_t sequence_number) {
pbos46ad5422015-12-07 14:29:14 -0800122 rtc::AtomicOps::ReleaseStore(&transport_seq_, sequence_number);
sprang867fb522015-08-03 04:38:41 -0700123}
124
125uint16_t PacketRouter::AllocateSequenceNumber() {
pbos46ad5422015-12-07 14:29:14 -0800126 int prev_seq = rtc::AtomicOps::AcquireLoad(&transport_seq_);
sprang867fb522015-08-03 04:38:41 -0700127 int desired_prev_seq;
128 int new_seq;
129 do {
130 desired_prev_seq = prev_seq;
131 new_seq = (desired_prev_seq + 1) & 0xFFFF;
132 // Note: CompareAndSwap returns the actual value of transport_seq at the
133 // time the CAS operation was executed. Thus, if prev_seq is returned, the
134 // operation was successful - otherwise we need to retry. Saving the
135 // return value saves us a load on retry.
pbos46ad5422015-12-07 14:29:14 -0800136 prev_seq = rtc::AtomicOps::CompareAndSwap(&transport_seq_, desired_prev_seq,
sprang867fb522015-08-03 04:38:41 -0700137 new_seq);
138 } while (prev_seq != desired_prev_seq);
139
140 return new_seq;
141}
142
nisse05843312017-04-18 23:38:35 -0700143void PacketRouter::OnReceiveBitrateChanged(const std::vector<uint32_t>& ssrcs,
144 uint32_t bitrate_bps) {
145 const int kRembSendIntervalMs = 200;
146
147 // % threshold for if we should send a new REMB asap.
148 const uint32_t kSendThresholdPercent = 97;
149
150 int64_t now_ms = rtc::TimeMillis();
151 {
152 rtc::CritScope lock(&remb_crit_);
153
154 // If we already have an estimate, check if the new total estimate is below
155 // kSendThresholdPercent of the previous estimate.
156 if (last_send_bitrate_bps_ > 0) {
157 uint32_t new_remb_bitrate_bps =
158 last_send_bitrate_bps_ - bitrate_bps_ + bitrate_bps;
159
160 if (new_remb_bitrate_bps <
161 kSendThresholdPercent * last_send_bitrate_bps_ / 100) {
162 // The new bitrate estimate is less than kSendThresholdPercent % of the
163 // last report. Send a REMB asap.
164 last_remb_time_ms_ = now_ms - kRembSendIntervalMs;
165 }
166 }
167 bitrate_bps_ = bitrate_bps;
168
169 if (now_ms - last_remb_time_ms_ < kRembSendIntervalMs) {
170 return;
171 }
172 // NOTE: Updated if we intend to send the data; we might not have
173 // a module to actually send it.
174 last_remb_time_ms_ = now_ms;
175 last_send_bitrate_bps_ = bitrate_bps;
176 }
177 SendRemb(bitrate_bps, ssrcs);
178}
179
180bool PacketRouter::SendRemb(uint32_t bitrate_bps,
181 const std::vector<uint32_t>& ssrcs) {
182 rtc::CritScope lock(&modules_crit_);
eladalon822ff2b2017-08-01 06:30:28 -0700183
184 if (!active_remb_module_) {
nisse05843312017-04-18 23:38:35 -0700185 return false;
eladalon822ff2b2017-08-01 06:30:28 -0700186 }
187
nisse05843312017-04-18 23:38:35 -0700188 // The Add* and Remove* methods above ensure that this (and only this) module
189 // has REMB enabled. REMB should be disabled on all other modules, because
190 // otherwise, they will send REMB with stale info.
eladalon822ff2b2017-08-01 06:30:28 -0700191 RTC_DCHECK(active_remb_module_->REMB());
192 active_remb_module_->SetREMBData(bitrate_bps, ssrcs);
193
nisse05843312017-04-18 23:38:35 -0700194 return true;
195}
196
197bool PacketRouter::SendTransportFeedback(rtcp::TransportFeedback* packet) {
erikvargabf5a2fc2017-06-16 05:02:05 -0700198 RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
stefanbba9dec2016-02-01 04:39:55 -0800199 rtc::CritScope cs(&modules_crit_);
nissefdbfdc92017-03-31 05:44:52 -0700200 // Prefer send modules.
201 for (auto* rtp_module : rtp_send_modules_) {
202 packet->SetSenderSsrc(rtp_module->SSRC());
203 if (rtp_module->SendFeedbackPacket(*packet))
204 return true;
205 }
206 for (auto* rtp_module : rtp_receive_modules_) {
danilchap822a16f2016-09-27 09:27:47 -0700207 packet->SetSenderSsrc(rtp_module->SSRC());
Peter Boström3dd5d1d2016-02-25 16:56:48 +0100208 if (rtp_module->SendFeedbackPacket(*packet))
209 return true;
210 }
sprang233bd872015-09-08 13:25:16 -0700211 return false;
212}
213
eladalon822ff2b2017-08-01 06:30:28 -0700214void PacketRouter::AddRembModuleCandidate(RtpRtcp* candidate_module,
215 bool sender) {
216 RTC_DCHECK(candidate_module);
217 std::vector<RtpRtcp*>& candidates =
218 sender ? sender_remb_candidates_ : receiver_remb_candidates_;
219 RTC_DCHECK(std::find(candidates.cbegin(), candidates.cend(),
220 candidate_module) == candidates.cend());
221 candidates.push_back(candidate_module);
222 DetermineActiveRembModule();
223}
224
225void PacketRouter::MaybeRemoveRembModuleCandidate(RtpRtcp* candidate_module,
226 bool sender) {
227 RTC_DCHECK(candidate_module);
228 std::vector<RtpRtcp*>& candidates =
229 sender ? sender_remb_candidates_ : receiver_remb_candidates_;
230 auto it = std::find(candidates.begin(), candidates.end(), candidate_module);
231
232 if (it == candidates.end()) {
233 return; // Function called due to removal of non-REMB-candidate module.
234 }
235
236 if (*it == active_remb_module_) {
237 UnsetActiveRembModule();
238 }
239 candidates.erase(it);
240 DetermineActiveRembModule();
241}
242
243void PacketRouter::UnsetActiveRembModule() {
244 RTC_CHECK(active_remb_module_);
245 RTC_DCHECK(active_remb_module_->REMB());
246 active_remb_module_->SetREMBStatus(false);
247 active_remb_module_ = nullptr;
248}
249
250void PacketRouter::DetermineActiveRembModule() {
251 // Sender modules take precedence over receiver modules, because SRs (sender
252 // reports) are sent more frequently than RR (receiver reports).
253 // When adding the first sender module, we should change the active REMB
254 // module to be that. Otherwise, we remain with the current active module.
255
256 RtpRtcp* new_active_remb_module_;
257
258 if (!sender_remb_candidates_.empty()) {
259 new_active_remb_module_ = sender_remb_candidates_.front();
260 } else if (!receiver_remb_candidates_.empty()) {
261 new_active_remb_module_ = receiver_remb_candidates_.front();
262 } else {
263 new_active_remb_module_ = nullptr;
264 }
265
266 if (new_active_remb_module_ != active_remb_module_) {
267 if (active_remb_module_) {
268 UnsetActiveRembModule();
269 }
270 if (new_active_remb_module_) {
271 RTC_DCHECK(!new_active_remb_module_->REMB());
272 new_active_remb_module_->SetREMBStatus(true);
273 }
274 }
275
276 active_remb_module_ = new_active_remb_module_;
277}
278
Stefan Holmere5904162015-03-26 11:11:06 +0100279} // namespace webrtc