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