xref: /aosp_15_r20/external/webrtc/call/rtp_video_sender.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 "call/rtp_video_sender.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker #include <memory>
15*d9f75844SAndroid Build Coastguard Worker #include <string>
16*d9f75844SAndroid Build Coastguard Worker #include <utility>
17*d9f75844SAndroid Build Coastguard Worker 
18*d9f75844SAndroid Build Coastguard Worker #include "absl/algorithm/container.h"
19*d9f75844SAndroid Build Coastguard Worker #include "absl/strings/match.h"
20*d9f75844SAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
21*d9f75844SAndroid Build Coastguard Worker #include "api/array_view.h"
22*d9f75844SAndroid Build Coastguard Worker #include "api/task_queue/task_queue_factory.h"
23*d9f75844SAndroid Build Coastguard Worker #include "api/transport/field_trial_based_config.h"
24*d9f75844SAndroid Build Coastguard Worker #include "api/video_codecs/video_codec.h"
25*d9f75844SAndroid Build Coastguard Worker #include "call/rtp_transport_controller_send_interface.h"
26*d9f75844SAndroid Build Coastguard Worker #include "modules/pacing/packet_router.h"
27*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
28*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtp_rtcp_impl2.h"
29*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtp_sender.h"
30*d9f75844SAndroid Build Coastguard Worker #include "modules/utility/maybe_worker_thread.h"
31*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/include/video_codec_interface.h"
32*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
33*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
34*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/task_queue.h"
35*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/trace_event.h"
36*d9f75844SAndroid Build Coastguard Worker 
37*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
38*d9f75844SAndroid Build Coastguard Worker 
39*d9f75844SAndroid Build Coastguard Worker namespace webrtc_internal_rtp_video_sender {
40*d9f75844SAndroid Build Coastguard Worker 
RtpStreamSender(std::unique_ptr<ModuleRtpRtcpImpl2> rtp_rtcp,std::unique_ptr<RTPSenderVideo> sender_video,std::unique_ptr<VideoFecGenerator> fec_generator)41*d9f75844SAndroid Build Coastguard Worker RtpStreamSender::RtpStreamSender(
42*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<ModuleRtpRtcpImpl2> rtp_rtcp,
43*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<RTPSenderVideo> sender_video,
44*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<VideoFecGenerator> fec_generator)
45*d9f75844SAndroid Build Coastguard Worker     : rtp_rtcp(std::move(rtp_rtcp)),
46*d9f75844SAndroid Build Coastguard Worker       sender_video(std::move(sender_video)),
47*d9f75844SAndroid Build Coastguard Worker       fec_generator(std::move(fec_generator)) {}
48*d9f75844SAndroid Build Coastguard Worker 
49*d9f75844SAndroid Build Coastguard Worker RtpStreamSender::~RtpStreamSender() = default;
50*d9f75844SAndroid Build Coastguard Worker 
51*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc_internal_rtp_video_sender
52*d9f75844SAndroid Build Coastguard Worker 
53*d9f75844SAndroid Build Coastguard Worker namespace {
54*d9f75844SAndroid Build Coastguard Worker static const int kMinSendSidePacketHistorySize = 600;
55*d9f75844SAndroid Build Coastguard Worker // We don't do MTU discovery, so assume that we have the standard ethernet MTU.
56*d9f75844SAndroid Build Coastguard Worker static const size_t kPathMTU = 1500;
57*d9f75844SAndroid Build Coastguard Worker 
58*d9f75844SAndroid Build Coastguard Worker using webrtc_internal_rtp_video_sender::RtpStreamSender;
59*d9f75844SAndroid Build Coastguard Worker 
PayloadTypeSupportsSkippingFecPackets(absl::string_view payload_name,const FieldTrialsView & trials)60*d9f75844SAndroid Build Coastguard Worker bool PayloadTypeSupportsSkippingFecPackets(absl::string_view payload_name,
61*d9f75844SAndroid Build Coastguard Worker                                            const FieldTrialsView& trials) {
62*d9f75844SAndroid Build Coastguard Worker   const VideoCodecType codecType =
63*d9f75844SAndroid Build Coastguard Worker       PayloadStringToCodecType(std::string(payload_name));
64*d9f75844SAndroid Build Coastguard Worker   if (codecType == kVideoCodecVP8 || codecType == kVideoCodecVP9) {
65*d9f75844SAndroid Build Coastguard Worker     return true;
66*d9f75844SAndroid Build Coastguard Worker   }
67*d9f75844SAndroid Build Coastguard Worker   if (codecType == kVideoCodecGeneric &&
68*d9f75844SAndroid Build Coastguard Worker       absl::StartsWith(trials.Lookup("WebRTC-GenericPictureId"), "Enabled")) {
69*d9f75844SAndroid Build Coastguard Worker     return true;
70*d9f75844SAndroid Build Coastguard Worker   }
71*d9f75844SAndroid Build Coastguard Worker   return false;
72*d9f75844SAndroid Build Coastguard Worker }
73*d9f75844SAndroid Build Coastguard Worker 
ShouldDisableRedAndUlpfec(bool flexfec_enabled,const RtpConfig & rtp_config,const FieldTrialsView & trials)74*d9f75844SAndroid Build Coastguard Worker bool ShouldDisableRedAndUlpfec(bool flexfec_enabled,
75*d9f75844SAndroid Build Coastguard Worker                                const RtpConfig& rtp_config,
76*d9f75844SAndroid Build Coastguard Worker                                const FieldTrialsView& trials) {
77*d9f75844SAndroid Build Coastguard Worker   // Consistency of NACK and RED+ULPFEC parameters is checked in this function.
78*d9f75844SAndroid Build Coastguard Worker   const bool nack_enabled = rtp_config.nack.rtp_history_ms > 0;
79*d9f75844SAndroid Build Coastguard Worker 
80*d9f75844SAndroid Build Coastguard Worker   // Shorthands.
81*d9f75844SAndroid Build Coastguard Worker   auto IsRedEnabled = [&]() { return rtp_config.ulpfec.red_payload_type >= 0; };
82*d9f75844SAndroid Build Coastguard Worker   auto IsUlpfecEnabled = [&]() {
83*d9f75844SAndroid Build Coastguard Worker     return rtp_config.ulpfec.ulpfec_payload_type >= 0;
84*d9f75844SAndroid Build Coastguard Worker   };
85*d9f75844SAndroid Build Coastguard Worker 
86*d9f75844SAndroid Build Coastguard Worker   bool should_disable_red_and_ulpfec = false;
87*d9f75844SAndroid Build Coastguard Worker 
88*d9f75844SAndroid Build Coastguard Worker   if (absl::StartsWith(trials.Lookup("WebRTC-DisableUlpFecExperiment"),
89*d9f75844SAndroid Build Coastguard Worker                        "Enabled")) {
90*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_INFO) << "Experiment to disable sending ULPFEC is enabled.";
91*d9f75844SAndroid Build Coastguard Worker     should_disable_red_and_ulpfec = true;
92*d9f75844SAndroid Build Coastguard Worker   }
93*d9f75844SAndroid Build Coastguard Worker 
94*d9f75844SAndroid Build Coastguard Worker   // If enabled, FlexFEC takes priority over RED+ULPFEC.
95*d9f75844SAndroid Build Coastguard Worker   if (flexfec_enabled) {
96*d9f75844SAndroid Build Coastguard Worker     if (IsUlpfecEnabled()) {
97*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_INFO)
98*d9f75844SAndroid Build Coastguard Worker           << "Both FlexFEC and ULPFEC are configured. Disabling ULPFEC.";
99*d9f75844SAndroid Build Coastguard Worker     }
100*d9f75844SAndroid Build Coastguard Worker     should_disable_red_and_ulpfec = true;
101*d9f75844SAndroid Build Coastguard Worker   }
102*d9f75844SAndroid Build Coastguard Worker 
103*d9f75844SAndroid Build Coastguard Worker   // Payload types without picture ID cannot determine that a stream is complete
104*d9f75844SAndroid Build Coastguard Worker   // without retransmitting FEC, so using ULPFEC + NACK for H.264 (for instance)
105*d9f75844SAndroid Build Coastguard Worker   // is a waste of bandwidth since FEC packets still have to be transmitted.
106*d9f75844SAndroid Build Coastguard Worker   // Note that this is not the case with FlexFEC.
107*d9f75844SAndroid Build Coastguard Worker   if (nack_enabled && IsUlpfecEnabled() &&
108*d9f75844SAndroid Build Coastguard Worker       !PayloadTypeSupportsSkippingFecPackets(rtp_config.payload_name, trials)) {
109*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING)
110*d9f75844SAndroid Build Coastguard Worker         << "Transmitting payload type without picture ID using "
111*d9f75844SAndroid Build Coastguard Worker            "NACK+ULPFEC is a waste of bandwidth since ULPFEC packets "
112*d9f75844SAndroid Build Coastguard Worker            "also have to be retransmitted. Disabling ULPFEC.";
113*d9f75844SAndroid Build Coastguard Worker     should_disable_red_and_ulpfec = true;
114*d9f75844SAndroid Build Coastguard Worker   }
115*d9f75844SAndroid Build Coastguard Worker 
116*d9f75844SAndroid Build Coastguard Worker   // Verify payload types.
117*d9f75844SAndroid Build Coastguard Worker   if (IsUlpfecEnabled() ^ IsRedEnabled()) {
118*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING)
119*d9f75844SAndroid Build Coastguard Worker         << "Only RED or only ULPFEC enabled, but not both. Disabling both.";
120*d9f75844SAndroid Build Coastguard Worker     should_disable_red_and_ulpfec = true;
121*d9f75844SAndroid Build Coastguard Worker   }
122*d9f75844SAndroid Build Coastguard Worker 
123*d9f75844SAndroid Build Coastguard Worker   return should_disable_red_and_ulpfec;
124*d9f75844SAndroid Build Coastguard Worker }
125*d9f75844SAndroid Build Coastguard Worker 
126*d9f75844SAndroid Build Coastguard Worker // TODO(brandtr): Update this function when we support multistream protection.
MaybeCreateFecGenerator(Clock * clock,const RtpConfig & rtp,const std::map<uint32_t,RtpState> & suspended_ssrcs,int simulcast_index,const FieldTrialsView & trials)127*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<VideoFecGenerator> MaybeCreateFecGenerator(
128*d9f75844SAndroid Build Coastguard Worker     Clock* clock,
129*d9f75844SAndroid Build Coastguard Worker     const RtpConfig& rtp,
130*d9f75844SAndroid Build Coastguard Worker     const std::map<uint32_t, RtpState>& suspended_ssrcs,
131*d9f75844SAndroid Build Coastguard Worker     int simulcast_index,
132*d9f75844SAndroid Build Coastguard Worker     const FieldTrialsView& trials) {
133*d9f75844SAndroid Build Coastguard Worker   // If flexfec is configured that takes priority.
134*d9f75844SAndroid Build Coastguard Worker   if (rtp.flexfec.payload_type >= 0) {
135*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_GE(rtp.flexfec.payload_type, 0);
136*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_LE(rtp.flexfec.payload_type, 127);
137*d9f75844SAndroid Build Coastguard Worker     if (rtp.flexfec.ssrc == 0) {
138*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_WARNING) << "FlexFEC is enabled, but no FlexFEC SSRC given. "
139*d9f75844SAndroid Build Coastguard Worker                              "Therefore disabling FlexFEC.";
140*d9f75844SAndroid Build Coastguard Worker       return nullptr;
141*d9f75844SAndroid Build Coastguard Worker     }
142*d9f75844SAndroid Build Coastguard Worker     if (rtp.flexfec.protected_media_ssrcs.empty()) {
143*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_WARNING)
144*d9f75844SAndroid Build Coastguard Worker           << "FlexFEC is enabled, but no protected media SSRC given. "
145*d9f75844SAndroid Build Coastguard Worker              "Therefore disabling FlexFEC.";
146*d9f75844SAndroid Build Coastguard Worker       return nullptr;
147*d9f75844SAndroid Build Coastguard Worker     }
148*d9f75844SAndroid Build Coastguard Worker 
149*d9f75844SAndroid Build Coastguard Worker     if (rtp.flexfec.protected_media_ssrcs.size() > 1) {
150*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_WARNING)
151*d9f75844SAndroid Build Coastguard Worker           << "The supplied FlexfecConfig contained multiple protected "
152*d9f75844SAndroid Build Coastguard Worker              "media streams, but our implementation currently only "
153*d9f75844SAndroid Build Coastguard Worker              "supports protecting a single media stream. "
154*d9f75844SAndroid Build Coastguard Worker              "To avoid confusion, disabling FlexFEC completely.";
155*d9f75844SAndroid Build Coastguard Worker       return nullptr;
156*d9f75844SAndroid Build Coastguard Worker     }
157*d9f75844SAndroid Build Coastguard Worker 
158*d9f75844SAndroid Build Coastguard Worker     if (absl::c_find(rtp.flexfec.protected_media_ssrcs,
159*d9f75844SAndroid Build Coastguard Worker                      rtp.ssrcs[simulcast_index]) ==
160*d9f75844SAndroid Build Coastguard Worker         rtp.flexfec.protected_media_ssrcs.end()) {
161*d9f75844SAndroid Build Coastguard Worker       // Media SSRC not among flexfec protected SSRCs.
162*d9f75844SAndroid Build Coastguard Worker       return nullptr;
163*d9f75844SAndroid Build Coastguard Worker     }
164*d9f75844SAndroid Build Coastguard Worker 
165*d9f75844SAndroid Build Coastguard Worker     const RtpState* rtp_state = nullptr;
166*d9f75844SAndroid Build Coastguard Worker     auto it = suspended_ssrcs.find(rtp.flexfec.ssrc);
167*d9f75844SAndroid Build Coastguard Worker     if (it != suspended_ssrcs.end()) {
168*d9f75844SAndroid Build Coastguard Worker       rtp_state = &it->second;
169*d9f75844SAndroid Build Coastguard Worker     }
170*d9f75844SAndroid Build Coastguard Worker 
171*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_EQ(1U, rtp.flexfec.protected_media_ssrcs.size());
172*d9f75844SAndroid Build Coastguard Worker     return std::make_unique<FlexfecSender>(
173*d9f75844SAndroid Build Coastguard Worker         rtp.flexfec.payload_type, rtp.flexfec.ssrc,
174*d9f75844SAndroid Build Coastguard Worker         rtp.flexfec.protected_media_ssrcs[0], rtp.mid, rtp.extensions,
175*d9f75844SAndroid Build Coastguard Worker         RTPSender::FecExtensionSizes(), rtp_state, clock);
176*d9f75844SAndroid Build Coastguard Worker   } else if (rtp.ulpfec.red_payload_type >= 0 &&
177*d9f75844SAndroid Build Coastguard Worker              rtp.ulpfec.ulpfec_payload_type >= 0 &&
178*d9f75844SAndroid Build Coastguard Worker              !ShouldDisableRedAndUlpfec(/*flexfec_enabled=*/false, rtp,
179*d9f75844SAndroid Build Coastguard Worker                                         trials)) {
180*d9f75844SAndroid Build Coastguard Worker     // Flexfec not configured, but ulpfec is and is not disabled.
181*d9f75844SAndroid Build Coastguard Worker     return std::make_unique<UlpfecGenerator>(
182*d9f75844SAndroid Build Coastguard Worker         rtp.ulpfec.red_payload_type, rtp.ulpfec.ulpfec_payload_type, clock);
183*d9f75844SAndroid Build Coastguard Worker   }
184*d9f75844SAndroid Build Coastguard Worker 
185*d9f75844SAndroid Build Coastguard Worker   // Not a single FEC is given.
186*d9f75844SAndroid Build Coastguard Worker   return nullptr;
187*d9f75844SAndroid Build Coastguard Worker }
188*d9f75844SAndroid Build Coastguard Worker 
CreateRtpStreamSenders(Clock * clock,const RtpConfig & rtp_config,const RtpSenderObservers & observers,int rtcp_report_interval_ms,Transport * send_transport,RtcpBandwidthObserver * bandwidth_callback,RtpTransportControllerSendInterface * transport,const std::map<uint32_t,RtpState> & suspended_ssrcs,RtcEventLog * event_log,RateLimiter * retransmission_rate_limiter,FrameEncryptorInterface * frame_encryptor,const CryptoOptions & crypto_options,rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,const FieldTrialsView & trials,TaskQueueFactory * task_queue_factory)189*d9f75844SAndroid Build Coastguard Worker std::vector<RtpStreamSender> CreateRtpStreamSenders(
190*d9f75844SAndroid Build Coastguard Worker     Clock* clock,
191*d9f75844SAndroid Build Coastguard Worker     const RtpConfig& rtp_config,
192*d9f75844SAndroid Build Coastguard Worker     const RtpSenderObservers& observers,
193*d9f75844SAndroid Build Coastguard Worker     int rtcp_report_interval_ms,
194*d9f75844SAndroid Build Coastguard Worker     Transport* send_transport,
195*d9f75844SAndroid Build Coastguard Worker     RtcpBandwidthObserver* bandwidth_callback,
196*d9f75844SAndroid Build Coastguard Worker     RtpTransportControllerSendInterface* transport,
197*d9f75844SAndroid Build Coastguard Worker     const std::map<uint32_t, RtpState>& suspended_ssrcs,
198*d9f75844SAndroid Build Coastguard Worker     RtcEventLog* event_log,
199*d9f75844SAndroid Build Coastguard Worker     RateLimiter* retransmission_rate_limiter,
200*d9f75844SAndroid Build Coastguard Worker     FrameEncryptorInterface* frame_encryptor,
201*d9f75844SAndroid Build Coastguard Worker     const CryptoOptions& crypto_options,
202*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
203*d9f75844SAndroid Build Coastguard Worker     const FieldTrialsView& trials,
204*d9f75844SAndroid Build Coastguard Worker     TaskQueueFactory* task_queue_factory) {
205*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GT(rtp_config.ssrcs.size(), 0);
206*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(task_queue_factory);
207*d9f75844SAndroid Build Coastguard Worker 
208*d9f75844SAndroid Build Coastguard Worker   RtpRtcpInterface::Configuration configuration;
209*d9f75844SAndroid Build Coastguard Worker   configuration.clock = clock;
210*d9f75844SAndroid Build Coastguard Worker   configuration.audio = false;
211*d9f75844SAndroid Build Coastguard Worker   configuration.receiver_only = false;
212*d9f75844SAndroid Build Coastguard Worker   configuration.outgoing_transport = send_transport;
213*d9f75844SAndroid Build Coastguard Worker   configuration.intra_frame_callback = observers.intra_frame_callback;
214*d9f75844SAndroid Build Coastguard Worker   configuration.rtcp_loss_notification_observer =
215*d9f75844SAndroid Build Coastguard Worker       observers.rtcp_loss_notification_observer;
216*d9f75844SAndroid Build Coastguard Worker   configuration.bandwidth_callback = bandwidth_callback;
217*d9f75844SAndroid Build Coastguard Worker   configuration.network_state_estimate_observer =
218*d9f75844SAndroid Build Coastguard Worker       transport->network_state_estimate_observer();
219*d9f75844SAndroid Build Coastguard Worker   configuration.transport_feedback_callback =
220*d9f75844SAndroid Build Coastguard Worker       transport->transport_feedback_observer();
221*d9f75844SAndroid Build Coastguard Worker   configuration.rtt_stats = observers.rtcp_rtt_stats;
222*d9f75844SAndroid Build Coastguard Worker   configuration.rtcp_packet_type_counter_observer =
223*d9f75844SAndroid Build Coastguard Worker       observers.rtcp_type_observer;
224*d9f75844SAndroid Build Coastguard Worker   configuration.report_block_data_observer =
225*d9f75844SAndroid Build Coastguard Worker       observers.report_block_data_observer;
226*d9f75844SAndroid Build Coastguard Worker   configuration.paced_sender = transport->packet_sender();
227*d9f75844SAndroid Build Coastguard Worker   configuration.send_bitrate_observer = observers.bitrate_observer;
228*d9f75844SAndroid Build Coastguard Worker   configuration.send_side_delay_observer = observers.send_delay_observer;
229*d9f75844SAndroid Build Coastguard Worker   configuration.send_packet_observer = observers.send_packet_observer;
230*d9f75844SAndroid Build Coastguard Worker   configuration.event_log = event_log;
231*d9f75844SAndroid Build Coastguard Worker   configuration.retransmission_rate_limiter = retransmission_rate_limiter;
232*d9f75844SAndroid Build Coastguard Worker   configuration.rtp_stats_callback = observers.rtp_stats;
233*d9f75844SAndroid Build Coastguard Worker   configuration.frame_encryptor = frame_encryptor;
234*d9f75844SAndroid Build Coastguard Worker   configuration.require_frame_encryption =
235*d9f75844SAndroid Build Coastguard Worker       crypto_options.sframe.require_frame_encryption;
236*d9f75844SAndroid Build Coastguard Worker   configuration.extmap_allow_mixed = rtp_config.extmap_allow_mixed;
237*d9f75844SAndroid Build Coastguard Worker   configuration.rtcp_report_interval_ms = rtcp_report_interval_ms;
238*d9f75844SAndroid Build Coastguard Worker   configuration.field_trials = &trials;
239*d9f75844SAndroid Build Coastguard Worker 
240*d9f75844SAndroid Build Coastguard Worker   std::vector<RtpStreamSender> rtp_streams;
241*d9f75844SAndroid Build Coastguard Worker 
242*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(rtp_config.rtx.ssrcs.empty() ||
243*d9f75844SAndroid Build Coastguard Worker              rtp_config.rtx.ssrcs.size() == rtp_config.ssrcs.size());
244*d9f75844SAndroid Build Coastguard Worker 
245*d9f75844SAndroid Build Coastguard Worker   // Some streams could have been disabled, but the rids are still there.
246*d9f75844SAndroid Build Coastguard Worker   // This will occur when simulcast has been disabled for a codec (e.g. VP9)
247*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(rtp_config.rids.empty() ||
248*d9f75844SAndroid Build Coastguard Worker              rtp_config.rids.size() >= rtp_config.ssrcs.size());
249*d9f75844SAndroid Build Coastguard Worker 
250*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < rtp_config.ssrcs.size(); ++i) {
251*d9f75844SAndroid Build Coastguard Worker     RTPSenderVideo::Config video_config;
252*d9f75844SAndroid Build Coastguard Worker     configuration.local_media_ssrc = rtp_config.ssrcs[i];
253*d9f75844SAndroid Build Coastguard Worker 
254*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<VideoFecGenerator> fec_generator =
255*d9f75844SAndroid Build Coastguard Worker         MaybeCreateFecGenerator(clock, rtp_config, suspended_ssrcs, i, trials);
256*d9f75844SAndroid Build Coastguard Worker     configuration.fec_generator = fec_generator.get();
257*d9f75844SAndroid Build Coastguard Worker 
258*d9f75844SAndroid Build Coastguard Worker     configuration.rtx_send_ssrc =
259*d9f75844SAndroid Build Coastguard Worker         rtp_config.GetRtxSsrcAssociatedWithMediaSsrc(rtp_config.ssrcs[i]);
260*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_EQ(configuration.rtx_send_ssrc.has_value(),
261*d9f75844SAndroid Build Coastguard Worker                   !rtp_config.rtx.ssrcs.empty());
262*d9f75844SAndroid Build Coastguard Worker 
263*d9f75844SAndroid Build Coastguard Worker     configuration.rid = (i < rtp_config.rids.size()) ? rtp_config.rids[i] : "";
264*d9f75844SAndroid Build Coastguard Worker 
265*d9f75844SAndroid Build Coastguard Worker     configuration.need_rtp_packet_infos = rtp_config.lntf.enabled;
266*d9f75844SAndroid Build Coastguard Worker 
267*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<ModuleRtpRtcpImpl2> rtp_rtcp(
268*d9f75844SAndroid Build Coastguard Worker         ModuleRtpRtcpImpl2::Create(configuration));
269*d9f75844SAndroid Build Coastguard Worker     rtp_rtcp->SetSendingStatus(false);
270*d9f75844SAndroid Build Coastguard Worker     rtp_rtcp->SetSendingMediaStatus(false);
271*d9f75844SAndroid Build Coastguard Worker     rtp_rtcp->SetRTCPStatus(RtcpMode::kCompound);
272*d9f75844SAndroid Build Coastguard Worker     // Set NACK.
273*d9f75844SAndroid Build Coastguard Worker     rtp_rtcp->SetStorePacketsStatus(true, kMinSendSidePacketHistorySize);
274*d9f75844SAndroid Build Coastguard Worker 
275*d9f75844SAndroid Build Coastguard Worker     video_config.clock = configuration.clock;
276*d9f75844SAndroid Build Coastguard Worker     video_config.rtp_sender = rtp_rtcp->RtpSender();
277*d9f75844SAndroid Build Coastguard Worker     video_config.frame_encryptor = frame_encryptor;
278*d9f75844SAndroid Build Coastguard Worker     video_config.require_frame_encryption =
279*d9f75844SAndroid Build Coastguard Worker         crypto_options.sframe.require_frame_encryption;
280*d9f75844SAndroid Build Coastguard Worker     video_config.enable_retransmit_all_layers = false;
281*d9f75844SAndroid Build Coastguard Worker     video_config.field_trials = &trials;
282*d9f75844SAndroid Build Coastguard Worker 
283*d9f75844SAndroid Build Coastguard Worker     const bool using_flexfec =
284*d9f75844SAndroid Build Coastguard Worker         fec_generator &&
285*d9f75844SAndroid Build Coastguard Worker         fec_generator->GetFecType() == VideoFecGenerator::FecType::kFlexFec;
286*d9f75844SAndroid Build Coastguard Worker     const bool should_disable_red_and_ulpfec =
287*d9f75844SAndroid Build Coastguard Worker         ShouldDisableRedAndUlpfec(using_flexfec, rtp_config, trials);
288*d9f75844SAndroid Build Coastguard Worker     if (!should_disable_red_and_ulpfec &&
289*d9f75844SAndroid Build Coastguard Worker         rtp_config.ulpfec.red_payload_type != -1) {
290*d9f75844SAndroid Build Coastguard Worker       video_config.red_payload_type = rtp_config.ulpfec.red_payload_type;
291*d9f75844SAndroid Build Coastguard Worker     }
292*d9f75844SAndroid Build Coastguard Worker     if (fec_generator) {
293*d9f75844SAndroid Build Coastguard Worker       video_config.fec_type = fec_generator->GetFecType();
294*d9f75844SAndroid Build Coastguard Worker       video_config.fec_overhead_bytes = fec_generator->MaxPacketOverhead();
295*d9f75844SAndroid Build Coastguard Worker     }
296*d9f75844SAndroid Build Coastguard Worker     video_config.frame_transformer = frame_transformer;
297*d9f75844SAndroid Build Coastguard Worker     video_config.task_queue_factory = task_queue_factory;
298*d9f75844SAndroid Build Coastguard Worker     auto sender_video = std::make_unique<RTPSenderVideo>(video_config);
299*d9f75844SAndroid Build Coastguard Worker     rtp_streams.emplace_back(std::move(rtp_rtcp), std::move(sender_video),
300*d9f75844SAndroid Build Coastguard Worker                              std::move(fec_generator));
301*d9f75844SAndroid Build Coastguard Worker   }
302*d9f75844SAndroid Build Coastguard Worker   return rtp_streams;
303*d9f75844SAndroid Build Coastguard Worker }
304*d9f75844SAndroid Build Coastguard Worker 
GetVideoCodecType(const RtpConfig & config)305*d9f75844SAndroid Build Coastguard Worker absl::optional<VideoCodecType> GetVideoCodecType(const RtpConfig& config) {
306*d9f75844SAndroid Build Coastguard Worker   if (config.raw_payload) {
307*d9f75844SAndroid Build Coastguard Worker     return absl::nullopt;
308*d9f75844SAndroid Build Coastguard Worker   }
309*d9f75844SAndroid Build Coastguard Worker   return PayloadStringToCodecType(config.payload_name);
310*d9f75844SAndroid Build Coastguard Worker }
TransportSeqNumExtensionConfigured(const RtpConfig & config)311*d9f75844SAndroid Build Coastguard Worker bool TransportSeqNumExtensionConfigured(const RtpConfig& config) {
312*d9f75844SAndroid Build Coastguard Worker   return absl::c_any_of(config.extensions, [](const RtpExtension& ext) {
313*d9f75844SAndroid Build Coastguard Worker     return ext.uri == RtpExtension::kTransportSequenceNumberUri;
314*d9f75844SAndroid Build Coastguard Worker   });
315*d9f75844SAndroid Build Coastguard Worker }
316*d9f75844SAndroid Build Coastguard Worker 
317*d9f75844SAndroid Build Coastguard Worker // Returns true when some coded video sequence can be decoded starting with
318*d9f75844SAndroid Build Coastguard Worker // this frame without requiring any previous frames.
319*d9f75844SAndroid Build Coastguard Worker // e.g. it is the same as a key frame when spatial scalability is not used.
320*d9f75844SAndroid Build Coastguard Worker // When spatial scalability is used, then it is true for layer frames of
321*d9f75844SAndroid Build Coastguard Worker // a key frame without inter-layer dependencies.
IsFirstFrameOfACodedVideoSequence(const EncodedImage & encoded_image,const CodecSpecificInfo * codec_specific_info)322*d9f75844SAndroid Build Coastguard Worker bool IsFirstFrameOfACodedVideoSequence(
323*d9f75844SAndroid Build Coastguard Worker     const EncodedImage& encoded_image,
324*d9f75844SAndroid Build Coastguard Worker     const CodecSpecificInfo* codec_specific_info) {
325*d9f75844SAndroid Build Coastguard Worker   if (encoded_image._frameType != VideoFrameType::kVideoFrameKey) {
326*d9f75844SAndroid Build Coastguard Worker     return false;
327*d9f75844SAndroid Build Coastguard Worker   }
328*d9f75844SAndroid Build Coastguard Worker 
329*d9f75844SAndroid Build Coastguard Worker   if (codec_specific_info != nullptr) {
330*d9f75844SAndroid Build Coastguard Worker     if (codec_specific_info->generic_frame_info.has_value()) {
331*d9f75844SAndroid Build Coastguard Worker       // This function is used before
332*d9f75844SAndroid Build Coastguard Worker       // `codec_specific_info->generic_frame_info->frame_diffs` are calculated,
333*d9f75844SAndroid Build Coastguard Worker       // so need to use a more complicated way to check for presence of the
334*d9f75844SAndroid Build Coastguard Worker       // dependencies.
335*d9f75844SAndroid Build Coastguard Worker       return absl::c_none_of(
336*d9f75844SAndroid Build Coastguard Worker           codec_specific_info->generic_frame_info->encoder_buffers,
337*d9f75844SAndroid Build Coastguard Worker           [](const CodecBufferUsage& buffer) { return buffer.referenced; });
338*d9f75844SAndroid Build Coastguard Worker     }
339*d9f75844SAndroid Build Coastguard Worker 
340*d9f75844SAndroid Build Coastguard Worker     if (codec_specific_info->codecType == VideoCodecType::kVideoCodecVP8 ||
341*d9f75844SAndroid Build Coastguard Worker         codec_specific_info->codecType == VideoCodecType::kVideoCodecH264 ||
342*d9f75844SAndroid Build Coastguard Worker         codec_specific_info->codecType == VideoCodecType::kVideoCodecGeneric) {
343*d9f75844SAndroid Build Coastguard Worker       // These codecs do not support intra picture dependencies, so a frame
344*d9f75844SAndroid Build Coastguard Worker       // marked as a key frame should be a key frame.
345*d9f75844SAndroid Build Coastguard Worker       return true;
346*d9f75844SAndroid Build Coastguard Worker     }
347*d9f75844SAndroid Build Coastguard Worker   }
348*d9f75844SAndroid Build Coastguard Worker 
349*d9f75844SAndroid Build Coastguard Worker   // Without depenedencies described in generic format do an educated guess.
350*d9f75844SAndroid Build Coastguard Worker   // It might be wrong for VP9 with spatial layer 0 skipped or higher spatial
351*d9f75844SAndroid Build Coastguard Worker   // layer not depending on the spatial layer 0. This corner case is unimportant
352*d9f75844SAndroid Build Coastguard Worker   // for current usage of this helper function.
353*d9f75844SAndroid Build Coastguard Worker 
354*d9f75844SAndroid Build Coastguard Worker   // Use <= to accept both 0 (i.e. the first) and nullopt (i.e. the only).
355*d9f75844SAndroid Build Coastguard Worker   return encoded_image.SpatialIndex() <= 0;
356*d9f75844SAndroid Build Coastguard Worker }
357*d9f75844SAndroid Build Coastguard Worker 
358*d9f75844SAndroid Build Coastguard Worker }  // namespace
359*d9f75844SAndroid Build Coastguard Worker 
RtpVideoSender(Clock * clock,const std::map<uint32_t,RtpState> & suspended_ssrcs,const std::map<uint32_t,RtpPayloadState> & states,const RtpConfig & rtp_config,int rtcp_report_interval_ms,Transport * send_transport,const RtpSenderObservers & observers,RtpTransportControllerSendInterface * transport,RtcEventLog * event_log,RateLimiter * retransmission_limiter,std::unique_ptr<FecController> fec_controller,FrameEncryptorInterface * frame_encryptor,const CryptoOptions & crypto_options,rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,const FieldTrialsView & field_trials,TaskQueueFactory * task_queue_factory)360*d9f75844SAndroid Build Coastguard Worker RtpVideoSender::RtpVideoSender(
361*d9f75844SAndroid Build Coastguard Worker     Clock* clock,
362*d9f75844SAndroid Build Coastguard Worker     const std::map<uint32_t, RtpState>& suspended_ssrcs,
363*d9f75844SAndroid Build Coastguard Worker     const std::map<uint32_t, RtpPayloadState>& states,
364*d9f75844SAndroid Build Coastguard Worker     const RtpConfig& rtp_config,
365*d9f75844SAndroid Build Coastguard Worker     int rtcp_report_interval_ms,
366*d9f75844SAndroid Build Coastguard Worker     Transport* send_transport,
367*d9f75844SAndroid Build Coastguard Worker     const RtpSenderObservers& observers,
368*d9f75844SAndroid Build Coastguard Worker     RtpTransportControllerSendInterface* transport,
369*d9f75844SAndroid Build Coastguard Worker     RtcEventLog* event_log,
370*d9f75844SAndroid Build Coastguard Worker     RateLimiter* retransmission_limiter,
371*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<FecController> fec_controller,
372*d9f75844SAndroid Build Coastguard Worker     FrameEncryptorInterface* frame_encryptor,
373*d9f75844SAndroid Build Coastguard Worker     const CryptoOptions& crypto_options,
374*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
375*d9f75844SAndroid Build Coastguard Worker     const FieldTrialsView& field_trials,
376*d9f75844SAndroid Build Coastguard Worker     TaskQueueFactory* task_queue_factory)
377*d9f75844SAndroid Build Coastguard Worker     : field_trials_(field_trials),
378*d9f75844SAndroid Build Coastguard Worker       use_frame_rate_for_overhead_(absl::StartsWith(
379*d9f75844SAndroid Build Coastguard Worker           field_trials_.Lookup("WebRTC-Video-UseFrameRateForOverhead"),
380*d9f75844SAndroid Build Coastguard Worker           "Enabled")),
381*d9f75844SAndroid Build Coastguard Worker       has_packet_feedback_(TransportSeqNumExtensionConfigured(rtp_config)),
382*d9f75844SAndroid Build Coastguard Worker       active_(false),
383*d9f75844SAndroid Build Coastguard Worker       fec_controller_(std::move(fec_controller)),
384*d9f75844SAndroid Build Coastguard Worker       fec_allowed_(true),
385*d9f75844SAndroid Build Coastguard Worker       rtp_streams_(CreateRtpStreamSenders(clock,
386*d9f75844SAndroid Build Coastguard Worker                                           rtp_config,
387*d9f75844SAndroid Build Coastguard Worker                                           observers,
388*d9f75844SAndroid Build Coastguard Worker                                           rtcp_report_interval_ms,
389*d9f75844SAndroid Build Coastguard Worker                                           send_transport,
390*d9f75844SAndroid Build Coastguard Worker                                           transport->GetBandwidthObserver(),
391*d9f75844SAndroid Build Coastguard Worker                                           transport,
392*d9f75844SAndroid Build Coastguard Worker                                           suspended_ssrcs,
393*d9f75844SAndroid Build Coastguard Worker                                           event_log,
394*d9f75844SAndroid Build Coastguard Worker                                           retransmission_limiter,
395*d9f75844SAndroid Build Coastguard Worker                                           frame_encryptor,
396*d9f75844SAndroid Build Coastguard Worker                                           crypto_options,
397*d9f75844SAndroid Build Coastguard Worker                                           std::move(frame_transformer),
398*d9f75844SAndroid Build Coastguard Worker                                           field_trials_,
399*d9f75844SAndroid Build Coastguard Worker                                           task_queue_factory)),
400*d9f75844SAndroid Build Coastguard Worker       rtp_config_(rtp_config),
401*d9f75844SAndroid Build Coastguard Worker       codec_type_(GetVideoCodecType(rtp_config)),
402*d9f75844SAndroid Build Coastguard Worker       transport_(transport),
403*d9f75844SAndroid Build Coastguard Worker       transport_overhead_bytes_per_packet_(0),
404*d9f75844SAndroid Build Coastguard Worker       encoder_target_rate_bps_(0),
405*d9f75844SAndroid Build Coastguard Worker       frame_counts_(rtp_config.ssrcs.size()),
406*d9f75844SAndroid Build Coastguard Worker       frame_count_observer_(observers.frame_count_observer) {
407*d9f75844SAndroid Build Coastguard Worker   transport_checker_.Detach();
408*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(rtp_config_.ssrcs.size(), rtp_streams_.size());
409*d9f75844SAndroid Build Coastguard Worker   if (has_packet_feedback_)
410*d9f75844SAndroid Build Coastguard Worker     transport_->IncludeOverheadInPacedSender();
411*d9f75844SAndroid Build Coastguard Worker   // SSRCs are assumed to be sorted in the same order as `rtp_modules`.
412*d9f75844SAndroid Build Coastguard Worker   for (uint32_t ssrc : rtp_config_.ssrcs) {
413*d9f75844SAndroid Build Coastguard Worker     // Restore state if it previously existed.
414*d9f75844SAndroid Build Coastguard Worker     const RtpPayloadState* state = nullptr;
415*d9f75844SAndroid Build Coastguard Worker     auto it = states.find(ssrc);
416*d9f75844SAndroid Build Coastguard Worker     if (it != states.end()) {
417*d9f75844SAndroid Build Coastguard Worker       state = &it->second;
418*d9f75844SAndroid Build Coastguard Worker       shared_frame_id_ = std::max(shared_frame_id_, state->shared_frame_id);
419*d9f75844SAndroid Build Coastguard Worker     }
420*d9f75844SAndroid Build Coastguard Worker     params_.push_back(RtpPayloadParams(ssrc, state, field_trials_));
421*d9f75844SAndroid Build Coastguard Worker   }
422*d9f75844SAndroid Build Coastguard Worker 
423*d9f75844SAndroid Build Coastguard Worker   // RTP/RTCP initialization.
424*d9f75844SAndroid Build Coastguard Worker 
425*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < rtp_config_.extensions.size(); ++i) {
426*d9f75844SAndroid Build Coastguard Worker     const std::string& extension = rtp_config_.extensions[i].uri;
427*d9f75844SAndroid Build Coastguard Worker     int id = rtp_config_.extensions[i].id;
428*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(RtpExtension::IsSupportedForVideo(extension));
429*d9f75844SAndroid Build Coastguard Worker     for (const RtpStreamSender& stream : rtp_streams_) {
430*d9f75844SAndroid Build Coastguard Worker       stream.rtp_rtcp->RegisterRtpHeaderExtension(extension, id);
431*d9f75844SAndroid Build Coastguard Worker     }
432*d9f75844SAndroid Build Coastguard Worker   }
433*d9f75844SAndroid Build Coastguard Worker 
434*d9f75844SAndroid Build Coastguard Worker   ConfigureSsrcs(suspended_ssrcs);
435*d9f75844SAndroid Build Coastguard Worker 
436*d9f75844SAndroid Build Coastguard Worker   if (!rtp_config_.mid.empty()) {
437*d9f75844SAndroid Build Coastguard Worker     for (const RtpStreamSender& stream : rtp_streams_) {
438*d9f75844SAndroid Build Coastguard Worker       stream.rtp_rtcp->SetMid(rtp_config_.mid);
439*d9f75844SAndroid Build Coastguard Worker     }
440*d9f75844SAndroid Build Coastguard Worker   }
441*d9f75844SAndroid Build Coastguard Worker 
442*d9f75844SAndroid Build Coastguard Worker   bool fec_enabled = false;
443*d9f75844SAndroid Build Coastguard Worker   for (const RtpStreamSender& stream : rtp_streams_) {
444*d9f75844SAndroid Build Coastguard Worker     // Simulcast has one module for each layer. Set the CNAME on all modules.
445*d9f75844SAndroid Build Coastguard Worker     stream.rtp_rtcp->SetCNAME(rtp_config_.c_name.c_str());
446*d9f75844SAndroid Build Coastguard Worker     stream.rtp_rtcp->SetMaxRtpPacketSize(rtp_config_.max_packet_size);
447*d9f75844SAndroid Build Coastguard Worker     stream.rtp_rtcp->RegisterSendPayloadFrequency(rtp_config_.payload_type,
448*d9f75844SAndroid Build Coastguard Worker                                                   kVideoPayloadTypeFrequency);
449*d9f75844SAndroid Build Coastguard Worker     if (stream.fec_generator != nullptr) {
450*d9f75844SAndroid Build Coastguard Worker       fec_enabled = true;
451*d9f75844SAndroid Build Coastguard Worker     }
452*d9f75844SAndroid Build Coastguard Worker   }
453*d9f75844SAndroid Build Coastguard Worker   // Currently, both ULPFEC and FlexFEC use the same FEC rate calculation logic,
454*d9f75844SAndroid Build Coastguard Worker   // so enable that logic if either of those FEC schemes are enabled.
455*d9f75844SAndroid Build Coastguard Worker   fec_controller_->SetProtectionMethod(fec_enabled, NackEnabled());
456*d9f75844SAndroid Build Coastguard Worker 
457*d9f75844SAndroid Build Coastguard Worker   fec_controller_->SetProtectionCallback(this);
458*d9f75844SAndroid Build Coastguard Worker 
459*d9f75844SAndroid Build Coastguard Worker   // Construction happens on the worker thread (see Call::CreateVideoSendStream)
460*d9f75844SAndroid Build Coastguard Worker   // but subseqeuent calls to the RTP state will happen on one of two threads:
461*d9f75844SAndroid Build Coastguard Worker   // * The pacer thread for actually sending packets.
462*d9f75844SAndroid Build Coastguard Worker   // * The transport thread when tearing down and quering GetRtpState().
463*d9f75844SAndroid Build Coastguard Worker   // Detach thread checkers.
464*d9f75844SAndroid Build Coastguard Worker   for (const RtpStreamSender& stream : rtp_streams_) {
465*d9f75844SAndroid Build Coastguard Worker     stream.rtp_rtcp->OnPacketSendingThreadSwitched();
466*d9f75844SAndroid Build Coastguard Worker   }
467*d9f75844SAndroid Build Coastguard Worker }
468*d9f75844SAndroid Build Coastguard Worker 
~RtpVideoSender()469*d9f75844SAndroid Build Coastguard Worker RtpVideoSender::~RtpVideoSender() {
470*d9f75844SAndroid Build Coastguard Worker   // TODO(bugs.webrtc.org/13517): Remove once RtpVideoSender gets deleted on the
471*d9f75844SAndroid Build Coastguard Worker   // transport task queue.
472*d9f75844SAndroid Build Coastguard Worker   transport_checker_.Detach();
473*d9f75844SAndroid Build Coastguard Worker 
474*d9f75844SAndroid Build Coastguard Worker   SetActiveModulesLocked(
475*d9f75844SAndroid Build Coastguard Worker       std::vector<bool>(rtp_streams_.size(), /*active=*/false));
476*d9f75844SAndroid Build Coastguard Worker 
477*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!registered_for_feedback_);
478*d9f75844SAndroid Build Coastguard Worker }
479*d9f75844SAndroid Build Coastguard Worker 
Stop()480*d9f75844SAndroid Build Coastguard Worker void RtpVideoSender::Stop() {
481*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&transport_checker_);
482*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
483*d9f75844SAndroid Build Coastguard Worker   if (!active_)
484*d9f75844SAndroid Build Coastguard Worker     return;
485*d9f75844SAndroid Build Coastguard Worker 
486*d9f75844SAndroid Build Coastguard Worker   const std::vector<bool> active_modules(rtp_streams_.size(), false);
487*d9f75844SAndroid Build Coastguard Worker   SetActiveModulesLocked(active_modules);
488*d9f75844SAndroid Build Coastguard Worker }
489*d9f75844SAndroid Build Coastguard Worker 
SetActiveModules(const std::vector<bool> & active_modules)490*d9f75844SAndroid Build Coastguard Worker void RtpVideoSender::SetActiveModules(const std::vector<bool>& active_modules) {
491*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&transport_checker_);
492*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
493*d9f75844SAndroid Build Coastguard Worker   return SetActiveModulesLocked(active_modules);
494*d9f75844SAndroid Build Coastguard Worker }
495*d9f75844SAndroid Build Coastguard Worker 
SetActiveModulesLocked(const std::vector<bool> & active_modules)496*d9f75844SAndroid Build Coastguard Worker void RtpVideoSender::SetActiveModulesLocked(
497*d9f75844SAndroid Build Coastguard Worker     const std::vector<bool>& active_modules) {
498*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&transport_checker_);
499*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(rtp_streams_.size(), active_modules.size());
500*d9f75844SAndroid Build Coastguard Worker   active_ = false;
501*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < active_modules.size(); ++i) {
502*d9f75844SAndroid Build Coastguard Worker     if (active_modules[i]) {
503*d9f75844SAndroid Build Coastguard Worker       active_ = true;
504*d9f75844SAndroid Build Coastguard Worker     }
505*d9f75844SAndroid Build Coastguard Worker 
506*d9f75844SAndroid Build Coastguard Worker     RtpRtcpInterface& rtp_module = *rtp_streams_[i].rtp_rtcp;
507*d9f75844SAndroid Build Coastguard Worker     const bool was_active = rtp_module.Sending();
508*d9f75844SAndroid Build Coastguard Worker     const bool should_be_active = active_modules[i];
509*d9f75844SAndroid Build Coastguard Worker 
510*d9f75844SAndroid Build Coastguard Worker     // Sends a kRtcpByeCode when going from true to false.
511*d9f75844SAndroid Build Coastguard Worker     rtp_module.SetSendingStatus(active_modules[i]);
512*d9f75844SAndroid Build Coastguard Worker 
513*d9f75844SAndroid Build Coastguard Worker     if (was_active && !should_be_active) {
514*d9f75844SAndroid Build Coastguard Worker       // Disabling media, remove from packet router map to reduce size and
515*d9f75844SAndroid Build Coastguard Worker       // prevent any stray packets in the pacer from asynchronously arriving
516*d9f75844SAndroid Build Coastguard Worker       // to a disabled module.
517*d9f75844SAndroid Build Coastguard Worker       transport_->packet_router()->RemoveSendRtpModule(&rtp_module);
518*d9f75844SAndroid Build Coastguard Worker     }
519*d9f75844SAndroid Build Coastguard Worker 
520*d9f75844SAndroid Build Coastguard Worker     // If set to false this module won't send media.
521*d9f75844SAndroid Build Coastguard Worker     rtp_module.SetSendingMediaStatus(active_modules[i]);
522*d9f75844SAndroid Build Coastguard Worker 
523*d9f75844SAndroid Build Coastguard Worker     if (!was_active && should_be_active) {
524*d9f75844SAndroid Build Coastguard Worker       // Turning on media, register with packet router.
525*d9f75844SAndroid Build Coastguard Worker       transport_->packet_router()->AddSendRtpModule(&rtp_module,
526*d9f75844SAndroid Build Coastguard Worker                                                     /*remb_candidate=*/true);
527*d9f75844SAndroid Build Coastguard Worker     }
528*d9f75844SAndroid Build Coastguard Worker   }
529*d9f75844SAndroid Build Coastguard Worker   if (!active_) {
530*d9f75844SAndroid Build Coastguard Worker     auto* feedback_provider = transport_->GetStreamFeedbackProvider();
531*d9f75844SAndroid Build Coastguard Worker     if (registered_for_feedback_) {
532*d9f75844SAndroid Build Coastguard Worker       feedback_provider->DeRegisterStreamFeedbackObserver(this);
533*d9f75844SAndroid Build Coastguard Worker       registered_for_feedback_ = false;
534*d9f75844SAndroid Build Coastguard Worker     }
535*d9f75844SAndroid Build Coastguard Worker   } else if (!registered_for_feedback_) {
536*d9f75844SAndroid Build Coastguard Worker     auto* feedback_provider = transport_->GetStreamFeedbackProvider();
537*d9f75844SAndroid Build Coastguard Worker     feedback_provider->RegisterStreamFeedbackObserver(rtp_config_.ssrcs, this);
538*d9f75844SAndroid Build Coastguard Worker     registered_for_feedback_ = true;
539*d9f75844SAndroid Build Coastguard Worker   }
540*d9f75844SAndroid Build Coastguard Worker }
541*d9f75844SAndroid Build Coastguard Worker 
IsActive()542*d9f75844SAndroid Build Coastguard Worker bool RtpVideoSender::IsActive() {
543*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&transport_checker_);
544*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
545*d9f75844SAndroid Build Coastguard Worker   return IsActiveLocked();
546*d9f75844SAndroid Build Coastguard Worker }
547*d9f75844SAndroid Build Coastguard Worker 
IsActiveLocked()548*d9f75844SAndroid Build Coastguard Worker bool RtpVideoSender::IsActiveLocked() {
549*d9f75844SAndroid Build Coastguard Worker   return active_ && !rtp_streams_.empty();
550*d9f75844SAndroid Build Coastguard Worker }
551*d9f75844SAndroid Build Coastguard Worker 
OnEncodedImage(const EncodedImage & encoded_image,const CodecSpecificInfo * codec_specific_info)552*d9f75844SAndroid Build Coastguard Worker EncodedImageCallback::Result RtpVideoSender::OnEncodedImage(
553*d9f75844SAndroid Build Coastguard Worker     const EncodedImage& encoded_image,
554*d9f75844SAndroid Build Coastguard Worker     const CodecSpecificInfo* codec_specific_info) {
555*d9f75844SAndroid Build Coastguard Worker   fec_controller_->UpdateWithEncodedData(encoded_image.size(),
556*d9f75844SAndroid Build Coastguard Worker                                          encoded_image._frameType);
557*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
558*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!rtp_streams_.empty());
559*d9f75844SAndroid Build Coastguard Worker   if (!active_)
560*d9f75844SAndroid Build Coastguard Worker     return Result(Result::ERROR_SEND_FAILED);
561*d9f75844SAndroid Build Coastguard Worker 
562*d9f75844SAndroid Build Coastguard Worker   shared_frame_id_++;
563*d9f75844SAndroid Build Coastguard Worker   size_t stream_index = 0;
564*d9f75844SAndroid Build Coastguard Worker   if (codec_specific_info &&
565*d9f75844SAndroid Build Coastguard Worker       (codec_specific_info->codecType == kVideoCodecVP8 ||
566*d9f75844SAndroid Build Coastguard Worker        codec_specific_info->codecType == kVideoCodecH264 ||
567*d9f75844SAndroid Build Coastguard Worker        codec_specific_info->codecType == kVideoCodecGeneric)) {
568*d9f75844SAndroid Build Coastguard Worker     // Map spatial index to simulcast.
569*d9f75844SAndroid Build Coastguard Worker     stream_index = encoded_image.SpatialIndex().value_or(0);
570*d9f75844SAndroid Build Coastguard Worker   }
571*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_LT(stream_index, rtp_streams_.size());
572*d9f75844SAndroid Build Coastguard Worker 
573*d9f75844SAndroid Build Coastguard Worker   uint32_t rtp_timestamp =
574*d9f75844SAndroid Build Coastguard Worker       encoded_image.Timestamp() +
575*d9f75844SAndroid Build Coastguard Worker       rtp_streams_[stream_index].rtp_rtcp->StartTimestamp();
576*d9f75844SAndroid Build Coastguard Worker 
577*d9f75844SAndroid Build Coastguard Worker   // RTCPSender has it's own copy of the timestamp offset, added in
578*d9f75844SAndroid Build Coastguard Worker   // RTCPSender::BuildSR, hence we must not add the in the offset for this call.
579*d9f75844SAndroid Build Coastguard Worker   // TODO(nisse): Delete RTCPSender:timestamp_offset_, and see if we can confine
580*d9f75844SAndroid Build Coastguard Worker   // knowledge of the offset to a single place.
581*d9f75844SAndroid Build Coastguard Worker   if (!rtp_streams_[stream_index].rtp_rtcp->OnSendingRtpFrame(
582*d9f75844SAndroid Build Coastguard Worker           encoded_image.Timestamp(), encoded_image.capture_time_ms_,
583*d9f75844SAndroid Build Coastguard Worker           rtp_config_.payload_type,
584*d9f75844SAndroid Build Coastguard Worker           encoded_image._frameType == VideoFrameType::kVideoFrameKey)) {
585*d9f75844SAndroid Build Coastguard Worker     // The payload router could be active but this module isn't sending.
586*d9f75844SAndroid Build Coastguard Worker     return Result(Result::ERROR_SEND_FAILED);
587*d9f75844SAndroid Build Coastguard Worker   }
588*d9f75844SAndroid Build Coastguard Worker 
589*d9f75844SAndroid Build Coastguard Worker   absl::optional<int64_t> expected_retransmission_time_ms;
590*d9f75844SAndroid Build Coastguard Worker   if (encoded_image.RetransmissionAllowed()) {
591*d9f75844SAndroid Build Coastguard Worker     expected_retransmission_time_ms =
592*d9f75844SAndroid Build Coastguard Worker         rtp_streams_[stream_index].rtp_rtcp->ExpectedRetransmissionTimeMs();
593*d9f75844SAndroid Build Coastguard Worker   }
594*d9f75844SAndroid Build Coastguard Worker 
595*d9f75844SAndroid Build Coastguard Worker   if (IsFirstFrameOfACodedVideoSequence(encoded_image, codec_specific_info)) {
596*d9f75844SAndroid Build Coastguard Worker     // In order to use the dependency descriptor RTP header extension:
597*d9f75844SAndroid Build Coastguard Worker     //  - Pass along any `FrameDependencyStructure` templates produced by the
598*d9f75844SAndroid Build Coastguard Worker     //    encoder adapter.
599*d9f75844SAndroid Build Coastguard Worker     //  - If none were produced the `RtpPayloadParams::*ToGeneric` for the
600*d9f75844SAndroid Build Coastguard Worker     //    particular codec have simulated a dependency structure, so provide a
601*d9f75844SAndroid Build Coastguard Worker     //    minimal set of templates.
602*d9f75844SAndroid Build Coastguard Worker     //  - Otherwise, don't pass along any templates at all which will disable
603*d9f75844SAndroid Build Coastguard Worker     //    the generation of a dependency descriptor.
604*d9f75844SAndroid Build Coastguard Worker     RTPSenderVideo& sender_video = *rtp_streams_[stream_index].sender_video;
605*d9f75844SAndroid Build Coastguard Worker     if (codec_specific_info && codec_specific_info->template_structure) {
606*d9f75844SAndroid Build Coastguard Worker       sender_video.SetVideoStructure(&*codec_specific_info->template_structure);
607*d9f75844SAndroid Build Coastguard Worker     } else if (absl::optional<FrameDependencyStructure> structure =
608*d9f75844SAndroid Build Coastguard Worker                    params_[stream_index].GenericStructure(
609*d9f75844SAndroid Build Coastguard Worker                        codec_specific_info)) {
610*d9f75844SAndroid Build Coastguard Worker       sender_video.SetVideoStructure(&*structure);
611*d9f75844SAndroid Build Coastguard Worker     } else {
612*d9f75844SAndroid Build Coastguard Worker       sender_video.SetVideoStructure(nullptr);
613*d9f75844SAndroid Build Coastguard Worker     }
614*d9f75844SAndroid Build Coastguard Worker   }
615*d9f75844SAndroid Build Coastguard Worker 
616*d9f75844SAndroid Build Coastguard Worker   bool send_result = rtp_streams_[stream_index].sender_video->SendEncodedImage(
617*d9f75844SAndroid Build Coastguard Worker       rtp_config_.payload_type, codec_type_, rtp_timestamp, encoded_image,
618*d9f75844SAndroid Build Coastguard Worker       params_[stream_index].GetRtpVideoHeader(
619*d9f75844SAndroid Build Coastguard Worker           encoded_image, codec_specific_info, shared_frame_id_),
620*d9f75844SAndroid Build Coastguard Worker       expected_retransmission_time_ms);
621*d9f75844SAndroid Build Coastguard Worker   if (frame_count_observer_) {
622*d9f75844SAndroid Build Coastguard Worker     FrameCounts& counts = frame_counts_[stream_index];
623*d9f75844SAndroid Build Coastguard Worker     if (encoded_image._frameType == VideoFrameType::kVideoFrameKey) {
624*d9f75844SAndroid Build Coastguard Worker       ++counts.key_frames;
625*d9f75844SAndroid Build Coastguard Worker     } else if (encoded_image._frameType == VideoFrameType::kVideoFrameDelta) {
626*d9f75844SAndroid Build Coastguard Worker       ++counts.delta_frames;
627*d9f75844SAndroid Build Coastguard Worker     } else {
628*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK(encoded_image._frameType == VideoFrameType::kEmptyFrame);
629*d9f75844SAndroid Build Coastguard Worker     }
630*d9f75844SAndroid Build Coastguard Worker     frame_count_observer_->FrameCountUpdated(counts,
631*d9f75844SAndroid Build Coastguard Worker                                              rtp_config_.ssrcs[stream_index]);
632*d9f75844SAndroid Build Coastguard Worker   }
633*d9f75844SAndroid Build Coastguard Worker   if (!send_result)
634*d9f75844SAndroid Build Coastguard Worker     return Result(Result::ERROR_SEND_FAILED);
635*d9f75844SAndroid Build Coastguard Worker 
636*d9f75844SAndroid Build Coastguard Worker   return Result(Result::OK, rtp_timestamp);
637*d9f75844SAndroid Build Coastguard Worker }
638*d9f75844SAndroid Build Coastguard Worker 
OnBitrateAllocationUpdated(const VideoBitrateAllocation & bitrate)639*d9f75844SAndroid Build Coastguard Worker void RtpVideoSender::OnBitrateAllocationUpdated(
640*d9f75844SAndroid Build Coastguard Worker     const VideoBitrateAllocation& bitrate) {
641*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&transport_checker_);
642*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
643*d9f75844SAndroid Build Coastguard Worker   if (IsActiveLocked()) {
644*d9f75844SAndroid Build Coastguard Worker     if (rtp_streams_.size() == 1) {
645*d9f75844SAndroid Build Coastguard Worker       // If spatial scalability is enabled, it is covered by a single stream.
646*d9f75844SAndroid Build Coastguard Worker       rtp_streams_[0].rtp_rtcp->SetVideoBitrateAllocation(bitrate);
647*d9f75844SAndroid Build Coastguard Worker     } else {
648*d9f75844SAndroid Build Coastguard Worker       std::vector<absl::optional<VideoBitrateAllocation>> layer_bitrates =
649*d9f75844SAndroid Build Coastguard Worker           bitrate.GetSimulcastAllocations();
650*d9f75844SAndroid Build Coastguard Worker       // Simulcast is in use, split the VideoBitrateAllocation into one struct
651*d9f75844SAndroid Build Coastguard Worker       // per rtp stream, moving over the temporal layer allocation.
652*d9f75844SAndroid Build Coastguard Worker       for (size_t i = 0; i < rtp_streams_.size(); ++i) {
653*d9f75844SAndroid Build Coastguard Worker         // The next spatial layer could be used if the current one is
654*d9f75844SAndroid Build Coastguard Worker         // inactive.
655*d9f75844SAndroid Build Coastguard Worker         if (layer_bitrates[i]) {
656*d9f75844SAndroid Build Coastguard Worker           rtp_streams_[i].rtp_rtcp->SetVideoBitrateAllocation(
657*d9f75844SAndroid Build Coastguard Worker               *layer_bitrates[i]);
658*d9f75844SAndroid Build Coastguard Worker         } else {
659*d9f75844SAndroid Build Coastguard Worker           // Signal a 0 bitrate on a simulcast stream.
660*d9f75844SAndroid Build Coastguard Worker           rtp_streams_[i].rtp_rtcp->SetVideoBitrateAllocation(
661*d9f75844SAndroid Build Coastguard Worker               VideoBitrateAllocation());
662*d9f75844SAndroid Build Coastguard Worker         }
663*d9f75844SAndroid Build Coastguard Worker       }
664*d9f75844SAndroid Build Coastguard Worker     }
665*d9f75844SAndroid Build Coastguard Worker   }
666*d9f75844SAndroid Build Coastguard Worker }
OnVideoLayersAllocationUpdated(const VideoLayersAllocation & allocation)667*d9f75844SAndroid Build Coastguard Worker void RtpVideoSender::OnVideoLayersAllocationUpdated(
668*d9f75844SAndroid Build Coastguard Worker     const VideoLayersAllocation& allocation) {
669*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
670*d9f75844SAndroid Build Coastguard Worker   if (IsActiveLocked()) {
671*d9f75844SAndroid Build Coastguard Worker     for (size_t i = 0; i < rtp_streams_.size(); ++i) {
672*d9f75844SAndroid Build Coastguard Worker       VideoLayersAllocation stream_allocation = allocation;
673*d9f75844SAndroid Build Coastguard Worker       stream_allocation.rtp_stream_index = i;
674*d9f75844SAndroid Build Coastguard Worker       rtp_streams_[i].sender_video->SetVideoLayersAllocation(
675*d9f75844SAndroid Build Coastguard Worker           std::move(stream_allocation));
676*d9f75844SAndroid Build Coastguard Worker       // Only send video frames on the rtp module if the encoder is configured
677*d9f75844SAndroid Build Coastguard Worker       // to send. This is to prevent stray frames to be sent after an encoder
678*d9f75844SAndroid Build Coastguard Worker       // has been reconfigured.
679*d9f75844SAndroid Build Coastguard Worker       rtp_streams_[i].rtp_rtcp->SetSendingMediaStatus(
680*d9f75844SAndroid Build Coastguard Worker           absl::c_any_of(allocation.active_spatial_layers,
681*d9f75844SAndroid Build Coastguard Worker                          [&i](const VideoLayersAllocation::SpatialLayer layer) {
682*d9f75844SAndroid Build Coastguard Worker                            return layer.rtp_stream_index == static_cast<int>(i);
683*d9f75844SAndroid Build Coastguard Worker                          }));
684*d9f75844SAndroid Build Coastguard Worker     }
685*d9f75844SAndroid Build Coastguard Worker   }
686*d9f75844SAndroid Build Coastguard Worker }
687*d9f75844SAndroid Build Coastguard Worker 
NackEnabled() const688*d9f75844SAndroid Build Coastguard Worker bool RtpVideoSender::NackEnabled() const {
689*d9f75844SAndroid Build Coastguard Worker   const bool nack_enabled = rtp_config_.nack.rtp_history_ms > 0;
690*d9f75844SAndroid Build Coastguard Worker   return nack_enabled;
691*d9f75844SAndroid Build Coastguard Worker }
692*d9f75844SAndroid Build Coastguard Worker 
GetPacketizationOverheadRate() const693*d9f75844SAndroid Build Coastguard Worker uint32_t RtpVideoSender::GetPacketizationOverheadRate() const {
694*d9f75844SAndroid Build Coastguard Worker   uint32_t packetization_overhead_bps = 0;
695*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < rtp_streams_.size(); ++i) {
696*d9f75844SAndroid Build Coastguard Worker     if (rtp_streams_[i].rtp_rtcp->SendingMedia()) {
697*d9f75844SAndroid Build Coastguard Worker       packetization_overhead_bps +=
698*d9f75844SAndroid Build Coastguard Worker           rtp_streams_[i].sender_video->PacketizationOverheadBps();
699*d9f75844SAndroid Build Coastguard Worker     }
700*d9f75844SAndroid Build Coastguard Worker   }
701*d9f75844SAndroid Build Coastguard Worker   return packetization_overhead_bps;
702*d9f75844SAndroid Build Coastguard Worker }
703*d9f75844SAndroid Build Coastguard Worker 
DeliverRtcp(const uint8_t * packet,size_t length)704*d9f75844SAndroid Build Coastguard Worker void RtpVideoSender::DeliverRtcp(const uint8_t* packet, size_t length) {
705*d9f75844SAndroid Build Coastguard Worker   // Runs on a network thread.
706*d9f75844SAndroid Build Coastguard Worker   for (const RtpStreamSender& stream : rtp_streams_)
707*d9f75844SAndroid Build Coastguard Worker     stream.rtp_rtcp->IncomingRtcpPacket(packet, length);
708*d9f75844SAndroid Build Coastguard Worker }
709*d9f75844SAndroid Build Coastguard Worker 
ConfigureSsrcs(const std::map<uint32_t,RtpState> & suspended_ssrcs)710*d9f75844SAndroid Build Coastguard Worker void RtpVideoSender::ConfigureSsrcs(
711*d9f75844SAndroid Build Coastguard Worker     const std::map<uint32_t, RtpState>& suspended_ssrcs) {
712*d9f75844SAndroid Build Coastguard Worker   // Configure regular SSRCs.
713*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(ssrc_to_rtp_module_.empty());
714*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < rtp_config_.ssrcs.size(); ++i) {
715*d9f75844SAndroid Build Coastguard Worker     uint32_t ssrc = rtp_config_.ssrcs[i];
716*d9f75844SAndroid Build Coastguard Worker     RtpRtcpInterface* const rtp_rtcp = rtp_streams_[i].rtp_rtcp.get();
717*d9f75844SAndroid Build Coastguard Worker 
718*d9f75844SAndroid Build Coastguard Worker     // Restore RTP state if previous existed.
719*d9f75844SAndroid Build Coastguard Worker     auto it = suspended_ssrcs.find(ssrc);
720*d9f75844SAndroid Build Coastguard Worker     if (it != suspended_ssrcs.end())
721*d9f75844SAndroid Build Coastguard Worker       rtp_rtcp->SetRtpState(it->second);
722*d9f75844SAndroid Build Coastguard Worker 
723*d9f75844SAndroid Build Coastguard Worker     ssrc_to_rtp_module_[ssrc] = rtp_rtcp;
724*d9f75844SAndroid Build Coastguard Worker   }
725*d9f75844SAndroid Build Coastguard Worker 
726*d9f75844SAndroid Build Coastguard Worker   // Set up RTX if available.
727*d9f75844SAndroid Build Coastguard Worker   if (rtp_config_.rtx.ssrcs.empty())
728*d9f75844SAndroid Build Coastguard Worker     return;
729*d9f75844SAndroid Build Coastguard Worker 
730*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(rtp_config_.rtx.ssrcs.size(), rtp_config_.ssrcs.size());
731*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < rtp_config_.rtx.ssrcs.size(); ++i) {
732*d9f75844SAndroid Build Coastguard Worker     uint32_t ssrc = rtp_config_.rtx.ssrcs[i];
733*d9f75844SAndroid Build Coastguard Worker     RtpRtcpInterface* const rtp_rtcp = rtp_streams_[i].rtp_rtcp.get();
734*d9f75844SAndroid Build Coastguard Worker     auto it = suspended_ssrcs.find(ssrc);
735*d9f75844SAndroid Build Coastguard Worker     if (it != suspended_ssrcs.end())
736*d9f75844SAndroid Build Coastguard Worker       rtp_rtcp->SetRtxState(it->second);
737*d9f75844SAndroid Build Coastguard Worker   }
738*d9f75844SAndroid Build Coastguard Worker 
739*d9f75844SAndroid Build Coastguard Worker   // Configure RTX payload types.
740*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GE(rtp_config_.rtx.payload_type, 0);
741*d9f75844SAndroid Build Coastguard Worker   for (const RtpStreamSender& stream : rtp_streams_) {
742*d9f75844SAndroid Build Coastguard Worker     stream.rtp_rtcp->SetRtxSendPayloadType(rtp_config_.rtx.payload_type,
743*d9f75844SAndroid Build Coastguard Worker                                            rtp_config_.payload_type);
744*d9f75844SAndroid Build Coastguard Worker     stream.rtp_rtcp->SetRtxSendStatus(kRtxRetransmitted |
745*d9f75844SAndroid Build Coastguard Worker                                       kRtxRedundantPayloads);
746*d9f75844SAndroid Build Coastguard Worker   }
747*d9f75844SAndroid Build Coastguard Worker   if (rtp_config_.ulpfec.red_payload_type != -1 &&
748*d9f75844SAndroid Build Coastguard Worker       rtp_config_.ulpfec.red_rtx_payload_type != -1) {
749*d9f75844SAndroid Build Coastguard Worker     for (const RtpStreamSender& stream : rtp_streams_) {
750*d9f75844SAndroid Build Coastguard Worker       stream.rtp_rtcp->SetRtxSendPayloadType(
751*d9f75844SAndroid Build Coastguard Worker           rtp_config_.ulpfec.red_rtx_payload_type,
752*d9f75844SAndroid Build Coastguard Worker           rtp_config_.ulpfec.red_payload_type);
753*d9f75844SAndroid Build Coastguard Worker     }
754*d9f75844SAndroid Build Coastguard Worker   }
755*d9f75844SAndroid Build Coastguard Worker }
756*d9f75844SAndroid Build Coastguard Worker 
OnNetworkAvailability(bool network_available)757*d9f75844SAndroid Build Coastguard Worker void RtpVideoSender::OnNetworkAvailability(bool network_available) {
758*d9f75844SAndroid Build Coastguard Worker   for (const RtpStreamSender& stream : rtp_streams_) {
759*d9f75844SAndroid Build Coastguard Worker     stream.rtp_rtcp->SetRTCPStatus(network_available ? rtp_config_.rtcp_mode
760*d9f75844SAndroid Build Coastguard Worker                                                      : RtcpMode::kOff);
761*d9f75844SAndroid Build Coastguard Worker   }
762*d9f75844SAndroid Build Coastguard Worker }
763*d9f75844SAndroid Build Coastguard Worker 
GetRtpStates() const764*d9f75844SAndroid Build Coastguard Worker std::map<uint32_t, RtpState> RtpVideoSender::GetRtpStates() const {
765*d9f75844SAndroid Build Coastguard Worker   std::map<uint32_t, RtpState> rtp_states;
766*d9f75844SAndroid Build Coastguard Worker 
767*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < rtp_config_.ssrcs.size(); ++i) {
768*d9f75844SAndroid Build Coastguard Worker     uint32_t ssrc = rtp_config_.ssrcs[i];
769*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_EQ(ssrc, rtp_streams_[i].rtp_rtcp->SSRC());
770*d9f75844SAndroid Build Coastguard Worker     rtp_states[ssrc] = rtp_streams_[i].rtp_rtcp->GetRtpState();
771*d9f75844SAndroid Build Coastguard Worker 
772*d9f75844SAndroid Build Coastguard Worker     // Only happens during shutdown, when RTP module is already inactive,
773*d9f75844SAndroid Build Coastguard Worker     // so OK to call fec generator here.
774*d9f75844SAndroid Build Coastguard Worker     if (rtp_streams_[i].fec_generator) {
775*d9f75844SAndroid Build Coastguard Worker       absl::optional<RtpState> fec_state =
776*d9f75844SAndroid Build Coastguard Worker           rtp_streams_[i].fec_generator->GetRtpState();
777*d9f75844SAndroid Build Coastguard Worker       if (fec_state) {
778*d9f75844SAndroid Build Coastguard Worker         uint32_t ssrc = rtp_config_.flexfec.ssrc;
779*d9f75844SAndroid Build Coastguard Worker         rtp_states[ssrc] = *fec_state;
780*d9f75844SAndroid Build Coastguard Worker       }
781*d9f75844SAndroid Build Coastguard Worker     }
782*d9f75844SAndroid Build Coastguard Worker   }
783*d9f75844SAndroid Build Coastguard Worker 
784*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < rtp_config_.rtx.ssrcs.size(); ++i) {
785*d9f75844SAndroid Build Coastguard Worker     uint32_t ssrc = rtp_config_.rtx.ssrcs[i];
786*d9f75844SAndroid Build Coastguard Worker     rtp_states[ssrc] = rtp_streams_[i].rtp_rtcp->GetRtxState();
787*d9f75844SAndroid Build Coastguard Worker   }
788*d9f75844SAndroid Build Coastguard Worker 
789*d9f75844SAndroid Build Coastguard Worker   return rtp_states;
790*d9f75844SAndroid Build Coastguard Worker }
791*d9f75844SAndroid Build Coastguard Worker 
GetRtpPayloadStates() const792*d9f75844SAndroid Build Coastguard Worker std::map<uint32_t, RtpPayloadState> RtpVideoSender::GetRtpPayloadStates()
793*d9f75844SAndroid Build Coastguard Worker     const {
794*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
795*d9f75844SAndroid Build Coastguard Worker   std::map<uint32_t, RtpPayloadState> payload_states;
796*d9f75844SAndroid Build Coastguard Worker   for (const auto& param : params_) {
797*d9f75844SAndroid Build Coastguard Worker     payload_states[param.ssrc()] = param.state();
798*d9f75844SAndroid Build Coastguard Worker     payload_states[param.ssrc()].shared_frame_id = shared_frame_id_;
799*d9f75844SAndroid Build Coastguard Worker   }
800*d9f75844SAndroid Build Coastguard Worker   return payload_states;
801*d9f75844SAndroid Build Coastguard Worker }
802*d9f75844SAndroid Build Coastguard Worker 
OnTransportOverheadChanged(size_t transport_overhead_bytes_per_packet)803*d9f75844SAndroid Build Coastguard Worker void RtpVideoSender::OnTransportOverheadChanged(
804*d9f75844SAndroid Build Coastguard Worker     size_t transport_overhead_bytes_per_packet) {
805*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
806*d9f75844SAndroid Build Coastguard Worker   transport_overhead_bytes_per_packet_ = transport_overhead_bytes_per_packet;
807*d9f75844SAndroid Build Coastguard Worker 
808*d9f75844SAndroid Build Coastguard Worker   size_t max_rtp_packet_size =
809*d9f75844SAndroid Build Coastguard Worker       std::min(rtp_config_.max_packet_size,
810*d9f75844SAndroid Build Coastguard Worker                kPathMTU - transport_overhead_bytes_per_packet_);
811*d9f75844SAndroid Build Coastguard Worker   for (const RtpStreamSender& stream : rtp_streams_) {
812*d9f75844SAndroid Build Coastguard Worker     stream.rtp_rtcp->SetMaxRtpPacketSize(max_rtp_packet_size);
813*d9f75844SAndroid Build Coastguard Worker   }
814*d9f75844SAndroid Build Coastguard Worker }
815*d9f75844SAndroid Build Coastguard Worker 
OnBitrateUpdated(BitrateAllocationUpdate update,int framerate)816*d9f75844SAndroid Build Coastguard Worker void RtpVideoSender::OnBitrateUpdated(BitrateAllocationUpdate update,
817*d9f75844SAndroid Build Coastguard Worker                                       int framerate) {
818*d9f75844SAndroid Build Coastguard Worker   // Substract overhead from bitrate.
819*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
820*d9f75844SAndroid Build Coastguard Worker   size_t num_active_streams = 0;
821*d9f75844SAndroid Build Coastguard Worker   size_t overhead_bytes_per_packet = 0;
822*d9f75844SAndroid Build Coastguard Worker   for (const auto& stream : rtp_streams_) {
823*d9f75844SAndroid Build Coastguard Worker     if (stream.rtp_rtcp->SendingMedia()) {
824*d9f75844SAndroid Build Coastguard Worker       overhead_bytes_per_packet += stream.rtp_rtcp->ExpectedPerPacketOverhead();
825*d9f75844SAndroid Build Coastguard Worker       ++num_active_streams;
826*d9f75844SAndroid Build Coastguard Worker     }
827*d9f75844SAndroid Build Coastguard Worker   }
828*d9f75844SAndroid Build Coastguard Worker   if (num_active_streams > 1) {
829*d9f75844SAndroid Build Coastguard Worker     overhead_bytes_per_packet /= num_active_streams;
830*d9f75844SAndroid Build Coastguard Worker   }
831*d9f75844SAndroid Build Coastguard Worker 
832*d9f75844SAndroid Build Coastguard Worker   DataSize packet_overhead = DataSize::Bytes(
833*d9f75844SAndroid Build Coastguard Worker       overhead_bytes_per_packet + transport_overhead_bytes_per_packet_);
834*d9f75844SAndroid Build Coastguard Worker   DataSize max_total_packet_size = DataSize::Bytes(
835*d9f75844SAndroid Build Coastguard Worker       rtp_config_.max_packet_size + transport_overhead_bytes_per_packet_);
836*d9f75844SAndroid Build Coastguard Worker   uint32_t payload_bitrate_bps = update.target_bitrate.bps();
837*d9f75844SAndroid Build Coastguard Worker   if (has_packet_feedback_) {
838*d9f75844SAndroid Build Coastguard Worker     DataRate overhead_rate =
839*d9f75844SAndroid Build Coastguard Worker         CalculateOverheadRate(update.target_bitrate, max_total_packet_size,
840*d9f75844SAndroid Build Coastguard Worker                               packet_overhead, Frequency::Hertz(framerate));
841*d9f75844SAndroid Build Coastguard Worker     // TODO(srte): We probably should not accept 0 payload bitrate here.
842*d9f75844SAndroid Build Coastguard Worker     payload_bitrate_bps = rtc::saturated_cast<uint32_t>(payload_bitrate_bps -
843*d9f75844SAndroid Build Coastguard Worker                                                         overhead_rate.bps());
844*d9f75844SAndroid Build Coastguard Worker   }
845*d9f75844SAndroid Build Coastguard Worker 
846*d9f75844SAndroid Build Coastguard Worker   // Get the encoder target rate. It is the estimated network rate -
847*d9f75844SAndroid Build Coastguard Worker   // protection overhead.
848*d9f75844SAndroid Build Coastguard Worker   // TODO(srte): We should multiply with 255 here.
849*d9f75844SAndroid Build Coastguard Worker   encoder_target_rate_bps_ = fec_controller_->UpdateFecRates(
850*d9f75844SAndroid Build Coastguard Worker       payload_bitrate_bps, framerate,
851*d9f75844SAndroid Build Coastguard Worker       rtc::saturated_cast<uint8_t>(update.packet_loss_ratio * 256),
852*d9f75844SAndroid Build Coastguard Worker       loss_mask_vector_, update.round_trip_time.ms());
853*d9f75844SAndroid Build Coastguard Worker   if (!fec_allowed_) {
854*d9f75844SAndroid Build Coastguard Worker     encoder_target_rate_bps_ = payload_bitrate_bps;
855*d9f75844SAndroid Build Coastguard Worker     // fec_controller_->UpdateFecRates() was still called so as to allow
856*d9f75844SAndroid Build Coastguard Worker     // `fec_controller_` to update whatever internal state it might have,
857*d9f75844SAndroid Build Coastguard Worker     // since `fec_allowed_` may be toggled back on at any moment.
858*d9f75844SAndroid Build Coastguard Worker   }
859*d9f75844SAndroid Build Coastguard Worker 
860*d9f75844SAndroid Build Coastguard Worker   // Subtract packetization overhead from the encoder target. If target rate
861*d9f75844SAndroid Build Coastguard Worker   // is really low, cap the overhead at 50%. This also avoids the case where
862*d9f75844SAndroid Build Coastguard Worker   // `encoder_target_rate_bps_` is 0 due to encoder pause event while the
863*d9f75844SAndroid Build Coastguard Worker   // packetization rate is positive since packets are still flowing.
864*d9f75844SAndroid Build Coastguard Worker   uint32_t packetization_rate_bps =
865*d9f75844SAndroid Build Coastguard Worker       std::min(GetPacketizationOverheadRate(), encoder_target_rate_bps_ / 2);
866*d9f75844SAndroid Build Coastguard Worker   encoder_target_rate_bps_ -= packetization_rate_bps;
867*d9f75844SAndroid Build Coastguard Worker 
868*d9f75844SAndroid Build Coastguard Worker   loss_mask_vector_.clear();
869*d9f75844SAndroid Build Coastguard Worker 
870*d9f75844SAndroid Build Coastguard Worker   uint32_t encoder_overhead_rate_bps = 0;
871*d9f75844SAndroid Build Coastguard Worker   if (has_packet_feedback_) {
872*d9f75844SAndroid Build Coastguard Worker     // TODO(srte): The packet size should probably be the same as in the
873*d9f75844SAndroid Build Coastguard Worker     // CalculateOverheadRate call above (just max_total_packet_size), it doesn't
874*d9f75844SAndroid Build Coastguard Worker     // make sense to use different packet rates for different overhead
875*d9f75844SAndroid Build Coastguard Worker     // calculations.
876*d9f75844SAndroid Build Coastguard Worker     DataRate encoder_overhead_rate = CalculateOverheadRate(
877*d9f75844SAndroid Build Coastguard Worker         DataRate::BitsPerSec(encoder_target_rate_bps_),
878*d9f75844SAndroid Build Coastguard Worker         max_total_packet_size - DataSize::Bytes(overhead_bytes_per_packet),
879*d9f75844SAndroid Build Coastguard Worker         packet_overhead, Frequency::Hertz(framerate));
880*d9f75844SAndroid Build Coastguard Worker     encoder_overhead_rate_bps = std::min(
881*d9f75844SAndroid Build Coastguard Worker         encoder_overhead_rate.bps<uint32_t>(),
882*d9f75844SAndroid Build Coastguard Worker         update.target_bitrate.bps<uint32_t>() - encoder_target_rate_bps_);
883*d9f75844SAndroid Build Coastguard Worker   }
884*d9f75844SAndroid Build Coastguard Worker   const uint32_t media_rate = encoder_target_rate_bps_ +
885*d9f75844SAndroid Build Coastguard Worker                               encoder_overhead_rate_bps +
886*d9f75844SAndroid Build Coastguard Worker                               packetization_rate_bps;
887*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GE(update.target_bitrate, DataRate::BitsPerSec(media_rate));
888*d9f75844SAndroid Build Coastguard Worker   // `protection_bitrate_bps_` includes overhead.
889*d9f75844SAndroid Build Coastguard Worker   protection_bitrate_bps_ = update.target_bitrate.bps() - media_rate;
890*d9f75844SAndroid Build Coastguard Worker }
891*d9f75844SAndroid Build Coastguard Worker 
GetPayloadBitrateBps() const892*d9f75844SAndroid Build Coastguard Worker uint32_t RtpVideoSender::GetPayloadBitrateBps() const {
893*d9f75844SAndroid Build Coastguard Worker   return encoder_target_rate_bps_;
894*d9f75844SAndroid Build Coastguard Worker }
895*d9f75844SAndroid Build Coastguard Worker 
GetProtectionBitrateBps() const896*d9f75844SAndroid Build Coastguard Worker uint32_t RtpVideoSender::GetProtectionBitrateBps() const {
897*d9f75844SAndroid Build Coastguard Worker   return protection_bitrate_bps_;
898*d9f75844SAndroid Build Coastguard Worker }
899*d9f75844SAndroid Build Coastguard Worker 
GetSentRtpPacketInfos(uint32_t ssrc,rtc::ArrayView<const uint16_t> sequence_numbers) const900*d9f75844SAndroid Build Coastguard Worker std::vector<RtpSequenceNumberMap::Info> RtpVideoSender::GetSentRtpPacketInfos(
901*d9f75844SAndroid Build Coastguard Worker     uint32_t ssrc,
902*d9f75844SAndroid Build Coastguard Worker     rtc::ArrayView<const uint16_t> sequence_numbers) const {
903*d9f75844SAndroid Build Coastguard Worker   for (const auto& rtp_stream : rtp_streams_) {
904*d9f75844SAndroid Build Coastguard Worker     if (ssrc == rtp_stream.rtp_rtcp->SSRC()) {
905*d9f75844SAndroid Build Coastguard Worker       return rtp_stream.rtp_rtcp->GetSentRtpPacketInfos(sequence_numbers);
906*d9f75844SAndroid Build Coastguard Worker     }
907*d9f75844SAndroid Build Coastguard Worker   }
908*d9f75844SAndroid Build Coastguard Worker   return std::vector<RtpSequenceNumberMap::Info>();
909*d9f75844SAndroid Build Coastguard Worker }
910*d9f75844SAndroid Build Coastguard Worker 
ProtectionRequest(const FecProtectionParams * delta_params,const FecProtectionParams * key_params,uint32_t * sent_video_rate_bps,uint32_t * sent_nack_rate_bps,uint32_t * sent_fec_rate_bps)911*d9f75844SAndroid Build Coastguard Worker int RtpVideoSender::ProtectionRequest(const FecProtectionParams* delta_params,
912*d9f75844SAndroid Build Coastguard Worker                                       const FecProtectionParams* key_params,
913*d9f75844SAndroid Build Coastguard Worker                                       uint32_t* sent_video_rate_bps,
914*d9f75844SAndroid Build Coastguard Worker                                       uint32_t* sent_nack_rate_bps,
915*d9f75844SAndroid Build Coastguard Worker                                       uint32_t* sent_fec_rate_bps) {
916*d9f75844SAndroid Build Coastguard Worker   *sent_video_rate_bps = 0;
917*d9f75844SAndroid Build Coastguard Worker   *sent_nack_rate_bps = 0;
918*d9f75844SAndroid Build Coastguard Worker   *sent_fec_rate_bps = 0;
919*d9f75844SAndroid Build Coastguard Worker   for (const RtpStreamSender& stream : rtp_streams_) {
920*d9f75844SAndroid Build Coastguard Worker       stream.rtp_rtcp->SetFecProtectionParams(*delta_params, *key_params);
921*d9f75844SAndroid Build Coastguard Worker 
922*d9f75844SAndroid Build Coastguard Worker       auto send_bitrate = stream.rtp_rtcp->GetSendRates();
923*d9f75844SAndroid Build Coastguard Worker       *sent_video_rate_bps += send_bitrate[RtpPacketMediaType::kVideo].bps();
924*d9f75844SAndroid Build Coastguard Worker       *sent_fec_rate_bps +=
925*d9f75844SAndroid Build Coastguard Worker           send_bitrate[RtpPacketMediaType::kForwardErrorCorrection].bps();
926*d9f75844SAndroid Build Coastguard Worker       *sent_nack_rate_bps +=
927*d9f75844SAndroid Build Coastguard Worker           send_bitrate[RtpPacketMediaType::kRetransmission].bps();
928*d9f75844SAndroid Build Coastguard Worker   }
929*d9f75844SAndroid Build Coastguard Worker   return 0;
930*d9f75844SAndroid Build Coastguard Worker }
931*d9f75844SAndroid Build Coastguard Worker 
SetFecAllowed(bool fec_allowed)932*d9f75844SAndroid Build Coastguard Worker void RtpVideoSender::SetFecAllowed(bool fec_allowed) {
933*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
934*d9f75844SAndroid Build Coastguard Worker   fec_allowed_ = fec_allowed;
935*d9f75844SAndroid Build Coastguard Worker }
936*d9f75844SAndroid Build Coastguard Worker 
OnPacketFeedbackVector(std::vector<StreamPacketInfo> packet_feedback_vector)937*d9f75844SAndroid Build Coastguard Worker void RtpVideoSender::OnPacketFeedbackVector(
938*d9f75844SAndroid Build Coastguard Worker     std::vector<StreamPacketInfo> packet_feedback_vector) {
939*d9f75844SAndroid Build Coastguard Worker   if (fec_controller_->UseLossVectorMask()) {
940*d9f75844SAndroid Build Coastguard Worker     MutexLock lock(&mutex_);
941*d9f75844SAndroid Build Coastguard Worker     for (const StreamPacketInfo& packet : packet_feedback_vector) {
942*d9f75844SAndroid Build Coastguard Worker       loss_mask_vector_.push_back(!packet.received);
943*d9f75844SAndroid Build Coastguard Worker     }
944*d9f75844SAndroid Build Coastguard Worker   }
945*d9f75844SAndroid Build Coastguard Worker 
946*d9f75844SAndroid Build Coastguard Worker   // Map from SSRC to all acked packets for that RTP module.
947*d9f75844SAndroid Build Coastguard Worker   std::map<uint32_t, std::vector<uint16_t>> acked_packets_per_ssrc;
948*d9f75844SAndroid Build Coastguard Worker   for (const StreamPacketInfo& packet : packet_feedback_vector) {
949*d9f75844SAndroid Build Coastguard Worker     if (packet.received && packet.ssrc) {
950*d9f75844SAndroid Build Coastguard Worker       acked_packets_per_ssrc[*packet.ssrc].push_back(
951*d9f75844SAndroid Build Coastguard Worker           packet.rtp_sequence_number);
952*d9f75844SAndroid Build Coastguard Worker     }
953*d9f75844SAndroid Build Coastguard Worker   }
954*d9f75844SAndroid Build Coastguard Worker 
955*d9f75844SAndroid Build Coastguard Worker   // Map from SSRC to vector of RTP sequence numbers that are indicated as
956*d9f75844SAndroid Build Coastguard Worker   // lost by feedback, without being trailed by any received packets.
957*d9f75844SAndroid Build Coastguard Worker   std::map<uint32_t, std::vector<uint16_t>> early_loss_detected_per_ssrc;
958*d9f75844SAndroid Build Coastguard Worker 
959*d9f75844SAndroid Build Coastguard Worker   for (const StreamPacketInfo& packet : packet_feedback_vector) {
960*d9f75844SAndroid Build Coastguard Worker     // Only include new media packets, not retransmissions/padding/fec.
961*d9f75844SAndroid Build Coastguard Worker     if (!packet.received && packet.ssrc && !packet.is_retransmission) {
962*d9f75844SAndroid Build Coastguard Worker       // Last known lost packet, might not be detectable as lost by remote
963*d9f75844SAndroid Build Coastguard Worker       // jitter buffer.
964*d9f75844SAndroid Build Coastguard Worker       early_loss_detected_per_ssrc[*packet.ssrc].push_back(
965*d9f75844SAndroid Build Coastguard Worker           packet.rtp_sequence_number);
966*d9f75844SAndroid Build Coastguard Worker     } else {
967*d9f75844SAndroid Build Coastguard Worker       // Packet received, so any loss prior to this is already detectable.
968*d9f75844SAndroid Build Coastguard Worker       early_loss_detected_per_ssrc.erase(*packet.ssrc);
969*d9f75844SAndroid Build Coastguard Worker     }
970*d9f75844SAndroid Build Coastguard Worker   }
971*d9f75844SAndroid Build Coastguard Worker 
972*d9f75844SAndroid Build Coastguard Worker   for (const auto& kv : early_loss_detected_per_ssrc) {
973*d9f75844SAndroid Build Coastguard Worker     const uint32_t ssrc = kv.first;
974*d9f75844SAndroid Build Coastguard Worker     auto it = ssrc_to_rtp_module_.find(ssrc);
975*d9f75844SAndroid Build Coastguard Worker     RTC_CHECK(it != ssrc_to_rtp_module_.end());
976*d9f75844SAndroid Build Coastguard Worker     RTPSender* rtp_sender = it->second->RtpSender();
977*d9f75844SAndroid Build Coastguard Worker     for (uint16_t sequence_number : kv.second) {
978*d9f75844SAndroid Build Coastguard Worker       rtp_sender->ReSendPacket(sequence_number);
979*d9f75844SAndroid Build Coastguard Worker     }
980*d9f75844SAndroid Build Coastguard Worker   }
981*d9f75844SAndroid Build Coastguard Worker 
982*d9f75844SAndroid Build Coastguard Worker   for (const auto& kv : acked_packets_per_ssrc) {
983*d9f75844SAndroid Build Coastguard Worker     const uint32_t ssrc = kv.first;
984*d9f75844SAndroid Build Coastguard Worker     auto it = ssrc_to_rtp_module_.find(ssrc);
985*d9f75844SAndroid Build Coastguard Worker     if (it == ssrc_to_rtp_module_.end()) {
986*d9f75844SAndroid Build Coastguard Worker       // No media, likely FEC or padding. Ignore since there's no RTP history to
987*d9f75844SAndroid Build Coastguard Worker       // clean up anyway.
988*d9f75844SAndroid Build Coastguard Worker       continue;
989*d9f75844SAndroid Build Coastguard Worker     }
990*d9f75844SAndroid Build Coastguard Worker     rtc::ArrayView<const uint16_t> rtp_sequence_numbers(kv.second);
991*d9f75844SAndroid Build Coastguard Worker     it->second->OnPacketsAcknowledged(rtp_sequence_numbers);
992*d9f75844SAndroid Build Coastguard Worker   }
993*d9f75844SAndroid Build Coastguard Worker }
994*d9f75844SAndroid Build Coastguard Worker 
SetEncodingData(size_t width,size_t height,size_t num_temporal_layers)995*d9f75844SAndroid Build Coastguard Worker void RtpVideoSender::SetEncodingData(size_t width,
996*d9f75844SAndroid Build Coastguard Worker                                      size_t height,
997*d9f75844SAndroid Build Coastguard Worker                                      size_t num_temporal_layers) {
998*d9f75844SAndroid Build Coastguard Worker   fec_controller_->SetEncodingData(width, height, num_temporal_layers,
999*d9f75844SAndroid Build Coastguard Worker                                    rtp_config_.max_packet_size);
1000*d9f75844SAndroid Build Coastguard Worker }
1001*d9f75844SAndroid Build Coastguard Worker 
CalculateOverheadRate(DataRate data_rate,DataSize packet_size,DataSize overhead_per_packet,Frequency framerate) const1002*d9f75844SAndroid Build Coastguard Worker DataRate RtpVideoSender::CalculateOverheadRate(DataRate data_rate,
1003*d9f75844SAndroid Build Coastguard Worker                                                DataSize packet_size,
1004*d9f75844SAndroid Build Coastguard Worker                                                DataSize overhead_per_packet,
1005*d9f75844SAndroid Build Coastguard Worker                                                Frequency framerate) const {
1006*d9f75844SAndroid Build Coastguard Worker   Frequency packet_rate = data_rate / packet_size;
1007*d9f75844SAndroid Build Coastguard Worker   if (use_frame_rate_for_overhead_) {
1008*d9f75844SAndroid Build Coastguard Worker     framerate = std::max(framerate, Frequency::Hertz(1));
1009*d9f75844SAndroid Build Coastguard Worker     DataSize frame_size = data_rate / framerate;
1010*d9f75844SAndroid Build Coastguard Worker     int packets_per_frame = ceil(frame_size / packet_size);
1011*d9f75844SAndroid Build Coastguard Worker     packet_rate = packets_per_frame * framerate;
1012*d9f75844SAndroid Build Coastguard Worker   }
1013*d9f75844SAndroid Build Coastguard Worker   return packet_rate.RoundUpTo(Frequency::Hertz(1)) * overhead_per_packet;
1014*d9f75844SAndroid Build Coastguard Worker }
1015*d9f75844SAndroid Build Coastguard Worker 
1016*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
1017