xref: /aosp_15_r20/external/webrtc/modules/pacing/packet_router.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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