1 /*
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
11 #include "modules/pacing/packet_router.h"
12
13 #include <algorithm>
14 #include <cstdint>
15 #include <limits>
16 #include <memory>
17 #include <utility>
18
19 #include "absl/types/optional.h"
20 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
21 #include "modules/rtp_rtcp/source/rtcp_packet.h"
22 #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
23 #include "modules/rtp_rtcp/source/rtp_rtcp_interface.h"
24 #include "rtc_base/checks.h"
25 #include "rtc_base/logging.h"
26 #include "rtc_base/system/unused.h"
27 #include "rtc_base/time_utils.h"
28 #include "rtc_base/trace_event.h"
29
30 namespace webrtc {
31
PacketRouter()32 PacketRouter::PacketRouter() : PacketRouter(0) {}
33
PacketRouter(uint16_t start_transport_seq)34 PacketRouter::PacketRouter(uint16_t start_transport_seq)
35 : last_send_module_(nullptr),
36 active_remb_module_(nullptr),
37 transport_seq_(start_transport_seq) {}
38
~PacketRouter()39 PacketRouter::~PacketRouter() {
40 RTC_DCHECK(send_modules_map_.empty());
41 RTC_DCHECK(send_modules_list_.empty());
42 RTC_DCHECK(rtcp_feedback_senders_.empty());
43 RTC_DCHECK(sender_remb_candidates_.empty());
44 RTC_DCHECK(receiver_remb_candidates_.empty());
45 RTC_DCHECK(active_remb_module_ == nullptr);
46 }
47
AddSendRtpModule(RtpRtcpInterface * rtp_module,bool remb_candidate)48 void PacketRouter::AddSendRtpModule(RtpRtcpInterface* rtp_module,
49 bool remb_candidate) {
50 MutexLock lock(&modules_mutex_);
51
52 AddSendRtpModuleToMap(rtp_module, rtp_module->SSRC());
53 if (absl::optional<uint32_t> rtx_ssrc = rtp_module->RtxSsrc()) {
54 AddSendRtpModuleToMap(rtp_module, *rtx_ssrc);
55 }
56 if (absl::optional<uint32_t> flexfec_ssrc = rtp_module->FlexfecSsrc()) {
57 AddSendRtpModuleToMap(rtp_module, *flexfec_ssrc);
58 }
59
60 if (rtp_module->SupportsRtxPayloadPadding()) {
61 last_send_module_ = rtp_module;
62 }
63
64 if (remb_candidate) {
65 AddRembModuleCandidate(rtp_module, /* media_sender = */ true);
66 }
67 }
68
AddSendRtpModuleToMap(RtpRtcpInterface * rtp_module,uint32_t ssrc)69 void PacketRouter::AddSendRtpModuleToMap(RtpRtcpInterface* rtp_module,
70 uint32_t ssrc) {
71 RTC_DCHECK(send_modules_map_.find(ssrc) == send_modules_map_.end());
72
73 // Signal to module that the pacer thread is attached and can send packets.
74 rtp_module->OnPacketSendingThreadSwitched();
75
76 // Always keep the audio modules at the back of the list, so that when we
77 // iterate over the modules in order to find one that can send padding we
78 // will prioritize video. This is important to make sure they are counted
79 // into the bandwidth estimate properly.
80 if (rtp_module->IsAudioConfigured()) {
81 send_modules_list_.push_back(rtp_module);
82 } else {
83 send_modules_list_.push_front(rtp_module);
84 }
85 send_modules_map_[ssrc] = rtp_module;
86 }
87
RemoveSendRtpModuleFromMap(uint32_t ssrc)88 void PacketRouter::RemoveSendRtpModuleFromMap(uint32_t ssrc) {
89 auto it = send_modules_map_.find(ssrc);
90 RTC_DCHECK(it != send_modules_map_.end());
91 send_modules_list_.remove(it->second);
92 send_modules_map_.erase(it);
93 }
94
RemoveSendRtpModule(RtpRtcpInterface * rtp_module)95 void PacketRouter::RemoveSendRtpModule(RtpRtcpInterface* rtp_module) {
96 MutexLock lock(&modules_mutex_);
97 MaybeRemoveRembModuleCandidate(rtp_module, /* media_sender = */ true);
98
99 RemoveSendRtpModuleFromMap(rtp_module->SSRC());
100 if (absl::optional<uint32_t> rtx_ssrc = rtp_module->RtxSsrc()) {
101 RemoveSendRtpModuleFromMap(*rtx_ssrc);
102 }
103 if (absl::optional<uint32_t> flexfec_ssrc = rtp_module->FlexfecSsrc()) {
104 RemoveSendRtpModuleFromMap(*flexfec_ssrc);
105 }
106
107 if (last_send_module_ == rtp_module) {
108 last_send_module_ = nullptr;
109 }
110 rtp_module->OnPacketSendingThreadSwitched();
111 }
112
AddReceiveRtpModule(RtcpFeedbackSenderInterface * rtcp_sender,bool remb_candidate)113 void PacketRouter::AddReceiveRtpModule(RtcpFeedbackSenderInterface* rtcp_sender,
114 bool remb_candidate) {
115 MutexLock lock(&modules_mutex_);
116 RTC_DCHECK(std::find(rtcp_feedback_senders_.begin(),
117 rtcp_feedback_senders_.end(),
118 rtcp_sender) == rtcp_feedback_senders_.end());
119
120 rtcp_feedback_senders_.push_back(rtcp_sender);
121
122 if (remb_candidate) {
123 AddRembModuleCandidate(rtcp_sender, /* media_sender = */ false);
124 }
125 }
126
RemoveReceiveRtpModule(RtcpFeedbackSenderInterface * rtcp_sender)127 void PacketRouter::RemoveReceiveRtpModule(
128 RtcpFeedbackSenderInterface* rtcp_sender) {
129 MutexLock lock(&modules_mutex_);
130 MaybeRemoveRembModuleCandidate(rtcp_sender, /* media_sender = */ false);
131 auto it = std::find(rtcp_feedback_senders_.begin(),
132 rtcp_feedback_senders_.end(), rtcp_sender);
133 RTC_DCHECK(it != rtcp_feedback_senders_.end());
134 rtcp_feedback_senders_.erase(it);
135 }
136
SendPacket(std::unique_ptr<RtpPacketToSend> packet,const PacedPacketInfo & cluster_info)137 void PacketRouter::SendPacket(std::unique_ptr<RtpPacketToSend> packet,
138 const PacedPacketInfo& cluster_info) {
139 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("webrtc"), "PacketRouter::SendPacket",
140 "sequence_number", packet->SequenceNumber(), "rtp_timestamp",
141 packet->Timestamp());
142
143 MutexLock lock(&modules_mutex_);
144 // With the new pacer code path, transport sequence numbers are only set here,
145 // on the pacer thread. Therefore we don't need atomics/synchronization.
146 bool assign_transport_sequence_number =
147 packet->HasExtension<TransportSequenceNumber>();
148 if (assign_transport_sequence_number) {
149 packet->SetExtension<TransportSequenceNumber>((transport_seq_ + 1) &
150 0xFFFF);
151 }
152
153 uint32_t ssrc = packet->Ssrc();
154 auto it = send_modules_map_.find(ssrc);
155 if (it == send_modules_map_.end()) {
156 RTC_LOG(LS_WARNING)
157 << "Failed to send packet, matching RTP module not found "
158 "or transport error. SSRC = "
159 << packet->Ssrc() << ", sequence number " << packet->SequenceNumber();
160 return;
161 }
162
163 RtpRtcpInterface* rtp_module = it->second;
164 if (!rtp_module->TrySendPacket(packet.get(), cluster_info)) {
165 RTC_LOG(LS_WARNING) << "Failed to send packet, rejected by RTP module.";
166 return;
167 }
168
169 // Sending succeeded.
170
171 if (assign_transport_sequence_number) {
172 ++transport_seq_;
173 }
174
175 if (rtp_module->SupportsRtxPayloadPadding()) {
176 // This is now the last module to send media, and has the desired
177 // properties needed for payload based padding. Cache it for later use.
178 last_send_module_ = rtp_module;
179 }
180
181 for (auto& packet : rtp_module->FetchFecPackets()) {
182 pending_fec_packets_.push_back(std::move(packet));
183 }
184 }
185
FetchFec()186 std::vector<std::unique_ptr<RtpPacketToSend>> PacketRouter::FetchFec() {
187 MutexLock lock(&modules_mutex_);
188 std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
189 std::move(pending_fec_packets_);
190 pending_fec_packets_.clear();
191 return fec_packets;
192 }
193
GeneratePadding(DataSize size)194 std::vector<std::unique_ptr<RtpPacketToSend>> PacketRouter::GeneratePadding(
195 DataSize size) {
196 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("webrtc"),
197 "PacketRouter::GeneratePadding", "bytes", size.bytes());
198
199 MutexLock lock(&modules_mutex_);
200 // First try on the last rtp module to have sent media. This increases the
201 // the chance that any payload based padding will be useful as it will be
202 // somewhat distributed over modules according the packet rate, even if it
203 // will be more skewed towards the highest bitrate stream. At the very least
204 // this prevents sending payload padding on a disabled stream where it's
205 // guaranteed not to be useful.
206 std::vector<std::unique_ptr<RtpPacketToSend>> padding_packets;
207 if (last_send_module_ != nullptr &&
208 last_send_module_->SupportsRtxPayloadPadding()) {
209 padding_packets = last_send_module_->GeneratePadding(size.bytes());
210 }
211
212 if (padding_packets.empty()) {
213 // Iterate over all modules send module. Video modules will be at the front
214 // and so will be prioritized. This is important since audio packets may not
215 // be taken into account by the bandwidth estimator, e.g. in FF.
216 for (RtpRtcpInterface* rtp_module : send_modules_list_) {
217 if (rtp_module->SupportsPadding()) {
218 padding_packets = rtp_module->GeneratePadding(size.bytes());
219 if (!padding_packets.empty()) {
220 last_send_module_ = rtp_module;
221 break;
222 }
223 }
224 }
225 }
226
227 for (auto& packet : padding_packets) {
228 RTC_UNUSED(packet);
229 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("webrtc"),
230 "PacketRouter::GeneratePadding::Loop", "sequence_number",
231 packet->SequenceNumber(), "rtp_timestamp",
232 packet->Timestamp());
233 }
234
235 return padding_packets;
236 }
237
OnAbortedRetransmissions(uint32_t ssrc,rtc::ArrayView<const uint16_t> sequence_numbers)238 void PacketRouter::OnAbortedRetransmissions(
239 uint32_t ssrc,
240 rtc::ArrayView<const uint16_t> sequence_numbers) {
241 MutexLock lock(&modules_mutex_);
242 auto it = send_modules_map_.find(ssrc);
243 if (it != send_modules_map_.end()) {
244 it->second->OnAbortedRetransmissions(sequence_numbers);
245 }
246 }
247
GetRtxSsrcForMedia(uint32_t ssrc) const248 absl::optional<uint32_t> PacketRouter::GetRtxSsrcForMedia(uint32_t ssrc) const {
249 MutexLock lock(&modules_mutex_);
250 auto it = send_modules_map_.find(ssrc);
251 if (it != send_modules_map_.end() && it->second->SSRC() == ssrc) {
252 // A module is registered with the given SSRC, and that SSRC is the main
253 // media SSRC for that RTP module.
254 return it->second->RtxSsrc();
255 }
256 return absl::nullopt;
257 }
258
CurrentTransportSequenceNumber() const259 uint16_t PacketRouter::CurrentTransportSequenceNumber() const {
260 MutexLock lock(&modules_mutex_);
261 return transport_seq_ & 0xFFFF;
262 }
263
SendRemb(int64_t bitrate_bps,std::vector<uint32_t> ssrcs)264 void PacketRouter::SendRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs) {
265 MutexLock lock(&modules_mutex_);
266
267 if (!active_remb_module_) {
268 return;
269 }
270
271 // The Add* and Remove* methods above ensure that REMB is disabled on all
272 // other modules, because otherwise, they will send REMB with stale info.
273 active_remb_module_->SetRemb(bitrate_bps, std::move(ssrcs));
274 }
275
SendCombinedRtcpPacket(std::vector<std::unique_ptr<rtcp::RtcpPacket>> packets)276 void PacketRouter::SendCombinedRtcpPacket(
277 std::vector<std::unique_ptr<rtcp::RtcpPacket>> packets) {
278 MutexLock lock(&modules_mutex_);
279
280 // Prefer send modules.
281 for (RtpRtcpInterface* rtp_module : send_modules_list_) {
282 if (rtp_module->RTCP() == RtcpMode::kOff) {
283 continue;
284 }
285 rtp_module->SendCombinedRtcpPacket(std::move(packets));
286 return;
287 }
288
289 if (rtcp_feedback_senders_.empty()) {
290 return;
291 }
292 auto* rtcp_sender = rtcp_feedback_senders_[0];
293 rtcp_sender->SendCombinedRtcpPacket(std::move(packets));
294 }
295
AddRembModuleCandidate(RtcpFeedbackSenderInterface * candidate_module,bool media_sender)296 void PacketRouter::AddRembModuleCandidate(
297 RtcpFeedbackSenderInterface* candidate_module,
298 bool media_sender) {
299 RTC_DCHECK(candidate_module);
300 std::vector<RtcpFeedbackSenderInterface*>& candidates =
301 media_sender ? sender_remb_candidates_ : receiver_remb_candidates_;
302 RTC_DCHECK(std::find(candidates.cbegin(), candidates.cend(),
303 candidate_module) == candidates.cend());
304 candidates.push_back(candidate_module);
305 DetermineActiveRembModule();
306 }
307
MaybeRemoveRembModuleCandidate(RtcpFeedbackSenderInterface * candidate_module,bool media_sender)308 void PacketRouter::MaybeRemoveRembModuleCandidate(
309 RtcpFeedbackSenderInterface* candidate_module,
310 bool media_sender) {
311 RTC_DCHECK(candidate_module);
312 std::vector<RtcpFeedbackSenderInterface*>& candidates =
313 media_sender ? sender_remb_candidates_ : receiver_remb_candidates_;
314 auto it = std::find(candidates.begin(), candidates.end(), candidate_module);
315
316 if (it == candidates.end()) {
317 return; // Function called due to removal of non-REMB-candidate module.
318 }
319
320 if (*it == active_remb_module_) {
321 UnsetActiveRembModule();
322 }
323 candidates.erase(it);
324 DetermineActiveRembModule();
325 }
326
UnsetActiveRembModule()327 void PacketRouter::UnsetActiveRembModule() {
328 RTC_CHECK(active_remb_module_);
329 active_remb_module_->UnsetRemb();
330 active_remb_module_ = nullptr;
331 }
332
DetermineActiveRembModule()333 void PacketRouter::DetermineActiveRembModule() {
334 // Sender modules take precedence over receiver modules, because SRs (sender
335 // reports) are sent more frequently than RR (receiver reports).
336 // When adding the first sender module, we should change the active REMB
337 // module to be that. Otherwise, we remain with the current active module.
338
339 RtcpFeedbackSenderInterface* new_active_remb_module;
340
341 if (!sender_remb_candidates_.empty()) {
342 new_active_remb_module = sender_remb_candidates_.front();
343 } else if (!receiver_remb_candidates_.empty()) {
344 new_active_remb_module = receiver_remb_candidates_.front();
345 } else {
346 new_active_remb_module = nullptr;
347 }
348
349 if (new_active_remb_module != active_remb_module_ && active_remb_module_) {
350 UnsetActiveRembModule();
351 }
352
353 active_remb_module_ = new_active_remb_module;
354 }
355
356 } // namespace webrtc
357