blob: 2946b5c13942d360fbd152e7d993f803b997d523 [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"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "rtc_base/atomic_ops.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "rtc_base/checks.h"
Erik Språng58ee1872019-06-18 16:20:11 +020026#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "rtc_base/time_utils.h"
Stefan Holmere5904162015-03-26 11:11:06 +010028
29namespace webrtc {
danilchap47085372017-08-10 06:03:57 -070030namespace {
31
32constexpr int kRembSendIntervalMs = 200;
33
34} // namespace
Stefan Holmere5904162015-03-26 11:11:06 +010035
nisse05843312017-04-18 23:38:35 -070036PacketRouter::PacketRouter()
Erik Språng8b7ca4a2018-05-17 13:43:35 +020037 : last_send_module_(nullptr),
38 last_remb_time_ms_(rtc::TimeMillis()),
nisse05843312017-04-18 23:38:35 -070039 last_send_bitrate_bps_(0),
danilchap47085372017-08-10 06:03:57 -070040 bitrate_bps_(0),
41 max_bitrate_bps_(std::numeric_limits<decltype(max_bitrate_bps_)>::max()),
eladalon822ff2b2017-08-01 06:30:28 -070042 active_remb_module_(nullptr),
erikvargabf5a2fc2017-06-16 05:02:05 -070043 transport_seq_(0) {}
Stefan Holmere5904162015-03-26 11:11:06 +010044
45PacketRouter::~PacketRouter() {
nissefdbfdc92017-03-31 05:44:52 -070046 RTC_DCHECK(rtp_send_modules_.empty());
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010047 RTC_DCHECK(rtcp_feedback_senders_.empty());
eladalon822ff2b2017-08-01 06:30:28 -070048 RTC_DCHECK(sender_remb_candidates_.empty());
49 RTC_DCHECK(receiver_remb_candidates_.empty());
50 RTC_DCHECK(active_remb_module_ == nullptr);
Stefan Holmere5904162015-03-26 11:11:06 +010051}
52
eladalon822ff2b2017-08-01 06:30:28 -070053void PacketRouter::AddSendRtpModule(RtpRtcp* rtp_module, bool remb_candidate) {
stefanbba9dec2016-02-01 04:39:55 -080054 rtc::CritScope cs(&modules_crit_);
nissefdbfdc92017-03-31 05:44:52 -070055 RTC_DCHECK(std::find(rtp_send_modules_.begin(), rtp_send_modules_.end(),
56 rtp_module) == rtp_send_modules_.end());
stefan16b02212017-01-27 07:12:16 -080057 // Put modules which can use regular payload packets (over rtx) instead of
58 // padding first as it's less of a waste
Erik Språng4208a132019-08-26 08:58:45 +020059 if (rtp_module->SupportsRtxPayloadPadding()) {
nissefdbfdc92017-03-31 05:44:52 -070060 rtp_send_modules_.push_front(rtp_module);
stefan16b02212017-01-27 07:12:16 -080061 } else {
nissefdbfdc92017-03-31 05:44:52 -070062 rtp_send_modules_.push_back(rtp_module);
stefan16b02212017-01-27 07:12:16 -080063 }
eladalon822ff2b2017-08-01 06:30:28 -070064
65 if (remb_candidate) {
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010066 AddRembModuleCandidate(rtp_module, /* media_sender = */ true);
eladalon822ff2b2017-08-01 06:30:28 -070067 }
Stefan Holmere5904162015-03-26 11:11:06 +010068}
69
nissefdbfdc92017-03-31 05:44:52 -070070void PacketRouter::RemoveSendRtpModule(RtpRtcp* rtp_module) {
stefanbba9dec2016-02-01 04:39:55 -080071 rtc::CritScope cs(&modules_crit_);
Danil Chapovalovdb59de32019-06-26 11:06:41 +020072 rtp_module_cache_map_.clear();
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010073 MaybeRemoveRembModuleCandidate(rtp_module, /* media_sender = */ true);
eladalon822ff2b2017-08-01 06:30:28 -070074 auto it =
75 std::find(rtp_send_modules_.begin(), rtp_send_modules_.end(), rtp_module);
76 RTC_DCHECK(it != rtp_send_modules_.end());
77 rtp_send_modules_.erase(it);
Erik Språng8b7ca4a2018-05-17 13:43:35 +020078 if (last_send_module_ == rtp_module) {
79 last_send_module_ = nullptr;
80 }
nissefdbfdc92017-03-31 05:44:52 -070081}
82
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010083void PacketRouter::AddReceiveRtpModule(RtcpFeedbackSenderInterface* rtcp_sender,
eladalon822ff2b2017-08-01 06:30:28 -070084 bool remb_candidate) {
nissefdbfdc92017-03-31 05:44:52 -070085 rtc::CritScope cs(&modules_crit_);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010086 RTC_DCHECK(std::find(rtcp_feedback_senders_.begin(),
87 rtcp_feedback_senders_.end(),
88 rtcp_sender) == rtcp_feedback_senders_.end());
eladalon822ff2b2017-08-01 06:30:28 -070089
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010090 rtcp_feedback_senders_.push_back(rtcp_sender);
eladalon822ff2b2017-08-01 06:30:28 -070091
92 if (remb_candidate) {
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010093 AddRembModuleCandidate(rtcp_sender, /* media_sender = */ false);
eladalon822ff2b2017-08-01 06:30:28 -070094 }
nissefdbfdc92017-03-31 05:44:52 -070095}
96
Danil Chapovaloveb0edd82017-12-14 16:02:31 +010097void PacketRouter::RemoveReceiveRtpModule(
98 RtcpFeedbackSenderInterface* rtcp_sender) {
nissefdbfdc92017-03-31 05:44:52 -070099 rtc::CritScope cs(&modules_crit_);
Danil Chapovaloveb0edd82017-12-14 16:02:31 +0100100 MaybeRemoveRembModuleCandidate(rtcp_sender, /* media_sender = */ false);
101 auto it = std::find(rtcp_feedback_senders_.begin(),
102 rtcp_feedback_senders_.end(), rtcp_sender);
103 RTC_DCHECK(it != rtcp_feedback_senders_.end());
104 rtcp_feedback_senders_.erase(it);
Stefan Holmere5904162015-03-26 11:11:06 +0100105}
106
Danil Chapovalovdb59de32019-06-26 11:06:41 +0200107RtpRtcp* PacketRouter::FindRtpModule(uint32_t ssrc) {
108 auto it = rtp_module_cache_map_.find(ssrc);
109 if (it != rtp_module_cache_map_.end()) {
110 if (ssrc == it->second->SSRC() || ssrc == it->second->FlexfecSsrc()) {
111 return it->second;
Erik Språng8b7ca4a2018-05-17 13:43:35 +0200112 }
Danil Chapovalovdb59de32019-06-26 11:06:41 +0200113 // This entry is stale due to a changed ssrc - remove it.
114 rtp_module_cache_map_.erase(it);
115 }
116 // Slow path - find and cache matching module
117 for (RtpRtcp* rtp_module : rtp_send_modules_) {
brandtr9dfff292016-11-14 05:14:50 -0800118 if (ssrc == rtp_module->SSRC() || ssrc == rtp_module->FlexfecSsrc()) {
Danil Chapovalovdb59de32019-06-26 11:06:41 +0200119 rtp_module_cache_map_[ssrc] = rtp_module;
120 return rtp_module;
Stefan Holmere5904162015-03-26 11:11:06 +0100121 }
122 }
Danil Chapovalovdb59de32019-06-26 11:06:41 +0200123 return nullptr;
Stefan Holmere5904162015-03-26 11:11:06 +0100124}
125
Erik Språng58ee1872019-06-18 16:20:11 +0200126void PacketRouter::SendPacket(std::unique_ptr<RtpPacketToSend> packet,
127 const PacedPacketInfo& cluster_info) {
128 rtc::CritScope cs(&modules_crit_);
Erik Språngf6468d22019-07-05 16:53:43 +0200129 // With the new pacer code path, transport sequence numbers are only set here,
130 // on the pacer thread. Therefore we don't need atomics/synchronization.
Erik Språng6cdab462019-07-15 19:40:13 +0200131 if (packet->IsExtensionReserved<TransportSequenceNumber>()) {
Erik Språng4208a132019-08-26 08:58:45 +0200132 packet->SetExtension<TransportSequenceNumber>(AllocateSequenceNumber());
Erik Språngf6468d22019-07-05 16:53:43 +0200133 }
Mirko Bonadei999a72a2019-07-12 17:33:46 +0000134
135 auto it = rtp_module_cache_map_.find(packet->Ssrc());
136 if (it != rtp_module_cache_map_.end()) {
137 if (TrySendPacket(packet.get(), cluster_info, it->second)) {
138 return;
139 }
140 // Entry is stale, remove it.
141 rtp_module_cache_map_.erase(it);
142 }
143
144 // Slow path, find the correct send module.
Erik Språng58ee1872019-06-18 16:20:11 +0200145 for (auto* rtp_module : rtp_send_modules_) {
Mirko Bonadei999a72a2019-07-12 17:33:46 +0000146 if (TrySendPacket(packet.get(), cluster_info, rtp_module)) {
Erik Språng58ee1872019-06-18 16:20:11 +0200147 return;
148 }
149 }
150
151 RTC_LOG(LS_WARNING) << "Failed to send packet, matching RTP module not found "
152 "or transport error. SSRC = "
153 << packet->Ssrc() << ", sequence number "
154 << packet->SequenceNumber();
155}
156
Erik Språngf6468d22019-07-05 16:53:43 +0200157std::vector<std::unique_ptr<RtpPacketToSend>> PacketRouter::GeneratePadding(
158 size_t target_size_bytes) {
Erik Språng478cb462019-06-26 15:49:27 +0200159 rtc::CritScope cs(&modules_crit_);
160 // First try on the last rtp module to have sent media. This increases the
161 // the chance that any payload based padding will be useful as it will be
162 // somewhat distributed over modules according the packet rate, even if it
163 // will be more skewed towards the highest bitrate stream. At the very least
164 // this prevents sending payload padding on a disabled stream where it's
165 // guaranteed not to be useful.
Mirko Bonadei999a72a2019-07-12 17:33:46 +0000166 if (last_send_module_ != nullptr &&
167 last_send_module_->SupportsRtxPayloadPadding()) {
Erik Språng478cb462019-06-26 15:49:27 +0200168 RTC_DCHECK(std::find(rtp_send_modules_.begin(), rtp_send_modules_.end(),
169 last_send_module_) != rtp_send_modules_.end());
Erik Språngf6468d22019-07-05 16:53:43 +0200170 return last_send_module_->GeneratePadding(target_size_bytes);
Erik Språng478cb462019-06-26 15:49:27 +0200171 }
172
173 // Rtp modules are ordered by which stream can most benefit from padding.
174 for (RtpRtcp* rtp_module : rtp_send_modules_) {
Mirko Bonadei999a72a2019-07-12 17:33:46 +0000175 if (rtp_module->SupportsPadding()) {
176 auto padding_packets = rtp_module->GeneratePadding(target_size_bytes);
177 if (!padding_packets.empty()) {
178 last_send_module_ = rtp_module;
179 }
180 return padding_packets;
Erik Språng478cb462019-06-26 15:49:27 +0200181 }
182 }
Erik Språngf6468d22019-07-05 16:53:43 +0200183
184 return {};
Erik Språng478cb462019-06-26 15:49:27 +0200185}
186
sprang867fb522015-08-03 04:38:41 -0700187void PacketRouter::SetTransportWideSequenceNumber(uint16_t sequence_number) {
pbos46ad5422015-12-07 14:29:14 -0800188 rtc::AtomicOps::ReleaseStore(&transport_seq_, sequence_number);
sprang867fb522015-08-03 04:38:41 -0700189}
190
191uint16_t PacketRouter::AllocateSequenceNumber() {
pbos46ad5422015-12-07 14:29:14 -0800192 int prev_seq = rtc::AtomicOps::AcquireLoad(&transport_seq_);
sprang867fb522015-08-03 04:38:41 -0700193 int desired_prev_seq;
194 int new_seq;
195 do {
196 desired_prev_seq = prev_seq;
197 new_seq = (desired_prev_seq + 1) & 0xFFFF;
198 // Note: CompareAndSwap returns the actual value of transport_seq at the
199 // time the CAS operation was executed. Thus, if prev_seq is returned, the
200 // operation was successful - otherwise we need to retry. Saving the
201 // return value saves us a load on retry.
pbos46ad5422015-12-07 14:29:14 -0800202 prev_seq = rtc::AtomicOps::CompareAndSwap(&transport_seq_, desired_prev_seq,
sprang867fb522015-08-03 04:38:41 -0700203 new_seq);
204 } while (prev_seq != desired_prev_seq);
205
206 return new_seq;
207}
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.
284 for (auto* rtp_module : rtp_send_modules_) {
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
Mirko Bonadei999a72a2019-07-12 17:33:46 +0000360bool PacketRouter::TrySendPacket(RtpPacketToSend* packet,
361 const PacedPacketInfo& cluster_info,
362 RtpRtcp* rtp_module) {
363 uint32_t ssrc = packet->Ssrc();
364 if (rtp_module->TrySendPacket(packet, cluster_info)) {
365 // Sending succeeded, make sure this SSRC mapping for future use.
366 rtp_module_cache_map_[ssrc] = rtp_module;
367
368 if (rtp_module->SupportsRtxPayloadPadding()) {
369 // This is now the last module to send media, and has the desired
370 // properties needed for payload based padding. Cache it for later use.
371 last_send_module_ = rtp_module;
372 }
373
374 return true;
375 }
376 return false;
377}
378
Stefan Holmere5904162015-03-26 11:11:06 +0100379} // namespace webrtc